LewisBabong commited on
Commit
da25611
·
verified ·
1 Parent(s): 09a5896

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +324 -175
app.py CHANGED
@@ -2,220 +2,296 @@ import streamlit as st
2
  import requests
3
  import tempfile
4
  import uuid
 
5
  import os
6
- from dotenv import load_dotenv
 
7
 
8
- load_dotenv() # charge les variables depuis le fichier .env
9
- # === Nouvelle clé API et modèles plus performants ===
10
- HF_TOKEN_SECRET = os.getenv("HF_TOKEN_SECRET")
11
- HF_TOKEN = f"Bearer {HF_TOKEN_SECRET}"
12
 
13
 
14
- # === Configuration de la page ===
 
 
15
  st.set_page_config(
16
- page_title="🧠 NLP Magique avec Hugging Face",
17
  page_icon="✨",
18
- layout="wide"
 
19
  )
20
 
21
- # === CSS personnalisé haut de gamme ===
22
  st.markdown("""
23
  <style>
24
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
 
25
  .stApp {
26
- background: linear-gradient(135deg, #e0e7ff, #c4b5fd);
27
- font-family: 'Poppins', sans-serif;
28
- padding: 1.5rem;
29
- min-height: 100vh;
30
  }
31
- .title {
 
32
  text-align: center;
33
- font-size: 4em;
34
  font-weight: 700;
35
- color: #5B21B6;
36
- margin-bottom: 1.5rem;
37
- animation: fadeIn 1.5s ease-in-out;
38
- text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
39
- }
40
- .subheader {
41
- color: #4C1D95;
42
- font-size: 2em;
43
- margin: 2rem 0 1rem;
44
- font-weight: 600;
45
- text-shadow: 1px 1px 3px rgba(0,0,0,0.1);
46
  }
 
 
 
 
 
47
  .card {
48
- background: rgba(255,255,255,0.9);
49
- border-radius: 15px;
50
  padding: 2rem;
51
- margin: 1rem 0;
52
- box-shadow: 0 8px 20px rgba(0,0,0,0.1);
53
- transition: transform 0.3s ease, box-shadow 0.3s ease;
 
54
  }
 
55
  .card:hover {
56
- transform: translateY(-5px);
57
- box-shadow: 0 12px 25px rgba(0,0,0,0.15);
58
  }
 
59
  .stButton>button {
60
- background: linear-gradient(45deg, #7C3AED, #A78BFA);
61
  color: white;
62
  font-weight: 600;
63
- border-radius: 12px;
64
- padding: 15px 35px;
65
  border: none;
66
- box-shadow: 0 6px 15px rgba(0,0,0,0.2);
67
  transition: all 0.3s ease;
 
68
  }
 
69
  .stButton>button:hover {
70
- background: linear-gradient(45deg, #5B21B6, #7C3AED);
71
- transform: translateY(-3px);
72
- box-shadow: 0 10px 20px rgba(0,0,0,0.25);
73
  }
 
74
  .stTextArea textarea, .stSlider>div {
75
- background: #f8fafc;
76
- border-radius: 12px;
77
- padding: 15px;
78
- font-size: 1.1em;
79
  border: 1px solid #d1d5db;
80
- box-shadow: inset 0 2px 5px rgba(0,0,0,0.05);
81
- transition: all 0.3s ease;
82
- }
83
- .stTextArea textarea:focus, .stSlider>div:focus {
84
- border-color: #7C3AED;
85
- box-shadow: 0 0 8px rgba(124,58,237,0.3);
86
- outline: none;
87
- }
88
- .stTabs [data-baseweb="tab-list"] {
89
- background: rgba(255,255,255,0.1);
90
- backdrop-filter: blur(10px);
91
- padding: 12px 20px;
92
- border-radius: 15px;
93
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
94
- position: sticky;
95
- top: 0;
96
- z-index: 100;
97
- display: flex;
98
- align-items: center;
99
- gap: 10px;
100
- }
101
- .stTabs [data-baseweb="tab"] {
102
- color: #000;
103
- font-weight: 600;
104
- font-size: 1.2em;
105
- padding: 12px 25px;
106
- border-radius: 10px;
107
  transition: all 0.3s ease;
108
- display: flex;
109
- align-items: center;
110
- gap: 8px;
111
  }
112
- .stTabs [data-baseweb="tab"]:hover {
113
- background: rgba(124,58,237,0.3);
114
- color: white;
115
- }
116
- .stTabs [aria-selected="true"] {
117
- background: #7C3AED;
118
- color: white;
119
- box-shadow: 0 3px 8px rgba(0,0,0,0.2);
120
  }
 
121
  .stFileUploader {
122
- background: #f8fafc;
123
- border-radius: 12px;
124
- padding: 15px;
125
  border: 1px solid #d1d5db;
126
- box-shadow: 0 2px 5px rgba(0,0,0,0.05);
127
- }
128
- .stFileUploader:hover {
129
- border-color: #7C3AED;
130
- }
131
- .stSpinner .spinner {
132
- border-top-color: #7C3AED;
133
  }
 
134
  .output-card {
135
- background: #f8fafc;
136
- border-radius: 12px;
137
  padding: 1.5rem;
138
  margin-top: 1rem;
139
  border: 1px solid #e5e7eb;
140
- box-shadow: 0 4px 10px rgba(0,0,0,0.1);
141
  position: relative;
 
 
142
  }
 
143
  .copy-button {
144
  position: absolute;
145
- top: 10px;
146
- right: 10px;
147
- background: #7C3AED;
148
  color: white;
149
  border: none;
150
- border-radius: 8px;
151
- padding: 8px 12px;
 
152
  cursor: pointer;
153
- transition: background 0.3s ease;
154
  }
 
155
  .copy-button:hover {
156
- background: #5B21B6;
157
  }
158
- @keyframes fadeIn {
159
- from { opacity: 0; transform: translateY(-20px); }
160
- to { opacity: 1; transform: translateY(0); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  .footer {
163
  text-align: center;
164
- font-size: 1.2em;
165
- color: #4C1D95;
166
  margin-top: 3rem;
167
- padding: 1.5rem;
168
- background: rgba(255,255,255,0.9);
169
- border-radius: 15px;
170
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
171
- animation: glow 3s ease-in-out infinite;
172
  }
 
173
  .footer a {
174
- color: #7C3AED;
175
- text-decoration: none;
176
  font-weight: 600;
177
- transition: color 0.3s ease;
178
  }
 
179
  .footer a:hover {
180
- color: #5B21B6;
181
  text-decoration: underline;
182
  }
 
183
  .social-icons img {
184
- width: 30px;
185
- margin: 0 10px;
186
  transition: transform 0.3s ease;
187
  }
 
188
  .social-icons img:hover {
189
  transform: scale(1.2);
190
  }
191
- @keyframes glow {
192
- 0% { box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
193
- 50% { box-shadow: 0 4px 20px rgba(124,58,237,0.3); }
194
- 100% { box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
 
 
 
 
 
195
  }
 
196
  @media (max-width: 768px) {
197
- .title { font-size: 2.5em; }
198
- .subheader { font-size: 1.5em; }
199
- .stTabs [data-baseweb="tab"] { font-size: 1em; padding: 10px 15px; }
200
  .card { padding: 1.5rem; }
 
201
  }
202
  </style>
203
  """, unsafe_allow_html=True)
