mechakc commited on
Commit
9aabd3a
·
verified ·
1 Parent(s): 00d9f12

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +208 -35
src/streamlit_app.py CHANGED
@@ -1,40 +1,213 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
- import streamlit as st
 
 
 
 
5
 
 
 
 
 
6
  """
7
- # Welcome to Streamlit!
8
 
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
 
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ """
2
+ CodeAlpha - Task 1: Language Translation Tool
3
+ Author: (Loic HOUNYOVI)
4
+ Description: Application web permettant de traduire du texte d'une langue
5
+ source vers une langue cible en utilisant un vrai modèle de
6
+ deep learning (Meta NLLB-200) chargé localement via la
7
+ librairie Hugging Face `transformers`, avec en bonus une
8
+ synthèse vocale (text-to-speech) et un bouton copier.
9
 
10
+ Modèle utilisé : facebook/nllb-200-distilled-600M
11
+ - Modèle Seq2Seq (encoder-decoder) multilingue, pré-entraîné par Meta AI
12
+ - Supporte ~200 langues avec un seul et même modèle
13
+ - Chargé via transformers.pipeline("translation", ...)
14
  """
 
15
 
16
+ import io
 
 
17
 
18
+ import streamlit as st
19
+ from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
20
+ from gtts import gTTS
21
+
22
+ try:
23
+ from langdetect import detect as detect_lang
24
+ LANGDETECT_AVAILABLE = True
25
+ except ImportError:
26
+ LANGDETECT_AVAILABLE = False
27
+
28
+ # ---------------------------------------------------------
29
+ # Configuration de la page
30
+ st.set_page_config(
31
+ page_title="CodeAlpha Language Translator (AI Model)",
32
+ page_icon="🌐",
33
+ layout="centered",
34
+ )
35
+
36
+ # ---------------------------------------------------------
37
+ # Langues supportées : code affichage -> (code NLLB / FLORES-200, code gTTS)
38
+ LANGUAGES = {
39
+ "en": "Anglais",
40
+ "fr": "Français",
41
+ "es": "Espagnol",
42
+ "de": "Allemand",
43
+ "it": "Italien",
44
+ "pt": "Portugais",
45
+ "ar": "Arabe",
46
+ "zh-CN": "Chinois (simplifié)",
47
+ "ja": "Japonais",
48
+ "ko": "Coréen",
49
+ "ru": "Russe",
50
+ "hi": "Hindi",
51
+ "nl": "Néerlandais",
52
+ "tr": "Turc",
53
+ }
54
+
55
+ NLLB_CODES = {
56
+ "en": "eng_Latn",
57
+ "fr": "fra_Latn",
58
+ "es": "spa_Latn",
59
+ "de": "deu_Latn",
60
+ "it": "ita_Latn",
61
+ "pt": "por_Latn",
62
+ "ar": "arb_Arab",
63
+ "zh-CN": "zho_Hans",
64
+ "ja": "jpn_Jpan",
65
+ "ko": "kor_Hang",
66
+ "ru": "rus_Cyrl",
67
+ "hi": "hin_Deva",
68
+ "nl": "nld_Latn",
69
+ "tr": "tur_Latn",
70
+ }
71
+
72
+ # gTTS accepte directement des codes ISO classiques (tous nos codes conviennent)
73
+ TTS_SUPPORTED = set(LANGUAGES.keys())
74
+
75
+
76
+ # ---------------------------------------------------------
77
+ # Chargement du modèle (mis en cache : ne se recharge pas à chaque interaction)
78
+ MODEL_NAME = "facebook/nllb-200-distilled-600M"
79
+
80
+
81
+ @st.cache_resource(show_spinner="Chargement du modèle NLLB-200 (peut prendre un moment la 1ère fois)...")
82
+ def load_model():
83
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
84
+ model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME)
85
+ return tokenizer, model
86
+
87
+
88
+ def translate_text(text: str, src_code: str, tgt_code: str) -> str:
89
+ """Traduit `text` de src_code vers tgt_code (codes FLORES-200) via NLLB-200."""
90
+ tokenizer, model = load_model()
91
+ tokenizer.src_lang = src_code
92
+ inputs = tokenizer(text, return_tensors="pt", truncation=True)
93
+ forced_bos_token_id = tokenizer.convert_tokens_to_ids(tgt_code)
94
+ generated_tokens = model.generate(
95
+ **inputs,
96
+ forced_bos_token_id=forced_bos_token_id,
97
+ max_length=400,
98
+ )
99
+ return tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)[0]
100
+
101
+ # ---------------------------------------------------------
102
+ # En-tête
103
+ st.title("🌐 Language Translation Tool")
104
+ st.caption("CodeAlpha Artificial Intelligence Internship — Task 1")
105
+
106
+ st.write(
107
+ "Entrez votre texte, choisissez la langue source et la langue cible, "
108
+ "puis cliquez sur **Traduire**."
109
+ )
110
+
111
+ # ---------------------------------------------------------
112
+ # Zone de saisie
113
+ input_text = st.text_area("Texte à traduire :", height=150, placeholder="Écrivez ou collez votre texte ici...")
114
+
115
+ col1, col2 = st.columns(2)
116
+ with col1:
117
+ source_options = ["auto"] + list(LANGUAGES.keys()) if LANGDETECT_AVAILABLE else list(LANGUAGES.keys())
118
+ source_lang = st.selectbox(
119
+ "Langue source",
120
+ options=source_options,
121
+ format_func=lambda code: "Détection automatique" if code == "auto" else LANGUAGES[code],
122
+ index=0,
123
+ )
124
+ with col2:
125
+ # Langue cible par défaut : anglais si la source n'est pas anglais, sinon français
126
+ target_options = [c for c in LANGUAGES.keys() if c != "auto"]
127
+ target_lang = st.selectbox(
128
+ "Langue cible",
129
+ options=target_options,
130
+ format_func=lambda code: LANGUAGES[code],
131
+ index=target_options.index("fr") if "fr" in target_options else 0,
132
+ )
133
+
134
+ translate_clicked = st.button("🔄 Traduire", type="primary", use_container_width=True)
135
+
136
+ # ---------------------------------------------------------
137
+ # Logique de traduction
138
+ if "translated_text" not in st.session_state:
139
+ st.session_state.translated_text = ""
140
+
141
+ if translate_clicked:
142
+ if not input_text.strip():
143
+ st.warning("Merci d'entrer du texte avant de traduire.")
144
+ else:
145
+ try:
146
+ # --- Détection automatique de la langue source si demandé ---
147
+ actual_source = source_lang
148
+ if source_lang == "auto":
149
+ if LANGDETECT_AVAILABLE:
150
+ detected = detect_lang(input_text)
151
+ # langdetect renvoie parfois "zh-cn" au lieu de "zh-CN"
152
+ detected = "zh-CN" if detected.lower().startswith("zh") else detected
153
+ actual_source = detected if detected in LANGUAGES else "en"
154
+ else:
155
+ actual_source = "en"
156
+
157
+ src_code = NLLB_CODES.get(actual_source)
158
+ tgt_code = NLLB_CODES.get(target_lang)
159
+
160
+ if src_code is None or tgt_code is None:
161
+ st.error("Langue non supportée par le modèle.")
162
+ else:
163
+ with st.spinner("Traduction en cours (inférence du modèle)..."):
164
+ result = translate_text(input_text, src_code, tgt_code)
165
+ st.session_state.translated_text = result
166
+ if source_lang == "auto":
167
+ st.caption(f"🔍 Langue détectée : {LANGUAGES.get(actual_source, actual_source)}")
168
+ except Exception as e:
169
+ st.error(f"Une erreur est survenue lors de la traduction : {e}")
170
+
171
+ # ---------------------------------------------------------
172
+ # Affichage du résultat
173
+ if st.session_state.translated_text:
174
+ st.subheader("Traduction :")
175
+ st.text_area(
176
+ "Résultat",
177
+ value=st.session_state.translated_text,
178
+ height=150,
179
+ label_visibility="collapsed",
180
+ )
181
+
182
+ col_a, col_b = st.columns(2)
183
+
184
+ # --- Bouton copier (via un petit composant HTML/JS) ---
185
+ with col_a:
186
+ copy_html = f"""
187
+ <textarea id="toCopy" style="display:none;">{st.session_state.translated_text}</textarea>
188
+ <button onclick="navigator.clipboard.writeText(document.getElementById('toCopy').value)"
189
+ style="width:100%; padding:8px; border-radius:6px; border:1px solid #ccc; cursor:pointer;">
190
+ 📋 Copier le texte
191
+ </button>
192
+ """
193
+ st.components.v1.html(copy_html, height=45)
194
+
195
+ # --- Bouton text-to-speech ---
196
+ with col_b:
197
+ if target_lang in TTS_SUPPORTED:
198
+ if st.button("🔊 Écouter la traduction", use_container_width=True):
199
+ try:
200
+ tts = gTTS(text=st.session_state.translated_text, lang=target_lang)
201
+ audio_bytes = io.BytesIO()
202
+ tts.write_to_fp(audio_bytes)
203
+ audio_bytes.seek(0)
204
+ st.audio(audio_bytes, format="audio/mp3")
205
+ except Exception as e:
206
+ st.error(f"Impossible de générer l'audio : {e}")
207
+ else:
208
+ st.info("🔇 Audio non disponible pour cette langue.")
209
 
210
+ # ---------------------------------------------------------
211
+ # Pied de page
212
+ st.divider()
213
+ st.caption("Projet réalisé dans le cadre du stage AI @CodeAlpha")