import streamlit as st import requests import re import tempfile import os from dotenv import load_dotenv # Nouveaux imports pour Groq et LangSmith from groq import Groq from langsmith import traceable # Charger les variables d'environnement load_dotenv() # --- INTERFACE STREAMLIT --- st.set_page_config(page_title="nlp", layout="wide") st.title("SN NATURAL LANGUAGE PROCESSING") st.subheader('Étudiant MASTER II: TATSA TCHINDA Colince') # Sidebar logo try: image_path = 'src/Keyce.jpg' st.sidebar.image(image_path, caption="Keyce informatique et intelligence artificielle", use_container_width=True) except FileNotFoundError: st.sidebar.warning("Image 'keyce.jpg' non trouvée. Assurez-vous qu'elle est dans le même répertoire que le script.") # --- GESTION DES CLÉS API (depuis .env) --- st.session_state["API_TOKEN_HF"] = os.getenv("HUGGINGFACE_API_KEY") st.session_state["API_TOKEN_GROQ"] = os.getenv("GROQ_API_KEY") api_token_langsmith = os.getenv("LANGCHAIN_API_KEY") # Configuration de LangSmith si la clé est fournie if api_token_langsmith: st.session_state["LANGSMITH_CONFIGURED"] = True os.environ["LANGCHAIN_TRACING_V2"] = "true" os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com" os.environ["LANGCHAIN_API_KEY"] = api_token_langsmith os.environ["LANGCHAIN_PROJECT"] = "Mon App Streamlit NLP" # Nom du projet dans LangSmith st.sidebar.info("Tracing LangSmith activé.") else: st.session_state["LANGSMITH_CONFIGURED"] = False # Désactiver le tracing si aucune clé n'est fournie if "LANGCHAIN_TRACING_V2" in os.environ: del os.environ["LANGCHAIN_TRACING_V2"] # --- INITIALISATION DES CLIENTS --- headers = {} if st.session_state.get("API_TOKEN_HF"): headers = {"Authorization": f"Bearer {st.session_state['API_TOKEN_HF']}"} # --- FONCTIONS UTILES --- def nettoyer_reponse(text): # La fonction de nettoyage n'est plus nécessaire pour Groq, mais on la garde au cas où. cleaned = re.sub(r".*?", "", text, flags=re.DOTALL) return cleaned.strip() @traceable(name="Groq Llama3 Generator") # Le décorateur @traceable active le suivi LangSmith def generate_with_groq_llama(prompt, api_key): """ Génère du texte en utilisant l'API Groq avec un modèle Llama3 et trace l'appel avec LangSmith. """ try: client_groq = Groq(api_key=api_key) chat_completion = client_groq.chat.completions.create( messages=[ { "role": "user", "content": prompt, } ], model="llama3-8b-8192", temperature=0.7, max_tokens=1024, ) return chat_completion.choices[0].message.content except Groq.APIConnectionError as e: st.error(f"Erreur de connexion avec Groq: {e.__cause__}") return "Impossible de se connecter à l'API Groq. Veuillez vérifier votre connexion réseau." except Exception as e: st.error(f"Une erreur inattendue est survenue avec Groq: {e}") return "Une erreur est survenue lors de la génération de texte." def transcribe_audio(path, content_type): request_headers = headers.copy() if not request_headers.get("Authorization"): st.error("Veuillez entrer une clé API Hugging Face pour utiliser cette fonctionnalité.") return "Erreur : clé API Hugging Face manquante." request_headers["Content-Type"] = content_type API_URL = "https://api-inference.huggingface.co/models/openai/whisper-large-v2" # Débogage st.info(f"Tentative de transcription audio...") st.info(f"Chemin du fichier audio : {path}") st.info(f"Type de contenu (Content-Type) : {content_type}") st.info(f"En-têtes de la requête (partie Authorization masquée) : {{'Authorization': 'Bearer [MASQUÉE]', 'Content-Type': '{content_type}'}}") if not st.session_state.get("API_TOKEN_HF"): st.error("DEBUG: La clé API Hugging Face n'est PAS présente dans st.session_state.") else: st.success("DEBUG: La clé API Hugging Face est présente dans st.session_state.") try: with open(path, "rb") as f: response = requests.post(API_URL, headers=request_headers, data=f) response.raise_for_status() # Lève une exception pour les codes d'erreur HTTP return response.json().get("text", "Erreur: 'text' non trouvé dans la réponse.") except requests.exceptions.HTTPError as err: st.error(f"Erreur Whisper Large: {err.response.status_code} - {err.response.text}") return f"Erreur lors de la transcription (Code: {err.response.status_code}). Vérifiez votre clé API HF et les limites d'utilisation." except Exception as e: st.error(f"Une erreur inattendue est survenue lors de la transcription : {str(e)}") return "Erreur lors de la transcription." def summarize_text(text): """ Génère un résumé de texte en utilisant le modèle Groq Llama3. """ if not st.session_state.get("API_TOKEN_GROQ"): st.error("Veuillez configurer votre clé API Groq dans le fichier .env pour le résumé.") return "Erreur : clé API Groq manquante." prompt = f"Résume le texte suivant de manière concise en français :\n\nTexte : '''{text}'''\n\nRésumé :" summary = generate_with_groq_llama(prompt, st.session_state["API_TOKEN_GROQ"]) return summary # --- MENU --- option = st.sidebar.radio( "Choisissez une fonctionnalité :", ["📝 Générateur de texte", "🎙 Audio vers texte", "🧠 Résumeur de texte"] ) # --- GÉNÉRATEUR DE TEXTE --- if option == "📝 Générateur de texte": st.subheader("📝 Génération de texte (Groq Llama3)") st.markdown("Utilise le modèle `llama3-8b-8192` via l'API ultra-rapide de Groq.") if st.session_state.get("LANGSMITH_CONFIGURED"): st.info("Le suivi avec LangSmith est activé. [Voir le projet](https://smith.langchain.com/)", icon="🔗") if not st.session_state.get("API_TOKEN_GROQ"): st.warning("Veuillez entrer une clé API Groq dans votre fichier `.env` pour utiliser le générateur de texte.") else: prompt = st.text_area("Entrez votre prompt :", key="prompt", height=150) if st.button("Générer", key="gen"): if prompt.strip(): with st.spinner("Génération en cours avec Groq..."): try: output = generate_with_groq_llama(prompt, st.session_state["API_TOKEN_GROQ"]) st.success("Texte généré :") st.write(output) except Exception as e: st.error(f"Erreur lors de la génération avec Groq : {e}") else: st.warning("Veuillez entrer un prompt.") # --- AUDIO VERS TEXTE --- elif option == "🎙 Audio vers texte": st.subheader("🎧 Transcription automatisée d’un fichier audio (30 sec max)") if not st.session_state.get("API_TOKEN_HF"): st.warning("Veuillez entrer une clé API Hugging Face dans votre fichier `.env` pour utiliser cette fonctionnalité.") else: audio_file = st.file_uploader("🎵 Chargez un fichier audio", type=["wav", "mp3", "m4a"]) if audio_file is not None: # Créer un fichier temporaire pour sauvegarder l'audio with tempfile.NamedTemporaryFile(delete=False, suffix=f'.{audio_file.name.split(".")[-1]}') as tmp_file: tmp_file.write(audio_file.getvalue()) audio_path = tmp_file.name st.audio(audio_path) if st.button("✍️ Transcrire"): with st.spinner("Transcription en cours..."): # On passe le type MIME du fichier original à la fonction transcript = transcribe_audio(audio_path, audio_file.type) if "Erreur" not in transcript: # Vérifiez si la transcription n'est pas une erreur st.markdown(f"**Transcription :**") st.text_area("Résultat", transcript, height=150) # Nettoyer le fichier temporaire os.unlink(audio_path) # --- RÉSUMEUR DE TEXTE --- elif option == "🧠 Résumeur de texte": st.subheader("🧠 Résumé de texte (Groq Llama3)") st.markdown("Utilise le modèle `llama3-8b-8192` pour générer un résumé.") if not st.session_state.get("API_TOKEN_GROQ"): st.warning("Veuillez vous assurer qu'une clé API Groq est configurée dans votre fichier .env pour utiliser cette fonctionnalité.") else: input_text = st.text_area("Texte à résumer :", height=300) if st.button("Résumer"): if input_text.strip(): with st.spinner("Résumé en cours avec Groq..."): summary = summarize_text(input_text) st.success("Résumé généré :") st.write(summary) else: st.warning("Veuillez entrer un texte à résumer.")