ArchCoder commited on
Commit
3683c2c
·
verified ·
1 Parent(s): 990db9b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -38
app.py CHANGED
@@ -4,6 +4,9 @@ from transformers import AutoTokenizer, AutoModelForCausalLM
4
  from duckduckgo_search import DDGS
5
  import time
6
  import torch
 
 
 
7
 
8
  # Initialize models
9
  print("Loading Whisper model...")
@@ -23,7 +26,7 @@ model = AutoModelForCausalLM.from_pretrained(
23
  ddgs = DDGS(timeout=3)
24
 
25
  def search_web(query, max_results=2):
26
- """Perform web search using DuckDuckGo (FREE & UNLIMITED)"""
27
  try:
28
  results = ddgs.text(
29
  keywords=query,
@@ -44,8 +47,70 @@ def search_web(query, max_results=2):
44
  except Exception as e:
45
  return f"Search failed: {str(e)}"
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  def process_audio(audio_path, question_text=None):
48
- """Main pipeline: audio -> text -> search -> answer"""
49
  start_time = time.time()
50
 
51
  # Step 1: Transcribe audio if provided
@@ -68,52 +133,22 @@ def process_audio(audio_path, question_text=None):
68
  search_results = search_web(question, max_results=2)
69
  search_time = time.time() - search_start
70
 
71
- # Step 3: Generate answer with LLM
72
  llm_start = time.time()
73
-
74
- messages = [
75
- {"role": "system", "content": "You are a helpful assistant. Answer questions briefly using the provided context."},
76
- {"role": "user", "content": f"Context:\n{search_results}\n\nQuestion: {question}\n\nAnswer:"}
77
- ]
78
-
79
- try:
80
- text = tokenizer.apply_chat_template(
81
- messages,
82
- tokenize=False,
83
- add_generation_prompt=True
84
- )
85
-
86
- inputs = tokenizer([text], return_tensors="pt").to("cpu")
87
-
88
- with torch.no_grad():
89
- outputs = model.generate(
90
- **inputs,
91
- max_new_tokens=120,
92
- temperature=0.2,
93
- do_sample=True,
94
- top_p=0.85,
95
- pad_token_id=tokenizer.eos_token_id
96
- )
97
-
98
- response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)
99
- answer = response.strip()
100
-
101
- except Exception as e:
102
- answer = f"❌ LLM error: {str(e)}"
103
-
104
  llm_time = time.time() - llm_start
105
- total_time = time.time() - start_time
106
 
 
107
  time_emoji = "🟢" if total_time < 3.0 else "🟡" if total_time < 3.5 else "🔴"
108
  timing_info = f"\n\n{time_emoji} **Timing:** Trans={transcription_time:.2f}s | Search={search_time:.2f}s | LLM={llm_time:.2f}s | **Total={total_time:.2f}s**"
109
 
110
  return answer + timing_info, total_time
111
 
112
- # Create Gradio interface (same as before)
113
- with gr.Blocks(title="Fast Q&A - No Building Required!", theme=gr.themes.Soft()) as demo:
114
  gr.Markdown("""
115
  # ⚡ Ultra-Fast Political Q&A System
116
- **No wheel building** - Fast deployment with transformers!
117
 
118
  **Features:** Whisper-tiny + Qwen2.5-0.5B + DuckDuckGo (FREE unlimited search)
119
  """)
@@ -169,11 +204,72 @@ with gr.Blocks(title="Fast Q&A - No Building Required!", theme=gr.themes.Soft())
169
  inputs=text_input
170
  )
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  gr.Markdown("""
173
  ---
174
  🟢 = Under 3s | 🟡 = 3-3.5s | 🔴 = Over 3.5s
175
  """)
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  if __name__ == "__main__":
178
  demo.queue(max_size=5)
179
  demo.launch()
 
4
  from duckduckgo_search import DDGS
5
  import time
6
  import torch
7
+ import base64
8
+ import tempfile
9
+ import os
10
 
11
  # Initialize models
12
  print("Loading Whisper model...")
 
26
  ddgs = DDGS(timeout=3)
27
 
28
  def search_web(query, max_results=2):
29
+ """Perform web search using DuckDuckGo"""
30
  try:
31
  results = ddgs.text(
32
  keywords=query,
 
47
  except Exception as e:
48
  return f"Search failed: {str(e)}"
49
 
50
+ def transcribe_audio_base64(audio_base64):
51
+ """Transcribe audio from base64 string (for Pluely STT endpoint)"""
52
+ try:
53
+ # Decode base64 audio
54
+ audio_bytes = base64.b64decode(audio_base64)
55
+
56
+ # Save to temporary file
57
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_audio:
58
+ temp_audio.write(audio_bytes)
59
+ temp_path = temp_audio.name
60
+
61
+ # Transcribe
62
+ segments, _ = whisper_model.transcribe(temp_path, language="en", beam_size=1)
63
+ transcription = " ".join([seg.text for seg in segments])
64
+
65
+ # Cleanup
66
+ os.unlink(temp_path)
67
+
68
+ return {"text": transcription.strip()}
69
+
70
+ except Exception as e:
71
+ return {"error": f"Transcription failed: {str(e)}"}
72
+
73
+ def generate_answer(text_input):
74
+ """Generate answer from text input (for Pluely AI endpoint)"""
75
+ try:
76
+ if not text_input or text_input.strip() == "":
77
+ return "No input provided"
78
+
79
+ # Web search
80
+ search_results = search_web(text_input, max_results=2)
81
+
82
+ # Generate answer
83
+ messages = [
84
+ {"role": "system", "content": "You are a helpful assistant. Answer briefly using provided context. Keep responses under 40 words."},
85
+ {"role": "user", "content": f"Context:\n{search_results}\n\nQuestion: {text_input}\n\nAnswer:"}
86
+ ]
87
+
88
+ text = tokenizer.apply_chat_template(
89
+ messages,
90
+ tokenize=False,
91
+ add_generation_prompt=True
92
+ )
93
+
94
+ inputs = tokenizer([text], return_tensors="pt").to("cpu")
95
+
96
+ with torch.no_grad():
97
+ outputs = model.generate(
98
+ **inputs,
99
+ max_new_tokens=80,
100
+ temperature=0.2,
101
+ do_sample=True,
102
+ top_p=0.85,
103
+ pad_token_id=tokenizer.eos_token_id
104
+ )
105
+
106
+ response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)
107
+ return response.strip()
108
+
109
+ except Exception as e:
110
+ return f"Error: {str(e)}"
111
+
112
  def process_audio(audio_path, question_text=None):
