iisadia commited on
Commit
767b287
·
verified ·
1 Parent(s): 5b5e12a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +346 -46
app.py CHANGED
@@ -3,52 +3,112 @@ import time
3
  import requests
4
  from streamlit.components.v1 import html
5
  import os
 
 
6
 
 
7
  @st.cache_resource
8
  def get_help_agent():
9
  from transformers import pipeline
 
10
  return pipeline("conversational", model="facebook/blenderbot-400M-distill")
11
 
 
12
  def inject_custom_css():
13
  st.markdown("""
14
  <style>
15
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
16
- * { font-family: 'Poppins', sans-serif; }
17
- .title { font-size: 3rem !important; font-weight: 700 !important; color: #6C63FF !important; text-align: center; margin-bottom: 0.5rem; }
18
- .subtitle { font-size: 1.2rem !important; text-align: center; color: #666 !important; margin-bottom: 2rem; }
19
- .question-box { background: #F8F9FA; border-radius: 15px; padding: 2rem; margin: 1.5rem 0; box-shadow: 0 4px 6px rgba(0,0,0,0.1); color: black !important; }
20
- .answer-btn { border-radius: 12px !important; padding: 0.5rem 1.5rem !important; font-weight: 600 !important; margin: 0.5rem !important; }
21
- .yes-btn { background: #6C63FF !important; color: white !important; }
22
- .no-btn { background: #FF6B6B !important; color: white !important; }
23
- .final-reveal { animation: fadeIn 2s; font-size: 2.5rem; color: #6C63FF; text-align: center; margin: 2rem 0; }
24
- @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
25
- .confetti { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1000; }
26
- .confidence-meter { height: 10px; background: linear-gradient(90deg, #FF6B6B 0%, #6C63FF 100%); border-radius: 5px; margin: 10px 0; }
27
- .mic-btn { margin-top: 29px; border: none; background: none; cursor: pointer; font-size: 1.5em; padding: 0; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  </style>
29
- <script>
30
- function startSpeechRecognition(inputId) {
31
- const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
32
- recognition.lang = 'en-US';
33
- recognition.interimResults = false;
34
- recognition.maxAlternatives = 1;
35
- recognition.onresult = function(event) {
36
- const transcript = event.results[0][0].transcript.toLowerCase();
37
- const inputElement = document.getElementById(inputId);
38
- if (inputElement) {
39
- inputElement.value = transcript;
40
- const event = new Event('input', { bubbles: true });
41
- inputElement.dispatchEvent(event);
42
- }
43
- };
44
- recognition.onerror = function(event) {
45
- console.error('Speech recognition error', event.error);
46
- };
47
- recognition.start();
48
- }
49
- </script>
50
  """, unsafe_allow_html=True)
51
 
 
52
  def show_confetti():
53
  html("""
54
  <canvas id="confetti-canvas" class="confetti"></canvas>
@@ -56,11 +116,16 @@ def show_confetti():
56
  <script>
57
  const canvas = document.getElementById('confetti-canvas');
58
  const confetti = confetti.create(canvas, { resize: true });
59
- confetti({ particleCount: 150, spread: 70, origin: { y: 0.6 } });
 
 
 
 
60
  setTimeout(() => { canvas.remove(); }, 5000);
61
  </script>
62
  """)
63
 
 
64
  def ask_llama(conversation_history, category, is_final_guess=False):
65
  api_url = "https://api.groq.com/openai/v1/chat/completions"
