iisadia commited on
Commit
98d16e6
·
verified ·
1 Parent(s): 5829c26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -550
app.py CHANGED
@@ -1,560 +1,139 @@
1
- import streamlit as st
2
- import time
3
- import requests
4
- from streamlit.components.v1 import html
5
- import os
6
- from dotenv import load_dotenv
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- # Speech recognition component
9
- def add_mic_button(target_input_key, is_select=False):
10
- html(f"""
11
- <script>
12
- function startSpeechRecognition{target_input_key}() {{
13
- const targetElem = document.querySelector('input[data-testid="stTextInput-{target_input_key}"]');
14
- const statusDiv = document.getElementById('status-{target_input_key}');
15
- const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
16
- recognition.lang = 'en-US';
17
-
18
- recognition.onstart = () => {{
19
- statusDiv.innerHTML = '<div style="color: red; margin-left: 5px; animation: blink 1s infinite;">🎤 Listening...</div>';
20
- }};
21
-
22
- recognition.onresult = (event) => {{
23
- const transcript = event.results[0][0].transcript;
24
- {"if(targetElem) targetElem.value = transcript;" if not is_select else
25
- "const selectElem = document.querySelector('select[data-testid=\"stSelectbox-{target_input_key}\"]');" +
26
- "if(selectElem) { const option = Array.from(selectElem.options).find(opt => opt.text.toLowerCase().includes(transcript.toLowerCase()));" +
27
- "if(option) selectElem.value = option.value; }"}
28
- }};
29
-
30
- recognition.onerror = () => {{
31
- statusDiv.innerHTML = '<div style="color: red; margin-left: 5px;">❌ Error</div>';
32
- }};
33
-
34
- recognition.start();
35
- }}
36
- </script>
37
 
38
- <style>
39
- @keyframes blink {{
40
- 0% {{ opacity: 1; }}
41
- 50% {{ opacity: 0; }}
42
- 100% {{ opacity: 1; }}
43
- }}
44
- .mic-button {{
45
- background: #6C63FF !important;
46
- border-radius: 50%;
47
- width: 36px;
48
- height: 36px;
49
- display: flex;
50
- align-items: center;
51
- justify-content: center;
52
- cursor: pointer;
53
- margin-left: 8px;
54
- }}
55
- .input-row {{
56
- display: flex;
57
- align-items: center;
58
- gap: 8px;
59
- }}
60
- </style>
61
 
62
- <div class="input-row">
63
- <div id="status-{target_input_key}" style="display: flex; align-items: center;"></div>
64
- <button class="mic-button" onclick="startSpeechRecognition{target_input_key}()">
65
- <svg style="width:20px;height:20px;fill:white;" viewBox="0 0 24 24">
66
- <path d="M12,2A3,3 0 0,1 15,5V11A3,3 0 0,1 12,14A3,3 0 0,1 9,11V5A3,3 0 0,1 12,2M19,11C19,14.53 16.39,17.44 13,17.93V21H11V17.93C7.61,17.44 5,14.53 5,11H7A5,5 0 0,0 12,16A5,5 0 0,0 17,11H19Z"/>
67
- </svg>
68
- </button>
69
- </div>
70
- """)
71
-
72
- # Import transformers and cache the help agent for performance
73
- @st.cache_resource
74
- def get_help_agent():
75
- from transformers import pipeline
76
- # Using BlenderBot 400M Distill as the public conversational model (used elsewhere)
77
- return pipeline("conversational", model="facebook/blenderbot-400M-distill")
78
-
79
- # Enhanced Custom CSS with modern design
80
- def inject_custom_css():
81
- st.markdown("""
82
- <style>
83
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
84
- @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css');
85
- * {
86
- font-family: 'Inter', sans-serif;
87
- }
88
- body {
89
- background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
90
- }
91
- .title {
92
- font-size: 2.8rem !important;
93
- font-weight: 800 !important;
94
- background: linear-gradient(45deg, #6C63FF, #3B82F6);
95
- -webkit-background-clip: text;
96
- -webkit-text-fill-color: transparent;
97
- text-align: center;
98
- margin: 1rem 0;
99
- letter-spacing: -1px;
100
- }
101
- .subtitle {
102
- font-size: 1.1rem !important;
103
- text-align: center;
104
- color: #64748B !important;
105
- margin-bottom: 2.5rem;
106
- animation: fadeInSlide 1s ease;
107
- }
108
- .question-box {
109
- background: white;
110
- border-radius: 20px;
111
- padding: 2rem;
112
- margin: 1.5rem 0;
113
- box-shadow: 0 10px 25px rgba(0,0,0,0.08);
114
- border: 1px solid #e2e8f0;
115
- position: relative;
116
- transition: transform 0.2s ease;
117
- color: black;
118
- }
119
- .question-box:hover {
120
- transform: translateY(-3px);
121
- }
122
- .question-box::before {
123
- content: "🕹️";
124
- position: absolute;
125
- left: -15px;
126
- top: -15px;
127
- background: white;
128
- border-radius: 50%;
129
- padding: 8px;
130
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
131
- font-size: 1.2rem;
132
- }
133
- .input-box {
134
- background: white;
135
- border-radius: 12px;
136
- padding: 1.5rem;
137
- margin: 1rem 0;
138
- box-shadow: 0 4px 6px rgba(0,0,0,0.05);
139
- }
140
- .stTextInput input {
141
- border: 2px solid #e2e8f0 !important;
142
- border-radius: 10px !important;
143
- padding: 12px 16px !important;
144
- transition: all 0.3s ease !important;
145
- }
146
- .stTextInput input:focus {
147
- border-color: #6C63FF !important;
148
- box-shadow: 0 0 0 3px rgba(108, 99, 255, 0.2) !important;
149
- }
150
- button {
151
- background: linear-gradient(45deg, #6C63FF, #3B82F6) !important;
152
- color: white !important;
153
- border: none !important;
154
- border-radius: 10px !important;
155
- padding: 12px 24px !important;
156
- font-weight: 600 !important;
157
- transition: all 0.3s ease !important;
158
- }
159
- button:hover {
160
- transform: translateY(-2px);
161
- box-shadow: 0 5px 15px rgba(108, 99, 255, 0.3) !important;
162
- }
163
- .final-reveal {
164
- animation: fadeInUp 1s ease;
165
- font-size: 2.8rem;
166
- background: linear-gradient(45deg, #6C63FF, #3B82F6);
167
- -webkit-background-clip: text;
168
- -webkit-text-fill-color: transparent;
169
- text-align: center;
170
- margin: 2rem 0;
171
- font-weight: 800;
172
- }
173
- .help-chat {
174
- background: rgba(255,255,255,0.9);
175
- backdrop-filter: blur(10px);
176
- border-radius: 15px;
177
- padding: 1rem;
178
- margin: 1rem 0;
179
- box-shadow: 0 8px 30px rgba(0,0,0,0.12);
180
- }
181
- @keyframes fadeInSlide {
182
- 0% { opacity: 0; transform: translateY(20px); }
183
- 100% { opacity: 1; transform: translateY(0); }
184
- }
185
- @keyframes fadeInUp {
186
- 0% { opacity: 0; transform: translateY(30px); }
187
- 100% { opacity: 1; transform: translateY(0); }
188
- }
189
- .progress-bar {
190
- height: 6px;
191
- background: #e2e8f0;
192
- border-radius: 3px;
193
- margin: 1.5rem 0;
194
- overflow: hidden;
195
- }
196
- .progress-fill {
197
- height: 100%;
198
- background: linear-gradient(90deg, #6C63FF, #3B82F6);
199
- transition: width 0.5s ease;
200
- }
201
- .question-count {
202
- color: #6C63FF;
203
- font-weight: 600;
204
- font-size: 0.9rem;
205
- margin-bottom: 0.5rem;
206
- }
207
- </style>
208
- """, unsafe_allow_html=True)
209
-
210
- # Confetti animation (enhanced)
211
- def show_confetti():
212
- html("""
213
- <canvas id="confetti-canvas" class="confetti"></canvas>
214
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js"></script>
215
- <script>
216
- const count = 200;
217
- const defaults = {
218
- origin: { y: 0.7 },
219
- zIndex: 1050
220
- };
221
- function fire(particleRatio, opts) {
222
- confetti(Object.assign({}, defaults, opts, {
223
- particleCount: Math.floor(count * particleRatio)
224
- }));
225
  }
226
- fire(0.25, { spread: 26, startVelocity: 55 });
227
- fire(0.2, { spread: 60 });
228
- fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
229
- fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
230
- fire(0.1, { spread: 120, startVelocity: 45 });
231
- </script>
232
- """)
233
-
234
- # Enhanced AI question generation for guessing game using Llama model
235
- def ask_llama(conversation_history, category, is_final_guess=False):
236
- api_url = "https://api.groq.com/openai/v1/chat/completions"
237
- headers = {
238
- "Authorization": "Bearer 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",
239
- "Content-Type": "application/json"
240
  }