113
+ """Main pipeline for Gradio UI"""
114
  start_time = time.time()
115
 
116
  # Step 1: Transcribe audio if provided
 
133
  search_results = search_web(question, max_results=2)
134
  search_time = time.time() - search_start
135
 
136
+ # Step 3: Generate answer
137
  llm_start = time.time()
138
+ answer = generate_answer(question)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  llm_time = time.time() - llm_start
 
140
 
141
+ total_time = time.time() - start_time
142
  time_emoji = "🟢" if total_time < 3.0 else "🟡" if total_time < 3.5 else "🔴"
143
  timing_info = f"\n\n{time_emoji} **Timing:** Trans={transcription_time:.2f}s | Search={search_time:.2f}s | LLM={llm_time:.2f}s | **Total={total_time:.2f}s**"
144
 
145
  return answer + timing_info, total_time
146
 
147
+ # Create Gradio interface with API endpoints
148
+ with gr.Blocks(title="Fast Q&A - Pluely Compatible", theme=gr.themes.Soft()) as demo:
149
  gr.Markdown("""
150
  # ⚡ Ultra-Fast Political Q&A System
151
+ **Pluely Compatible** - Direct STT and AI endpoints available!
152
 
153
  **Features:** Whisper-tiny + Qwen2.5-0.5B + DuckDuckGo (FREE unlimited search)
154
  """)
 
204
  inputs=text_input
205
  )
206
 
207
+ # Hidden API endpoints for Pluely
208
+ with gr.Tab("🔌 Pluely Integration"):
209
+ gr.Markdown("""
210
+ ## Dedicated Endpoints for Pluely
211
+
212
+ ### 1. STT Endpoint (Audio Transcription)
213
+ ```
214
+ curl -X POST https://archcoder-basic-app.hf.space/call/transcribe_stt \\
215
+ -H "Content-Type: application/json" \\
216
+ -d '{"data": ["BASE64_AUDIO_DATA"]}'
217
+ ```
218
+ **Returns:** `{"data": [{"text": "transcribed text"}]}`
219
+
220
+ ### 2. AI Endpoint (Text to Answer)
221
+ ```
222
+ curl -X POST https://archcoder-basic-app.hf.space/call/answer_ai \\
223
+ -H "Content-Type: application/json" \\
224
+ -d '{"data": ["Your question here"]}'
225
+ ```
226
+ **Returns:** `{"data": ["Answer text"]}`
227
+
228
+ ---
229
+
230
+ ## Pluely Configuration
231
+
232
+ ### Custom STT Provider:
233
+ **Curl Command:**
234
+ ```
235
+ curl --location 'https://archcoder-basic-app.hf.space/call/transcribe_stt' \\
236
+ --header 'Content-Type: application/json' \\
237
+ --data '{"data": ["{{AUDIO_BASE64}}"]}'
238
+ ```
239
+ **Response Content Path:** `data[0].text`
240
+
241
+ ### Custom AI Provider:
242
+ **Curl Command:**
243
+ ```
244
+ curl --location 'https://archcoder-basic-app.hf.space/call/answer_ai' \\
245
+ --header 'Content-Type: application/json' \\
246
+ --data '{"data": ["{{TEXT}}"]}'
247
+ ```
248
+ **Response Content Path:** `data[0]`
249
+ """)
250
+
251
  gr.Markdown("""
252
  ---
253
  🟢 = Under 3s | 🟡 = 3-3.5s | 🔴 = Over 3.5s
254
  """)
255
 
256
+ # Register API endpoints
257
+ demo.api_name = "pluely_integration"
258
+
259
+ # STT endpoint for Pluely
260
+ @demo.api(api_name="transcribe_stt")
261
+ def api_transcribe(audio_base64: str):
262
+ """API endpoint for audio transcription (Pluely STT)"""
263
+ result = transcribe_audio_base64(audio_base64)
264
+ return result
265
+
266
+ # AI endpoint for Pluely
267
+ @demo.api(api_name="answer_ai")
268
+ def api_answer(text: str):
269
+ """API endpoint for text-to-answer (Pluely AI)"""
270
+ answer = generate_answer(text)
271
+ return answer
272
+
273
  if __name__ == "__main__":
274
  demo.queue(max_size=5)
275
  demo.launch()