204
 
205
- # === JavaScript pour la fonctionnalité de copie ===
206
  st.markdown("""
207
  <script>
208
  function copyToClipboard(text) {
209
  navigator.clipboard.writeText(text).then(() => {
210
- alert('Texte copié dans le presse-papiers !');
211
  });
212
  }
213
  </script>
214
  """, unsafe_allow_html=True)
215
 
216
-
217
- # === Fonctions API ===
218
-
219
  def generate_text(prompt):
220
  url = "https://api-inference.huggingface.co/models/gpt2"
221
  headers = {"Authorization": HF_TOKEN}
@@ -224,10 +300,9 @@ def generate_text(prompt):
224
  if response.ok:
225
  return response.json()[0]["generated_text"]
226
  else:
227
- st.error(f"Erreur FLAN-T5: {response.status_code} - {response.text}")
228
  return "Erreur lors de la génération."
229
 
230
-
231
  def summarize_text(text):
232
  url = "https://api-inference.huggingface.co/models/facebook/bart-large-cnn"
233
  headers = {"Authorization": HF_TOKEN}
@@ -236,10 +311,9 @@ def summarize_text(text):
236
  if response.ok:
237
  return response.json()[0]["summary_text"]
238
  else:
239
- st.error(f"Erreur BART: {response.status_code} - {response.text}")
240
  return "Erreur lors du résumé."