241
-
242
- system_prompt = f"""You're playing 20 questions to guess a {category}. Follow these rules:
243
- 1. Ask strategic, non-repeating yes/no questions that narrow down possibilities
244
- 2. Consider all previous answers carefully before asking next question
245
- 3. If you're very confident (80%+ sure), respond with "Final Guess: [your guess]"
246
- 4. For places: ask about continent, climate, famous landmarks, country, city or population
247
- 5. For people: ask about fictional or real, profession, gender, alive/dead, nationality, or fame
248
- 6. For objects: ask about size, color, usage, material, or where it's found
249
- 7. Never repeat questions and always make progress toward guessing"""
250
-
251
- if is_final_guess:
252
- prompt = f"""Based on these answers about a {category}, provide ONLY your final guess with no extra text:
253
- {conversation_history}"""
254
- else:
255
- prompt = "Ask your next strategic yes/no question that will best narrow down the possibilities."
256
-
257
- messages = [
258
- {"role": "system", "content": system_prompt},
259
- *conversation_history,
260
- {"role": "user", "content": prompt}
261
- ]
262
-
263
- data = {
264
- "model": "llama-3.3-70b-versatile",
265
- "messages": messages,
266
- "temperature": 0.7 if is_final_guess else 0.8,
267
- "max_tokens": 100
268
  }
