pierreguillou commited on
Commit
077986a
·
verified ·
1 Parent(s): 0965cce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +3 -336
app.py CHANGED
@@ -6,6 +6,7 @@ from datetime import datetime
6
  from langchain_openai import ChatOpenAI
7
  from langchain_anthropic import ChatAnthropic
8
  from langchain_google_genai import ChatGoogleGenerativeAI
 
9
  from langchain_core.messages import HumanMessage
10
  import PyPDF2
11
  import docx
@@ -44,8 +45,8 @@ MODELS = {
44
  }
45
  }
46
 
47
- # API par défaut pour Gemini 2.5 Flash
48
- DEFAULT_GEMINI_API = os.getenv("FLASH_GOOGLE_API_KEY")
49
 
50
  def extract_text_from_file(file):
51
  """Extrait le texte d'un fichier uploadé"""
@@ -64,338 +65,4 @@ def extract_text_from_file(file):
64
  return text
65
 
66
  elif file_extension == '.docx':
67
- doc = docx.Document(file.name)
68
- text = ""
69
- for paragraph in doc.paragraphs:
70
- text += paragraph.text + "\n"
71
- return text
72
-
73
- elif file_extension == '.txt':
74
- with open(file.name, 'r', encoding='utf-8') as f:
75
- return f.read()
76
-
77
- elif file_extension in ['.xlsx', '.xls']:
78
- df = pd.read_excel(file.name)
79
- return df.to_string()
80
-
81
- elif file_extension == '.pptx':
82
- prs = Presentation(file.name)
83
- text = ""
84
- for slide in prs.slides:
85
- for shape in slide.shapes:
86
- if hasattr(shape, "text"):
87
- text += shape.text + "\n"
88
- return text
89
-
90
- else:
91
- return "Format de fichier non supporté"
92
-
93
- except Exception as e:
94
- return f"Erreur lors de la lecture du fichier: {str(e)}"
95
-
96
- def extract_text_from_url(url):
97
- """Extrait le texte d'une URL"""
98
- try:
99
- response = requests.get(url, timeout=10)
100
- response.raise_for_status()
101
-
102
- # Simple extraction du contenu textuel
103
- content = response.text
104
- # Suppression basique des balises HTML
105
- content = re.sub(r'<[^>]+>', '', content)
106
- content = re.sub(r'\s+', ' ', content).strip()
107
-
108
- return content[:10000] # Limite à 10k caractères
109
-
110
- except Exception as e:
111
- return f"Erreur lors de la récupération de l'URL: {str(e)}"
112
-
113
- def get_document_content(text_input, url_input, file_input):
114
- """Récupère le contenu du document selon la source"""
115
- if text_input.strip():
116
- return text_input.strip()
117
- elif url_input.strip():
118
- return extract_text_from_url(url_input.strip())
119
- elif file_input is not None:
120
- return extract_text_from_file(file_input)
121
- else:
122
- return ""
123
-
124
- def create_llm_instance(model_name, api_key):
125
- """Crée une instance du modèle LLM"""
126
- model_config = MODELS[model_name]
127
-
128
- if model_config["provider"] == "OpenAI":
129
- return model_config["class"](
130
- model=model_config["model_name"],
131
- api_key=api_key,
132
- temperature=0.7
133
- )
134
- elif model_config["provider"] == "Anthropic":
135
- return model_config["class"](
136
- model=model_config["model_name"],
137
- api_key=api_key,
138
- temperature=0.7
139
- )
140
- elif model_config["provider"] == "Google AI":
141
- api_to_use = api_key if api_key else DEFAULT_GEMINI_API
142
- return model_config["class"](
143
- model=model_config["model_name"],
144
- google_api_key=api_to_use,
145
- temperature=0.7
146
- )
147
-
148
- def generate_html(model_name, api_key, text_input, url_input, file_input):
149
- """Génère le fichier HTML éducatif"""
150
- start_time = time.time()
151
-
152
- # Validation des entrées
153
- if model_name != "Gemini 2.5 Flash (Google AI)" and not api_key.strip():
154
- return None, "❌ Erreur: Veuillez fournir une clé API pour ce modèle.", 0
155
-
156
- document_content = get_document_content(text_input, url_input, file_input)
157
- if not document_content:
158
- return None, "❌ Erreur: Veuillez fournir un document (texte, URL ou fichier).", 0
159
-
160
- try:
161
- # Création de l'instance LLM
162
- llm = create_llm_instance(model_name, api_key)
163
-
164
- # Lecture du prompt template
165
- with open("creation_educational_html_from_any_document_18082025.txt", "r", encoding="utf-8") as f:
166
- prompt_template = f.read()
167
-
168
- # Remplacement des variables
169
- model_config = MODELS[model_name]
170
- prompt = prompt_template.format(
171
- model_name=model_config["model_name"],
172
- provider_name=model_config["provider"],
173
- document=document_content
174
- )
175
-
176
- # Génération du contenu
177
- message = HumanMessage(content=prompt)
178
- response = llm.invoke([message])
179
-
180
- html_content = response.content
181
-
182
- # Calcul du temps de génération
183
- generation_time = time.time() - start_time
184
-
185
- # Sauvegarde du fichier HTML
186
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
187
- filename = f"document_educatif_{timestamp}.html"
188
-
189
- with open(filename, "w", encoding="utf-8") as f:
190
- f.write(html_content)
191
-
192
- success_message = f"✅ Fichier HTML généré avec succès en {generation_time:.2f} secondes!"
193
-
194
- return filename, success_message, generation_time
195
-
196
- except Exception as e:
197
- error_message = f"❌ Erreur lors de la génération: {str(e)}"
198
- return None, error_message, 0
199
-
200
- def reset_form():
201
- """Remet à zéro le formulaire"""
202
- return (
203
- "Gemini 2.5 Flash (Google AI)", # model_name
204
- "", # api_key
205
- "", # text_input
206
- "", # url_input
207
- None, # file_input
208
- "", # status_message
209
- None, # html_file
210
- "" # html_preview
211
- )
212
-
213
- def update_api_info(model_name):
214
- """Met à jour les informations sur l'API selon le modèle sélectionné"""
215
- if model_name == "Gemini 2.5 Flash (Google AI)":
216
- return gr.update(
217
- label="Clé API (optionnelle)",
218
- placeholder="API gratuite disponible jusqu'à épuisement, ou utilisez votre propre clé",
219
- info="💡 Une API gratuite est déjà configurée pour ce modèle. Vous pouvez utiliser votre propre clé si vous le souhaitez."
220
- )
221
- else:
222
- return gr.update(
223
- label="Clé API (obligatoire)",
224
- placeholder="Entrez votre clé API",
225
- info="🔑 Clé API requise pour ce modèle"
226
- )
227
-
228
- # Interface Gradio
229
- with gr.Blocks(
230
- title="EduHTML Creator - Générateur de contenu éducatif HTML",
231
- theme=gr.themes.Soft(),
232
- css="""
233
- .main-container {
234
- max-width: 1200px;
235
- margin: 0 auto;
236
- padding: 20px;
237
- }
238
- .header {
239
- text-align: center;
240
- margin-bottom: 30px;
241
- padding: 30px;
242
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
243
- border-radius: 15px;
244
- color: white;
245
- }
246
- .form-section {
247
- background: white;
248
- padding: 25px;
249
- border-radius: 15px;
250
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
251
- margin-bottom: 20px;
252
- }
253
- .apple-button {
254
- background: #007AFF;
255
- color: white;
256
- border: none;
257
- border-radius: 8px;
258
- padding: 12px 24px;
259
- font-weight: 500;
260
- transition: all 0.3s ease;
261
- }
262
- .apple-button:hover {
263
- background: #0056CC;
264
- transform: translateY(-1px);
265
- }
266
- .reset-button {
267
- background: #FF3B30;
268
- color: white;
269
- border: none;
270
- border-radius: 8px;
271
- padding: 12px 24px;
272
- font-weight: 500;
273
- }
274
- .status-success {
275
- color: #34C759;
276
- font-weight: 500;
277
- }
278
- .status-error {
279
- color: #FF3B30;
280
- font-weight: 500;
281
- }
282
- """
283
- ) as app:
284
-
285
- gr.HTML("""
286
- <div class="header">
287
- <h1>🎓 EduHTML Creator</h1>
288
- <p style="font-size: 18px; margin: 10px 0;">Transformez n'importe quel document en contenu éducatif HTML interactif</p>
289
- <p style="font-size: 14px; opacity: 0.9;">
290
- Cette application utilise l'intelligence artificielle pour créer des pages HTML éducatives élégantes et interactives
291
- à partir de vos documents. Le design s'inspire du style Apple pour une expérience utilisateur premium.
292
- L'objectif éducatif est de faciliter l'apprentissage grâce à la structuration, l'interactivité et la visualisation
293
- des informations clés de vos documents originaux.
294
- </p>
295
- </div>
296
- """)
297
-
298
- with gr.Row():
299
- with gr.Column(scale=1):
300
- gr.HTML("<div class='form-section'>")
301
-
302
- # Sélection du modèle
303
- model_dropdown = gr.Dropdown(
304
- choices=list(MODELS.keys()),
305
- value="Gemini 2.5 Flash (Google AI)",
306
- label="🤖 Modèle LLM",
307
- info="Choisissez le modèle d'IA à utiliser"
308
- )
309
-
310
- # Champ API
311
- api_input = gr.Textbox(
312
- label="Clé API (optionnelle)",
313
- placeholder="API gratuite disponible jusqu'à épuisement, ou utilisez votre propre clé",
314
- info="💡 Une API gratuite est déjà configurée pour ce modèle. Vous pouvez utiliser votre propre clé si vous le souhaitez.",
315
- type="password"
316
- )
317
-
318
- gr.HTML("</div>")
319
-
320
- gr.HTML("<div class='form-section'>")
321
- gr.HTML("<h3>📄 Source du document</h3>")
322
-
323
- # Entrées de document
324
- text_input = gr.Textbox(
325
- label="Texte copié/collé",
326
- placeholder="Collez votre texte ici...",
327
- lines=5
328
- )
329
-
330
- url_input = gr.Textbox(
331
- label="Lien Web",
332
- placeholder="https://exemple.com/article"
333
- )
334
-
335
- file_input = gr.File(
336
- label="Fichier",
337
- file_types=[".pdf", ".txt", ".docx", ".xlsx", ".xls", ".pptx"]
338
- )
339
-
340
- gr.HTML("</div>")
341
-
342
- # Boutons
343
- with gr.Row():
344
- submit_btn = gr.Button(
345
- "🚀 Générer le HTML",
346
- variant="primary",
347
- elem_classes=["apple-button"]
348
- )
349
- reset_btn = gr.Button(
350
- "🔄 Reset",
351
- elem_classes=["reset-button"]
352
- )
353
-
354
- with gr.Column(scale=1):
355
- # Statut et résultats
356
- status_output = gr.HTML(label="Statut")
357
-
358
- # Fichier téléchargeable
359
- html_file_output = gr.File(
360
- label="📥 Fichier HTML téléchargeable",
361
- visible=False
362
- )
363
-
364
- # Prévisualisation
365
- html_preview = gr.HTML(
366
- label="👀 Prévisualisation",
367
- visible=False
368
- )
369
-
370
- # Événements
371
- model_dropdown.change(
372
- fn=update_api_info,
373
- inputs=[model_dropdown],
374
- outputs=[api_input]
375
- )
376
-
377
- submit_btn.click(
378
- fn=generate_html,
379
- inputs=[model_dropdown, api_input, text_input, url_input, file_input],
380
- outputs=[html_file_output, status_output, gr.State()]
381
- ).then(
382
- fn=lambda file, status, time_taken: (
383
- gr.update(visible=file is not None),
384
- status,
385
- gr.update(visible=file is not None, value=open(file, 'r', encoding='utf-8').read() if file else "")
386
- ),
387
- inputs=[html_file_output, status_output, gr.State()],
388
- outputs=[html_file_output, status_output, html_preview]
389
- )
390
-
391
- reset_btn.click(
392
- fn=reset_form,
393
- outputs=[model_dropdown, api_input, text_input, url_input, file_input, status_output, html_file_output, html_preview]
394
- )
395
-
396
- if __name__ == "__main__":
397
- app.launch(
398
- server_name="0.0.0.0",
399
- server_port=7860,
400
- share=True
401
  )
 
6
  from langchain_openai import ChatOpenAI
7
  from langchain_anthropic import ChatAnthropic
8
  from langchain_google_genai import ChatGoogleGenerativeAI
9
+ # Correctif lié à Pydantic v2 pour ChatGoogleGenerativeAI\nChatGoogleGenerativeAI.model_rebuild()
10
  from langchain_core.messages import HumanMessage
11
  import PyPDF2
12
  import docx
 
45
  }
46
  }
47
 
48
+ # API par défaut pour Gemini 2.5 Flash via HF Spaces Secrets
49
+ DEFAULT_GEMINI_API = os.getenv("GOOGLE_API_KEY")
50
 
51
  def extract_text_from_file(file):
52
  """Extrait le texte d'un fichier uploadé"""
 
65
  return text
66
 
67
  elif file_extension == '.docx':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  )