241
 
242
-
243
  def transcribe_audio(path):
244
  url = "https://api-inference.huggingface.co/models/openai/whisper-large-v2"
245
  headers = {
@@ -251,77 +325,152 @@ def transcribe_audio(path):
251
  if response.ok:
252
  return response.json()["text"]
253
  else:
254
- st.error(f"Erreur Whisper Large: {response.status_code} - {response.text}")
255
  return "Erreur lors de la transcription."
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
- # === Titre principal ===
259
- st.markdown('<div class="title">✨ NLP Magique avec Hugging Face ✨</div>', unsafe_allow_html=True)
260
- st.markdown("---")
 
 
 
 
 
 
 
261
 
262
- # === AppBar avec onglets ===
263
- tabs = st.tabs([ f"📄 Résumeur", f"📝 Générateur", f"🎧 Transcripteur"])
 
 
 
 
264
 
265
- # === Générateur de texte ===
266
- with tabs[1]:
267
- st.markdown('<div class="subheader">📝 Génération de contenu créatif</div>', unsafe_allow_html=True)
268
  with st.container():
269
- st.markdown('<div class="card">', unsafe_allow_html=True)
270
- prompt = st.text_area("💡 Saisissez une idée ou une phrase :", "La médecine moderne", height=150,
271
- placeholder="Entrez votre texte ici...")
272
- temp = st.slider("🎯 Niveau de créativité", 0.1, 1.0, 0.7, step=0.1)
273
- if st.button("🚀 Générer"):
274
- with st.spinner("Génération en cours..."):
275
  output = generate_text(prompt)
276
  st.markdown(
277
  f'<div class="output-card">{output}<button class="copy-button" onclick="copyToClipboard(\'{output}\')">Copier</button></div>',
278
  unsafe_allow_html=True)
279
- st.markdown('</div>', unsafe_allow_html=True)
280
 
281
- # === Résumeur de texte ===
282
- with tabs[0]:
283
- st.markdown('<div class="subheader">📄 Synthèse intelligente de textes</div>', unsafe_allow_html=True)
284
  with st.container():
285
- st.markdown('<div class="card">', unsafe_allow_html=True)
286
- texte = st.text_area("✍️ Collez votre texte à résumer :", height=200, placeholder="Collez un long texte ici...")
287
- if st.button("🧠 Résumer"):
288
- with st.spinner("Analyse et synthèse en cours..."):
 
289
  summary = summarize_text(texte)
290
  st.markdown(
291
  f'<div class="output-card">{summary}<button class="copy-button" onclick="copyToClipboard(\'{summary}\')">Copier</button></div>',
292
  unsafe_allow_html=True)
293
- st.markdown('</div>', unsafe_allow_html=True)
294
 
295
- # === Transcription audio ===
296
- with tabs[2]:
297
- st.markdown('<div class="subheader">🎧 Transcription automatisée d’audio (Vidéo Maximumu de 30 secondes net)</div>', unsafe_allow_html=True)
298
  with st.container():
299
- st.markdown('<div class="card">', unsafe_allow_html=True)
300
- audio_file = st.file_uploader("🎵 Chargez un fichier audio (Vidéo Maximumu de 30 secondes net)", type=["wav", "mp3", "m4a"],
301
- help="Formats supportés : WAV, MP3, M4A")
302
- if audio_file is not None:
303
  with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
304
  tmp_file.write(audio_file.read())
305
  audio_path = tmp_file.name
306
  st.audio(audio_path)
307
- if st.button("✍️ Transcrire"):
308
- with st.spinner("Transcription en cours..."):
309
  transcript = transcribe_audio(audio_path)
310
  st.markdown(
311
  f'<div class="output-card">{transcript}<button class="copy-button" onclick="copyToClipboard(\'{transcript}\')">Copier</button></div>',
312
  unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
314
 
315
- # === Pied de page amélioré ===
316
- st.markdown("---")
317
  st.markdown("""
318
  <div class="footer">
319
- <p> Propriété intellectuelle de NTONGA BABONG Entrepreneur<br>
320
- Créé grâce à <a href='https://huggingface.co/' target='_blank'>Hugging Face</a> et <a href='https://streamlit.io' target='_blank'>Streamlit</a></p>
321
  <div class="social-icons">
322
- <a href="https://twitter.com" target="_blank"><img src="https://img.icons8.com/color/48/000000/twitter--v1.png"/></a>
323
- <a href="https://linkedin.com" target="_blank"><img src="https://img.icons8.com/color/48/000000/linkedin.png"/></a>
324
- <a href="https://github.com" target="_blank"><img src="https://img.icons8.com/color/48/000000/github--v1.png"/></a>
325
  </div>
326
  </div>
327
  """, unsafe_allow_html=True)
 
2
  import requests
3
  import tempfile
4
  import uuid
5
+ from groq import Groq
6
  import os
7
+ from langsmith import Client as LangSmithClient
8
+ import time
9
 
10
+ HF_TOKEN = f"Bearer {os.getenv('HF_TOKEN_SECRET')}"
11
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
12
+ LANGSMITH_API_KEY = os.getenv("LANGSMITH_API_KEY")
 
13
 
14
 
15
+ groq_client = Groq(api_key=GROQ_API_KEY)
16
+ langsmith_client = LangSmithClient(api_key=LANGSMITH_API_KEY)
17
+
18
  st.set_page_config(
19
+ page_title="🧠 NLP Magique",
20
  page_icon="✨",
21
+ layout="wide",
22
+ initial_sidebar_state="expanded"
23
  )
24
 
 
25
  st.markdown("""
26
  <style>
27
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
28
+
29
  .stApp {
30
+ background: linear-gradient(135deg, #f5f7ff, #e4e9ff);
31
+ font-family: 'Inter', sans-serif;
32
+ color: #1f2937;
 
33
  }
34
+
35
+ .main-title {
36
  text-align: center;
37
+ font-size: 3.5rem;
38
  font-weight: 700;
39
+ color: #4f46e5;
40
+ margin: 2rem 0;
41
+ animation: fadeInDown 1s ease-out;
42
+ }
43
+
44
+ .sidebar .sidebar-content {
45
+ background: #ffffff;
46
+ border-right: 1px solid #e5e7eb;
47
+ padding: 2rem;
 
 
48
  }
49
+
50
+ .stSidebar .element-container {
51
+ margin-bottom: 1rem;
52
+ }
53
+
54
  .card {
55
+ background: linear-gradient(145deg, #ffffff, #f9fafb);
56
+ border-radius: 16px;
57
  padding: 2rem;
58
+ margin: 1.5rem 0;
59
+ box-shadow: 0 4px 20px rgba(0,0,0,0.08);
60
+ transition: all 0.3s ease;
61
+ border: 1px solid #e5e7eb;
62
  }
63
+
64
  .card:hover {
65
+ transform: translateY(-4px);
66
+ box-shadow: 0 6px 24px rgba(0,0,0,0.12);
67
  }
68
+
69
  .stButton>button {
70
+ background: linear-gradient(90deg, #4f46e5, #7c3aed);
71
  color: white;
72
  font-weight: 600;
73
+ border-radius: 8px;
74
+ padding: 0.75rem 1.5rem;
75
  border: none;
 
76
  transition: all 0.3s ease;
77
+ width: 100%;
78
  }
79
+
80
  .stButton>button:hover {
81
+ background: linear-gradient(90deg, #4338ca, #6d28d9);
82
+ transform: translateY(-2px);
83
+ box-shadow: 0 4px 12px rgba(79,70,229,0.3);
84
  }
85
+
86
  .stTextArea textarea, .stSlider>div {
87
+ background: #f9fafb;
88
+ border-radius: 8px;
89
+ padding: 1rem;
 
90
  border: 1px solid #d1d5db;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  transition: all 0.3s ease;
 
 
 
92
  }
93
+
94
+ .stTextArea textarea:focus {
95
+ border-color: #4f46e5;
96
+ box-shadow: 0 0 0 3px rgba(79,70,229,0.1);
 
 
 
 
97
  }
98
+
99
  .stFileUploader {
100
+ background: #f9fafb;
101
+ border-radius: 8px;
102
+ padding: 1rem;
103
  border: 1px solid #d1d5db;
 
 
 
 
 
 
 
104
  }
105
+
106
  .output-card {
107
+ background: #f9fafb;
108
+ border-radius: 8px;
109
  padding: 1.5rem;
110
  margin-top: 1rem;
111
  border: 1px solid #e5e7eb;
 
112
  position: relative;
113
+ font-size: 1rem;
114
+ line-height: 1.6;
115
  }
116
+
117
  .copy-button {
118
  position: absolute;
119
+ top: 0.5rem;
120
+ right: 0.5rem;
121
+ background: #4f46e5;
122
  color: white;
123
  border: none;
124
+ border-radius: 6px;
125
+ padding: 0.5rem 1rem;
126
+ font-size: 0.875rem;
127
  cursor: pointer;
128
+ transition: all 0.3s ease;
129
  }
130
+
131
  .copy-button:hover {
132
+ background: #4338ca;
133
  }
134
+
135
+ /* Chatbot Styles */
136
+ .chat-tooltip {
137
+ position: fixed;
138
+ bottom: 1.5rem;
139
+ left: 1.5rem;
140
+ z-index: 1000;
141
+ }
142
+
143
+ .chat-button {
144
+ background: #4f46e5;
145
+ color: white;
146
+ width: 60px;
147
+ height: 60px;
148
+ border-radius: 50%;
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
153
+ cursor: pointer;
154
+ transition: all 0.3s ease;
155
+ font-size: 1.5rem;
156
+ }
157
+
158
+ .chat-button:hover {
159
+ background: #4338ca;
160
+ transform: scale(1.1);
161
  }
162
+
163
+ .chat-window {
164
+ width: 360px;
165
+ height: 500px;
166
+ background: #ffffff;
167
+ border-radius: 12px;
168
+ box-shadow: 0 8px 24px rgba(0,0,0,0.2);
169
+ display: flex;
170
+ flex-direction: column;
171
+ overflow: hidden;
172
+ animation: slideIn 0.3s ease-out;
173
+ }
174
+
175
+ .chat-header {
176
+ background: #4f46e5;
177
+ color: white;
178
+ padding: 1rem;
179
+ display: flex;
180
+ justify-content: space-between;
181
+ align-items: center;
182
+ font-weight: 600;
183
+ }
184
+
185
+ .chat-body {
186
+ flex: 1;
187
+ overflow-y: auto;
188
+ padding: 1rem;
189
+ background: #f9fafb;
190
+ }
191
+
192
+ .chat-message {
193
+ margin: 0.5rem 0;
194
+ padding: 0.75rem;
195
+ border-radius: 8px;
196
+ max-width: 80%;
197
+ font-size: 0.875rem;
198
+ line-height: 1.4;
199
+ }
200
+
201
+ .user-message {
202
+ background: #e0e7ff;
203
+ margin-left: auto;
204
+ border: 1px solid #c7d2fe;
205
+ }
206
+
207
+ .bot-message {
208
+ background: #f3e8ff;
209
+ margin-right: auto;
210
+ border: 1px solid #e9d5ff;
211
+ position: relative;
212
+ }
213
+
214
+ .chat-input {
215
+ padding: 1rem;
216
+ background: #ffffff;
217
+ border-top: 1px solid #e5e7eb;
218
+ }
219
+
220
+ .chat-input textarea {
221
+ width: 100%;
222
+ resize: none;
223
+ border-radius: 6px;
224
+ padding: 0.5rem;
225
+ border: 1px solid #d1d5db;
226
+ font-size: 0.875rem;
227
+ }
228
+
229
+ .chat-footer {
230
+ display: flex;
231
+ gap: 0.5rem;
232
+ margin-top: 0.5rem;
233
+ }
234
+
235
  .footer {
236
  text-align: center;
237
+ padding: 2rem;
 
238
  margin-top: 3rem;
239
+ background: #ffffff;
240
+ border-radius: 12px;
241
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
242
+ font-size: 1rem;
243
+ color: #4b5563;
244
  }
245
+
246
  .footer a {
247
+ color: #4f46e5;
 
248
  font-weight: 600;
249
+ text-decoration: none;
250
  }
251
+
252
  .footer a:hover {
253
+ color: #4338ca;
254
  text-decoration: underline;
255
  }
256
+
257
  .social-icons img {
258
+ width: 24px;
259
+ margin: 0 0.5rem;
260
  transition: transform 0.3s ease;
261
  }
262
+
263
  .social-icons img:hover {
264
  transform: scale(1.2);
265
  }
266
+
267
+ @keyframes fadeInDown {
268
+ from { opacity: 0; transform: translateY(-20px); }
269
+ to { opacity: 1; transform: translateY(0); }
270
+ }
271
+
272
+ @keyframes slideIn {
273
+ from { opacity: 0; transform: translateY(20px); }
274
+ to { opacity: 1; transform: translateY(0); }
275
  }
276
+
277
  @media (max-width: 768px) {
278
+ .main-title { font-size: 2.5rem; }
 
 
279
  .card { padding: 1.5rem; }
280
+ .chat-window { width: 90vw; height: 80vh; }
281
  }
282
  </style>
283
  """, unsafe_allow_html=True)
284
 
 
285
  st.markdown("""
286
  <script>
287
  function copyToClipboard(text) {
288
  navigator.clipboard.writeText(text).then(() => {
289
+ alert('Texte copié !');
290
  });
291
  }
292
  </script>
293
  """, unsafe_allow_html=True)
294
 
 
 
 
295
  def generate_text(prompt):
296
  url = "https://api-inference.huggingface.co/models/gpt2"
297
  headers = {"Authorization": HF_TOKEN}
 
300
  if response.ok:
301
  return response.json()[0]["generated_text"]
302
  else:
303
+ st.error(f"Erreur: {response.status_code} - {response.text}")
304
  return "Erreur lors de la génération."
305
 
 
306
  def summarize_text(text):
307
  url = "https://api-inference.huggingface.co/models/facebook/bart-large-cnn"
308
  headers = {"Authorization": HF_TOKEN}
 
311
  if response.ok:
312
  return response.json()[0]["summary_text"]
313
  else:
314
+ st.error(f"Erreur: {response.status_code} - {response.text}")
315
  return "Erreur lors du résumé."
316
 
 
317
  def transcribe_audio(path):
318
  url = "https://api-inference.huggingface.co/models/openai/whisper-large-v2"
319
  headers = {
 
325
  if response.ok:
326
  return response.json()["text"]
327
  else:
328
+ st.error(f"Erreur: {response.status_code} - {response.text}")
329
  return "Erreur lors de la transcription."
330
 
331
+ def chat_with_grok(user_input, conversation_id):
332
+ try:
333
+ run = langsmith_client.create_run(
334
+ name="Grok_Chat",
335
+ run_type="chain",
336
+ inputs={"user_input": user_input, "conversation_id": conversation_id}
337
+ )
338
+
339
+ response = groq_client.chat.completions.create(
340
+ messages=[
341
+ {"role": "system", "content": "Vous êtes Grok, un assistant IA créé par xAI. Répondez en français avec précision et clarté."},
342
+ {"role": "user", "content": user_input}
343
+ ],
344
+ model="mixtral-8x7b-32768",
345
+ temperature=0.7,
346
+ max_tokens=1000
347
+ )
348
+
349
+ response_text = response.choices[0].message.content
350
+ run.update({"outputs": response_text, "end_time": time.time()})
351
+ return response_text
352
+ except Exception as e:
353
+ run.update({"outputs": {"error": str(e)}, "end_time": time.time(), "status": "error"})
354
+ st.error(f"Erreur: {str(e)}")
355
+ return "Une erreur s'est produite. Réessayez."
356
+
357
+ st.markdown('<h1 class="main-title">✨ NLP Magique</h1>', unsafe_allow_html=True)
358
 
359
+ with st.sidebar:
360
+ st.image("https://via.placeholder.com/100?text=Logo", width=100)
361
+ st.markdown("### Navigation")
362
+ page = st.selectbox(
363
+ "Choisir une fonctionnalité",
364
+ ["Résumé", "Génération", "Transcription"]
365
+ )
366
+ st.markdown("---")
367
+ st.markdown("### À propos")
368
+ st.write("Une application NLP avancée utilisant Hugging Face et xAI.")
369
 
370
+ if 'chat_history' not in st.session_state:
371
+ st.session_state.chat_history = []
372
+ if 'conversation_id' not in st.session_state:
373
+ st.session_state.conversation_id = str(uuid4())
374
+ if 'chat_open' not in st.session_state:
375
+ st.session_state.chat_open = False
376
 
377
+ if page == "Génération":
 
 
378
  with st.container():
379
+ st.markdown("<div class='card'>", unsafe_allow_html=True)
380
+ st.subheader("Génération de texte")
381
+ prompt = st.text_area("Entrez votre idée :", "La médecine moderne", height=150)
382
+ temp = st.slider("Créativité", 0.1, 1.0, 0.7, step=0.1)
383
+ if st.button("Générer"):
384
+ with st.spinner("Génération..."):
385
  output = generate_text(prompt)
386
  st.markdown(
387
  f'<div class="output-card">{output}<button class="copy-button" onclick="copyToClipboard(\'{output}\')">Copier</button></div>',
388
  unsafe_allow_html=True)
389
+ st.markdown("</div>", unsafe_allow_html=True)
390
 
391
+ elif page == "Résumé":
 
 
392
  with st.container():
393
+ st.markdown("<div class='card'>", unsafe_allow_html=True)
394
+ st.subheader("Résumé de texte")
395
+ texte = st.text_area("Collez votre texte :", height=200)
396
+ if st.button("Résumer"):
397
+ with st.spinner("Résumé..."):
398
  summary = summarize_text(texte)
399
  st.markdown(
400
  f'<div class="output-card">{summary}<button class="copy-button" onclick="copyToClipboard(\'{summary}\')">Copier</button></div>',
401
  unsafe_allow_html=True)
402
+ st.markdown("</div>", unsafe_allow_html=True)
403
 
404
+ elif page == "Transcription":
 
 
405
  with st.container():
406
+ st.markdown("<div class='card'>", unsafe_allow_html=True)
407
+ st.subheader("Transcription audio")
408
+ audio_file = st.file_uploader("Chargez un audio (max 30s)", type=["wav", "mp3", "m4a"])
409
+ if audio_file:
410
  with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as tmp_file:
411
  tmp_file.write(audio_file.read())
412
  audio_path = tmp_file.name
413
  st.audio(audio_path)
414
+ if st.button("Transcrire"):
415
+ with st.spinner("Transcription..."):
416
  transcript = transcribe_audio(audio_path)
417
  st.markdown(
418
  f'<div class="output-card">{transcript}<button class="copy-button" onclick="copyToClipboard(\'{transcript}\')">Copier</button></div>',
419
  unsafe_allow_html=True)
420
+ st.markdown("</div>", unsafe_allow_html=True)
421
+
422
+ # Chatbot Tooltip
423
+ with st.container():
424
+ st.markdown('<div class="chat-tooltip">', unsafe_allow_html=True)
425
+ if not st.session_state.chat_open:
426
+ if st.button("💬", key="chat_toggle", help="Ouvrir le chatbot"):
427
+ st.session_state.chat_open = True
428
+ st.rerun()
429
+ else:
430
+ st.markdown('<div class="chat-window">', unsafe_allow_html=True)
431
+ st.markdown('<div class="chat-header">Grok AI<div class="chat-button" onclick="this.closest(\'.chat-tooltip\').querySelector(\'.stButton>button\').click()">✖</div></div>', unsafe_allow_html=True)
432
+
433
+ st.markdown('<div class="chat-body">', unsafe_allow_html=True)
434
+ for message in st.session_state.chat_history:
435
+ if message['role'] == 'user':
436
+ st.markdown(f'<div class="chat-message user-message">{message["content"]}</div>', unsafe_allow_html=True)
437
+ else:
438
+ st.markdown(f'<div class="chat-message bot-message">{message["content"]}<button class="copy-button" onclick="copyToClipboard(\'{message["content"]}\')">Copier</button></div>', unsafe_allow_html=True)
439
+ st.markdown('</div>', unsafe_allow_html=True)
440
+
441
+ st.markdown('<div class="chat-input">', unsafe_allow_html=True)
442
+ user_input = st.text_area("Votre message :", height=80, key="chat_input")
443
+ st.markdown('<div class="chat-footer">', unsafe_allow_html=True)
444
+ col1, col2 = st.columns([3, 1])
445
+ with col1:
446
+ if st.button("Envoyer"):
447
+ if user_input:
448
+ with st.spinner("Grok répond..."):
449
+ st.session_state.chat_history.append({"role": "user", "content": user_input})
450
+ response = chat_with_grok(user_input, st.session_state.conversation_id)
451
+ st.session_state.chat_history.append({"role": "assistant", "content": response})
452
+ st.rerun()
453
+ with col2:
454
+ if st.button("Effacer"):
455
+ st.session_state.chat_history = []
456
+ st.session_state.conversation_id = str(uuid4())
457
+ st.rerun()
458
+ st.markdown('</div>', unsafe_allow_html=True)
459
  st.markdown('</div>', unsafe_allow_html=True)
460
+
461
+ if st.button("💬", key="chat_toggle_close", help="Fermer le chatbot"):
462
+ st.session_state.chat_open = False
463
+ st.rerun()
464
+ st.markdown('</div>', unsafe_allow_html=True)
465
 
 
 
466
  st.markdown("""
467
  <div class="footer">
468
+ <p>© 2025 NTONGA BABONG<br>
469
+ Propulsé par <a href='https://huggingface.co/' target='_blank'>Hugging Face</a>, <a href='https://streamlit.io' target='_blank'>Streamlit</a> et <a href='https://x.ai' target='_blank'>xAI</a></p>
470
  <div class="social-icons">
471
+ <a href="https://twitter.com" target="_blank"><img src="https://img.icons8.com/color/48/twitter--v1.png"/></a>
472
+ <a href="https://linkedin.com" target="_blank"><img src="https://img.icons8.com/color/48/linkedin.png"/></a>
473
+ <a href="https://github.com" target="_blank"><img src="https://img.icons8.com/color/48/github--v1.png"/></a>
474
  </div>
475
  </div>
476
  """, unsafe_allow_html=True)