Docfile commited on
Commit
39019f1
·
verified ·
1 Parent(s): 054d99e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -232
app.py CHANGED
@@ -1,45 +1,33 @@
1
- from flask import Flask, render_template, request, jsonify
2
- import google.generativeai as genai
3
- from google.generativeai import types
4
  import os
5
  from PIL import Image
6
  import io
7
  import logging
 
 
 
 
8
 
9
  # Configuration du logging
10
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
 
12
  app = Flask(__name__)
13
 
14
- # Configuration de l'API Gemini
15
  token = os.environ.get("TOKEN")
16
- genai.configure(api_key=token)
17
-
18
- generation_config = {
19
- "temperature": 1,
20
- "max_output_tokens": 8192,
21
- }
22
 
23
- safety_settings = [
24
- {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
25
- {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
26
- {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
27
- {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
28
- ]
29
 
30
  # Define model names
31
- STANDARD_MODEL_NAME = "gemini-2.5-flash-preview-05-20" # Using latest flash
32
- # MODIFICATION: Utilisation du nom de modèle Pro spécifié (attention: peut être expérimental/non disponible)
33
- DEEPTHINK_MODEL_NAME = "gemini-2.5-flash-preview-05-20" # Using stable latest Pro model is generally safer
34
- # DEEPTHINK_MODEL_NAME = "models/gemini-1.5-pro-exp-0325" # Si vous voulez absolument tester ce modèle expérimental spécifique
35
- # Note: Les noms de modèles expérimentaux peuvent nécessiter un préfixe "models/"
36
-
37
- # Default model instance (used for etude-texte)
38
- default_model = genai.GenerativeModel(
39
- model_name=STANDARD_MODEL_NAME,
40
- generation_config=generation_config,
41
- safety_settings=safety_settings
42
- )
43
 
44
  @app.route('/')
45
  def index():
@@ -48,12 +36,11 @@ def index():
48
 
49
  @app.route('/api/francais', methods=['POST'])
50
  def gpt_francais():
51
- """Handles French questions with optional DeepThink model."""
52
  logging.info("Received request at /api/francais")
53
  french_prompt = request.form.get('sujet', '').strip()
54
  choix = request.form.get('choix', '').strip()
55
  style = request.form.get('style', '').strip()
56
- # MODIFICATION: Lire le nouveau paramètre 'use_deepthink'
57
  use_deepthink_str = request.form.get('use_deepthink', 'false')
58
  use_deepthink = use_deepthink_str.lower() == 'true'
59
 
@@ -61,221 +48,137 @@ def gpt_francais():
61
 
62
  if not french_prompt:
63
  logging.warning("French prompt is empty.")
64
- return jsonify({"output": "Veuillez saisir un thème."}), 400
65
-
66
- # MODIFICATION: Sélectionner le nom du modèle basé sur use_deepthink
67
- model_to_use_name = DEEPTHINK_MODEL_NAME if use_deepthink else STANDARD_MODEL_NAME
68
- logging.info(f"Using model: {model_to_use_name}") # Log for debugging
69
-
70
- # Le reste de la logique de construction du prompt reste identique...
71
- if choix == "discuter":
72
- prompt = f""" Je veux faire mon travail de français de niveau lycée sous la forme d'un travail argumentatif.
73
- La question du travail est la suivante : "{french_prompt}". Tu devras discuter ce thème.
74
- tu utiliseras la méthodologie suivante :
75
-
76
- # INTRODUCTION:
77
- - Approche par constat
78
- - Problématique
79
- - Annonce du plan
80
-
81
- # DÉVELOPPEMENT:
82
- ## Partie 1 : Thèse
83
- - Introduction partielle (énonce la thèse)
84
- - Argument 1:
85
- * Explications
86
- * Illustration (exemple + explication)
87
- - Argument 2:
88
- * Explications
89
- * Illustration (exemple + explication)
90
- - Argument 3:
91
- * Explications
92
- * Illustration (exemple + explication)
93
-
94
- # phrase de Transiton vers la deuxieme partie :
95
-
96
- ## Partie 2 : Antithèse
97
- - Introduction partielle (énonce l'antithèse)
98
- - Argument 1:
99
- * Explications
100
- * Illustration (exemple + explication)
101
- - Argument 2:
102
- * Explications
103
- * Illustration (exemple + explication)
104
- - Argument 3:
105
- * Explications
106
- * Illustration (exemple + explication)
107
-
108
- #Conclusion
109
- * Bilan (Synthèse des arguments pour et contre)
110
- * Ouverture du sujet (sous forme de phrase interrogative )
111
-
112
- Je veux que tu utilises un style d'écriture {style}."""
113
-
114
- elif choix == "dissertation":
115
- prompt = f""" Je veux faire mon travail de français de niveau lycée sous la forme d'une dissertation.
116
- La question du travail est la suivante : "{french_prompt}". Tu devras traiter ce sujet de manière approfondie.
117
- tu utiliseras la méthodologie suivante :
118
-
119
-
120
-
121
- Présentation Globale de la Méthodologie de Dissertation.
122
-
123
- Phase 1 : L'Introduction (en un seul paragraphe)
124
-
125
- Amorce : Introduire le thème général lié au sujet.
126
-
127
- Position du Sujet : Présenter l'auteur/œuvre (si pertinent), citer le sujet exact, et le reformuler pour montrer votre compréhension. C'est la Thèse initiale qui sera discutée.
128
-
129
- Problématique : Poser la question centrale (ou les questions) que soulève cette thèse et qui guidera la discussion dialectique (Ex : Dans quelle mesure [Thèse] est-elle valide ? Ne faut-il pas considérer également [Antithèse] ? Comment dépasser cette opposition ?).
130
-
131
- Annonce du Plan : Annoncer clairement les étapes thèse et antithèse :
132
-
133
- L'analyse qui soutient la thèse (Ex : "Nous examinerons d'abord la pertinence de l'affirmation selon laquelle...") [Annonce Thèse].
134
-
135
- L'analyse qui nuance ou contredit la thèse (Ex : "...avant de considérer les limites de ce point de vue en montrant que...") [Annonce Antithèse].
136
-
137
-
138
- Phase 2 : Le Développement (en trois grandes parties distinctes)
139
-
140
- Chaque partie est séparée par un saut de ligne et idéalement introduite par une courte transition. Chaque partie contient plusieurs paragraphes argumentatifs (structure A.I.E : Affirmation - Illustration/Exemple - Explication).
141
-
142
- Partie 1 : La Thèse
143
-
144
- Objectif : Explorer et justifier l'affirmation initiale du sujet. Vous défendez l'idée présentée.
145
-
146
- Contenu : Développer 2 ou 3 arguments (chacun dans un paragraphe A.I.E) qui soutiennent la thèse, illustrés par des exemples littéraires précis et analysés.
147
-
148
- Partie 2 : L'Antithèse
149
-
150
- Objectif : Nuancer, critiquer, ou présenter le point de vue opposé à la thèse. Vous montrez les limites ou les contradictions de l'idée initiale.
151
-
152
- Contenu : Développer 2 ou 3 arguments (chacun dans un paragraphe A.I.E) qui s'opposent à la thèse ou la nuancent fortement, toujours illustrés par des exemples littéraires précis et analysés.
153
 
154
- Transition : Une phrase liant la Thèse à l'Antithèse est cruciale (Ex : "Cependant, cette vision mérite d'être nuancée...", "Toutefois, limiter [Thème] à [Thèse] serait réducteur...").
155
-
156
- Partie 3 : La Synthèse
157
-
158
- Objectif : Dépasser l'opposition entre la Thèse et l'Antithèse. Ce n'est PAS un simple résumé ni un compromis faible. C'est une nouvelle perspective, plus riche et nuancée, qui intègre les éléments valides des deux premières parties tout en les transcendant.
159
-
160
- Contenu :
161
-
162
- Reconnaître la complexité du problème.
163
-
164
- Proposer une idée nouvelle qui réconcilie les aspects contradictoires, ou montre que la vérité réside dans la tension elle-même, ou redéfinit le problème, ou introduit une condition/contexte.
165
-
166
- Développer 2 ou 3 arguments (chacun dans un paragraphe A.I.E) soutenant cette nouvelle perspective de dépassement, illustrés par des exemples littéraires précis et analysés.
167
-
168
- Transition : Une phrase liant l'Antithèse à la Synthèse est importante (Ex : "Face à cette opposition, il convient de proposer une perspective qui...", "Pour dépasser cette contradiction, on peut considérer que...").
169
-
170
- Phase 3 : La Conclusion (en un seul paragraphe)
171
-
172
- Bilan Synthétique : Résumer très brièvement les étapes clés de votre parcours dialectique (les conclusions principales de la Thèse, de l'Antithèse, et surtout de la Synthèse).
173
-
174
- Réponse Claire à la Problématique : Fournir une réponse finale, nuancée (souvent issue de votre synthèse), à la question posée en introduction.
175
-
176
- Ouverture : Élargir la réflexion en reliant le sujet à un contexte plus large (autre art, autre époque, question philosophique, actualité pertinente) sans relancer un nouveau débat.
177
-
178
- En Bref : Le plan dialectique vous demande d'examiner une idée (Thèse), de considérer son contraire ou ses limites (Antithèse), puis de construire une réflexion supérieure qui dépasse cette opposition (Synthèse), le tout étant encadré par une introduction qui pose le débat et une conclusion qui le résout de manière nuancée. La Synthèse est donc la partie la plus créative et réflexive du développement, où vous montrez votre capacité à résoudre une tension intellectuelle.
179
-
180
-
181
- Principes Transversaux :
182
-
183
- Cohérence : L'introduction, le développement et la conclusion doivent être parfaitement alignés. Le plan annoncé doit être suivi.
184
-
185
- Argumentation et Preuves : La dissertation est une démonstration. Chaque affirmation doit être soutenue par des arguments logiques et des exemples littéraires précis et analysés.
186
-
187
- Clarté et Précision : Utilisez un langage clair, un vocabulaire littéraire approprié. Soyez précis dans vos références.
188
-
189
- Focus sur la Problématique : Gardez toujours à l'esprit la question centrale et assurez-vous que chaque partie de votre devoir y contribue.
190
-
191
-
192
-
193
-
194
- Je veux que tu utilises un style d'écriture {style}."""
195
-
196
- else: # Cas pour "Etaye" et "refute"
197
- prompt = f"""Je veux faire mon travail de français de niveau lycée sous la forme d'un travail argumentatif.
198
- La question du travail est la suivante : "{french_prompt}". Tu devras {choix} ce thème.
199
- tu utiliseras la méthodologie suivante :
200
-
201
- # INTRODUCTION:
202
- - Approche par constat
203
- - Problématique
204
- - Annonce du plan
205
-
206
- # DÉVELOPPEMENT:
207
- - Phrase chapeau (énonce la thèse principale : pour étayer ou contre pour réfuter)
208
- - Argument 1:
209
- * Explications
210
- * Illustration (exemple + explication)
211
- - Argument 2:
212
- * Explications
213
- * Illustration (exemple + explication)
214
- - Argument 3:
215
- * Explications
216
- * Illustration (exemple + explication)
217
-
218
- #Conclusion
219
- * Bilan (rappel de la thèse + arguments principaux)
220
- * Ouverture du sujet ( sous forme de phrase interrogative )
221
-
222
- Je veux que tu utilises un style d'écriture {style}."""
223
 
 
224
  try:
225
- # MODIFICATION: Instancier le modèle spécifique pour cette requête
226
- # Utiliser les mêmes configurations que le modèle par défaut
227
- logging.info(f"Creating GenerativeModel instance with model name: {model_to_use_name}")
228
- selected_model = genai.GenerativeModel(
229
- model_name=model_to_use_name,
230
- generation_config=generation_config,
231
- safety_settings=safety_settings
232
- )
233
- logging.info("Generating content...")
234
- response = selected_model.generate_content(prompt)
235
- logging.info("Content generated successfully.")
236
- return jsonify({"output": response.text}), 200
237
  except Exception as e:
238
- # Log l'erreur pour le débogage côté serveur
239
- logging.exception(f"Error generating content with model {model_to_use_name}: {e}")
240
- # Retourne un message d'erreur générique à l'utilisateur
241
- # Vérifier si l'erreur est due à un modèle invalide/non disponible
242
- if "model" in str(e).lower() and "not found" in str(e).lower():
243
- logging.error(f"Model '{model_to_use_name}' not found.")
244
- return jsonify({"output": f"Erreur: Le modèle '{model_to_use_name}' n'est pas accessible ou n'existe pas. Essayez sans l'option DeepThink."}), 500
245
- logging.error(f"Internal error occurred: {e}")
246
- return jsonify({"output":"Une erreur interne est survenue lors de la génération du contenu. Veuillez réessayer."}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
 
249
  @app.route('/api/etude-texte', methods=['POST'])
250
  def gpt_francais_cc():
 
251
  if 'images' not in request.files:
252
- return jsonify({"output": "Aucune image n'a été téléchargée."}), 400
 
253
 
254
  images = request.files.getlist('images')
255
  if not images:
256
- return jsonify({"output": "Aucune image sélectionnée."}), 400
257
-
258
- prompt = "réponds aux questions présentes."
259
-
260
- try:
261
- # Préparer les images pour Gemini
262
- content = [prompt]
263
- for image in images:
264
- if image.filename:
265
- img_data = image.read()
266
- img = Image.open(io.BytesIO(img_data))
267
- content.append(img)
268
-
269
- # Générer la réponse
270
- response = default_model.generate_content(content)
271
- return jsonify({"output": response.text}), 200
272
-
273
- except Exception as e:
274
- return jsonify({"output": "Erreur lors de l'analyse des images."}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
 
277
  if __name__ == '__main__':
278
- # Désactiver le reloader Flask si vous avez des problèmes avec les instances multiples de modèle ou la mémoire
279
- # app.run(debug=True, use_reloader=False)
280
- logging.info("Starting the Flask app...")
281
  app.run(debug=True)
 
1
+ from flask import Flask, render_template, request, jsonify, Response
2
+ from google import genai
3
+ from google.genai import types
4
  import os
5
  from PIL import Image
6
  import io
7
  import logging
8
+ import json
9
+
10
+ def load_prompt():
11
+ return " fais une dissertation "
12
 
13
  # Configuration du logging
14
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
15
 
16
  app = Flask(__name__)
17
 
18
+ # Configuration du client Gemini
19
  token = os.environ.get("TOKEN")
20
+ client = genai.Client(api_key=token)
 
 
 
 
 
21
 
22
+ # Configuration de génération par défaut
23
+ default_generation_config = types.GenerateContentConfig(
24
+ temperature=1,
25
+ max_output_tokens=8192
26
+ )
 
27
 
28
  # Define model names
29
+ STANDARD_MODEL_NAME = "gemini-2.5-flash"
30
+ DEEPTHINK_MODEL_NAME = "gemini-2.5-pro"
 
 
 
 
 
 
 
 
 
 
31
 
32
  @app.route('/')
33
  def index():
 
36
 
37
  @app.route('/api/francais', methods=['POST'])
38
  def gpt_francais():
39
+ """Handles French questions with streaming enabled by default."""
40
  logging.info("Received request at /api/francais")
41
  french_prompt = request.form.get('sujet', '').strip()
42
  choix = request.form.get('choix', '').strip()
43
  style = request.form.get('style', '').strip()
 
44
  use_deepthink_str = request.form.get('use_deepthink', 'false')
45
  use_deepthink = use_deepthink_str.lower() == 'true'
46
 
 
48
 
49
  if not french_prompt:
50
  logging.warning("French prompt is empty.")
51
+ return Response(f"data: {json.dumps({'type': 'error', 'content': 'Veuillez saisir un thème.'})}\n\n",
52
+ mimetype='text/event-stream'), 400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
+ # Sélectionner le modèle
55
+ model_to_use = DEEPTHINK_MODEL_NAME if use_deepthink else STANDARD_MODEL_NAME
56
+ logging.info(f"Using model: {model_to_use}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ # Charger l'instruction système
59
  try:
60
+ system_instruction = load_prompt("français")
 
 
 
 
 
 
 
 
 
 
 
61
  except Exception as e:
62
+ logging.error(f"Error loading system prompt: {e}")
63
+ system_instruction = "Tu es un assistant spécialisé en français."
64
+
65
+ # Construire le prompt utilisateur basé sur les paramètres
66
+ user_prompt = f"Sujet: {french_prompt}\nType: {choix}\nStyle: {style}"
67
+
68
+ # Configuration pour cette requête
69
+ config = types.GenerateContentConfig(
70
+ system_instruction=system_instruction,
71
+ temperature=1,
72
+ max_output_tokens=8192
73
+ )
74
+
75
+ # Ajouter la configuration de pensée pour DeepThink
76
+ if use_deepthink:
77
+ config.thinking_config = types.ThinkingConfig(
78
+ include_thoughts=True
79
+ )
80
+
81
+ def generate_stream():
82
+ try:
83
+ thoughts = ""
84
+ answer = ""
85
+
86
+ for chunk in client.models.generate_content_stream(
87
+ model=model_to_use,
88
+ contents=[user_prompt],
89
+ config=config
90
+ ):
91
+ for part in chunk.candidates[0].content.parts:
92
+ if not part.text:
93
+ continue
94
+ elif hasattr(part, 'thought') and part.thought:
95
+ if not thoughts:
96
+ yield f"data: {json.dumps({'type': 'thoughts_start'})}\n\n"
97
+ thoughts += part.text
98
+ yield f"data: {json.dumps({'type': 'thought', 'content': part.text})}\n\n"
99
+ else:
100
+ if not answer:
101
+ yield f"data: {json.dumps({'type': 'answer_start'})}\n\n"
102
+ answer += part.text
103
+ yield f"data: {json.dumps({'type': 'answer', 'content': part.text})}\n\n"
104
+
105
+ yield f"data: {json.dumps({'type': 'done'})}\n\n"
106
+
107
+ except Exception as e:
108
+ logging.exception(f"Error generating content with model {model_to_use}: {e}")
109
+
110
+ if "model" in str(e).lower() and ("not found" in str(e).lower() or "not available" in str(e).lower()):
111
+ logging.error(f"Model '{model_to_use}' not found.")
112
+ yield f"data: {json.dumps({'type': 'error', 'content': f'Erreur: Le modèle {model_to_use} n\\'est pas accessible. Essayez sans l\\'option DeepThink.'})}\n\n"
113
+ else:
114
+ logging.error(f"Internal error occurred: {e}")
115
+ yield f"data: {json.dumps({'type': 'error', 'content': 'Une erreur interne est survenue lors de la génération du contenu. Veuillez réessayer.'})}\n\n"
116
+
117
+ return Response(generate_stream(), mimetype='text/event-stream')
118
+
119
+
120
+ # Endpoint supprimé - streaming imposé sur l'endpoint principal
121
 
122
 
123
  @app.route('/api/etude-texte', methods=['POST'])
124
  def gpt_francais_cc():
125
+ """Analyse d'images avec streaming imposé."""
126
  if 'images' not in request.files:
127
+ return Response(f"data: {json.dumps({'type': 'error', 'content': 'Aucune image n\\'a été téléchargée.'})}\n\n",
128
+ mimetype='text/event-stream'), 400
129
 
130
  images = request.files.getlist('images')
131
  if not images:
132
+ return Response(f"data: {json.dumps({'type': 'error', 'content': 'Aucune image sélectionnée.'})}\n\n",
133
+ mimetype='text/event-stream'), 400
134
+
135
+ def generate_image_analysis():
136
+ try:
137
+ # Charger l'instruction système
138
+ try:
139
+ system_instruction = load_prompt("analyse_texte")
140
+ except Exception as e:
141
+ logging.error(f"Error loading system prompt for text analysis: {e}")
142
+ system_instruction = "Tu es un assistant spécialisé dans l'analyse de textes et de documents."
143
+
144
+ content = ["Réponds aux questions présentes dans les images."]
145
+
146
+ for image in images:
147
+ if image.filename:
148
+ img_data = image.read()
149
+ img_part = types.Part.from_bytes(
150
+ data=img_data,
151
+ mime_type=image.content_type or 'image/jpeg'
152
+ )
153
+ content.append(img_part)
154
+
155
+ config = types.GenerateContentConfig(
156
+ system_instruction=system_instruction,
157
+ temperature=0.7,
158
+ max_output_tokens=4096
159
+ )
160
+
161
+ for chunk in client.models.generate_content_stream(
162
+ model=STANDARD_MODEL_NAME,
163
+ contents=content,
164
+ config=config
165
+ ):
166
+ for part in chunk.candidates[0].content.parts:
167
+ if part.text:
168
+ yield f"data: {json.dumps({'type': 'content', 'content': part.text})}\n\n"
169
+
170
+ yield f"data: {json.dumps({'type': 'done'})}\n\n"
171
+
172
+ except Exception as e:
173
+ logging.exception(f"Error in image analysis streaming: {e}")
174
+ yield f"data: {json.dumps({'type': 'error', 'content': 'Erreur lors de l\\'analyse des images.'})}\n\n"
175
+
176
+ return Response(generate_image_analysis(), mimetype='text/event-stream')
177
+
178
+
179
+ # Endpoint supprimé - streaming imposé sur l'endpoint principal
180
 
181
 
182
  if __name__ == '__main__':
183
+ logging.info("Starting the Flask app with new Gemini SDK...")
 
 
184
  app.run(debug=True)