269
-
270
- try:
271
- response = requests.post(api_url, headers=headers, json=data)
272
- response.raise_for_status()
273
- return response.json()["choices"][0]["message"]["content"]
274
- except Exception as e:
275
- st.error(f"Error calling Llama API: {str(e)}")
276
- return "Could not generate question"
277
-
278
- # New function for the help AI assistant using the Hugging Face InferenceClient
279
- MISTRAL_API_KEY = "wm5eLl09b9I9cOxR3E9n5rrRr1CRQQjn"
280
- def ask_help_agent(query):
281
- try:
282
- # Prepare Mistral API request
283
- url = "https://api.mistral.ai/v1/chat/completions"
284
- headers = {
285
- "Authorization": f"Bearer {MISTRAL_API_KEY}",
286
- "Content-Type": "application/json"
287
- }
288
-
289
- system_message = "You are a friendly Chatbot."
290
-
291
- # Build message history
292
- messages = [{"role": "system", "content": system_message}]
293
- if "help_conversation" in st.session_state:
294
- for msg in st.session_state.help_conversation:
295
- if msg.get("query"):
296
- messages.append({"role": "user", "content": msg["query"]})
297
- if msg.get("response"):
298
- messages.append({"role": "assistant", "content": msg["response"]})
299
-
300
- # Add current user query
301
- messages.append({"role": "user", "content": query})
302
-
303
- # API payload
304
- payload = {
305
- "model": "mistral-tiny",
306
- "messages": messages,
307
- "temperature": 0.7,
308
- "top_p": 0.95
309
- }
310
-
311
- # Send POST request
312
- response = requests.post(url, headers=headers, json=payload)
313
-
314
- if response.status_code == 200:
315
- result = response.json()
316
- return result["choices"][0]["message"]["content"]
317
- else:
318
- return f"API Error {response.status_code}: {response.text}"
319
-
320
- except Exception as e:
321
- return f"Error in help agent: {str(e)}"
322
-
323
- # Main game logic with enhanced UI
324
- def main():
325
- inject_custom_css()
326
-
327
- st.markdown('<div class="title">KASOTI</div>', unsafe_allow_html=True)
328
- st.markdown('<div class="subtitle">AI-Powered Guessing Game Challenge</div>', unsafe_allow_html=True)
329
-
330
- if 'game_state' not in st.session_state:
331
- st.session_state.game_state = "start"
332
- st.session_state.questions = []
333
- st.session_state.current_q = 0
334
- st.session_state.answers = []
335
- st.session_state.conversation_history = []
336
- st.session_state.category = None
337
- st.session_state.final_guess = None
338
- st.session_state.help_conversation = [] # separate history for help agent
339
-
340
- # Start screen with enhanced layout
341
- if st.session_state.game_state == "start":
342
- with st.container():
343
- st.markdown("""
344
- <div class="question-box">
345
- <h3 style="color: #6C63FF; margin-bottom: 1.5rem;">🎮 Welcome to KASOTI</h3>
346
- <p style="line-height: 1.6; color: #64748B;">
347
- Think of something and I'll try to guess it in 20 questions or less!<br>
348
- Choose from these categories:
349
- </p>
350
- <div style="display: grid; gap: 1rem; margin: 2rem 0;">
351
- <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
352
- <h4 style="margin: 0; color: #6C63FF;">🧑 Person</h4>
353
- <p style="margin: 0.5rem 0 0; color: #64748B;">Celebrity, fictional character, historical figure</p>
354
- </div>
355
- <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
356
- <h4 style="margin: 0; color: #6C63FF;">🌍 Place</h4>
357
- <p style="margin: 0.5rem 0 0; color: #64748B;">City, country, landmark, geographical location</p>
358
- </div>
359
- <div style="padding: 1.5rem; background: #f8f9fa; border-radius: 12px;">
360
- <h4 style="margin: 0; color: #6C63FF;">🎯 Object</h4>
361
- <p style="margin: 0.5rem 0 0; color: #64748B;">Everyday item, tool, vehicle, or concept</p>
362
- </div>
363
- </div>
364
- </div>
365
- """, unsafe_allow_html=True)
366
-
367
- with st.form("start_form"):
368
- col1, col2 = st.columns([4, 1])
369
- with col1:
370
- category_input = st.text_input("Enter category (person/place/object):", key="category_input").strip().lower()
371
- with col2:
372
- st.markdown("<div style='height: 30px;'></div>")
373
- add_mic_button("category_input")
374
 
