DavidNgoue's picture
Update app.py
d92220d verified
import streamlit as st
from transformers import pipeline, AutoTokenizer, AutoModelForCausalLM, VitsModel
import torch
import tempfile
import soundfile as sf
import time
from groq import Groq
from langsmith import Client
from langsmith.run_helpers import traceable
from langsmith.run_trees import RunTree
import os
from dotenv import load_dotenv
import json
from pathlib import Path
import streamlit.components.v1 as components
from streamlit_lottie import st_lottie
import requests
from streamlit_option_menu import option_menu
# Load environment variables
load_dotenv()
# ========== LangSmith & Env Setup (Official Best Practice) ==========
# Set LangSmith environment variables for tracing and project
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGSMITH_API_KEY"] = "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"
os.environ["LANGSMITH_PROJECT"] = "pr-complicated-oatmeal-59" # Nom de projet personnalisé
# Optionally, set OpenAI key if needed for other chains
# os.environ["OPENAI_API_KEY"] = "<your-openai-api-key>"
# Initialize LangSmith client (tracing is now automatic)
langsmith_client = Client()
# Initialize Groq client with default key
GROQ_API_KEY = "gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Remplacez par votre clé API Groq
os.environ["GROQ_API_KEY"] = GROQ_API_KEY
groq_client = Groq(api_key=GROQ_API_KEY)
# --------- UTILS for Lottie ---------
def load_lottieurl(url: str):
r = requests.get(url)
if r.status_code != 200:
return None
return r.json()
# --------- LOTTIE ANIMATIONS ---------
main_animation = load_lottieurl("https://assets2.lottiefiles.com/packages/lf20_4kx2q32n.json")
loading_animation = load_lottieurl("https://assets3.lottiefiles.com/packages/lf20_p8bfn5to.json")
about_animation = load_lottieurl("https://assets2.lottiefiles.com/packages/lf20_0yfsb3a1.json")
# ---------- PAGE CONFIG ----------
st.set_page_config(
page_title="Multi-IA 🌐✨",
layout="wide",
page_icon="🤖",
initial_sidebar_state="expanded"
)
# ---------- MODERN CSS (Pastel/Glassmorphism Palette) ----------
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@400;700&display=swap');
* { font-family: 'Quicksand', 'Poppins', sans-serif; }
body, .main {
background: linear-gradient(135deg, #fafdff 0%, #dbeafe 60%, #e0e7ff 100%) !important;
min-height: 100vh;
}
.stApp {
background: linear-gradient(135deg, #fafdff 0%, #dbeafe 60%, #e0e7ff 100%) !important;
}
.section-card, .visual-card, .metric-card {
background: rgba(255,255,255,0.92);
border-radius: 32px;
box-shadow: 0 8px 40px 0 #c7d2fe33, 0 1.5px 8px #e0e7ff33;
padding: 2.2rem 2rem;
margin-bottom: 2rem;
transition: box-shadow 0.3s, transform 0.2s;
backdrop-filter: blur(8px);
}
.section-card:hover, .visual-card:hover, .metric-card:hover {
box-shadow: 0 16px 48px 0 #c7d2fe44, 0 2px 12px #e0e7ff55;
transform: translateY(-2px) scale(1.01);
}
.section-title, .section-title-visual {
color: #6366f1;
font-size: 2.3em;
font-weight: 700;
margin-bottom: 0.5em;
text-shadow: 1px 1px 8px #e0e7ff44;
letter-spacing: 1px;
}
.badge, .ia-badge {
display: inline-block;
background: linear-gradient(90deg, #c7d2fe 0%, #e0e7ff 100%);
color: #6366f1;
border-radius: 16px;
padding: 0.4em 1.2em;
font-size: 1.05em;
font-weight: 700;
margin: 0.2em 0.3em;
box-shadow: 0 2px 8px #c7d2fe22;
letter-spacing: 1px;
}
.stButton>button, .glow-btn {
background: linear-gradient(90deg, #c7d2fe 0%, #e0e7ff 100%);
color: #6366f1;
border-radius: 32px;
padding: 1em 2.5em;
font-size: 1.18em;
font-weight: 700;
box-shadow: 0 4px 24px #c7d2fe33, 0 1.5px 8px #e0e7ff33;
margin-top: 0.5em;
margin-bottom: 1.2em;
transition: box-shadow 0.2s, transform 0.2s, background 0.2s;
cursor: pointer;
}
.stButton>button:hover, .glow-btn:hover {
box-shadow: 0 8px 32px #c7d2fe55, 0 2px 12px #e0e7ff55;
background: linear-gradient(90deg, #e0e7ff 0%, #c7d2fe 100%);
color: #3730a3;
transform: translateY(-2px) scale(1.04);
}
.about-avatar {
border-radius: 50%;
border: 4px solid #c7d2fe;
box-shadow: 0 4px 16px #c7d2fe33;
margin-bottom: 1em;
}
.about-contact-btn {
background: linear-gradient(90deg, #c7d2fe 0%, #e0e7ff 100%);
color: #6366f1;
border-radius: 22px;
padding: 0.6em 1.7em;
border: none;
font-weight: 700;
margin: 0.5em 0.5em 0.5em 0;
font-size: 1.13em;
box-shadow: 0 2px 8px #c7d2fe22;
transition: background 0.2s, color 0.2s;
}
.about-contact-btn:hover {
background: linear-gradient(90deg, #e0e7ff 0%, #c7d2fe 100%);
color: #3730a3;
}
.stTextInput > div > div > input, .stTextArea > div > div > textarea {
background: transparent !important;
color: #3730a3 !important;
}
.stTextInput > div > div > input:focus, .stTextArea > div > div > textarea:focus {
border-color: #6366f1;
box-shadow: 0 0 0 3px #c7d2fe33;
}
.stSelectbox > div > div {
background: transparent !important;
color: #3730a3 !important;
}
.stSelectbox label {
color: #6366f1 !important;
}
.stSelectbox div[role="option"] {
color: #3730a3 !important;
background: #f3f4f6 !important;
}
.stSelectbox span {
color: #3730a3 !important;
}
.sidebar .sidebar-content {
background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);
box-shadow: 2px 0 18px #c7d2fe22;
border-radius: 22px;
backdrop-filter: blur(6px);
}
.stProgress > div > div { background-color: #c7d2fe; }
.stAlert { border-radius: 14px; }
.section-sep {
border: none;
border-top: 2px solid #e0e7ff;
margin: 2.5em 0 2em 0;
width: 80%;
}
.card-fade {
opacity: 0;
transform: translateY(30px);
animation: fadeInUp 0.8s forwards;
animation-delay: 0.2s;
}
@keyframes fadeInUp {
to {
opacity: 1;
transform: none;
}
}
/* Option menu pastel doux */
.css-1d391kg, .css-1d391kg .sidebar-content {
background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%) !important;
border-radius: 22px !important;
box-shadow: 0 4px 24px #c7d2fe22 !important;
}
/* For the selectbox dropdown popup */
.stSelectbox [data-baseweb="select"] {
color: #3730a3 !important;
background: #fafdff !important;
}
.stSelectbox [data-baseweb="select"] * {
color: #3730a3 !important;
background: #fafdff !important;
}
.stSelectbox [data-baseweb="select"] div[role="option"] {
color: #3730a3 !important;
background: #f3f4f6 !important;
}
.stSelectbox [data-baseweb="select"] span {
color: #3730a3 !important;
}
.stSelectbox label {
color: #6366f1 !important;
}
</style>
""", unsafe_allow_html=True)
# ---------- SIDEBAR (Lottie + Option Menu) ----------
with st.sidebar:
st_lottie(main_animation, height=120, key="sidebar_animation")
selected = option_menu(
menu_title="Navigation",
options=["Accueil", "Génération de texte", "Text-to-Speech", "Traduction", "À propos"],
icons=['house', 'robot', 'volume-up', 'globe', 'info-circle'],
menu_icon="cast",
default_index=0,
styles={
"container": {
"padding": "0!important",
"background": "linear-gradient(135deg, #fafdff 0%, #dbeafe 60%, #e0e7ff 100%)",
"box-shadow": "0 4px 24px #c7d2fe22",
"border-radius": "22px"
},
"icon": {"color": "#6366f1", "font-size": "22px"},
"nav-link": {
"font-size": "17px",
"text-align": "left",
"margin": "0px",
"padding": "12px 18px",
"color": "#6366f1",
"background": "transparent",
"border-radius": "14px",
"transition": "background 0.2s, color 0.2s",
"--hover-color": "#e0e7ff",
},
"nav-link-selected": {
"background": "linear-gradient(90deg, #e0e7ff 0%, #c7d2fe 100%)",
"color": "#6366f1",
"box-shadow": "0 2px 12px #c7d2fe44",
},
}
)
# ---------- API Key Management ----------
def save_api_key(groq_api_key, langsmith_api_key):
config_file = "config.json"
config = {
"groq_api_key": groq_api_key,
"langsmith_api_key": langsmith_api_key
}
with open(config_file, "w") as f:
json.dump(config, f)
def load_api_key():
config_file = Path("config.json")
if config_file.exists():
with open(config_file, "r") as f:
config = json.load(f)
return config.get("groq_api_key"), config.get("langsmith_api_key")
return None, None
# ---------- API Key Setup Interface ----------
def show_api_key_setup():
st.markdown("""
<style>
.api-setup {
max-width: 800px;
margin: 2rem auto;
padding: 2rem;
background: rgba(255, 255, 255, 0.95);
border-radius: 1.5rem;
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
animation: fadeInUp 0.8s ease;
}
.api-setup h1 {
color: #1f3c88;
text-align: center;
margin-bottom: 1.5rem;
}
.api-setup p {
color: #4a5568;
text-align: center;
margin-bottom: 2rem;
}
.api-input {
background: #f8fafc;
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
padding: 0.75rem;
width: 100%;
margin-bottom: 1rem;
transition: all 0.3s ease;
}
.api-input:focus {
border-color: #4facfe;
box-shadow: 0 0 0 3px rgba(79, 172, 254, 0.1);
}
.api-button {
background: linear-gradient(to right, #4facfe, #00f2fe);
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 0.75rem;
width: 100%;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.api-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.api-info {
background: #ebf8ff;
border-radius: 0.75rem;
padding: 1rem;
margin-top: 1.5rem;
font-size: 0.9rem;
color: #2b6cb0;
}
.api-section {
background: #f8fafc;
border-radius: 1rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.api-section h3 {
color: #2c5282;
margin-bottom: 1rem;
}
</style>
""", unsafe_allow_html=True)
st.markdown("""
<div class="api-setup">
<h1>🔑 Configuration des API</h1>
<p>Pour utiliser toutes les fonctionnalités de Multi-IA, veuillez configurer vos clés API.</p>
</div>
""", unsafe_allow_html=True)
# Groq API Section
st.markdown("""
<div class="api-section">
<h3>🤖 API Groq</h3>
</div>
""", unsafe_allow_html=True)
groq_api_key = st.text_input(
"Clé API Groq",
type="password",
help="Entrez votre clé API Groq pour activer la génération de texte avancée"
)
# LangSmith API Section
st.markdown("""
<div class="api-section">
<h3>📊 API LangSmith</h3>
</div>
""", unsafe_allow_html=True)
langsmith_api_key = st.text_input(
"Clé API LangSmith",
type="password",
value="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",
help="Entrez votre clé API LangSmith pour activer le monitoring"
)
col1, col2 = st.columns([1, 2])
with col1:
if st.button("💾 Sauvegarder", use_container_width=True):
if groq_api_key and langsmith_api_key:
save_api_key(groq_api_key, langsmith_api_key)
st.success("Clés API sauvegardées avec succès!")
st.rerun()
else:
st.error("Veuillez entrer toutes les clés API requises")
with col2:
st.markdown("""
<div class="api-info">
<p>🔍 Comment obtenir vos clés API :</p>
<h4>Groq API :</h4>
<ol>
<li>Créez un compte sur <a href="https://console.groq.com" target="_blank">console.groq.com</a></li>
<li>Accédez à la section "API Keys"</li>
<li>Générez une nouvelle clé API</li>
</ol>
<h4>LangSmith API :</h4>
<ol>
<li>Créez un compte sur <a href="https://smith.langchain.com" target="_blank">smith.langchain.com</a></li>
<li>Accédez à vos paramètres</li>
<li>Générez une nouvelle clé API</li>
</ol>
</div>
""", unsafe_allow_html=True)
# ---------- Model Loading with Caching ----------
@st.cache_resource
def load_tts_model(language_code="eng"):
try:
model = VitsModel.from_pretrained(f"facebook/mms-tts-{language_code}")
tokenizer = AutoTokenizer.from_pretrained(f"facebook/mms-tts-{language_code}")
return model, tokenizer
except:
return None, None
@st.cache_resource
def load_models():
gen = pipeline("text-generation", model="gpt2")
tts_model, tts_tokenizer = load_tts_model()
return gen, tts_model, tts_tokenizer
text_gen, tts_model, tts_tokenizer = load_models()
# Initialize global clients
groq_client = None
langsmith_client = None
def initialize_clients(groq_api_key, langsmith_api_key):
global groq_client, langsmith_client
try:
groq_client = Groq(api_key=groq_api_key)
langsmith_client = Client(api_key=langsmith_api_key)
return True
except Exception as e:
st.error(f"Erreur lors de l'initialisation des clients: {str(e)}")
return False
# ---------- Enhanced Functions ----------
@traceable(run_type="chain", name="groq_text_generation")
def generate_text_with_groq(prompt, length, temperature=1.0):
try:
if not groq_client:
st.error("Client Groq non initialisé. Veuillez vérifier la configuration.")
return None
response = groq_client.chat.completions.create(
messages=[{"role": "user", "content": prompt}],
model="llama-3.3-70b-versatile",
temperature=temperature,
max_tokens=length
)
return response.choices[0].message.content
except Exception as e:
st.error(f"Erreur Groq: {str(e)}")
return None
@traceable(run_type="chain", name="translation")
def translate(text, src_lang, tgt_lang):
global langsmith_client
if not langsmith_client:
st.error("Le client LangSmith n'est pas initialisé. Veuillez configurer vos clés API.")
return None
try:
model_name = f"Helsinki-NLP/opus-mt-{src_lang}-{tgt_lang}"
translator = pipeline("translation", model=model_name)
result = translator(text)[0]["translation_text"]
return result
except Exception as e:
st.error(f"Erreur de traduction: {str(e)}")
return None
@traceable(run_type="chain", name="text_to_speech")
def text_to_speech(text, model, tokenizer):
global langsmith_client
if not langsmith_client:
st.error("Le client LangSmith n'est pas initialisé. Veuillez configurer vos clés API.")
return None
if model is None or tokenizer is None:
return None
try:
inputs = tokenizer(text, return_tensors="pt")
with torch.no_grad():
output = model(**inputs)
waveform = output.waveform[0].cpu().numpy()
sample_rate = model.config.sampling_rate
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as fp:
sf.write(fp.name, waveform, sample_rate)
audio_file = open(fp.name, "rb")
return audio_file.read()
except Exception as e:
st.error(f"Erreur TTS: {str(e)}")
return None
# ========== Modern LangSmith Monitoring Badge ==========
st.markdown(
'''
<style>
.ls-badge {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
animation: fadeIn 1.2s;
}
.ls-dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: linear-gradient(135deg, #4facfe, #00f2fe);
margin-right: 10px;
box-shadow: 0 0 10px #00f2fe, 0 0 20px #4facfe;
animation: pulse 1.5s infinite;
}
.ls-text {
font-weight: bold;
color: #1f3c88;
font-size: 1.1rem;
letter-spacing: 1px;
text-shadow: 0 2px 8px #e0f7fa;
}
@keyframes pulse {
0% { box-shadow: 0 0 10px #00f2fe, 0 0 20px #4facfe; }
50% { box-shadow: 0 0 20px #00f2fe, 0 0 40px #4facfe; }
100% { box-shadow: 0 0 10px #00f2fe, 0 0 20px #4facfe; }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
<div class="ls-badge">
<div class="ls-dot"></div>
<span class="ls-text">LangSmith Monitoring : <span style="color:#00b894">ACTIF</span></span>
</div>
''', unsafe_allow_html=True
)
# ---------- Main Application ----------
def main():
global groq_client, langsmith_client
# Check if API keys are configured
groq_api_key, langsmith_api_key = load_api_key()
if not groq_api_key or not langsmith_api_key:
show_api_key_setup()
return
# Initialize clients with the saved API keys
if not initialize_clients(groq_api_key, langsmith_api_key):
st.error("Impossible d'initialiser les clients API. Veuillez vérifier vos clés API.")
return
# Set up LangSmith environment
os.environ["LANGCHAIN_API_KEY"] = langsmith_api_key
os.environ["LANGCHAIN_PROJECT"] = "multi-ia-app"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
# ---------- Main Interface ----------
st.markdown(
"""
<div style="text-align: center; margin-bottom: 2rem;">
<h1 class="title-animation" style="color: white; font-size: 3rem; text-shadow: 2px 2px 4px rgba(0,0,0,0.2);">
✨ Multi-IA : Génération · Voix · Traduction ✨
</h1>
<p style="color: white; font-size: 1.2rem; opacity: 0.9;">
Bienvenue dans un univers intelligent où le texte prend vie ! 🧠🔊🌍
</p>
</div>
""",
unsafe_allow_html=True
)
# ---------- Dynamic Content ----------
if selected == "Accueil":
st.markdown("""
<div style='
text-align: center;
padding: 2.5rem 1rem 2rem 1rem;
background: linear-gradient(135deg, #f8fafc 0%, #e4e8eb 100%);
border-radius: 22px;
margin-bottom: 36px;
box-shadow: 0 6px 32px 0 rgba(76, 110, 245, 0.08);
'>
<h1 class='section-title' style='font-size:2.8em; margin-bottom:0.2em;'>✨ Multi-IA : Génération · Voix · Traduction ✨</h1>
<p style='color: #2c3e50; font-size: 1.35em; font-weight: 400; margin-bottom:0.8em;'>
<i>Bienvenue dans un univers intelligent où le texte prend vie ! 🧠🔊🌍</i>
</p>
<hr style='border: none; border-top: 1.5px solid #e4e8eb; width: 60%; margin: 1.5em auto 1.5em auto;'/>
<p style='color: #4b79a1; font-size: 1.1em; max-width: 700px; margin: auto;'>
Cette application met la puissance du machine learning et du NLP au service de la créativité et de la productivité : <b>génère, vocalise, traduis</b> en quelques clics.<br>
<span style='color:#283e51;'>Pensée pour les passionnés d'IA, accessible à tous.</span>
</p>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns([1.5, 1])
with col1:
st.markdown("""
<div class='section-card' style='margin-bottom:1.5em;'>
<h3 style='color:#4b79a1; font-size:1.3em;'>🎯 Mission</h3>
<p style='font-size:1.08em;'>
Offrir une plateforme IA tout-en-un pour explorer la génération de texte, la synthèse vocale et la traduction automatique, avec une expérience utilisateur moderne et agréable.
</p>
</div>
<div class='section-card'>
<h3 style='color:#4b79a1; font-size:1.2em;'>🔬 Technologies</h3>
<span class='badge'>Groq</span>
<span class='badge'>Meta MMS-TTS</span>
<span class='badge'>Helsinki-NLP</span>
<span class='badge'>LangSmith</span>
<span class='badge'>Streamlit</span>
<span class='badge'>Python</span>
</div>
""", unsafe_allow_html=True)
with col2:
st_lottie(main_animation, height=220, key="main_animation")
st.markdown("""
<div style='margin-top: 18px; background: linear-gradient(135deg, #4b79a1 0%, #283e51 100%); color: white; padding: 18px; border-radius: 12px; text-align: center; box-shadow: 0 2px 10px rgba(76,110,245,0.10);'>
<h2 style='margin:0;'>+1000</h2>
<p style='margin:0;'>Utilisateurs IA</p>
</div>
""", unsafe_allow_html=True)
elif selected == "Génération de texte":
st.markdown("""
<div style='background: rgba(255,255,255,0.75); border-radius: 38px; box-shadow: 0 12px 48px 0 #a18cd144, 0 2px 12px #fbc2eb55; padding: 2.8rem 2.2rem 2.2rem 2.2rem; margin-bottom: 2.5rem; position: relative; max-width: 900px; margin-left:auto; margin-right:auto;'>
<div style='display:flex; align-items:center; justify-content:center; margin-bottom:1.2em;'>
<img src="https://lottie.host/6e7e2e7b-6e7e-4e7e-8e7e-6e7e2e7b6e7e/ai.json" alt="AI" style="height:48px; margin-right:16px;"/>
<h1 style='font-size:2.3em; color:#a18cd1; font-weight:800; letter-spacing:1px; margin:0;'>Générateur de texte IA</h1>
</div>
<span class='badge'>Groq · Génération</span>
<hr class='section-sep' style='margin:1.2em 0 2em 0;'/>
</div>
<style>
.modern-input {background:rgba(255,255,255,0.92); border:2px solid #a18cd1; border-radius:20px; padding:0.85rem; font-size:1.08em; transition:all 0.3s;}
.modern-input:focus {border-color:#fbc2eb; box-shadow:0 0 0 3px #a18cd133;}
</style>
""", unsafe_allow_html=True)
col1, col2 = st.columns([2,1])
with col1:
prompt = st.text_area("Prompt", placeholder="Ex: Raconte-moi une histoire sur l'IA du futur...", key="modern-prompt", height=100)
with col2:
length = st.slider("Longueur du texte", 20, 200, 80, key="slider-longueur")
temperature = st.slider("Température", min_value=0.0, max_value=2.0, value=1.0, step=0.1, key="slider-temperature")
gen_btn = st.button("✨ Générer le texte", key="modern-gen-btn")
if gen_btn:
with st.spinner("Génération en cours..."):
st_lottie(loading_animation, height=80, key="loading-text-gen")
texte = generate_text_with_groq(prompt, length, temperature)
if texte:
st.markdown(f"""
<div class='fade-in-card' style='background: linear-gradient(120deg, #fafdff 60%, #fbc2eb 100%); border-radius: 28px; box-shadow: 0 4px 24px #a18cd122; padding: 2rem 1.5rem; margin-top:1.5em; max-width:700px; margin-left:auto; margin-right:auto;'>
<span class='ia-badge'>🤖 Réponse IA</span>
<div style='font-size:1.18em; color:#222; margin:1em 0 0.5em 0;'>{texte}</div>
<button class='copy-btn' onclick="navigator.clipboard.writeText(`{texte}`)">Copier</button>
</div>
""", unsafe_allow_html=True)
else:
st.error("Erreur lors de la génération du texte.")
elif selected == "Text-to-Speech":
with st.container():
st.subheader("🎤 Synthèse vocale", anchor="synthese-vocale")
st.markdown("""
<div class="block">
<p>Convertis n'importe quel texte en voix naturelle avec notre modèle TTS avancé.</p>
</div>
""", unsafe_allow_html=True)
realtime_option = st.checkbox("Mode progressif", value=True)
text_input = st.text_area("Texte à vocaliser :")
language = st.selectbox("Langue", ["eng", "fra", "spa", "deu", "ita"],
format_func=lambda x: {
"eng": "Anglais", "fra": "Français",
"spa": "Espagnol", "deu": "Allemand",
"ita": "Italien"
}[x])
if st.button("🔊 Écouter"):
with st.spinner("Génération audio en cours..."):
model, tokenizer = load_tts_model(language)
if model:
if realtime_option:
text_placeholder = st.empty()
audio_placeholder = st.empty()
words = text_input.split()
displayed_text = ""
audio = text_to_speech(text_input, model, tokenizer)
if audio:
for i, word in enumerate(words):
displayed_text += word + " "
text_placeholder.markdown(
f"<div class='generated-text'>{displayed_text}</div>",
unsafe_allow_html=True
)
if i == len(words) // 4:
audio_placeholder.audio(audio, format="audio/wav")
time.sleep(0.1)
else:
st.error("Erreur dans la synthèse vocale.")
else:
audio = text_to_speech(text_input, model, tokenizer)
if audio:
st.markdown(
f"<div class='generated-text'>{text_input}</div>",
unsafe_allow_html=True
)
st.audio(audio, format="audio/wav")
else:
st.error("Erreur dans la synthèse vocale.")
else:
st.error("Modèle TTS non chargé correctement.")
elif selected == "Traduction":
with st.container():
st.subheader("🌍 Traduction automatique", anchor="traduction-automatique")
st.markdown("""
<div class="block">
<p>Traduis instantanément entre plusieurs langues avec notre modèle de traduction avancé.</p>
</div>
""", unsafe_allow_html=True)
langues = {
"allemand (de)": "de",
"espagnol (es)": "es",
"français (fr)": "fr",
"anglais (en)": "en",
"italien (it)": "it",
"néerlandais (nl)": "nl",
"portugais (pt)": "pt",
}
col1, col2 = st.columns(2)
with col1:
src = st.selectbox("Langue source :", list(langues.keys()), index=0)
with col2:
tgt = st.selectbox("Langue cible :", list(langues.keys()), index=1)
if langues[src] == langues[tgt]:
st.warning("La langue source et la langue cible doivent être différentes.")
else:
texte_input = st.text_area("Texte à traduire :",
placeholder="Ex : Wie schön ist das Wetter heute?")
if st.button("📤 Traduire"):
with st.spinner("Traduction en cours..."):
result = translate(texte_input, langues[src], langues[tgt])
if result:
st.markdown(f"<div class='block'><p><strong>{src.capitalize()} :</strong> {texte_input}</p></div>",
unsafe_allow_html=True)
st.markdown(f"<div class='block'><p><strong>{tgt.capitalize()} :</strong> <span class='translated-text'>{result}</span></p></div>",
unsafe_allow_html=True)
else:
st.error("Erreur lors de la traduction ou modèle non disponible.")
elif selected == "À propos":
st.markdown("""
<div style='background: linear-gradient(120deg, #4b79a1 0%, #283e51 100%); padding: 2rem; border-radius: 18px; color: white; margin-bottom: 2rem; text-align: center; box-shadow: 0 4px 15px rgba(0,0,0,0.1);'>
<h1 class='section-title' style='color:white;'>À propos</h1>
<p>Découvrez le créateur, le projet et les technologies utilisées</p>
</div>
""", unsafe_allow_html=True)
col1, col2 = st.columns([1, 2])
with col1:
st_lottie(about_animation, height=220, key="about_animation")
st.image(
"https://avatars.githubusercontent.com/u/TheBeyonder237",
width=180,
caption="Ngoue David",
output_format="auto",
use_container_width=False,
channels="RGB"
)
st.markdown("""
<div style='text-align:center; margin-top:1em;'>
<button class='about-contact-btn' onclick="window.open('mailto:ngouedavidrogeryannick@gmail.com')">📧 Email</button>
<button class='about-contact-btn' onclick="window.open('https://github.com/TheBeyonder237')">🌐 GitHub</button>
</div>
""", unsafe_allow_html=True)
with col2:
st.markdown("""
<div class='section-card'>
<h2 class='section-title'>Qui suis-je ?</h2>
<p>
Je suis un passionné de l'intelligence artificielle et de la donnée.<br>
Actuellement en Master 2 en IA et Big Data, je travaille sur des solutions innovantes dans le domaine de l'Intelligence Artificielle appliquée à la finance et à la santé.
</p>
<h3 style='color:#4b79a1;'>Compétences</h3>
<span class='badge'>Python</span>
<span class='badge'>Machine Learning</span>
<span class='badge'>Deep Learning</span>
<span class='badge'>NLP</span>
<span class='badge'>Data Science</span>
<span class='badge'>Cloud Computing</span>
<span class='badge'>Streamlit</span>
<span class='badge'>Scikit-learn</span>
<span class='badge'>XGBoost</span>
<span class='badge'>Pandas</span>
<span class='badge'>Plotly</span>
<span class='badge'>SQL</span>
<h3 style='color:#4b79a1; margin-top:1.5em;'>Projets Récents</h3>
<ul>
<li><b>💳 Credit Card Expenditure Predictor</b> : Application de prédiction de dépenses de carte de crédit.</li>
<li><b>🫀 HeartGuard AI</b> : Prédiction de risques cardiaques par IA.</li>
<li><b>🔊 Multi-IA</b> : Plateforme multi-modèles pour la génération de texte, synthèse vocale et traduction.</li>
</ul>
</div>
""", unsafe_allow_html=True)
st.markdown("""
<div style='text-align: center; color: #666; padding: 20px;'>
Développé avec ❤️ par Ngoue David
</div>
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()