Mariam-france / app.py
Docfile's picture
Update app.py
923bcb0 verified
raw
history blame
10.2 kB
from flask import Flask, render_template, request, Response
from google import genai
from google.genai import types
import os
import logging
import json
load_prompt ="""
Tu es yn professeur expérimenté en langue française.
# Instruction pour travail argumentatif de français niveau lycée
## Paramètres d'entrée attendus :
- `sujet` : La question/thème à traiter
- `choix` : Type de travail ("discuter", "dissertation", "étayer", "réfuter")
- `style` : Style d'écriture souhaité (ex: "raffiné")
## Traitement automatique selon le type :
### Si choix = "discuter" :
Produire un travail argumentatif suivant cette méthodologie :
**INTRODUCTION:**
- Approche par constat
- Problématique
- Annonce du plan
**DÉVELOPPEMENT:**
*Partie 1 : Thèse*
- Introduction partielle (énonce la thèse)
- Argument 1: Explications + Illustration (exemple + explication)
- Argument 2: Explications + Illustration (exemple + explication)
- Argument 3: Explications + Illustration (exemple + explication)
*Phrase de transition vers la deuxième partie*
*Partie 2 : Antithèse*
- Introduction partielle (énonce l'antithèse)
- Argument 1: Explications + Illustration (exemple + explication)
- Argument 2: Explications + Illustration (exemple + explication)
- Argument 3: Explications + Illustration (exemple + explication)
**CONCLUSION:**
- Bilan (Synthèse des arguments pour et contre)
- Ouverture du sujet (sous forme de phrase interrogative)
### Si choix = "dissertation" :
Produire une dissertation suivant cette méthodologie :
**Phase 1 : L'Introduction (en un seul paragraphe)**
- Amorce : Introduire le thème général
- Position du Sujet : Présenter l'auteur/œuvre, citer et reformuler le sujet
- Problématique : Poser la question centrale dialectique
- Annonce du Plan : Annoncer thèse et antithèse
**Phase 2 : Le Développement (en trois parties distinctes)**
*Partie 1 : La Thèse*
- Explorer et justifier l'affirmation initiale
- 2-3 arguments (structure A.I.E : Affirmation-Illustration-Explication)
- Exemples littéraires précis et analysés
*Partie 2 : L'Antithèse*
- Nuancer, critiquer ou présenter le point de vue opposé
- 2-3 arguments (structure A.I.E)
- Transition cruciale depuis la thèse
- Exemples littéraires précis et analysés
*Partie 3 : La Synthèse*
- Dépasser l'opposition thèse/antithèse
- Nouvelle perspective intégrant les éléments valides
- 2-3 arguments (structure A.I.E)
- Transition depuis l'antithèse
- Exemples littéraires précis et analysés
**Phase 3 : La Conclusion (en un seul paragraphe)**
- Bilan synthétique du parcours dialectique
- Réponse claire à la problématique
- Ouverture vers contexte plus large
### Si choix = "étayer" ou "réfuter" :
Produire un travail argumentatif suivant cette méthodologie :
**INTRODUCTION:**
- Approche par constat
- Problématique
- Annonce du plan
**DÉVELOPPEMENT:**
- Phrase chapeau (énonce la thèse principale : pour étayer ou contre pour réfuter)
- Argument 1: Explications + Illustration (exemple + explication)
- Argument 2: Explications + Illustration (exemple + explication)
- Argument 3: Explications + Illustration (exemple + explication)
**CONCLUSION:**
- Bilan (rappel de la thèse + arguments principaux)
- Ouverture du sujet (sous forme de phrase interrogative)
## Application du style :
Adapter l'écriture selon le style demandé (ex: "raffiné" = vocabulaire soutenu, syntaxe élaborée, références culturelles).
## Exemple de traitement :
**Entrée :** `sujet='L'homme est inoffensif', choix='étayer', style='raffiné'`
**Action :** Générer un travail argumentatif défendant la thèse "L'homme est inoffensif" avec un style raffiné, suivant la méthodologie "étayer".
"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
app = Flask(__name__)
token = os.environ.get("TOKEN")
client = genai.Client(api_key=token)
default_generation_config = types.GenerateContentConfig(
temperature=1,
)
STANDARD_MODEL_NAME = "gemini-2.5-flash"
DEEPTHINK_MODEL_NAME = "gemini-2.5-pro"
# Page d'accueil
@app.route('/')
def index():
logging.info("Page index demandée.")
return render_template('index.html')
# API pour génération française
@app.route('/api/francais', methods=['POST', 'GET'])
def gpt_francais():
logging.info(f"Requête {request.method} reçue sur /api/francais")
french_prompt = request.args.get('sujet', '').strip()
choix = request.args.get('choix', '').strip()
style = request.args.get('style', '').strip()
use_deepthink = request.args.get('use_deepthink', 'false').lower() == 'true'
logging.info(
f"Données reçues : sujet='{french_prompt[:50]}', choix='{choix}', style='{style}', deepthink={use_deepthink}"
)
if not french_prompt:
logging.warning("Sujet vide, retour erreur.")
return Response(
"data: " + json.dumps({'type': 'error', 'content': 'Erreur: Le sujet ne peut pas être vide.'}) + "\n\n",
mimetype='text/event-stream'
), 400
model_to_use = DEEPTHINK_MODEL_NAME if use_deepthink else STANDARD_MODEL_NAME
logging.info(f"Modèle utilisé : {model_to_use}")
try:
system_instruction = load_prompt()
except Exception as e:
logging.exception("Erreur lors du chargement du prompt système.")
system_instruction = "Tu es un assistant spécialisé en français."
user_prompt = f"Sujet: {french_prompt}\nType: {choix}\nStyle: {style}"
config = types.GenerateContentConfig(
system_instruction=system_instruction,
temperature=1
)
if use_deepthink:
config.thinking_config = types.ThinkingConfig(include_thoughts=True)
def generate_stream():
try:
logging.info("Démarrage du streaming de génération...")
thoughts = ""
answer = ""
for chunk in client.models.generate_content_stream(
model=model_to_use,
contents=[user_prompt],
config=config
):
for part in chunk.candidates[0].content.parts:
if not part.text:
continue
elif hasattr(part, 'thought') and part.thought:
if not thoughts:
logging.info("Premiers éléments de réflexion envoyés.")
yield "data: " + json.dumps({'type': 'thoughts_start'}) + "\n\n"
thoughts += part.text
yield "data: " + json.dumps({'type': 'thought', 'content': part.text}) + "\n\n"
else:
if not answer:
logging.info("Premiers éléments de réponse envoyés.")
yield "data: " + json.dumps({'type': 'answer_start'}) + "\n\n"
answer += part.text
yield "data: " + json.dumps({'type': 'answer', 'content': part.text}) + "\n\n"
logging.info("Fin du streaming de génération.")
yield "data: " + json.dumps({'type': 'done'}) + "\n\n"
except Exception:
logging.exception("Erreur pendant la génération de contenu.")
yield "data: " + json.dumps({'type': 'error', 'content': 'Erreur serveur pendant la génération.'}) + "\n\n"
return Response(generate_stream(), mimetype='text/event-stream')
# API pour analyse de texte à partir d'images
@app.route('/api/etude-texte', methods=['POST', 'GET'])
def gpt_francais_cc():
logging.info("Requête reçue sur /api/etude-texte")
if 'images' not in request.files:
logging.warning("Aucun fichier image reçu.")
return Response(
"data: " + json.dumps({'type': 'error', 'content': 'Aucun fichier image envoyé.'}) + "\n\n",
mimetype='text/event-stream'
), 400
images = request.files.getlist('images')
if not images or not images[0].filename:
logging.warning("Liste d'images vide.")
return Response(
"data: " + json.dumps({'type': 'error', 'content': 'Aucune image sélectionnée.'}) + "\n\n",
mimetype='text/event-stream'
), 400
def generate_image_analysis():
try:
logging.info(f"Nombre d'images reçues : {len(images)}")
system_instruction = "Tu es un assistant spécialisé dans l'analyse de textes et de documents. réponds strictement aux questions."
content = ["Réponds aux questions présentes dans les images."]
for img in images:
if img.filename:
logging.info(f"Traitement image : {img.filename}")
img_data = img.read()
img_part = types.Part.from_bytes(
data=img_data,
mime_type=img.content_type or 'image/jpeg'
)
content.append(img_part)
config = types.GenerateContentConfig(
system_instruction=system_instruction,
temperature=0.7,
max_output_tokens=4096
)
logging.info("Démarrage du streaming d'analyse d'image...")
for chunk in client.models.generate_content_stream(
model=STANDARD_MODEL_NAME,
contents=content,
config=config
):
for part in chunk.candidates[0].content.parts:
if part.text:
yield "data: " + json.dumps({'type': 'content', 'content': part.text}) + "\n\n"
logging.info("Fin du streaming d'analyse d'image.")
yield "data: " + json.dumps({'type': 'done'}) + "\n\n"
except Exception:
logging.exception("Erreur pendant l'analyse d'image.")
yield "data: " + json.dumps({'type': 'error', 'content': "Erreur serveur pendant l'analyse de l'image."}) + "\n\n"
return Response(generate_image_analysis(), mimetype='text/event-stream')
if __name__ == '__main__':
logging.info("Démarrage du serveur Flask avec Gemini SDK...")
app.run(debug=True)