375
- if st.form_submit_button("Start Game"):
376
- if not category_input:
377
- st.error("Please enter a category!")
378
- elif category_input not in ["person", "place", "object"]:
379
- st.error("Please enter either 'person', 'place', or 'object'!")
380
- else:
381
- st.session_state.category = category_input
382
- first_question = ask_llama([
383
- {"role": "user", "content": "Ask your first strategic yes/no question."}
384
- ], category_input)
385
- st.session_state.questions = [first_question]
386
- st.session_state.conversation_history = [
387
- {"role": "assistant", "content": first_question}
388
- ]
389
- st.session_state.game_state = "gameplay"
390
- st.experimental_rerun()
391
-
392
- # Gameplay screen with progress bar
393
- elif st.session_state.game_state == "gameplay":
394
- with st.container():
395
- # Add progress bar
396
- progress = (st.session_state.current_q + 1) / 20
397
- st.markdown(f"""
398
- <div class="question-count">QUESTION {st.session_state.current_q + 1} OF 20</div>
399
- <div class="progress-bar">
400
- <div class="progress-fill" style="width: {progress * 100}%"></div>
401
- </div>
402
- """, unsafe_allow_html=True)
403
-
404
- current_question = st.session_state.questions[st.session_state.current_q]
405
-
406
- # Enhanced question box
407
- st.markdown(f'''
408
- <div class="question-box">
409
- <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
410
- <div style="background: #6C63FF; width: 40px; height: 40px; border-radius: 50%;
411
- display: flex; align-items: center; justify-content: center; color: white;">
412
- <i class="fas fa-robot"></i>
413
- </div>
414
- <h3 style="margin: 0; color: #1E293B;">AI Question</h3>
415
- </div>
416
- <p style="font-size: 1.1rem; line-height: 1.6; color: #1E293B;">{current_question}</p>
417
- </div>
418
- ''', unsafe_allow_html=True)
419
-
420
- # Check if AI made a guess
421
- if "Final Guess:" in current_question:
422
- st.session_state.final_guess = current_question.split("Final Guess:")[1].strip()
423
- st.session_state.game_state = "confirm_guess"
424
- st.experimental_rerun()
425
-
426
- with st.form("answer_form"):
427
- col1, col2 = st.columns([4, 1])
428
- with col1:
429
- answer_input = st.text_input("Your answer (yes/no/both):",
430
- key=f"answer_{st.session_state.current_q}").strip().lower()
431
- with col2:
432
- st.markdown("<div style='height: 30px;'></div>")
433
- add_mic_button(f"answer_{st.session_state.current_q}")
434
-
435
- if st.form_submit_button("Submit"):
436
- if answer_input not in ["yes", "no", "both"]:
437
- st.error("Please answer with 'yes', 'no', or 'both'!")
438
- else:
439
- st.session_state.answers.append(answer_input)
440
- st.session_state.conversation_history.append(
441
- {"role": "user", "content": answer_input}
442
- )
443
-
444
- # Generate next response
445
- next_response = ask_llama(
446
- st.session_state.conversation_history,
447
- st.session_state.category
448
- )
449
-
450
- # Check if AI made a guess
451
- if "Final Guess:" in next_response:
452
- st.session_state.final_guess = next_response.split("Final Guess:")[1].strip()
453
- st.session_state.game_state = "confirm_guess"
454
- else:
455
- st.session_state.questions.append(next_response)
456
- st.session_state.conversation_history.append(
457
- {"role": "assistant", "content": next_response}
458
- )
459
- st.session_state.current_q += 1
460
-
461
- # Stop after 20 questions max
462
- if st.session_state.current_q >= 20:
463
- st.session_state.game_state = "result"
464
-
465
- st.experimental_rerun()
466
-
467
- # Side Help Option: independent chat with an AI help assistant using Hugging Face model
468
- with st.expander("Need Help? Chat with AI Assistant"):
469
- help_query = st.text_input("Enter your help query:", key="help_query")
470
- if st.button("Send", key="send_help"):
471
- if help_query:
472
- help_response = ask_help_agent(help_query)
473
- st.session_state.help_conversation.append({"query": help_query, "response": help_response})
474
- else:
475
- st.error("Please enter a query!")
476
- if st.session_state.help_conversation:
477
- for msg in st.session_state.help_conversation:
478
- st.markdown(f"**You:** {msg['query']}")
479
- st.markdown(f"**Help Assistant:** {msg['response']}")
480
-
481
- # Guess confirmation screen using text input response
482
- elif st.session_state.game_state == "confirm_guess":
483
- st.markdown(f'''
484
- <div class="question-box">
485
- <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
486
- <div style="background: #6C63FF; width: 40px; height: 40px; border-radius: 50%;
487
- display: flex; align-items: center; justify-content: center; color: white;">
488
- <i class="fas fa-lightbulb"></i>
489
- </div>
490
- <h3 style="margin: 0; color: #1E293B;">AI's Final Guess</h3>
491
- </div>
492
- <p style="font-size: 1.2rem; line-height: 1.6; color: #1E293B;">
493
- Is it <strong style="color: #6C63FF;">{st.session_state.final_guess}</strong>?
494
- </p>
495
- </div>
496
- ''', unsafe_allow_html=True)
497
-
498
- with st.form("confirm_form"):
499
- col1, col2 = st.columns([4, 1])
500
- with col1:
501
- confirm_input = st.text_input("Type your answer (yes/no/both):", key="confirm_input").strip().lower()
502
- with col2:
503
- st.markdown("<div style='height: 30px;'></div>")
504
- add_mic_button("confirm_input")
505
-
506
- if st.form_submit_button("Submit"):
507
- if confirm_input not in ["yes", "no", "both"]:
508
- st.error("Please answer with 'yes', 'no', or 'both'!")
509
- else:
510
- if confirm_input == "yes":
511
- st.session_state.game_state = "result"
512
- st.experimental_rerun()
513
- st.stop() # Immediately halt further execution
514
- else:
515
- # Add negative response to history and continue gameplay
516
- st.session_state.conversation_history.append(
517
- {"role": "user", "content": "no"}
518
- )
519
- st.session_state.game_state = "gameplay"
520
- next_response = ask_llama(
521
- st.session_state.conversation_history,
522
- st.session_state.category
523
- )
524
- st.session_state.questions.append(next_response)
525
- st.session_state.conversation_history.append(
526
- {"role": "assistant", "content": next_response}
527
- )
528
- st.session_state.current_q += 1
529
- st.experimental_rerun()
530
-
531
- # Result screen with enhanced celebration
532
- elif st.session_state.game_state == "result":
533
- if not st.session_state.final_guess:
534
- # Generate final guess if not already made
535
- qa_history = "\n".join(
536
- [f"Q{i+1}: {q}\nA: {a}"
537
- for i, (q, a) in enumerate(zip(st.session_state.questions, st.session_state.answers))]
538
  )
