""" CodeAlpha - Task 1: Language Translation Tool Author: (Loic HOUNYOVI) Description: Application web permettant de traduire du texte d'une langue source vers une langue cible en utilisant un vrai modèle de deep learning (Meta NLLB-200) chargé localement via la librairie Hugging Face `transformers`, avec en bonus une synthèse vocale (text-to-speech) et un bouton copier. Modèle utilisé : facebook/nllb-200-distilled-600M - Modèle Seq2Seq (encoder-decoder) multilingue, pré-entraîné par Meta AI - Supporte ~200 langues avec un seul et même modèle - Chargé via transformers.pipeline("translation", ...) """ import io import streamlit as st from transformers import AutoModelForSeq2SeqLM, AutoTokenizer from gtts import gTTS try: from langdetect import detect as detect_lang LANGDETECT_AVAILABLE = True except ImportError: LANGDETECT_AVAILABLE = False # --------------------------------------------------------- # Configuration de la page st.set_page_config( page_title="CodeAlpha Language Translator (AI Model)", page_icon="🌐", layout="centered", ) # --------------------------------------------------------- # Langues supportées : code affichage -> (code NLLB / FLORES-200, code gTTS) LANGUAGES = { "en": "Anglais", "fr": "Français", "es": "Espagnol", "de": "Allemand", "it": "Italien", "pt": "Portugais", "ar": "Arabe", "zh-CN": "Chinois (simplifié)", "ja": "Japonais", "ko": "Coréen", "ru": "Russe", "hi": "Hindi", "nl": "Néerlandais", "tr": "Turc", } NLLB_CODES = { "en": "eng_Latn", "fr": "fra_Latn", "es": "spa_Latn", "de": "deu_Latn", "it": "ita_Latn", "pt": "por_Latn", "ar": "arb_Arab", "zh-CN": "zho_Hans", "ja": "jpn_Jpan", "ko": "kor_Hang", "ru": "rus_Cyrl", "hi": "hin_Deva", "nl": "nld_Latn", "tr": "tur_Latn", } # gTTS accepte directement des codes ISO classiques (tous nos codes conviennent) TTS_SUPPORTED = set(LANGUAGES.keys()) # --------------------------------------------------------- # Chargement du modèle (mis en cache : ne se recharge pas à chaque interaction) MODEL_NAME = "facebook/nllb-200-distilled-600M" @st.cache_resource(show_spinner="Chargement du modèle NLLB-200 (peut prendre un moment la 1ère fois)...") def load_model(): tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME) return tokenizer, model def translate_text(text: str, src_code: str, tgt_code: str) -> str: """Traduit `text` de src_code vers tgt_code (codes FLORES-200) via NLLB-200.""" tokenizer, model = load_model() tokenizer.src_lang = src_code inputs = tokenizer(text, return_tensors="pt", truncation=True) forced_bos_token_id = tokenizer.convert_tokens_to_ids(tgt_code) generated_tokens = model.generate( **inputs, forced_bos_token_id=forced_bos_token_id, max_length=400, ) return tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)[0] # --------------------------------------------------------- # En-tête st.title("🌐 Language Translation Tool") st.caption("CodeAlpha Artificial Intelligence Internship — Task 1") st.write( "Entrez votre texte, choisissez la langue source et la langue cible, " "puis cliquez sur **Traduire**." ) # --------------------------------------------------------- # Zone de saisie input_text = st.text_area("Texte à traduire :", height=150, placeholder="Écrivez ou collez votre texte ici...") col1, col2 = st.columns(2) with col1: source_options = ["auto"] + list(LANGUAGES.keys()) if LANGDETECT_AVAILABLE else list(LANGUAGES.keys()) source_lang = st.selectbox( "Langue source", options=source_options, format_func=lambda code: "Détection automatique" if code == "auto" else LANGUAGES[code], index=0, ) with col2: # Langue cible par défaut : anglais si la source n'est pas anglais, sinon français target_options = [c for c in LANGUAGES.keys() if c != "auto"] target_lang = st.selectbox( "Langue cible", options=target_options, format_func=lambda code: LANGUAGES[code], index=target_options.index("fr") if "fr" in target_options else 0, ) translate_clicked = st.button("🔄 Traduire", type="primary", use_container_width=True) # --------------------------------------------------------- # Logique de traduction if "translated_text" not in st.session_state: st.session_state.translated_text = "" if translate_clicked: if not input_text.strip(): st.warning("Merci d'entrer du texte avant de traduire.") else: try: # --- Détection automatique de la langue source si demandé --- actual_source = source_lang if source_lang == "auto": if LANGDETECT_AVAILABLE: detected = detect_lang(input_text) # langdetect renvoie parfois "zh-cn" au lieu de "zh-CN" detected = "zh-CN" if detected.lower().startswith("zh") else detected actual_source = detected if detected in LANGUAGES else "en" else: actual_source = "en" src_code = NLLB_CODES.get(actual_source) tgt_code = NLLB_CODES.get(target_lang) if src_code is None or tgt_code is None: st.error("Langue non supportée par le modèle.") else: with st.spinner("Traduction en cours (inférence du modèle)..."): result = translate_text(input_text, src_code, tgt_code) st.session_state.translated_text = result if source_lang == "auto": st.caption(f"🔍 Langue détectée : {LANGUAGES.get(actual_source, actual_source)}") except Exception as e: st.error(f"Une erreur est survenue lors de la traduction : {e}") # --------------------------------------------------------- # Affichage du résultat if st.session_state.translated_text: st.subheader("Traduction :") st.text_area( "Résultat", value=st.session_state.translated_text, height=150, label_visibility="collapsed", ) col_a, col_b = st.columns(2) # --- Bouton copier (via un petit composant HTML/JS) --- with col_a: copy_html = f""" """ st.components.v1.html(copy_html, height=45) # --- Bouton text-to-speech --- with col_b: if target_lang in TTS_SUPPORTED: if st.button("🔊 Écouter la traduction", use_container_width=True): try: tts = gTTS(text=st.session_state.translated_text, lang=target_lang) audio_bytes = io.BytesIO() tts.write_to_fp(audio_bytes) audio_bytes.seek(0) st.audio(audio_bytes, format="audio/mp3") except Exception as e: st.error(f"Impossible de générer l'audio : {e}") else: st.info("🔇 Audio non disponible pour cette langue.") # --------------------------------------------------------- # Pied de page st.divider() st.caption("Projet réalisé dans le cadre du stage AI @CodeAlpha")