mlamined commited on
Commit
9748475
·
verified ·
1 Parent(s): b192a00

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -137
app.py CHANGED
@@ -10,15 +10,47 @@ from transformers import (
10
  )
11
  from functools import lru_cache
12
 
13
- # Initialize models with caching
14
  @lru_cache(maxsize=1)
15
- def load_translator():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  """Load the French-to-Pular translator model"""
17
- print("Loading translator model...")
18
  model_name = "mlamined/fr_pl_130"
19
 
20
  try:
21
- # Load with NLLB tokenizer for proper language codes
22
  tokenizer = NllbTokenizer.from_pretrained(
23
  "facebook/nllb-200-distilled-600M",
24
  src_lang="fra_Latn",
@@ -37,10 +69,10 @@ def load_translator():
37
  num_beams=3,
38
  early_stopping=True
39
  )
40
- print("Translator model loaded successfully!")
41
  return translator
42
  except Exception as e:
43
- print(f"Error loading translator: {e}")
44
  return None
45
 
46
  @lru_cache(maxsize=1)
@@ -74,14 +106,114 @@ def load_llm():
74
  print(f"Error loading LLM: {e}")
75
  return None, None
76
 
77
- # Load models
78
- translator = load_translator()
79
- llm_model, llm_tokenizer = load_llm()
 
 
 
 
 
80
 
81
  # Check if models loaded
82
  use_llm = llm_model is not None and llm_tokenizer is not None
83
 
84
- # Improved system prompt with clearer instructions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  system_prompt = """You are a helpful assistant . Use simple, clear language as if explaining to a young child. Provide accurate and relevant responses. Answer in French, and keep responses short and friendly. Maintenant, réponds aux questions suivantes:"""
86
 
87
  def clean_french_response(text):
@@ -90,20 +222,18 @@ def clean_french_response(text):
90
  return ""
91
 
92
  # Remove markdown formatting
93
- text = re.sub(r'\*+', '', text) # Remove asterisks
94
- text = re.sub(r'#+\s*', '', text) # Remove headers
95
- text = re.sub(r'`.*?`', '', text) # Remove code blocks
96
- text = re.sub(r'\[.*?\]\(.*?\)', '', text) # Remove links
97
 
98
  # Remove any gibberish or repeated patterns
99
  lines = text.split('\n')
100
  clean_lines = []
101
  for line in lines:
102
  line = line.strip()
103
- # Skip empty lines or lines that look like gibberish
104
  if not line or len(line) < 3:
105
  continue
106
- # Skip lines that are just punctuation or symbols
107
  if re.match(r'^[^a-zA-Z0-9\s]*$', line):
108
  continue
109
  clean_lines.append(line)
@@ -112,7 +242,7 @@ def clean_french_response(text):
112
  if clean_lines:
113
  response = clean_lines[0]
114
  else:
115
- response = text[:200] # Fallback
116
 
117
  # Ensure it ends with proper punctuation
118
  if response and not response[-1] in '.!?':
@@ -123,7 +253,6 @@ def clean_french_response(text):
123
  def generate_french_response(user_input, history=None):
124
  """Generate French response using the actual LLM with improved prompting"""
125
  if not use_llm:
