File size: 9,608 Bytes
7bc796e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
import os
import logging
import base64
import json
import uuid
import google.generativeai as genai
from datetime import datetime
from functools import wraps
from flask import Flask, render_template, request, jsonify, session, redirect
from dotenv import load_dotenv
from werkzeug.utils import secure_filename

# Configure logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# Load environment variables
load_dotenv()

# Configure Google Gemini API
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
    logger.warning("GEMINI_API_KEY not found in environment variables")
else:
    logger.info("GEMINI_API_KEY found. API configured successfully.")

genai.configure(api_key=api_key)

# Initialize Flask app
app = Flask(__name__)
app.secret_key = os.environ.get("SESSION_SECRET", "default-dev-secret-key")
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024  # 10 MB max

# Middleware to ensure user has a session_id
def session_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'session_id' not in session:
            session['session_id'] = str(uuid.uuid4())
            logger.info(f"Created new session: {session['session_id']}")
        return f(*args, **kwargs)
    return decorated_function

# Ensure upload directory exists
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# Configure Gemini model with specific parameters for better responses
model = genai.GenerativeModel(
    model_name='gemini-2.0-flash',
    generation_config={
        'temperature': 0.7,  # Slightly creative but still focused
        'top_p': 0.9,        # Diverse output but not too random
        'top_k': 40,         # Reasonable range of tokens to consider
        'max_output_tokens': 2048  # Allow longer responses
    }
)

# Configure Gemini vision model for image processing
vision_model = genai.GenerativeModel('gemini-2.0-vision-flash')

@app.route('/')
@session_required
def index():
    """Render the chat interface."""
    return render_template('index.html')

@app.route('/api/chat', methods=['POST'])
@session_required
def chat():
    """Process chat messages and get responses from Gemini API."""
    try:
        data = request.json
        user_message = data.get('message', '')
        chat_history = data.get('history', [])
        image_data = data.get('image', None)
        
        if not user_message and not image_data:
            return jsonify({'error': 'Veuillez entrer un message ou joindre une image.'}), 400
        
        # Log the incoming request (but not full chat history for privacy)
        session_id = session.get('session_id')
        logger.info(f"Received chat request from session {session_id}. Message length: {len(user_message)}")
        
        # Format conversation history for context
        formatted_history = []
        for msg in chat_history[-15:]:  # Use the last 15 messages for more context
            role = "user" if msg['sender'] == 'user' else "model"
            formatted_history.append({"role": role, "parts": [msg['text']]})
        
        # Handle image processing if an image is included
        if image_data:
            try:
                # Process image with vision model
                image_base64 = image_data.split(',')[1]
                image = genai.types.Part.from_data(
                    data=base64.b64decode(image_base64),
                    mime_type="image/jpeg"
                )
                
                # Save image with timestamp in the session directory
                session_id = session.get('session_id')
                session_dir = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
                os.makedirs(session_dir, exist_ok=True)
                
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = secure_filename(f"image_{timestamp}.jpg")
                filepath = os.path.join(session_dir, filename)
                with open(filepath, "wb") as f:
                    f.write(base64.b64decode(image_base64))
                
                # Create message parts with both text and image
                parts = [image]
                if user_message:
                    parts.append(user_message)
                
                # Generate response using vision model
                response = vision_model.generate_content(parts)
                return jsonify({'response': response.text})
            
            except Exception as img_error:
                logger.error(f"Error processing image: {str(img_error)}")
                return jsonify({
                    'error': 'Désolé, une erreur est survenue lors du traitement de l\'image. Veuillez réessayer.'
                }), 500
        else:
            # Text-only processing
            # Create a chat session with history
            chat = model.start_chat(history=formatted_history)
            
            # Generate response
            response = chat.send_message(user_message)
            
            # Log successful response
            logger.info(f"Generated response successfully. Response length: {len(response.text)}")
            
            # Return the response
            return jsonify({'response': response.text})
    
    except genai.types.generation_types.BlockedPromptException as be:
        logger.warning(f"Content blocked: {str(be)}")
        return jsonify({
            'error': 'Votre message ou la conversation ne peut pas être traitée car elle contient du contenu potentiellement inapproprié.'
        }), 400
        
    except Exception as e:
        logger.error(f"Error in chat endpoint: {str(e)}")
        return jsonify({
            'error': 'Désolé, j\'ai rencontré une erreur lors du traitement de votre demande. Veuillez réessayer.'
        }), 500

@app.route('/api/save-chat', methods=['POST'])
@session_required
def save_chat():
    """Save the current chat history."""
    try:
        session_id = session.get('session_id')
        
        # Create session-specific directory
        session_dir = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
        os.makedirs(session_dir, exist_ok=True)
        
        data = request.json
        chat_history = data.get('history', [])
        
        if not chat_history:
            return jsonify({'error': 'Aucune conversation à sauvegarder.'}), 400
        
        # Generate filename with timestamp
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"chat_{timestamp}.json"
        filepath = os.path.join(session_dir, filename)
        
        # Save chat history to file
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(chat_history, f, ensure_ascii=False, indent=2)
        
        return jsonify({'success': True, 'filename': filename})
    
    except Exception as e:
        logger.error(f"Error saving chat: {str(e)}")
        return jsonify({
            'error': 'Désolé, une erreur est survenue lors de la sauvegarde de la conversation.'
        }), 500

@app.route('/api/load-chats', methods=['GET'])
@session_required
def load_chats():
    """Get a list of saved chat files for current session."""
    try:
        session_id = session.get('session_id')
        
        # Get session-specific directory
        session_dir = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
        
        # If the directory doesn't exist yet, return empty list
        if not os.path.exists(session_dir):
            return jsonify({'chats': []})
        
        chat_files = []
        for filename in os.listdir(session_dir):
            if filename.startswith('chat_') and filename.endswith('.json'):
                # Extract timestamp from filename
                timestamp = filename[5:-5]  # Remove 'chat_' and '.json'
                # Add to list
                chat_files.append({
                    'filename': filename,
                    'timestamp': timestamp
                })
        
        # Sort by timestamp (newest first)
        chat_files.sort(key=lambda x: x['timestamp'], reverse=True)
        
        logger.info(f"Loaded {len(chat_files)} chats for session {session_id}")
        return jsonify({'chats': chat_files})
    
    except Exception as e:
        logger.error(f"Error loading chat list: {str(e)}")
        return jsonify({
            'error': 'Désolé, une erreur est survenue lors du chargement des conversations.'
        }), 500

@app.route('/api/load-chat/<filename>', methods=['GET'])
@session_required
def load_chat(filename):
    """Load a specific chat history file."""
    try:
        session_id = session.get('session_id')
        
        # Load from session-specific directory
        session_dir = os.path.join(app.config['UPLOAD_FOLDER'], session_id)
        filepath = os.path.join(session_dir, secure_filename(filename))
        
        if not os.path.exists(filepath):
            return jsonify({'error': 'Conversation introuvable.'}), 404
        
        with open(filepath, 'r', encoding='utf-8') as f:
            chat_history = json.load(f)
        
        logger.info(f"Loaded chat {filename} for session {session_id}")
        return jsonify({'history': chat_history})
    
    except Exception as e:
        logger.error(f"Error loading chat file: {str(e)}")
        return jsonify({
            'error': 'Désolé, une erreur est survenue lors du chargement de la conversation.'
        }), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)