ColinceTatsa commited on
Commit
c494a1f
·
verified ·
1 Parent(s): 3f5cf62

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +201 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,203 @@
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
  import streamlit as st
2
+ import requests
3
+ import re
4
 
5
+ import tempfile
6
+ import os
7
+ from dotenv import load_dotenv
8
+
9
+ # Nouveaux imports pour Groq et LangSmith
10
+ from groq import Groq
11
+ from langsmith import traceable
12
+
13
+ # Charger les variables d'environnement
14
+ load_dotenv()
15
+
16
+ # ========= INTERFACE STREAMLIT =========
17
+ st.set_page_config(page_title="nlp", layout="wide")
18
+ st.title("SN NATURAL LANGUAGE PROCESSING")
19
+
20
+ st.subheader('Etudiant MASTER II: TATSA TCHINDA Colince')
21
+
22
+ # Sidebar logo
23
+ # Assurez-vous que le fichier 'keyce.jpg' est dans le même dossier que votre script
24
+ try:
25
+ image_path = 'src/keyce.jpg'
26
+ st.sidebar.image(image_path, caption="Keyce informatique et intelligence artificielle", use_container_width=True)
27
+ except FileNotFoundError:
28
+ st.sidebar.warning("Image 'keyce.jpg' non trouvée.")
29
+
30
+
31
+ # ========= GESTION DES CLÉS API (depuis .env) =========
32
+ # Les clés sont chargées depuis le fichier .env. Assurez-vous d'av
33
+
34
+ st.session_state["API_TOKEN_HF"] = os.getenv("HUGGINGFACE_API_KEY")
35
+ st.session_state["API_TOKEN_GROQ"] = os.getenv("GROQ_API_KEY")
36
+ api_token_langsmith = os.getenv("LANGCHAIN_API_KEY")
37
+
38
+ # Configuration de LangSmith si la clé est fournie
39
+ if api_token_langsmith:
40
+ st.session_state["LANGSMITH_CONFIGURED"] = True
41
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
42
+ os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
43
+ os.environ["LANGCHAIN_API_KEY"] = api_token_langsmith
44
+ os.environ["LANGCHAIN_PROJECT"] = "Mon App Streamlit NLP" # Nom du projet dans LangSmith
45
+ st.sidebar.info("Tracing LangSmith activé.")
46
+ else:
47
+ st.session_state["LANGSMITH_CONFIGURED"] = False
48
+ # Désactiver le tracing si aucune clé n'est fournie
49
+ if "LANGCHAIN_TRACING_V2" in os.environ:
50
+ del os.environ["LANGCHAIN_TRACING_V2"]
51
+
52
+ # ========= INITIALISATION DES CLIENTS =========
53
+ # Le header d'autorisation est préparé si la clé HF est disponible.
54
+ headers = {}
55
+ if st.session_state.get("API_TOKEN_HF"):
56
+ headers = {"Authorization": f"Bearer {st.session_state['API_TOKEN_HF']}"}
57
+
58
+
59
+ # ========= FONCTIONS UTILES =========
60
+
61
+ # La fonction de nettoyage n'est plus nécessaire pour Groq, mais on la garde au cas où.
62
+ def nettoyer_reponse(text):
63
+ cleaned = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL)
64
+ return cleaned.strip()
65
+
66
+ # --- NOUVELLE FONCTION DE GÉNÉRATION AVEC GROQ ET LANGSMITH ---
67
+ @traceable(name="Groq Llama3 Generator") # Le décorateur @traceable active le suivi LangSmith
68
+ def generate_with_groq_llama(prompt, api_key):
69
+ """
70
+ Génère du texte en utilisant l'API Groq avec un modèle Llama3 et trace l'appel avec LangSmith.
71
+ """
72
+ try:
73
+ client_groq = Groq(api_key=api_key)
74
+ chat_completion = client_groq.chat.completions.create(
75
+ messages=[
76
+ {
77
+ "role": "user",
78
+ "content": prompt,
79
+ }
80
+ ],
81
+ model="llama3-8b-8192",
82
+ temperature=0.7,
83
+ max_tokens=1024,
84
+ )
85
+ return chat_completion.choices[0].message.content
86
+ except Groq.APIConnectionError as e:
87
+ st.error(f"Erreur de connexion avec Groq: {e.__cause__}")
88
+ return "Impossible de se connecter à l'API Groq. Veuillez vérifier votre connexion réseau."
89
+ except Exception as e:
90
+ # Gérer d'autres erreurs potentielles de l'API
91
+ st.error(f"Une erreur inattendue est survenue avec Groq: {e}")
92
+ return "Une erreur est survenue lors de la génération de texte."
93
+
94
+ # --- Fonctions existantes ---
95
+ def transcribe_audio(path, content_type):
96
+ # Copie locale des en-têtes pour y ajouter le Content-Type
97
+ request_headers = headers.copy()
98
+ if not request_headers.get("Authorization"):
99
+ st.error("Veuillez entrer une clé API Hugging Face pour utiliser cette fonctionnalité.")
100
+ return "Erreur : clé API Hugging Face manquante."
101
+
102
+ # Ajout du Content-Type spécifique au fichier audio
103
+ request_headers["Content-Type"] = content_type
104
+
105
+ API_URL = "https://api-inference.huggingface.co/models/openai/whisper-large-v3"
106
+ try:
107
+ with open(path, "rb") as f:
108
+ data = f.read()
109
+ response = requests.post(API_URL, headers=request_headers, data=data)
110
+ response.raise_for_status() # Lève une exception pour les codes d'erreur HTTP
111
+ result = response.json()
112
+ return result.get("text", "Erreur: 'text' non trouvé dans la réponse.")
113
+ except requests.exceptions.HTTPError as err:
114
+ st.error(f"Erreur lors de la transcription : {err.response.text}")
115
+ return "Erreur lors de la transcription."
116
+ except Exception as e:
117
+ st.error(f"Erreur lors de la transcription : {str(e)}")
118
+ return "Erreur lors de la transcription."
119
+
120
+ def summarize_text(text):
121
+ """
122
+ Génère un résumé de texte en utilisant le modèle Groq Llama3.
123
+ """
124
+ if not st.session_state.get("API_TOKEN_GROQ"):
125
+ st.error("Veuillez configurer votre clé API Groq dans le fichier .env pour le résumé.")
126
+ return "Erreur : clé API Groq manquante."
127
+
128
+ # Prompt spécifique pour la tâche de résumé
129
+ prompt = f"Résume le texte suivant de manière concise en français :\n\nTexte : '''{text}'''\n\nRésumé :"
130
+
131
+ # Utilise la même fonction que pour la génération de texte
132
+ # La gestion des erreurs (connexion, etc.) est déjà dans generate_with_groq_llama
133
+ summary = generate_with_groq_llama(prompt, st.session_state["API_TOKEN_GROQ"])
134
+ return summary
135
+
136
+
137
+ # ========= MENU =========
138
+ option = st.sidebar.radio(
139
+ "Choisissez une fonctionnalité :",
140
+ ["📝 Générateur de texte", "🎙 Audio vers texte", "🧠 Résumeur de texte"]
141
+ )
142
+
143
+ # ========= GÉNÉRATEUR DE TEXTE (MODIFIÉ) =========
144
+ if option == "📝 Générateur de texte":
145
+ st.subheader("📝 Génération de texte (Groq Llama3)")
146
+ st.markdown("Utilise le modèle `llama3-8b-8192` via l'API ultra-rapide de Groq.")
147
+ if st.session_state.get("LANGSMITH_CONFIGURED"):
148
+ st.info("Le suivi avec LangSmith est activé. [Voir le projet](https://smith.langchain.com/)", icon="🔗")
149
+
150
+ if not st.session_state.get("API_TOKEN_GROQ"):
151
+ st.warning("Veuillez entrer une clé API Groq dans la barre latérale pour utiliser le générateur de texte.")
152
+ else:
153
+ prompt = st.text_area("Entrez votre prompt :", key="prompt", height=150)
154
+ if st.button("Générer", key="gen"):
155
+ if prompt.strip():
156
+ with st.spinner("Génération en cours avec Groq..."):
157
+ try:
158
+ # Appel de la nouvelle fonction
159
+ output = generate_with_groq_llama(prompt, st.session_state["API_TOKEN_GROQ"])
160
+ st.success("Texte généré :")
161
+ st.write(output)
162
+ except Exception as e:
163
+ st.error(f"Erreur lors de la génération avec Groq : {e}")
164
+ else:
165
+ st.warning("Veuillez entrer un prompt.")
166
+
167
+
168
+ # ========= AUDIO VERS TEXTE =========
169
+ elif option == "🎙 Audio vers texte":
170
+ if not st.session_state.get("API_TOKEN_HF"):
171
+ st.warning("Veuillez entrer une clé API Hugging Face dans la barre latérale pour utiliser cette fonctionnalité.")
172
+ else:
173
+ st.markdown('<div class="subheader">🎧 Transcription automatisée d’un fichier audio (30 sec max)</div>', unsafe_allow_html=True)
174
+ audio_file = st.file_uploader("🎵 Chargez un fichier audio", type=["wav", "mp3", "m4a"])
175
+ if audio_file is not None:
176
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
177
+ tmp_file.write(audio_file.getvalue())
178
+ audio_path = tmp_file.name
179
+ st.audio(audio_path)
180
+ if st.button("✍️ Transcrire"):
181
+ with st.spinner("Transcription en cours..."):
182
+ # On passe le type MIME du fichier original à la fonction
183
+ transcript = transcribe_audio(audio_path, audio_file.type)
184
+ st.markdown(f"**Transcription :**")
185
+ st.text_area("Résultat", transcript, height=150)
186
+
187
+
188
+ # ========= RÉSUMEUR DE TEXTE =========
189
+ elif option == "🧠 Résumeur de texte":
190
+ st.subheader("🧠 Résumé de texte (Groq Llama3)")
191
+ st.markdown("Utilise le modèle `llama3-8b-8192` pour générer un résumé.")
192
+ if not st.session_state.get("API_TOKEN_GROQ"):
193
+ st.warning("Veuillez vous assurer qu'une clé API Groq est configurée dans votre fichier .env pour utiliser cette fonctionnalité.")
194
+ else:
195
+ input_text = st.text_area("Texte à résumer :", height=300)
196
+ if st.button("Résumer"):
197
+ if input_text.strip():
198
+ with st.spinner("Résumé en cours avec Groq..."):
199
+ summary = summarize_text(input_text)
200
+ st.success("Résumé généré :")
201
+ st.write(summary)
202
+ else:
203
+ st.warning("Veuillez entrer un texte à résumer.")