126
- # Fallback responses if LLM is not available
127
  fallback_responses = [
128
  "Je comprends votre question. Pouvez-vous la reformuler?",
129
  "Je vais chercher cette information pour vous.",
@@ -140,7 +269,6 @@ def generate_french_response(user_input, history=None):
140
 
141
  # Add conversation history if available (simplified)
142
  if history and len(history) > 0:
143
- # Take only the last exchange for context
144
  recent = history[-2:] if len(history) >= 2 else history
145
  for msg in recent:
146
  if msg["role"] == "user":
@@ -169,9 +297,9 @@ def generate_french_response(user_input, history=None):
169
  with torch.no_grad():
170
  outputs = llm_model.generate(
171
  **inputs,
172
- max_new_tokens=100, # Reduced for cleaner responses
173
  do_sample=True,
174
- temperature=0.5, # Lower temperature for more focused responses
175
  top_p=0.9,
176
  top_k=50,
177
  pad_token_id=llm_tokenizer.pad_token_id,
@@ -185,11 +313,9 @@ def generate_french_response(user_input, history=None):
185
 
186
  # Extract only the assistant's response
187
  if "Réponse:" in response:
188
- # Take everything after the last "Réponse:"
189
  parts = response.split("Réponse:")
190
  french_response = parts[-1].strip()
191
  else:
192
- # If no "Réponse:" tag found, take everything after the prompt
193
  french_response = response[len(prompt):].strip()
194
 
195
  # Clean the response
@@ -200,68 +326,12 @@ def generate_french_response(user_input, history=None):
200
  french_response = "Je ne peux pas répondre à cette question pour le moment."
201
 
202
  print(f"Generated French response: {french_response[:150]}...")
203
- return french_response[:250] # Limit length
204
 
205
  except Exception as e:
206
  print(f"Error generating French response: {e}")
207
  return "Je rencontre des difficultés techniques. Pouvez-vous reformuler votre question?"
208
 
209
- def translate_french_to_pular(french_text):
210
- """Translate French text to Pular with improved cleaning"""
211
- if not translator:
212
- return "Erreur: Modèle de traduction non disponible."
213
-
214
- if not french_text or len(french_text.strip()) == 0:
215
- return ""
216
-
217
- try:
218
- # Clean the French text before translation
219
- clean_french = french_text
220
-
221
- # Remove any remaining markdown
222
- clean_french = re.sub(r'\*+', '', clean_french)
223
- clean_french = re.sub(r'\s+', ' ', clean_french).strip()
224
-
225
- # Limit length
226
- clean_french = clean_french[:300]
227
-
228
- print(f"Translating: {clean_french[:100]}...")
229
-
230
- # Translate
231
- result = translator(clean_french, max_length=256)
232
-
233
- # Extract translation
234
- if isinstance(result, list) and len(result) > 0:
235
- if isinstance(result[0], dict) and "translation_text" in result[0]:
236
- pular_text = result[0]["translation_text"]
237
- elif isinstance(result[0], str):
238
- pular_text = result[0]
239
- else:
240
- pular_text = str(result[0])
241
- elif isinstance(result, dict) and "translation_text" in result:
242
- pular_text = result["translation_text"]
243
- elif isinstance(result, str):
244
- pular_text = result
245
- else:
246
- return "Hakkunde ndee, mi wadataa."
247
-
248
- # Clean the Pular response
249
- pular_text = re.sub(r'\*.*?\*', '', pular_text)
250
- pular_text = re.sub(r'\bFinsitaare\b.*', '', pular_text)
251
- pular_text = re.sub(r'\[.*?\]|\(.*?\)', '', pular_text)
252
- pular_text = re.sub(r'\s+', ' ', pular_text).strip()
253
-
254
- # If translation seems problematic, provide a fallback
255
- if len(pular_text) < 3 or pular_text.lower().startswith("error"):
256
- pular_text = "Mi fahmina. Hakkunde ndee, tontu kadi."
257
-
258
- print(f"Translated to: {pular_text[:100]}...")
259
- return pular_text
260
-
261
- except Exception as e:
262
- print(f"Translation error: {e}")
263
- return "Hakkunde ndee, tontu kadi."
264
-
265
  def chat_function(user_input, chat_history):
266
  """Main chat function with improved response handling"""
267
  if not user_input.strip():
@@ -297,16 +367,12 @@ def chat_function(user_input, chat_history):
297
  details = f"**Erreur technique:** Veuillez réessayer."
298
  return chat_history, details
299
 
300
- def direct_translate(text):
301
- """Direct translation function"""
302
- return translate_french_to_pular(text)
303
-
304
- # Create Gradio interface
305
  with gr.Blocks(
306
- title="🤖 Chatbot Français-Pular avec IA",
307
  theme=gr.themes.Soft(),
308
  css="""
309
- .gradio-container {max-width: 800px; margin: auto;}
310
  .chatbot {min-height: 400px;}
311
  .details-box {
312
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -327,12 +393,19 @@ with gr.Blocks(
327
  margin: 2px;
328
  font-size: 12px;
329
  }
 
 
 
 
 
 
 
330
  """
331
  ) as demo:
332
  gr.Markdown("""
333
- # 🇫🇷 🌍 Chatbot Français-Pular avec IA Réelle
334
 
335
- ### Un assistant intelligent qui comprend le français et répond en pular
336
  """)
337
 
338
  # Status indicators
@@ -344,7 +417,10 @@ with gr.Blocks(
344
  <strong>🤖 Modèle IA (Gemma-2-2B):</strong> {'<span style="color: green;">✅ Actif</span>' if use_llm else '<span style="color: orange;">⚠️ Basique</span>'}
345
  </div>
346
  <div style='background: #e3f2fd; padding: 10px; border-radius: 5px; margin: 5px 0;'>
347
- <strong>🔤 Traducteur (mlamined/fr_pl_130):</strong> {'<span style="color: green;">✅ Actif</span>' if translator else '<span style="color: red;">❌ Erreur</span>'}
 
 
 
348
  </div>
349
  <div style='background: #fff3e0; padding: 10px; border-radius: 5px; margin: 5px 0;'>
350
  <strong>⚡ Performance:</strong> {'<span style="color: orange;">CPU</span>' if not torch.cuda.is_available() else '<span style="color: green;">GPU</span>'}
@@ -376,7 +452,6 @@ with gr.Blocks(
376
  with gr.Row():
377
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary", size="sm")
378
  show_details = gr.Checkbox(label="📋 Afficher les détails", value=True)
379
- # Empty column for spacing
380
  gr.Column(scale=4, min_width=0)
381
 
382
  details_output = gr.Markdown(
@@ -412,10 +487,6 @@ with gr.Blocks(
412
  def clear_chat():
413
  return [], gr.update(value="", visible=False)
414
 
415
- # Simple function to set the example text
416
- def set_example_text(example):
417
- return example
418
-
419
  # Connect events
420
  msg.submit(
421
  respond,
@@ -433,9 +504,8 @@ with gr.Blocks(
433
  [chatbot, details_output]
434
  )
435
 
436
- # Connect example buttons - SIMPLIFIED
437
  for i, btn in enumerate(example_buttons):
438
- # First set the example text
439
  btn.click(
440
  fn=lambda ex=examples[i]: ex,
441
  inputs=None,
@@ -446,70 +516,134 @@ with gr.Blocks(
446
  outputs=[msg, chatbot, details_output]
447
  )
448
 
449
- with gr.TabItem("🔤 Traducteur", id="translate"):
450
- gr.Markdown("### Traduction directe français → pular")
 
 
 
 
451
  with gr.Row():
 
452
  with gr.Column():
453
- french_input = gr.Textbox(
 
454
  label="Texte français",
455
- placeholder="Entrez du texte à traduire...",
456
- lines=5
457
  )
458
  with gr.Row():
459
- translate_btn = gr.Button("Traduire ", variant="primary")
460
- clear_translate = gr.Button("Effacer", variant="secondary")
461
-
462
- with gr.Column():
463
  pular_output = gr.Textbox(
464
  label="Traduction pular",
465
- lines=5,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  interactive=False
467
  )
468
 
469
- translate_btn.click(
470
- direct_translate,
471
- inputs=french_input,
 
 
472
  outputs=pular_output
473
  )
474
- french_input.submit(
475
- direct_translate,
476
- inputs=french_input,
477
  outputs=pular_output
478
  )
479
- clear_translate.click(
480
  lambda: ("", ""),
481
  None,
482
- [french_input, pular_output]
483
  )
484
 
485
- gr.Markdown("### 📝 Exemples rapides")
486
- translate_examples = gr.Examples(
487
- examples=[
488
- ["Bonjour, je m'appelle Mamadou et je suis guinéen."],
489
- ["L'éducation est la clé du développement d'un pays."],
490
- ["La culture guinéenne est riche et diversifiée."],
491
- ["Nous devons protéger notre environnement pour les générations futures."],
492
- ["La paix et la stabilité sont essentielles pour le progrès."]
493
- ],
494
- inputs=french_input,
495
- outputs=pular_output,
496
- fn=direct_translate,
497
- cache_examples=True,
498
- label="Cliquez sur un exemple"
499
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
 
501
  gr.Markdown("---")
502
  gr.Markdown("""
503
  ### ℹ️ À propos de ce système
504
 
 
 
 
 
 
505
  **Fonctionnement:**
506
- 1. Vous écrivez en français
507
- 4. Vous recevez une réponse naturelle et contextuelle
 
508
 
509
  **Capacités:**
510
  - Réponses intelligentes et contextuelles
511
- - Traduction précise français pular
512
- - Maintien du contexte de conversation
513
  - Interface intuitive et facile à utiliser
514
 
515
  **Note:** Les réponses peuvent prendre quelques secondes à générer sur CPU.
@@ -517,9 +651,10 @@ with gr.Blocks(
517
 
518
  if __name__ == "__main__":
519
  print("=" * 60)
520
- print("🚀 Démarrage du Chatbot Français-Pular")
521
  print(f"📊 Statut LLM: {'✅ Prêt' if use_llm else '❌ Échec'}")
522
- print(f"📊 Statut traducteur: {'✅ Prêt' if translator else '❌ Échec'}")
 
523
  print(f"⚡ Matériel: {'GPU' if torch.cuda.is_available() else 'CPU'}")
524
  print("=" * 60)
525
 
@@ -529,5 +664,4 @@ if __name__ == "__main__":
529
  share=True,
530
  debug=False,
531
  show_error=True
532
- )
533
-
 
10
  )
11
  from functools import lru_cache
12
 
13
+ # ==================== NEW: PULAR TO FRENCH TRANSLATOR ====================
14
  @lru_cache(maxsize=1)
15
+ def load_pular_to_french():
16
+ """Load the Pular-to-French translator model"""
17
+ print("Loading Pular→French translator model...")
18
+ model_name = "mlamined/pl_fr_104" # Your new checkpoint
19
+
20
+ try:
21
+ # Load with NLLB tokenizer for proper language codes
22
+ tokenizer = NllbTokenizer.from_pretrained(
23
+ "facebook/nllb-200-distilled-600M",
24
+ src_lang="fuv_Latn", # Pular source
25
+ tgt_lang="fra_Latn" # French target
26
+ )
27
+
28
+ model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
29
+
30
+ translator = pipeline(
31
+ "translation",
32
+ model=model,
33
+ tokenizer=tokenizer,
34
+ src_lang="fuv_Latn",
35
+ tgt_lang="fra_Latn",
36
+ max_length=256,
37
+ num_beams=3,
38
+ early_stopping=True
39
+ )
40
+ print("Pular→French translator model loaded successfully!")
41
+ return translator
42
+ except Exception as e:
43
+ print(f"Error loading Pular→French translator: {e}")
44
+ return None
45
+
46
+ # ==================== EXISTING MODELS ====================
47
+ @lru_cache(maxsize=1)
48
+ def load_french_to_pular():
49
  """Load the French-to-Pular translator model"""
50
+ print("Loading French→Pular translator model...")
51
  model_name = "mlamined/fr_pl_130"
52
 
53
  try:
 
54
  tokenizer = NllbTokenizer.from_pretrained(
55
  "facebook/nllb-200-distilled-600M",
56
  src_lang="fra_Latn",
 
69
  num_beams=3,
70
  early_stopping=True
71
  )
72
+ print("French→Pular translator model loaded successfully!")
73
  return translator
74
  except Exception as e:
75
+ print(f"Error loading French→Pular translator: {e}")
76
  return None
77
 
78
  @lru_cache(maxsize=1)
 
106
  print(f"Error loading LLM: {e}")
107
  return None, None
108
 
109
+ # ==================== LOAD ALL MODELS ====================
110
+ print("\n" + "="*60)
111
+ print("🚀 LOADING ALL MODELS")
112
+ print("="*60)
113
+
114
+ translator_pular_to_french = load_pular_to_french() # NEW
115
+ translator_french_to_pular = load_french_to_pular() # EXISTING
116
+ llm_model, llm_tokenizer = load_llm() # EXISTING
117
 
118
  # Check if models loaded
119
  use_llm = llm_model is not None and llm_tokenizer is not None
120
 
121
+ # ==================== TRANSLATION FUNCTIONS ====================
122
+ def translate_pular_to_french(pular_text):
123
+ """Translate Pular text to French"""
124
+ if not translator_pular_to_french:
125
+ return "Erreur: Modèle Pular→Français non disponible."
126
+
127
+ if not pular_text or len(pular_text.strip()) == 0:
128
+ return ""
129
+
130
+ try:
131
+ # Clean the Pular text
132
+ clean_pular = pular_text.strip()
133
+ clean_pular = re.sub(r'\s+', ' ', clean_pular)
134
+ clean_pular = clean_pular[:300] # Limit length
135
+
136
+ print(f"Translating Pular→French: {clean_pular[:100]}...")
137
+
138
+ # Translate
139
+ result = translator_pular_to_french(clean_pular, max_length=256)
140
+
141
+ # Extract translation
142
+ if isinstance(result, list) and len(result) > 0:
143
+ if isinstance(result[0], dict) and "translation_text" in result[0]:
144
+ french_text = result[0]["translation_text"]
145
+ elif isinstance(result[0], str):
146
+ french_text = result[0]
147
+ else:
148
+ french_text = str(result[0])
149
+ elif isinstance(result, dict) and "translation_text" in result:
150
+ french_text = result["translation_text"]
151
+ elif isinstance(result, str):
152
+ french_text = result
153
+ else:
154
+ return "Erreur de traduction. Veuillez réessayer."
155
+
156
+ # Clean the French response
157
+ french_text = re.sub(r'\*.*?\*', '', french_text)
158
+ french_text = re.sub(r'\[.*?\]|\(.*?\)', '', french_text)
159
+ french_text = re.sub(r'\s+', ' ', french_text).strip()
160
+
161
+ print(f"Translated to French: {french_text[:100]}...")
162
+ return french_text
163
+
164
+ except Exception as e:
165
+ print(f"Pular→French translation error: {e}")
166
+ return "Erreur technique lors de la traduction."
167
+
168
+ def translate_french_to_pular(french_text):
169
+ """Translate French text to Pular"""
170
+ if not translator_french_to_pular:
171
+ return "Hakkunde ndee, mi wadataa."
172
+
173
+ if not french_text or len(french_text.strip()) == 0:
174
+ return ""
175
+
176
+ try:
177
+ # Clean the French text
178
+ clean_french = french_text.strip()
179
+ clean_french = re.sub(r'\*+', '', clean_french)
180
+ clean_french = re.sub(r'\s+', ' ', clean_french)
181
+ clean_french = clean_french[:300] # Limit length
182
+
183
+ print(f"Translating French→Pular: {clean_french[:100]}...")
184
+
185
+ # Translate
186
+ result = translator_french_to_pular(clean_french, max_length=256)
187
+
188
+ # Extract translation
189
+ if isinstance(result, list) and len(result) > 0:
190
+ if isinstance(result[0], dict) and "translation_text" in result[0]:
191
+ pular_text = result[0]["translation_text"]
192
+ elif isinstance(result[0], str):
193
+ pular_text = result[0]
194
+ else:
195
+ pular_text = str(result[0])
196
+ elif isinstance(result, dict) and "translation_text" in result:
197
+ pular_text = result["translation_text"]
198
+ elif isinstance(result, str):
199
+ pular_text = result
200
+ else:
201
+ return "Hakkunde ndee, mi wadataa."
202
+
203
+ # Clean the Pular response
204
+ pular_text = re.sub(r'\*.*?\*', '', pular_text)
205
+ pular_text = re.sub(r'\bFinsitaare\b.*', '', pular_text)
206
+ pular_text = re.sub(r'\[.*?\]|\(.*?\)', '', pular_text)
207
+ pular_text = re.sub(r'\s+', ' ', pular_text).strip()
208
+
209
+ print(f"Translated to Pular: {pular_text[:100]}...")
210
+ return pular_text
211
+
212
+ except Exception as e:
213
+ print(f"French→Pular translation error: {e}")
214
+ return "Hakkunde ndee, tontu kadi."
215
+
216
+ # ==================== EXISTING FUNCTIONS (UNCHANGED) ====================
217
  system_prompt = """You are a helpful assistant . Use simple, clear language as if explaining to a young child. Provide accurate and relevant responses. Answer in French, and keep responses short and friendly. Maintenant, réponds aux questions suivantes:"""
218
 
219
  def clean_french_response(text):
 
222
  return ""
223
 
224
  # Remove markdown formatting
225
+ text = re.sub(r'\*+', '', text)
226
+ text = re.sub(r'#+\s*', '', text)
227
+ text = re.sub(r'`.*?`', '', text)
228
+ text = re.sub(r'\[.*?\]\(.*?\)', '', text)
229
 
230
  # Remove any gibberish or repeated patterns
231
  lines = text.split('\n')
232
  clean_lines = []
233
  for line in lines:
234
  line = line.strip()
 
235
  if not line or len(line) < 3:
236
  continue
 
237
  if re.match(r'^[^a-zA-Z0-9\s]*$', line):
238
  continue
239
  clean_lines.append(line)
 
242
  if clean_lines:
243
  response = clean_lines[0]
244
  else:
245
+ response = text[:200]
246
 
247
  # Ensure it ends with proper punctuation
248
  if response and not response[-1] in '.!?':
 
253
  def generate_french_response(user_input, history=None):
254
  """Generate French response using the actual LLM with improved prompting"""
255
  if not use_llm:
 
256
  fallback_responses = [
257
  "Je comprends votre question. Pouvez-vous la reformuler?",
258
  "Je vais chercher cette information pour vous.",
 
269
 
270
  # Add conversation history if available (simplified)
271
  if history and len(history) > 0:
 
272
  recent = history[-2:] if len(history) >= 2 else history
273
  for msg in recent:
274
  if msg["role"] == "user":
 
297
  with torch.no_grad():
298
  outputs = llm_model.generate(
299
  **inputs,
300
+ max_new_tokens=100,
301
  do_sample=True,
302
+ temperature=0.5,
303
  top_p=0.9,
304
  top_k=50,
305
  pad_token_id=llm_tokenizer.pad_token_id,
 
313
 
314
  # Extract only the assistant's response
315
  if "Réponse:" in response:
 
316
  parts = response.split("Réponse:")
317
  french_response = parts[-1].strip()
318
  else:
 
319
  french_response = response[len(prompt):].strip()
320
 
321
  # Clean the response
 
326
  french_response = "Je ne peux pas répondre à cette question pour le moment."
327
 
328
  print(f"Generated French response: {french_response[:150]}...")
329
+ return french_response[:250]
330
 
331
  except Exception as e:
332
  print(f"Error generating French response: {e}")
333
  return "Je rencontre des difficultés techniques. Pouvez-vous reformuler votre question?"
334
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  def chat_function(user_input, chat_history):
336
  """Main chat function with improved response handling"""
337
  if not user_input.strip():
 
367
  details = f"**Erreur technique:** Veuillez réessayer."
368
  return chat_history, details
369
 
370
+ # ==================== GRADIO INTERFACE ====================
 
 
 
 
371
  with gr.Blocks(
372
+ title="🤖 Chatbot Français-Pular avec IA - BIDIRECTIONNEL",
373
  theme=gr.themes.Soft(),
374
  css="""
375
+ .gradio-container {max-width: 900px; margin: auto;}
376
  .chatbot {min-height: 400px;}
377
  .details-box {
378
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
393
  margin: 2px;
394
  font-size: 12px;
395
  }
396
+ .translation-card {
397
+ background: #f8f9fa;
398
+ padding: 15px;
399
+ border-radius: 10px;
400
+ border: 1px solid #dee2e6;
401
+ margin: 10px 0;
402
+ }
403
  """
404
  ) as demo:
405
  gr.Markdown("""
406
+ # 🇫🇷 🌍 Chatbot Français-Pular avec IA - BIDIRECTIONNEL
407
 
408
+ ### Un assistant intelligent avec traduction dans les deux sens
409
  """)
410
 
411
  # Status indicators
 
417
  <strong>🤖 Modèle IA (Gemma-2-2B):</strong> {'<span style="color: green;">✅ Actif</span>' if use_llm else '<span style="color: orange;">⚠️ Basique</span>'}
418
  </div>
419
  <div style='background: #e3f2fd; padding: 10px; border-radius: 5px; margin: 5px 0;'>
420
+ <strong>🔤 Traducteur Pular→Français (mlamined/pl_fr_104):</strong> {'<span style="color: green;">✅ Actif</span>' if translator_pular_to_french else '<span style="color: red;">❌ Erreur</span>'}
421
+ </div>
422
+ <div style='background: #e3f2fd; padding: 10px; border-radius: 5px; margin: 5px 0;'>
423
+ <strong>🔤 Traducteur Français→Pular (mlamined/fr_pl_130):</strong> {'<span style="color: green;">✅ Actif</span>' if translator_french_to_pular else '<span style="color: red;">❌ Erreur</span>'}
424
  </div>
425
  <div style='background: #fff3e0; padding: 10px; border-radius: 5px; margin: 5px 0;'>
426
  <strong>⚡ Performance:</strong> {'<span style="color: orange;">CPU</span>' if not torch.cuda.is_available() else '<span style="color: green;">GPU</span>'}
 
452
  with gr.Row():
453
  clear_btn = gr.Button("🗑️ Effacer", variant="secondary", size="sm")
454
  show_details = gr.Checkbox(label="📋 Afficher les détails", value=True)
 
455
  gr.Column(scale=4, min_width=0)
456
 
457
  details_output = gr.Markdown(
 
487
  def clear_chat():
488
  return [], gr.update(value="", visible=False)
489
 
 
 
 
 
490
  # Connect events
491
  msg.submit(
492
  respond,
 
504
  [chatbot, details_output]
505
  )
506
 
507
+ # Connect example buttons
508
  for i, btn in enumerate(example_buttons):
 
509
  btn.click(
510
  fn=lambda ex=examples[i]: ex,
511
  inputs=None,
 
516
  outputs=[msg, chatbot, details_output]
517
  )
518
 
519
+ with gr.TabItem("🔤 Traducteur Bidirectionnel", id="translate"):
520
+ gr.Markdown("""
521
+ ### Traduction dans les deux sens
522
+ **🇫🇷 Français → 🌍 Pular** et **🌍 Pular → 🇫🇷 Français**
523
+ """)
524
+
525
  with gr.Row():
526
+ # French to Pular translation
527
  with gr.Column():
528
+ gr.Markdown("#### 🇫🇷 → 🌍 Français vers Pular")
529
+ french_input_ftop = gr.Textbox(
530
  label="Texte français",
531
+ placeholder="Entrez du texte français à traduire en pular...",
532
+ lines=4
533
  )
534
  with gr.Row():
535
+ translate_fr_to_pl = gr.Button("Traduire 🇫🇷→🌍", variant="primary")
536
+ clear_fr_to_pl = gr.Button("Effacer", variant="secondary")
 
 
537
  pular_output = gr.Textbox(
538
  label="Traduction pular",
539
+ lines=4,
540
+ interactive=False
541
+ )
542
+
543
+ # Pular to French translation (NEW)
544
+ with gr.Column():
545
+ gr.Markdown("#### 🌍 → 🇫🇷 Pular vers Français")
546
+ pular_input_ptof = gr.Textbox(
547
+ label="Texte pular",
548
+ placeholder="Entrez du texte pular à traduire en français...",
549
+ lines=4
550
+ )
551
+ with gr.Row():
552
+ translate_pl_to_fr = gr.Button("Traduire 🌍→🇫🇷", variant="primary")
553
+ clear_pl_to_fr = gr.Button("Effacer", variant="secondary")
554
+ french_output = gr.Textbox(
555
+ label="Traduction française",
556
+ lines=4,
557
  interactive=False
558
  )
559
 
560
+ # Connect buttons
561
+ # French to Pular
562
+ translate_fr_to_pl.click(
563
+ translate_french_to_pular,
564
+ inputs=french_input_ftop,
565
  outputs=pular_output
566
  )
567
+ french_input_ftop.submit(
568
+ translate_french_to_pular,
569
+ inputs=french_input_ftop,
570
  outputs=pular_output
571
  )
572
+ clear_fr_to_pl.click(
573
  lambda: ("", ""),
574
  None,
575
+ [french_input_ftop, pular_output]
576
  )
577
 
578
+ # Pular to French (NEW)
579
+ translate_pl_to_fr.click(
580
+ translate_pular_to_french,
581
+ inputs=pular_input_ptof,
582
+ outputs=french_output
583
+ )
584
+ pular_input_ptof.submit(
585
+ translate_pular_to_french,
586
+ inputs=pular_input_ptof,
587
+ outputs=french_output
 
 
 
 
588
  )
589
+ clear_pl_to_fr.click(
590
+ lambda: ("", ""),
591
+ None,
592
+ [pular_input_ptof, french_output]
593
+ )
594
+
595
+ gr.Markdown("### 📝 Exemples rapides")
596
+
597
+ with gr.Row():
598
+ # French to Pular examples
599
+ with gr.Column():
600
+ gr.Markdown("**Exemples Français→Pular:**")
601
+ fr_to_pl_examples = gr.Examples(
602
+ examples=[
603
+ ["Bonjour, je m'appelle Mamadou et je suis guinéen."],
604
+ ["L'éducation est la clé du développement d'un pays."],
605
+ ["La culture guinéenne est riche et diversifiée."]
606
+ ],
607
+ inputs=french_input_ftop,
608
+ outputs=pular_output,
609
+ fn=translate_french_to_pular,
610
+ cache_examples=True,
611
+ label="Cliquez sur un exemple"
612
+ )
613
+
614
+ # Pular to French examples (NEW)
615
+ with gr.Column():
616
+ gr.Markdown("**Exemples Pular→Français:**")
617
+ pl_to_fr_examples = gr.Examples(
618
+ examples=[
619
+ ["On jaaraama musee Alpha."],
620
+ ["Miɗo weelaa."],
621
+ ["Jannde ko saabi fii ɓantal leydi."]
622
+ ],
623
+ inputs=pular_input_ptof,
624
+ outputs=french_output,
625
+ fn=translate_pular_to_french,
626
+ cache_examples=True,
627
+ label="Cliquez sur un exemple"
628
+ )
629
 
630
  gr.Markdown("---")
631
  gr.Markdown("""
632
  ### ℹ️ À propos de ce système
633
 
634
+ **Nouveautés:**
635
+ - ✅ **Traduction Pular→Français** ajoutée (mlamined/pl_fr_104)
636
+ - 🔄 **Traduction bidirectionnelle** complète
637
+ - 🚀 **Deux modèles de traduction** indépendants
638
+
639
  **Fonctionnement:**
640
+ 1. Vous écrivez en français ou en pular
641
+ 2. Le système traduit dans la direction choisie
642
+ 3. Pour le chat: français → IA → pular
643
 
644
  **Capacités:**
645
  - Réponses intelligentes et contextuelles
646
+ - Traduction précise dans les deux sens
 
647
  - Interface intuitive et facile à utiliser
648
 
649
  **Note:** Les réponses peuvent prendre quelques secondes à générer sur CPU.
 
651
 
652
  if __name__ == "__main__":
653
  print("=" * 60)
654
+ print("🚀 DÉMARRAGE DU CHATBOT BIDIRECTIONNEL")
655
  print(f"📊 Statut LLM: {'✅ Prêt' if use_llm else '❌ Échec'}")
656
+ print(f"📊 Statut traducteur Pular→Français: {'✅ Prêt' if translator_pular_to_french else '❌ Échec'}")
657
+ print(f"📊 Statut traducteur Français→Pular: {'✅ Prêt' if translator_french_to_pular else '❌ Échec'}")
658
  print(f"⚡ Matériel: {'GPU' if torch.cuda.is_available() else 'CPU'}")
659
  print("=" * 60)
660
 
 
664
  share=True,
665
  debug=False,
666
  show_error=True
667
+ )