Chatm / app.py
Docfile's picture
Update app.py
4979ae3 verified
raw
history blame
8.69 kB
from flask import Flask, render_template, request, jsonify, session
import google.generativeai as genai
import os
from dotenv import load_dotenv
import http.client
import json
from werkzeug.utils import secure_filename
import tempfile
from datetime import datetime
import uuid
from pathlib import Path
app = Flask(__name__)
app.secret_key = os.urandom(24)
load_dotenv()
# Configuration des dossiers
UPLOAD_FOLDER = Path('uploads')
TEMP_FOLDER = Path('temp')
UPLOAD_FOLDER.mkdir(exist_ok=True)
TEMP_FOLDER.mkdir(exist_ok=True)
# Configuration de Google AI
genai.configure(api_key=os.getenv("GOOGLE_API_KEY"))
# Paramètres de sécurité
safety_settings = [
{"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
{"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
]
# Prompt système
SYSTEM_PROMPT = """
Tu es Mariam, une assistante IA créée par Youssouf. Tu es serviable, polie et tu t'exprimes en français.
Tu dois toujours :
- Répondre en français
- Être précise et concise dans tes réponses
- Utiliser un ton professionnel mais amical
- Proposer des solutions pratiques aux problèmes
- Demander des clarifications si nécessaire
"""
# Initialisation du modèle Gemini
model = genai.GenerativeModel('gemini-pro',
safety_settings=safety_settings)
# Stockage des conversations
conversations = {}
chat_sessions = {}
# Extensions de fichiers autorisées
ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'pdf', 'txt', 'doc', 'docx'}
def allowed_file(filename):
"""Vérifie si l'extension du fichier est autorisée"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def perform_web_search(query):
"""Effectue une recherche web via l'API Serper"""
conn = http.client.HTTPSConnection("google.serper.dev")
payload = json.dumps({"q": query})
headers = {
'X-API-KEY': os.getenv('SERPER_API_KEY'),
'Content-Type': 'application/json'
}
try:
conn.request("POST", "/search", payload, headers)
res = conn.getresponse()
data = json.loads(res.read().decode("utf-8"))
return data
except Exception as e:
print(f"Erreur de recherche web: {e}")
return None
finally:
conn.close()
def format_search_results(data):
"""Formate les résultats de recherche"""
if not data:
return "Aucun résultat trouvé"
formatted_results = []
# Traitement du Knowledge Graph
if 'knowledgeGraph' in data:
kg = data['knowledgeGraph']
formatted_results.append(f"### {kg.get('title', '')}")
if 'description' in kg:
formatted_results.append(f"{kg['description']}\n")
# Traitement des résultats organiques
if 'organic' in data:
formatted_results.append("### Résultats de recherche:")
for item in data['organic'][:3]: # Limite aux 3 premiers résultats
formatted_results.append(f"- **{item['title']}**")
formatted_results.append(f" {item['snippet']}\n")
return "\n".join(formatted_results)
def create_new_conversation():
"""Crée une nouvelle conversation"""
conversation_id = str(uuid.uuid4())
conversations[conversation_id] = {
'id': conversation_id,
'created_at': datetime.now().isoformat(),
'messages': []
}
chat_sessions[conversation_id] = model.start_chat(history=[])
return conversation_id
@app.route('/')
def home():
"""Page d'accueil"""
if 'user_id' not in session:
session['user_id'] = str(uuid.uuid4())
return render_template('index.html')
@app.route('/conversations', methods=['GET'])
def get_conversations():
"""Récupère la liste des conversations"""
user_conversations = [
{
'id': conv_id,
'created_at': conv['created_at'],
'preview': conv['messages'][0]['content'][:50] + '...' if conv['messages'] else 'Nouvelle conversation'
}
for conv_id, conv in conversations.items()
]
return jsonify(user_conversations)
@app.route('/conversation', methods=['POST'])
def create_conversation():
"""Crée une nouvelle conversation"""
conversation_id = create_new_conversation()
return jsonify({
'id': conversation_id,
'created_at': conversations[conversation_id]['created_at']
})
@app.route('/conversation/<conversation_id>', methods=['GET'])
def get_conversation(conversation_id):
"""Récupère une conversation spécifique"""
if conversation_id not in conversations:
return jsonify({'error': 'Conversation non trouvée'}), 404
return jsonify(conversations[conversation_id])
@app.route('/send_message', methods=['POST'])
def send_message():
"""Traite l'envoi d'un message"""
try:
data = request.json
message = data.get('message')
conversation_id = data.get('conversation_id')
web_search = data.get('web_search', False)
if not message:
return jsonify({'error': 'Message manquant'}), 400
# Crée une nouvelle conversation si nécessaire
if not conversation_id or conversation_id not in conversations:
conversation_id = create_new_conversation()
# Effectue une recherche web si activée
search_results = ""
if web_search:
results = perform_web_search(message)
if results:
search_results = format_search_results(results)
message = f"{message}\n\nContexte de recherche web:\n{search_results}"
# Envoie le message au modèle
response = chat_sessions[conversation_id].send_message(message)
# Enregistre les messages
conversations[conversation_id]['messages'].append({
'role': 'user',
'content': message,
'timestamp': datetime.now().isoformat()
})
conversations[conversation_id]['messages'].append({
'role': 'assistant',
'content': response.text,
'timestamp': datetime.now().isoformat()
})
return jsonify({
'conversation_id': conversation_id,
'response': response.text
})
except Exception as e:
print(f"Erreur lors de l'envoi du message: {e}")
return jsonify({'error': str(e)}), 500
@app.route('/upload', methods=['POST'])
def upload_file():
"""Gère l'upload de fichiers"""
if 'file' not in request.files:
return jsonify({'error': 'Aucun fichier fourni'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'Nom de fichier vide'}), 400
if file and allowed_file(file.filename):
try:
# Sécurise le nom du fichier
filename = secure_filename(file.filename)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
safe_filename = f"{timestamp}_{filename}"
# Sauvegarde le fichier
filepath = UPLOAD_FOLDER / safe_filename
file.save(filepath)
return jsonify({
'success': True,
'filename': safe_filename,
'message': 'Fichier uploadé avec succès'
})
except Exception as e:
return jsonify({'error': f'Erreur lors de l\'upload: {str(e)}'}), 500
return jsonify({'error': 'Type de fichier non autorisé'}), 400
@app.route('/clear_chat', methods=['POST'])
def clear_chat():
"""Efface une conversation"""
data = request.json
conversation_id = data.get('conversation_id')
if conversation_id:
if conversation_id in conversations:
del conversations[conversation_id]
if conversation_id in chat_sessions:
del chat_sessions[conversation_id]
return jsonify({'success': True})
@app.route('/download/<filename>')
def download_file(filename):
"""Télécharge un fichier"""
try:
return send_from_directory(UPLOAD_FOLDER, filename, as_attachment=True)
except Exception as e:
return jsonify({'error': f'Erreur lors du téléchargement: {str(e)}'}), 500
@app.errorhandler(404)
def not_found_error(error):
"""Gère les erreurs 404"""
return jsonify({'error': 'Page non trouvée'}), 404
@app.errorhandler(500)
def internal_error(error):
"""Gère les erreurs 500"""
return jsonify({'error': 'Erreur interne du serveur'}), 500
if __name__ == '__main__':
app.run(debug=True)