66
  headers = {
@@ -104,28 +169,89 @@ def ask_llama(conversation_history, category, is_final_guess=False):
104
  st.error(f"Error calling Llama API: {str(e)}")
105
  return "Could not generate question"
106
 
 
107
  def ask_help_agent(query):
108
  try:
109
  from huggingface_hub import InferenceClient
 
110
  client = InferenceClient("HuggingFaceH4/zephyr-7b-beta", token=os.environ.get("HF_HUB_TOKEN"))
111
  system_message = "You are a friendly Chatbot."
 
 
112
  history = []
113
  if "help_conversation" in st.session_state:
114
  for msg in st.session_state.help_conversation:
 
115
  history.append((msg.get("query", ""), msg.get("response", "")))
 
116
  messages = [{"role": "system", "content": system_message}]
117
  for user_msg, bot_msg in history:
118
- if user_msg: messages.append({"role": "user", "content": user_msg})
119
- if bot_msg: messages.append({"role": "assistant", "content": bot_msg})
 
 
120
  messages.append({"role": "user", "content": query})
 
121
  response_text = ""
122
- for message in client.chat_completion(messages, max_tokens=150, stream=True, temperature=0.7, top_p=0.95):
 
 
 
 
 
 
 
123
  token = message.choices[0].delta.content
124
  response_text += token
125
  return response_text
126
  except Exception as e:
127
  return f"Error in help agent: {str(e)}"
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  def main():
130
  inject_custom_css()
131
 
@@ -140,8 +266,9 @@ def main():
140
  st.session_state.conversation_history = []
141
  st.session_state.category = None
142
  st.session_state.final_guess = None
143
- st.session_state.help_conversation = []
144
 
 
145
  if st.session_state.game_state == "start":
146
  st.markdown("""
147
  <div class="question-box">
@@ -153,7 +280,7 @@ def main():
153
  <li><strong>Place</strong> - city, country, landmark, geographical location</li>
154
  <li><strong>Object</strong> - everyday item, tool, vehicle, etc.</li>
155
  </ul>
156
- <p>Type or speak your category below to begin:</p>
157
  </div>
158
  """, unsafe_allow_html=True)
159
 
@@ -162,20 +289,193 @@ def main():
162
  with col1:
163
  category_input = st.text_input("Enter category (person/place/object):", key="category_input").strip().lower()
164
  with col2:
165
- st.markdown("""
166
- <button type="button" onclick="startSpeechRecognition('text_input-category_input')" class="mic-btn">🎤</button>
167
- """, unsafe_allow_html=True)
 
 
 
 
 
168
  if st.form_submit_button("Start Game"):
 
169
  if not category_input:
170
  st.error("Please enter a category!")
171
  elif category_input not in ["person", "place", "object"]:
172
  st.error("Please enter either 'person', 'place', or 'object'!")
173
  else:
174
  st.session_state.category = category_input
175
- first_question = ask_llama([], category_input)
 
 
176
  st.session_state.questions = [first_question]
177
- st.session_state.conversation_history = [{"role": "assistant", "content": first_question}]
178
- st.session_state.game_state = "playing"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
  if __name__ == "__main__":
181
- main()
 
3
  import requests
4
  from streamlit.components.v1 import html
5
  import os
6
+ import speech_recognition as sr
7
+ from audio_recorder_streamlit import audio_recorder
8
 
9
+ # Import transformers and cache the help agent for performance
10
  @st.cache_resource
11
  def get_help_agent():
12
  from transformers import pipeline
13
+ # Using BlenderBot 400M Distill as the public conversational model (used elsewhere)
14
  return pipeline("conversational", model="facebook/blenderbot-400M-distill")
15
 
16
+ # Custom CSS for professional look (fixed text color)
17
  def inject_custom_css():
18
  st.markdown("""
19
  <style>
20
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
21
+
22
+ * {
23
+ font-family: 'Poppins', sans-serif;
24
+ }
25
+
26
+ .title {
27
+ font-size: 3rem !important;
28
+ font-weight: 700 !important;
29
+ color: #6C63FF !important;
30
+ text-align: center;
31
+ margin-bottom: 0.5rem;
32
+ }
33
+
34
+ .subtitle {
35
+ font-size: 1.2rem !important;
36
+ text-align: center;
37
+ color: #666 !important;
38
+ margin-bottom: 2rem;
39
+ }
40
+
41
+ .question-box {
42
+ background: #F8F9FA;
43
+ border-radius: 15px;
44
+ padding: 2rem;
45
+ margin: 1.5rem 0;
46
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
47
+ color: black !important;
48
+ }
49
+
50
+ .answer-btn {
51
+ border-radius: 12px !important;
52
+ padding: 0.5rem 1.5rem !important;
53
+ font-weight: 600 !important;
54
+ margin: 0.5rem !important;
55
+ }
56
+
57
+ .yes-btn {
58
+ background: #6C63FF !important;
59
+ color: white !important;
60
+ }
61
+
62
+ .no-btn {
63
+ background: #FF6B6B !important;
64
+ color: white !important;
65
+ }
66
+
67
+ .final-reveal {
68
+ animation: fadeIn 2s;
69
+ font-size: 2.5rem;
70
+ color: #6C63FF;
71
+ text-align: center;
72
+ margin: 2rem 0;
73
+ }
74
+
75
+ @keyframes fadeIn {
76
+ from { opacity: 0; }
77
+ to { opacity: 1; }
78
+ }
79
+
80
+ .confetti {
81
+ position: fixed;
82
+ top: 0;
83
+ left: 0;
84
+ width: 100%;
85
+ height: 100%;
86
+ pointer-events: none;
87
+ z-index: 1000;
88
+ }
89
+
90
+ .confidence-meter {
91
+ height: 10px;
92
+ background: linear-gradient(90deg, #FF6B6B 0%, #6C63FF 100%);
93
+ border-radius: 5px;
94
+ margin: 10px 0;
95
+ }
96
+
97
+ .mic-btn {
98
+ background: #6C63FF !important;
99
+ color: white !important;
100
+ border-radius: 50% !important;
101
+ width: 40px !important;
102
+ height: 40px !important;
103
+ padding: 0 !important;
104
+ display: flex !important;
105
+ align-items: center !important;
106
+ justify-content: center !important;
107
+ }
108
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  """, unsafe_allow_html=True)
110
 
111
+ # Confetti animation
112
  def show_confetti():
113
  html("""
114
  <canvas id="confetti-canvas" class="confetti"></canvas>
 
116
  <script>
117
  const canvas = document.getElementById('confetti-canvas');
118
  const confetti = confetti.create(canvas, { resize: true });
119
+ confetti({
120
+ particleCount: 150,
121
+ spread: 70,
122
+ origin: { y: 0.6 }
123
+ });
124
  setTimeout(() => { canvas.remove(); }, 5000);
125
  </script>
126
  """)
127
 
128
+ # Enhanced AI question generation for guessing game using Llama model
129
  def ask_llama(conversation_history, category, is_final_guess=False):
130
  api_url = "https://api.groq.com/openai/v1/chat/completions"
131
  headers = {
 
169
  st.error(f"Error calling Llama API: {str(e)}")
170
  return "Could not generate question"
171
 
172
+ # New function for the help AI assistant using the Hugging Face InferenceClient
173
  def ask_help_agent(query):
174
  try:
175
  from huggingface_hub import InferenceClient
176
+ # Initialize the client with the provided model
177
  client = InferenceClient("HuggingFaceH4/zephyr-7b-beta", token=os.environ.get("HF_HUB_TOKEN"))
178
  system_message = "You are a friendly Chatbot."
179
+
180
+ # Build history from session state (if any)
181
  history = []
182
  if "help_conversation" in st.session_state:
183
  for msg in st.session_state.help_conversation:
184
+ # Each history entry is a tuple: (user query, assistant response)
185
  history.append((msg.get("query", ""), msg.get("response", "")))
186
+
187
  messages = [{"role": "system", "content": system_message}]
188
  for user_msg, bot_msg in history:
189
+ if user_msg:
190
+ messages.append({"role": "user", "content": user_msg})
191
+ if bot_msg:
192
+ messages.append({"role": "assistant", "content": bot_msg})
193
  messages.append({"role": "user", "content": query})
194
+
195
  response_text = ""
196
+ # Using streaming to collect the entire response from the model
197
+ for message in client.chat_completion(
198
+ messages,
199
+ max_tokens=150,
200
+ stream=True,
201
+ temperature=0.7,
202
+ top_p=0.95,
203
+ ):
204
  token = message.choices[0].delta.content
205
  response_text += token
206
  return response_text
207
  except Exception as e:
208
  return f"Error in help agent: {str(e)}"
209
 
210
+ # Audio processing functions
211
+ def transcribe_audio(audio_bytes):
212
+ """Convert audio bytes to text using SpeechRecognition"""
213
+ recognizer = sr.Recognizer()
214
+ try:
215
+ # Create a temporary WAV file
216
+ with open("temp_audio.wav", "wb") as f:
217
+ f.write(audio_bytes)
218
+
219
+ with sr.AudioFile("temp_audio.wav") as source:
220
+ audio_data = recognizer.record(source)
221
+ text = recognizer.recognize_google(audio_data)
222
+ os.remove("temp_audio.wav")
223
+ return text.lower()
224
+ except sr.UnknownValueError:
225
+ st.error("Could not understand audio")
226
+ except sr.RequestError as e:
227
+ st.error(f"Speech recognition error: {e}")
228
+ except Exception as e:
229
+ st.error(f"Error processing audio: {e}")
230
+ finally:
231
+ if os.path.exists("temp_audio.wav"):
232
+ os.remove("temp_audio.wav")
233
+ return ""
234
+
235
+ def record_audio(key):
236
+ """Record audio and return transcribed text"""
237
+ audio_bytes = audio_recorder(
238
+ pause_threshold=2.0,
239
+ text="",
240
+ recording_color="#6C63FF",
241
+ neutral_color="#6C63FF",
242
+ icon_name="microphone",
243
+ icon_size="2x",
244
+ key=key
245
+ )
246
+
247
+ if audio_bytes:
248
+ with st.spinner("Processing audio..."):
249
+ text = transcribe_audio(audio_bytes)
250
+ if text:
251
+ return text
252
+ return None
253
+
254
+ # Main game logic
255
  def main():
256
  inject_custom_css()
257
 
 
266
  st.session_state.conversation_history = []
267
  st.session_state.category = None
268
  st.session_state.final_guess = None
269
+ st.session_state.help_conversation = [] # separate history for help agent
270
 
271
+ # Start screen
272
  if st.session_state.game_state == "start":
273
  st.markdown("""
274
  <div class="question-box">
 
280
  <li><strong>Place</strong> - city, country, landmark, geographical location</li>
281
  <li><strong>Object</strong> - everyday item, tool, vehicle, etc.</li>
282
  </ul>
283
+ <p>Type your category below to begin:</p>
284
  </div>
285
  """, unsafe_allow_html=True)
286
 
 
289
  with col1:
290
  category_input = st.text_input("Enter category (person/place/object):", key="category_input").strip().lower()
291
  with col2:
292
+ st.write("")
293
+ st.write("")
294
+ if st.form_submit_button("🎤", key="start_mic"):
295
+ audio_text = record_audio("start_mic")
296
+ if audio_text:
297
+ st.session_state.category_input = audio_text
298
+ st.experimental_rerun()
299
+
300
  if st.form_submit_button("Start Game"):
301
+ category_input = st.session_state.get("category_input", category_input)
302
  if not category_input:
303
  st.error("Please enter a category!")
304
  elif category_input not in ["person", "place", "object"]:
305
  st.error("Please enter either 'person', 'place', or 'object'!")
306
  else:
307
  st.session_state.category = category_input
308
+ first_question = ask_llama([
309
+ {"role": "user", "content": "Ask your first strategic yes/no question."}
310
+ ], category_input)
311
  st.session_state.questions = [first_question]
312
+ st.session_state.conversation_history = [
313
+ {"role": "assistant", "content": first_question}
314
+ ]
315
+ st.session_state.game_state = "gameplay"
316
+ st.experimental_rerun()
317
+
318
+ # Gameplay screen
319
+ elif st.session_state.game_state == "gameplay":
320
+ current_question = st.session_state.questions[st.session_state.current_q]
321
+
322
+ # Check if AI made a guess
323
+ if "Final Guess:" in current_question:
324
+ st.session_state.final_guess = current_question.split("Final Guess:")[1].strip()
325
+ st.session_state.game_state = "confirm_guess"
326
+ st.experimental_rerun()
327
+
328
+ st.markdown(f'<div class="question-box">Question {st.session_state.current_q + 1}/20:<br><br>'
329
+ f'<strong>{current_question}</strong></div>',
330
+ unsafe_allow_html=True)
331
+
332
+ with st.form("answer_form"):
333
+ col1, col2 = st.columns([4, 1])
334
+ with col1:
335
+ answer_input = st.text_input("Your answer (yes/no/both):",
336
+ key=f"answer_{st.session_state.current_q}").strip().lower()
337
+ with col2:
338
+ st.write("")
339
+ st.write("")
340
+ if st.form_submit_button("🎤", key=f"mic_{st.session_state.current_q}"):
341
+ audio_text = record_audio(f"mic_{st.session_state.current_q}")
342
+ if audio_text:
343
+ st.session_state[f"answer_{st.session_state.current_q}"] = audio_text
344
+ st.experimental_rerun()
345
+
346
+ if st.form_submit_button("Submit"):
347
+ answer_input = st.session_state.get(f"answer_{st.session_state.current_q}", answer_input)
348
+ if answer_input not in ["yes", "no", "both"]:
349
+ st.error("Please answer with 'yes', 'no', or 'both'!")
350
+ else:
351
+ st.session_state.answers.append(answer_input)
352
+ st.session_state.conversation_history.append(
353
+ {"role": "user", "content": answer_input}
354
+ )
355
+
356
+ # Generate next response
357
+ next_response = ask_llama(
358
+ st.session_state.conversation_history,
359
+ st.session_state.category
360
+ )
361
+
362
+ # Check if AI made a guess
363
+ if "Final Guess:" in next_response:
364
+ st.session_state.final_guess = next_response.split("Final Guess:")[1].strip()
365
+ st.session_state.game_state = "confirm_guess"
366
+ else:
367
+ st.session_state.questions.append(next_response)
368
+ st.session_state.conversation_history.append(
369
+ {"role": "assistant", "content": next_response}
370
+ )
371
+ st.session_state.current_q += 1
372
+
373
+ # Stop after 20 questions max
374
+ if st.session_state.current_q >= 20:
375
+ st.session_state.game_state = "result"
376
+
377
+ st.experimental_rerun()
378
+
379
+ # Side Help Option: independent chat with an AI help assistant using Hugging Face model
380
+ with st.expander("Need Help? Chat with AI Assistant"):
381
+ col1, col2 = st.columns([4, 1])
382
+ with col1:
383
+ help_query = st.text_input("Enter your help query:", key="help_query")
384
+ with col2:
385
+ st.write("")
386
+ st.write("")
387
+ if st.button("🎤", key="help_mic"):
388
+ audio_text = record_audio("help_mic")
389
+ if audio_text:
390
+ st.session_state.help_query = audio_text
391
+ st.experimental_rerun()
392
+
393
+ if st.button("Send", key="send_help"):
394
+ help_query = st.session_state.get("help_query", help_query)
395
+ if help_query:
396
+ help_response = ask_help_agent(help_query)
397
+ st.session_state.help_conversation.append({"query": help_query, "response": help_response})
398
+ st.session_state.help_query = "" # Clear the input after sending
399
+ st.experimental_rerun()
400
+ else:
401
+ st.error("Please enter a query!")
402
+
403
+ if st.session_state.help_conversation:
404
+ for msg in st.session_state.help_conversation:
405
+ st.markdown(f"**You:** {msg['query']}")
406
+ st.markdown(f"**Help Assistant:** {msg['response']}")
407
+
408
+ # Guess confirmation screen using text input response
409
+ elif st.session_state.game_state == "confirm_guess":
410
+ st.markdown(f'<div class="question-box">🤖 My Final Guess:<br><br>'
411
+ f'<strong>Is it {st.session_state.final_guess}?</strong></div>',
412
+ unsafe_allow_html=True)
413
+
414
+ with st.form("confirm_form"):
415
+ col1, col2 = st.columns([4, 1])
416
+ with col1:
417
+ confirm_input = st.text_input("Type your answer (yes/no/both):", key="confirm_input").strip().lower()
418
+ with col2:
419
+ st.write("")
420
+ st.write("")
421
+ if st.form_submit_button("🎤", key="confirm_mic"):
422
+ audio_text = record_audio("confirm_mic")
423
+ if audio_text:
424
+ st.session_state.confirm_input = audio_text
425
+ st.experimental_rerun()
426
+
427
+ if st.form_submit_button("Submit"):
428
+ confirm_input = st.session_state.get("confirm_input", confirm_input)
429
+ if confirm_input not in ["yes", "no", "both"]:
430
+ st.error("Please answer with 'yes', 'no', or 'both'!")
431
+ else:
432
+ if confirm_input == "yes":
433
+ st.session_state.game_state = "result"
434
+ st.experimental_rerun()
435
+ else:
436
+ # Add negative response to history and continue gameplay
437
+ st.session_state.conversation_history.append(
438
+ {"role": "user", "content": "no"}
439
+ )
440
+ st.session_state.game_state = "gameplay"
441
+ next_response = ask_llama(
442
+ st.session_state.conversation_history,
443
+ st.session_state.category
444
+ )
445
+ st.session_state.questions.append(next_response)
446
+ st.session_state.conversation_history.append(
447
+ {"role": "assistant", "content": next_response}
448
+ )
449
+ st.session_state.current_q += 1
450
+ st.experimental_rerun()
451
+
452
+ # Result screen
453
+ elif st.session_state.game_state == "result":
454
+ if not st.session_state.final_guess:
455
+ # Generate final guess if not already made
456
+ qa_history = "\n".join(
457
+ [f"Q{i+1}: {q}\nA: {a}"
458
+ for i, (q, a) in enumerate(zip(st.session_state.questions, st.session_state.answers))]
459
+ )
460
+
461
+ final_guess = ask_llama(
462
+ [{"role": "user", "content": qa_history}],
463
+ st.session_state.category,
464
+ is_final_guess=True
465
+ )
466
+ st.session_state.final_guess = final_guess.split("Final Guess:")[-1].strip()
467
+
468
+ show_confetti()
469
+ st.markdown(f'<div class="final-reveal">🎉 It\'s...</div>', unsafe_allow_html=True)
470
+ time.sleep(1)
471
+ st.markdown(f'<div class="final-reveal" style="font-size:3.5rem;color:#6C63FF;">{st.session_state.final_guess}</div>',
472
+ unsafe_allow_html=True)
473
+ st.markdown(f"<p style='text-align:center'>Guessed in {len(st.session_state.questions)} questions</p>",
474
+ unsafe_allow_html=True)
475
+
476
+ if st.button("Play Again", key="play_again"):
477
+ st.session_state.clear()
478
+ st.experimental_rerun()
479
 
480
  if __name__ == "__main__":
481
+ main()