539
-
540
- final_guess = ask_llama(
541
- [{"role": "user", "content": qa_history}],
542
- st.session_state.category,
543
- is_final_guess=True
544
- )
545
- st.session_state.final_guess = final_guess.split("Final Guess:")[-1].strip()
546
-
547
- show_confetti()
548
- st.markdown(f'<div class="final-reveal">🎉 It\'s...</div>', unsafe_allow_html=True)
549
- time.sleep(1)
550
- st.markdown(f'<div class="final-reveal" style="font-size:3.5rem;color:#6C63FF;">{st.session_state.final_guess}</div>',
551
- unsafe_allow_html=True)
552
- st.markdown(f"<p style='text-align:center; color:#64748B;'>Guessed in {len(st.session_state.questions)} questions</p>",
553
- unsafe_allow_html=True)
554
-
555
- if st.button("Play Again", key="play_again"):
556
- st.session_state.clear()
557
- st.experimental_rerun()
558
 
559
  if __name__ == "__main__":
560
- main()
 
 
1
+ import gradio as gr
2
+ import speech_recognition as sr
3
+ from time import time
4
+ import threading
5
+ from pydub import AudioSegment
6
+ from pydub.playback import play
7
+ import io
8
+
9
+ # Global variables
10
+ is_recording = False
11
+ start_beep = AudioSegment.silent(duration=200).append(AudioSegment.from_wav(io.BytesIO(b''), crossfade=100)
12
+ end_beep = AudioSegment.silent(duration=200).append(AudioSegment.from_wav(io.BytesIO(b'')), crossfade=100)
13
+
14
+ def play_start_sound():
15
+ try:
16
+ play(start_beep)
17
+ except:
18
+ pass
19
 
20
+ def play_end_sound():
21
+ try:
22
+ play(end_beep)
23
+ except:
24
+ pass
25
+
26
+ def start_recording(audio_time_limit):
27
+ global is_recording
28
+ is_recording = True
29
+ recognizer = sr.Recognizer()
30
+ microphone = sr.Microphone()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ play_start_sound()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ with microphone as source:
35
+ recognizer.adjust_for_ambient_noise(source, duration=0.5)
36
+ try:
37
+ audio = recognizer.listen(source, timeout=3, phrase_time_limit=audio_time_limit)
38
+ text = recognizer.recognize_google(audio)
39
+ return text
40
+ except sr.WaitTimeoutError:
41
+ return ""
42
+ except sr.UnknownValueError:
43
+ return ""
44
+ except Exception as e:
45
+ print(f"Error: {str(e)}")
46
+ return ""
47
+ finally:
48
+ play_end_sound()
49
+ is_recording = False
50
+
51
+ def transcribe_audio(audio_time_limit=10):
52
+ def execute_recording():
53
+ nonlocal result
54
+ result = start_recording(audio_time_limit)
55
+
56
+ result = ""
57
+ recording_thread = threading.Thread(target=execute_recording)
58
+ recording_thread.start()
59
+
60
+ start_time = time()
61
+ while is_recording and (time() - start_time) < audio_time_limit:
62
+ time_elapsed = time() - start_time
63
+ time_left = max(0, audio_time_limit - time_elapsed)
64
+ progress = 1 - (time_left / audio_time_limit)
65
+ yield {"__type__": "update", "value": f"🎤 Recording... {time_left:.1f}s left", "visible": True}, {"__type__": "update", "value": "", "visible": True}
66
+ gr.sleep(0.1)
67
+
68
+ recording_thread.join()
69
+ yield {"__type__": "update", "value": "✅ Done!", "visible": True}, {"__type__": "update", "value": result, "visible": True}
70
+
71
+ def create_ui():
72
+ css = """
73
+ .mic-button {
74
+ background: linear-gradient(45deg, #FF3366, #BA265D) !important;
75
+ border: none !important;
76
+ color: white !important;
77
+ padding: 12px !important;
78
+ border-radius: 50% !important;
79
+ height: 50px !important;
80
+ width: 50px !important;
81
+ margin-left: 10px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
83
+ .mic-button:hover {
84
+ transform: scale(1.05) !important;
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
+ .input-with-mic {
87
+ display: flex !important;
88
+ align-items: center !important;
89
+ gap: 10px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
+ .status-message {
92
+ font-style: italic;
93
+ color: #666;
94
+ margin-top: 5px;
95
+ }
96
+ """
97
+
98
+ with gr.Blocks(css=css) as demo:
99
+ gr.Markdown("## 🎤 Speech to Text Converter")
100
+
101
+ with gr.Group():
102
+ with gr.Row():
103
+ text_input = gr.Textbox(
104
+ label="Your Input",
105
+ placeholder="Click the mic button and speak...",
106
+ elem_classes=["input-box"],
107
+ scale=9
108
+ )
109
+ mic_button = gr.Button(
110
+ "🎤",
111
+ elem_classes=["mic-button"],
112
+ scale=1
113
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ status_display = gr.Textbox(
116
+ label="Status",
117
+ visible=False,
118
+ interactive=False,
119
+ elem_classes=["status-message"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  )
121
+
122
+ mic_button.click(
123
+ fn=transcribe_audio,
124
+ inputs=[gr.Slider(5, 30, value=10, label="Recording time limit (seconds)")],
125
+ outputs=[status_display, text_input],
126
+ show_progress="hidden"
127
+ )
128
+
129
+ gr.Examples(
130
+ examples=["Hello world", "How are you today?", "Please convert my speech to text"],
131
+ inputs=text_input,
132
+ label="Try these examples:"
133
+ )
134
+
135
+ return demo
 
 
 
 
136
 
137
  if __name__ == "__main__":
138
+ demo = create_ui()
139
+ demo.launch(debug=True)