ArchCoder commited on
Commit
a971d1c
·
verified ·
1 Parent(s): f81cf03

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -69
app.py CHANGED
@@ -1,20 +1,20 @@
1
  import gradio as gr
2
  from faster_whisper import WhisperModel
3
- from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer
4
  from duckduckgo_search import DDGS
5
  import time
6
  import torch
7
  import base64
8
  import tempfile
9
  import os
10
- from threading import Thread
11
 
12
  # Initialize models
13
  print("Loading Whisper model...")
14
  whisper_model = WhisperModel("tiny", device="cpu", compute_type="int8")
15
 
16
  print("Loading LLM...")
17
- model_name = "Qwen/Qwen2.5-0.5B-Instruct"
18
  tokenizer = AutoTokenizer.from_pretrained(model_name)
19
  model = AutoModelForCausalLM.from_pretrained(
20
  model_name,
@@ -26,7 +26,7 @@ model = AutoModelForCausalLM.from_pretrained(
26
  # Initialize DuckDuckGo Search
27
  ddgs = DDGS(timeout=3)
28
 
29
- def search_web(query, max_results=2):
30
  """Perform web search using DuckDuckGo"""
31
  try:
32
  results = ddgs.text(
@@ -41,7 +41,7 @@ def search_web(query, max_results=2):
41
  for i, result in enumerate(results[:max_results], 1):
42
  title = result.get('title', '')
43
  body = result.get('body', '')
44
- context += f"\n[{i}] {title}\n{body}\n"
45
 
46
  return context.strip() if context else "No search results found."
47
 
@@ -67,18 +67,41 @@ def transcribe_audio_base64(audio_base64):
67
  except Exception as e:
68
  return {"error": f"Transcription failed: {str(e)}"}
69
 
70
- def generate_answer_stream(text_input):
71
- """Generate streaming answer from text input"""
72
  try:
73
  if not text_input or text_input.strip() == "":
74
- yield "No input provided"
75
- return
76
 
77
- search_results = search_web(text_input, max_results=2)
 
78
 
 
 
 
 
79
  messages = [
80
- {"role": "system", "content": "You are a helpful assistant. Answer briefly using provided context. Keep responses under 40 words."},
81
- {"role": "user", "content": f"Context:\n{search_results}\n\nQuestion: {text_input}\n\nAnswer:"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  ]
83
 
84
  text = tokenizer.apply_chat_template(
@@ -88,32 +111,26 @@ def generate_answer_stream(text_input):
88
  )
89
 
90
  inputs = tokenizer([text], return_tensors="pt").to("cpu")
91
- streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
92
 
93
- generation_kwargs = dict(
94
- inputs=inputs['input_ids'],
95
- attention_mask=inputs['attention_mask'],
96
- max_new_tokens=80,
97
- temperature=0.2,
98
- do_sample=True,
99
- top_p=0.85,
100
- pad_token_id=tokenizer.eos_token_id,
101
- streamer=streamer
102
- )
103
 
104
- thread = Thread(target=model.generate, kwargs=generation_kwargs)
105
- thread.start()
106
-
107
- generated_text = ""
108
- for new_text in streamer:
109
- generated_text += new_text
110
- yield generated_text
111
 
112
  except Exception as e:
113
- yield f"Error: {str(e)}"
114
 
115
- def process_audio_stream(audio_path, question_text):
116
- """Streaming pipeline that yields tuples"""
117
  start_time = time.time()
118
 
119
  # Transcribe if audio provided
@@ -122,48 +139,48 @@ def process_audio_stream(audio_path, question_text):
122
  segments, _ = whisper_model.transcribe(audio_path, language="en", beam_size=1)
123
  question = " ".join([seg.text for seg in segments])
124
  except Exception as e:
125
- yield f"❌ Transcription error: {str(e)}", 0.0
126
- return
127
  else:
128
  question = question_text
129
 
130
  if not question or question.strip() == "":
131
- yield "❌ No input provided", 0.0
132
- return
133
 
134
  transcription_time = time.time() - start_time
135
 
136
  # Web search
137
  search_start = time.time()
138
- search_results = search_web(question, max_results=2)
139
  search_time = time.time() - search_start
140
 
141
- # Stream answer
142
  llm_start = time.time()
143
- for partial_answer in generate_answer_stream(question):
144
- current_time = time.time() - start_time
145
- time_emoji = "🟢" if current_time < 3.0 else "🟡" if current_time < 3.5 else "🔴"
146
- timing_info = f"\n\n{time_emoji} **Timing:** Trans={transcription_time:.2f}s | Search={search_time:.2f}s | LLM={(time.time()-llm_start):.2f}s | **Total={current_time:.2f}s**"
147
- yield partial_answer + timing_info, current_time
 
 
 
 
148
 
149
- # Wrapper functions for proper API handling
150
  def audio_handler(audio_path):
151
  """Wrapper for audio input"""
152
- for result in process_audio_stream(audio_path, None):
153
- yield result
154
 
155
  def text_handler(text_input):
156
  """Wrapper for text input"""
157
- for result in process_audio_stream(None, text_input):
158
- yield result
159
 
160
- # Create Gradio interface
161
- with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as demo:
162
  gr.Markdown("""
163
- # Ultra-Fast Political Q&A System
164
- **Streaming enabled** for instant feedback! Pluely compatible endpoints available.
165
 
166
- **Features:** Whisper-tiny + Qwen2.5-0.5B + DuckDuckGo + Real-time streaming
167
  """)
168
 
169
  with gr.Tab("🎙️ Audio Input"):
@@ -177,14 +194,14 @@ with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as
177
  audio_submit = gr.Button("🚀 Submit Audio", variant="primary", size="lg")
178
 
179
  with gr.Column():
180
- audio_output = gr.Textbox(label="Answer (Streaming)", lines=8, show_copy_button=True)
181
  audio_time = gr.Number(label="Response Time (seconds)", precision=2)
182
 
183
  audio_submit.click(
184
  fn=audio_handler,
185
  inputs=[audio_input],
186
  outputs=[audio_output, audio_time],
187
- api_name="audio_query_stream"
188
  )
189
 
190
  with gr.Tab("✍️ Text Input"):
@@ -198,21 +215,22 @@ with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as
198
  text_submit = gr.Button("🚀 Submit Text", variant="primary", size="lg")
199
 
200
  with gr.Column():
201
- text_output = gr.Textbox(label="Answer (Streaming)", lines=8, show_copy_button=True)
202
  text_time = gr.Number(label="Response Time (seconds)", precision=2)
203
 
204
  text_submit.click(
205
  fn=text_handler,
206
  inputs=[text_input],
207
  outputs=[text_output, text_time],
208
- api_name="text_query_stream"
209
  )
210
 
211
  gr.Examples(
212
  examples=[
213
  ["Who won the 2024 US presidential election?"],
214
  ["What is the current inflation rate in India?"],
215
- ["Who is the prime minister of UK?"]
 
216
  ],
217
  inputs=text_input
218
  )
@@ -220,21 +238,23 @@ with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as
220
  # API endpoints for Pluely
221
  with gr.Tab("🔌 Pluely Integration"):
222
  gr.Markdown("""
223
- ## Dedicated Endpoints for Pluely
224
 
225
- ### 1. STT Endpoint (Audio Transcription)
226
  ```
227
  curl -X POST https://archcoder-basic-app.hf.space/call/transcribe_stt \\
228
  -H "Content-Type: application/json" \\
229
  -d '{"data": ["BASE64_AUDIO_DATA"]}'
230
  ```
 
231
 
232
- ### 2. AI Endpoint - Streaming
233
  ```
234
- curl -X POST https://archcoder-basic-app.hf.space/call/answer_ai_stream \\
235
  -H "Content-Type: application/json" \\
236
  -d '{"data": ["Your question here"]}'
237
  ```
 
238
 
239
  ## Pluely Configuration
240
 
@@ -246,9 +266,9 @@ with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as
246
 
247
  ### Custom AI Provider:
248
  ```
249
- curl https://archcoder-basic-app.hf.space/call/answer_ai_stream -H "Content-Type: application/json" -d '{"data": ["{{TEXT}}"]}'
250
  ```
251
- **Response Path:** `data` | **Streaming:** ON ✅
252
  """)
253
 
254
  # Hidden components for API endpoints
@@ -268,16 +288,20 @@ with gr.Blocks(title="Fast Q&A - Streaming Enabled", theme=gr.themes.Soft()) as
268
 
269
  ai_btn = gr.Button("AI", visible=False)
270
  ai_btn.click(
271
- fn=generate_answer_stream,
272
  inputs=[ai_input],
273
  outputs=[ai_output],
274
- api_name="answer_ai_stream"
275
  )
276
 
277
  gr.Markdown("""
278
  ---
279
- 🟢 = Under 3s | 🟡 = 3-3.5s | 🔴 = Over 3.5s
280
- """)
 
 
 
 
281
 
282
  if __name__ == "__main__":
283
  demo.queue(max_size=5)
 
1
  import gradio as gr
2
  from faster_whisper import WhisperModel
3
+ from transformers import AutoTokenizer, AutoModelForCausalLM
4
  from duckduckgo_search import DDGS
5
  import time
6
  import torch
7
  import base64
8
  import tempfile
9
  import os
10
+ from datetime import datetime
11
 
12
  # Initialize models
13
  print("Loading Whisper model...")
14
  whisper_model = WhisperModel("tiny", device="cpu", compute_type="int8")
15
 
16
  print("Loading LLM...")
17
+ model_name = "Qwen/Qwen2.5-1.5B-Instruct" # Upgraded to 1.5B for better quality
18
  tokenizer = AutoTokenizer.from_pretrained(model_name)
19
  model = AutoModelForCausalLM.from_pretrained(
20
  model_name,
 
26
  # Initialize DuckDuckGo Search
27
  ddgs = DDGS(timeout=3)
28
 
29
+ def search_web(query, max_results=3):
30
  """Perform web search using DuckDuckGo"""
31
  try:
32
  results = ddgs.text(
 
41
  for i, result in enumerate(results[:max_results], 1):
42
  title = result.get('title', '')
43
  body = result.get('body', '')
44
+ context += f"\n[Source {i}] {title}\n{body}\n"
45
 
46
  return context.strip() if context else "No search results found."
47
 
 
67
  except Exception as e:
68
  return {"error": f"Transcription failed: {str(e)}"}
69
 
70
+ def generate_answer(text_input):
71
+ """Generate complete answer with context"""
72
  try:
73
  if not text_input or text_input.strip() == "":
74
+ return "No input provided"
 
75
 
76
+ # Get current date for context
77
+ current_date = datetime.now().strftime("%B %d, %Y")
78
 
79
+ # Web search for current information
80
+ search_results = search_web(text_input, max_results=3)
81
+
82
+ # Enhanced prompt for comprehensive responses
83
  messages = [
84
+ {"role": "system", "content": f"""You are a knowledgeable assistant providing comprehensive, well-researched answers. Today's date is {current_date}.
85
+
86
+ When answering:
87
+ 1. Provide the direct answer first
88
+ 2. Add relevant context and background information
89
+ 3. Include recent developments or current status when applicable
90
+ 4. Be informative but concise (150-200 words)
91
+ 5. Use the web search results to ensure accuracy and currency"""},
92
+ {"role": "user", "content": f"""Based on these current web search results:
93
+
94
+ {search_results}
95
+
96
+ Question: {text_input}
97
+
98
+ Provide a comprehensive answer that includes:
99
+ - Direct answer to the question
100
+ - Relevant context and background
101
+ - Recent developments (as of {current_date})
102
+ - Key points the user should know
103
+
104
+ Answer:"""}
105
  ]
106
 
107
  text = tokenizer.apply_chat_template(
 
111
  )
112
 
113
  inputs = tokenizer([text], return_tensors="pt").to("cpu")
 
114
 
115
+ with torch.no_grad():
116
+ outputs = model.generate(
117
+ **inputs,
118
+ max_new_tokens=250, # Increased from 80 to 250
119
+ temperature=0.3, # Slightly higher for more natural responses
120
+ do_sample=True,
121
+ top_p=0.9,
122
+ repetition_penalty=1.1,
123
+ pad_token_id=tokenizer.eos_token_id
124
+ )
125
 
126
+ response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)
127
+ return response.strip()
 
 
 
 
 
128
 
129
  except Exception as e:
130
+ return f"Error: {str(e)}"
131
 
132
+ def process_audio(audio_path, question_text):
133
+ """Main pipeline - returns tuple (answer, time)"""
134
  start_time = time.time()
135
 
136
  # Transcribe if audio provided
 
139
  segments, _ = whisper_model.transcribe(audio_path, language="en", beam_size=1)
140
  question = " ".join([seg.text for seg in segments])
141
  except Exception as e:
142
+ return f"❌ Transcription error: {str(e)}", 0.0
 
143
  else:
144
  question = question_text
145
 
146
  if not question or question.strip() == "":
147
+ return "❌ No input provided", 0.0
 
148
 
149
  transcription_time = time.time() - start_time
150
 
151
  # Web search
152
  search_start = time.time()
153
+ search_results = search_web(question, max_results=3)
154
  search_time = time.time() - search_start
155
 
156
+ # Generate answer
157
  llm_start = time.time()
158
+ answer = generate_answer(question)
159
+ llm_time = time.time() - llm_start
160
+
161
+ total_time = time.time() - start_time
162
+ time_emoji = "🟢" if total_time < 5.0 else "🟡" if total_time < 7.0 else "🔴"
163
+
164
+ timing_info = f"\n\n{time_emoji} **Performance:** Trans={transcription_time:.2f}s | Search={search_time:.2f}s | LLM={llm_time:.2f}s | **Total={total_time:.2f}s**"
165
+
166
+ return answer + timing_info, total_time
167
 
168
+ # Wrapper functions
169
  def audio_handler(audio_path):
170
  """Wrapper for audio input"""
171
+ return process_audio(audio_path, None)
 
172
 
173
  def text_handler(text_input):
174
  """Wrapper for text input"""
175
+ return process_audio(None, text_input)
 
176
 
177
+ # Gradio interface
178
+ with gr.Blocks(title="Enhanced Political Q&A", theme=gr.themes.Soft()) as demo:
179
  gr.Markdown("""
180
+ # 🎯 Enhanced Political Q&A System
181
+ **Comprehensive answers with context** - Powered by Qwen2.5-1.5B
182
 
183
+ **Features:** Whisper-tiny + Qwen2.5-1.5B + DuckDuckGo + Rich contextual responses
184
  """)
185
 
186
  with gr.Tab("🎙️ Audio Input"):
 
194
  audio_submit = gr.Button("🚀 Submit Audio", variant="primary", size="lg")
195
 
196
  with gr.Column():
197
+ audio_output = gr.Textbox(label="Comprehensive Answer", lines=12, show_copy_button=True)
198
  audio_time = gr.Number(label="Response Time (seconds)", precision=2)
199
 
200
  audio_submit.click(
201
  fn=audio_handler,
202
  inputs=[audio_input],
203
  outputs=[audio_output, audio_time],
204
+ api_name="audio_query"
205
  )
206
 
207
  with gr.Tab("✍️ Text Input"):
 
215
  text_submit = gr.Button("🚀 Submit Text", variant="primary", size="lg")
216
 
217
  with gr.Column():
218
+ text_output = gr.Textbox(label="Comprehensive Answer", lines=12, show_copy_button=True)
219
  text_time = gr.Number(label="Response Time (seconds)", precision=2)
220
 
221
  text_submit.click(
222
  fn=text_handler,
223
  inputs=[text_input],
224
  outputs=[text_output, text_time],
225
+ api_name="text_query"
226
  )
227
 
228
  gr.Examples(
229
  examples=[
230
  ["Who won the 2024 US presidential election?"],
231
  ["What is the current inflation rate in India?"],
232
+ ["Who is the prime minister of UK and what are their key policies?"],
233
+ ["Explain the latest developments in AI regulation"]
234
  ],
235
  inputs=text_input
236
  )
 
238
  # API endpoints for Pluely
239
  with gr.Tab("🔌 Pluely Integration"):
240
  gr.Markdown("""
241
+ ## API Endpoints for Pluely
242
 
243
+ ### STT Endpoint (Audio Transcription)
244
  ```
245
  curl -X POST https://archcoder-basic-app.hf.space/call/transcribe_stt \\
246
  -H "Content-Type: application/json" \\
247
  -d '{"data": ["BASE64_AUDIO_DATA"]}'
248
  ```
249
+ **Response:** `{"data": [{"text": "transcribed text"}]}`
250
 
251
+ ### AI Endpoint (Enhanced Responses)
252
  ```
253
+ curl -X POST https://archcoder-basic-app.hf.space/call/answer_ai \\
254
  -H "Content-Type: application/json" \\
255
  -d '{"data": ["Your question here"]}'
256
  ```
257
+ **Response:** `{"data": ["Comprehensive answer with context"]}`
258
 
259
  ## Pluely Configuration
260
 
 
266
 
267
  ### Custom AI Provider:
268
  ```
269
+ curl https://archcoder-basic-app.hf.space/call/answer_ai -H "Content-Type: application/json" -d '{"data": ["{{TEXT}}"]}'
270
  ```
271
+ **Response Path:** `data[0]` | **Streaming:** OFF
272
  """)
273
 
274
  # Hidden components for API endpoints
 
288
 
289
  ai_btn = gr.Button("AI", visible=False)
290
  ai_btn.click(
291
+ fn=generate_answer,
292
  inputs=[ai_input],
293
  outputs=[ai_output],
294
+ api_name="answer_ai"
295
  )
296
 
297
  gr.Markdown("""
298
  ---
299
+ **Model:** Qwen2.5-1.5B-Instruct (3x larger for better answers)
300
+ **Output:** 150-200 words with context and background
301
+ **Date-aware:** Responses reference current date ({})
302
+
303
+ 🟢 = Under 5s | 🟡 = 5-7s | 🔴 = Over 7s
304
+ """.format(datetime.now().strftime("%B %d, %Y")))
305
 
306
  if __name__ == "__main__":
307
  demo.queue(max_size=5)