Vibow commited on
Commit
99fb14e
ยท
verified ยท
1 Parent(s): 0366958

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -84
app.py CHANGED
@@ -90,15 +90,13 @@ def serpapi_search(query: str, location=None, num_results=3):
90
 
91
  # Set location and language based on query
92
  if is_indonesian_query:
93
- country = "id" # Indonesia
94
  lang = "id"
95
  search_location = location or "Indonesia"
96
- print(f"[SEARCH] ๐Ÿ‡ฎ๐Ÿ‡ฉ Indonesian query detected - Using ID region")
97
  else:
98
- country = "us" # Global (US default)
99
  lang = "en"
100
  search_location = location or ""
101
- print(f"[SEARCH] ๐ŸŒ Global query - Using worldwide search")
102
 
103
  url = "https://serpapi.com/search.json"
104
  params = {
@@ -115,25 +113,20 @@ def serpapi_search(query: str, location=None, num_results=3):
115
  images = []
116
 
117
  try:
118
- # Get text results
119
- print("[SEARCH] ๐Ÿ“„ Fetching text results...")
120
  r = requests.get(url, params=params, timeout=10)
121
  r.raise_for_status()
122
  data = r.json()
123
 
124
  if "organic_results" in data:
125
- print(f"[SEARCH] ๐Ÿ“„ Found {len(data['organic_results'])} organic results")
126
  for item in data["organic_results"][:num_results]:
127
  results.append({
128
  "title": item.get("title", ""),
129
  "snippet": item.get("snippet", ""),
130
  "link": item.get("link", "")
131
  })
132
- print(f"[SEARCH] - {item.get('title', 'No title')[:60]}")
133
- else:
134
- print("[SEARCH] โš ๏ธ No organic results found")
135
 
136
- # Get images - separate request for better results
137
  img_params = {
138
  "q": query,
139
  "engine": "google_images",
@@ -142,27 +135,23 @@ def serpapi_search(query: str, location=None, num_results=3):
142
  "gl": country,
143
  "hl": lang
144
  }
145
-
146
- print("[SEARCH] ๐Ÿ–ผ๏ธ Fetching images...")
147
  img_r = requests.get(url, params=img_params, timeout=10)
148
  img_r.raise_for_status()
149
  img_data = img_r.json()
150
-
151
  if "images_results" in img_data:
152
- print(f"[SEARCH] ๐Ÿ–ผ๏ธ Found {len(img_data['images_results'])} images")
153
  for img in img_data["images_results"][:3]:
154
  img_url = img.get("original", img.get("thumbnail", ""))
155
  if img_url:
156
  images.append(img_url)
157
- print(f"[SEARCH] - Image: {img_url[:60]}...")
158
- else:
159
- print("[SEARCH] โš ๏ธ No images found in image search")
160
 
161
- print(f"[SEARCH] โœ… Total: {len(results)} results, {len(images)} images\n")
 
 
 
162
  return {"results": results, "images": images}
163
 
164
  except Exception as e:
165
- print(f"[SEARCH] โŒ Error: {e}\n")
166
  return {"results": [], "images": []}
167
 
168
  # =========================
@@ -172,14 +161,11 @@ def stream_chat(prompt: str, history=None):
172
  wib = timezone(timedelta(hours=7))
173
  now = datetime.now(wib)
174
  sys_prompt = SYSTEM_PROMPT + f"\nCurrent time: {now.strftime('%A, %d %B %Y โ€” %H:%M:%S WIB')}."
175
-
176
  messages = [{"role": "system", "content": sys_prompt}]
177
  if history:
178
  messages += history
179
  messages.append({"role": "user", "content": prompt})
180
 
181
- print(f"[CHAT] ๐Ÿ’ฌ Sending request to LLM (history: {len(history) if history else 0} msgs)")
182
-
183
  payload = {
184
  "model": "moonshotai/kimi-k2-instruct-0905",
185
  "messages": messages,
@@ -187,25 +173,23 @@ def stream_chat(prompt: str, history=None):
187
  "max_tokens": 3600,
188
  "stream": True,
189
  }
190
-
191
  headers = {"Authorization": f"Bearer {GROQ_API_KEY_1}"}
192
 
193
- with requests.post(GROQ_URL_CHAT, headers=headers, json=payload, stream=True) as r:
194
- for line in r.iter_lines():
195
- if not line:
 
 
 
 
 
 
 
 
 
 
 
196
  continue
197
- line = line.decode()
198
- if line.startswith("data: "):
199
- data = line[6:]
200
- if data == "[DONE]":
201
- print("[CHAT] โœ… Stream completed")
202
- break
203
- try:
204
- delta = json.loads(data)["choices"][0]["delta"].get("content", "")
205
- if delta:
206
- yield delta
207
- except:
208
- continue
209
 
210
  # =========================
211
  # ๐Ÿš€ Chat Endpoint (Text + Voice)
@@ -215,89 +199,52 @@ def chat():
215
  print("\n" + "="*60)
216
  print(f"[REQUEST] ๐Ÿ“จ New request at {datetime.now().strftime('%H:%M:%S')}")
217
 
218
- # ๐ŸŽค Voice Mode
219
  if "audio" in request.files:
220
- print("[MODE] ๐ŸŽค Voice mode detected")
221
  audio = request.files["audio"]
222
  temp = f"/tmp/{time.time()}_{random.randint(1000,9999)}.wav"
223
  audio.save(temp)
224
- print(f"[AUDIO] ๐Ÿ’พ Saved to: {temp}")
225
-
226
  user_text = transcribe_audio(temp)
227
- if not user_text:
228
- print("[ERROR] โŒ STT failed")
229
- return jsonify({"error": "Failed STT"}), 500
230
-
231
- print(f"[USER] ๐Ÿ‘ค Transcribed: '{user_text}'")
232
 
233
  keywords = ["hotel", "mall", "resort", "villa", "tempat wisata", "restaurant", "cafe"]
234
  has_keyword = any(k in user_text.lower() for k in keywords)
235
-
236
  if has_keyword:
237
- print(f"[KEYWORD] โœ… Detected keyword in: '{user_text}'")
238
  serp = serpapi_search(user_text)
239
-
240
- if serp["images"]:
241
- print(f"[IMAGES] ๐Ÿ–ผ๏ธ Adding {len(serp['images'])} images to prompt")
242
- else:
243
- print("[IMAGES] โš ๏ธ No images to add")
244
-
245
  text = "\n".join([f"{r['title']} โ€” {r['snippet']} โ€” {r['link']}" for r in serp["results"]])
246
  imgs = " ".join(serp["images"])
247
  user_text = f"{user_text}\n\nGoogle Results:\n{text}\n\nImages: {imgs}\n\nExplain & recommend."
248
- print(f"[PROMPT] ๐Ÿ“ Enhanced prompt length: {len(user_text)} chars")
249
- else:
250
- print(f"[KEYWORD] โŒ No keyword detected in: '{user_text}'")
251
 
252
- print("[AI] ๐Ÿค– Generating response...")
253
  ai = "".join(chunk for chunk in stream_chat(user_text))
254
- print(f"[AI] โœ… Response generated ({len(ai)} chars)")
255
-
256
- print("[TTS] ๐Ÿ”Š Converting to audio...")
257
  audio_bytes = text_to_speech(ai)
258
 
259
- print("="*60 + "\n")
260
- return jsonify({
261
  "mode": "voice",
262
  "transcript": user_text,
263
  "reply_text": ai,
264
  "audio_base64": "data:audio/mp3;base64," + base64.b64encode(audio_bytes).decode()
265
- })
 
 
 
 
266
 
267
  # ๐Ÿ’ฌ Text Mode
268
- print("[MODE] ๐Ÿ’ฌ Text mode detected")
269
  data = request.get_json(force=True)
270
  prompt = data.get("prompt", "")
271
  history = data.get("history", [])
272
-
273
- print(f"[USER] ๐Ÿ‘ค Prompt: '{prompt}'")
274
- print(f"[HISTORY] ๐Ÿ“š History length: {len(history)} messages")
275
 
276
  keywords = ["hotel", "mall", "resort", "villa", "tempat wisata", "restaurant", "cafe"]
277
  has_keyword = any(k in prompt.lower() for k in keywords)
278
-
279
  if has_keyword:
280
- print(f"[KEYWORD] โœ… Detected keyword in: '{prompt}'")
281
  serp = serpapi_search(prompt)
282
-
283
- if serp["images"]:
284
- print(f"[IMAGES] ๐Ÿ–ผ๏ธ Adding {len(serp['images'])} images to prompt")
285
- else:
286
- print("[IMAGES] โš ๏ธ No images to add")
287
-
288
  text = "\n".join([f"{r['title']} โ€” {r['snippet']} โ€” {r['link']}" for r in serp["results"]])
289
  imgs = " ".join(serp["images"])
290
  prompt = f"{prompt}\n\nGoogle Results:\n{text}\n\nImages: {imgs}\n\nExplain & recommend."
291
- print(f"[PROMPT] ๐Ÿ“ Enhanced prompt length: {len(prompt)} chars")
292
- else:
293
- print(f"[KEYWORD] โŒ No keyword detected in: '{prompt}'")
294
-
295
- print("[AI] ๐Ÿค– Streaming response...")
296
 
297
  def generate():
298
  for chunk in stream_chat(prompt, history):
299
  yield chunk
300
- print("="*60 + "\n")
301
 
302
  return Response(generate(), mimetype="text/plain")
303
 
 
90
 
91
  # Set location and language based on query
92
  if is_indonesian_query:
93
+ country = "id"
94
  lang = "id"
95
  search_location = location or "Indonesia"
 
96
  else:
97
+ country = "us"
98
  lang = "en"
99
  search_location = location or ""
 
100
 
101
  url = "https://serpapi.com/search.json"
102
  params = {
 
113
  images = []
114
 
115
  try:
116
+ # Text results
 
117
  r = requests.get(url, params=params, timeout=10)
118
  r.raise_for_status()
119
  data = r.json()
120
 
121
  if "organic_results" in data:
 
122
  for item in data["organic_results"][:num_results]:
123
  results.append({
124
  "title": item.get("title", ""),
125
  "snippet": item.get("snippet", ""),
126
  "link": item.get("link", "")
127
  })
 
 
 
128
 
129
+ # Images search
130
  img_params = {
131
  "q": query,
132
  "engine": "google_images",
 
135
  "gl": country,
136
  "hl": lang
137
  }
 
 
138
  img_r = requests.get(url, params=img_params, timeout=10)
139
  img_r.raise_for_status()
140
  img_data = img_r.json()
 
141
  if "images_results" in img_data:
 
142
  for img in img_data["images_results"][:3]:
143
  img_url = img.get("original", img.get("thumbnail", ""))
144
  if img_url:
145
  images.append(img_url)
 
 
 
146
 
147
+ # Debug JSON
148
+ print("[DEBUG] ๐Ÿ”น SerpAPI JSON output:")
149
+ print(json.dumps({"results": results, "images": images}, indent=2))
150
+
151
  return {"results": results, "images": images}
152
 
153
  except Exception as e:
154
+ print(f"[SEARCH] โŒ Error: {e}")
155
  return {"results": [], "images": []}
156
 
157
  # =========================
 
161
  wib = timezone(timedelta(hours=7))
162
  now = datetime.now(wib)
163
  sys_prompt = SYSTEM_PROMPT + f"\nCurrent time: {now.strftime('%A, %d %B %Y โ€” %H:%M:%S WIB')}."
 
164
  messages = [{"role": "system", "content": sys_prompt}]
165
  if history:
166
  messages += history
167
  messages.append({"role": "user", "content": prompt})
168
 
 
 
169
  payload = {
170
  "model": "moonshotai/kimi-k2-instruct-0905",
171
  "messages": messages,
 
173
  "max_tokens": 3600,
174
  "stream": True,
175
  }
 
176
  headers = {"Authorization": f"Bearer {GROQ_API_KEY_1}"}
177
 
178
+ for line in requests.post(GROQ_URL_CHAT, headers=headers, json=payload, stream=True).iter_lines():
179
+ if not line:
180
+ continue
181
+ line = line.decode()
182
+ if line.startswith("data: "):
183
+ data = line[6:]
184
+ if data == "[DONE]":
185
+ break
186
+ try:
187
+ delta = json.loads(data)["choices"][0]["delta"].get("content", "")
188
+ if delta:
189
+ print("[DEBUG] ๐Ÿ”น AI chunk:", delta)
190
+ yield delta
191
+ except:
192
  continue
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  # =========================
195
  # ๐Ÿš€ Chat Endpoint (Text + Voice)
 
199
  print("\n" + "="*60)
200
  print(f"[REQUEST] ๐Ÿ“จ New request at {datetime.now().strftime('%H:%M:%S')}")
201
 
 
202
  if "audio" in request.files:
203
+ # ๐ŸŽค Voice Mode
204
  audio = request.files["audio"]
205
  temp = f"/tmp/{time.time()}_{random.randint(1000,9999)}.wav"
206
  audio.save(temp)
 
 
207
  user_text = transcribe_audio(temp)
 
 
 
 
 
208
 
209
  keywords = ["hotel", "mall", "resort", "villa", "tempat wisata", "restaurant", "cafe"]
210
  has_keyword = any(k in user_text.lower() for k in keywords)
 
211
  if has_keyword:
 
212
  serp = serpapi_search(user_text)
 
 
 
 
 
 
213
  text = "\n".join([f"{r['title']} โ€” {r['snippet']} โ€” {r['link']}" for r in serp["results"]])
214
  imgs = " ".join(serp["images"])
215
  user_text = f"{user_text}\n\nGoogle Results:\n{text}\n\nImages: {imgs}\n\nExplain & recommend."
 
 
 
216
 
 
217
  ai = "".join(chunk for chunk in stream_chat(user_text))
 
 
 
218
  audio_bytes = text_to_speech(ai)
219
 
220
+ # Debug final JSON
221
+ debug_json = {
222
  "mode": "voice",
223
  "transcript": user_text,
224
  "reply_text": ai,
225
  "audio_base64": "data:audio/mp3;base64," + base64.b64encode(audio_bytes).decode()
226
+ }
227
+ print("[DEBUG] ๐Ÿ”น Final JSON to frontend:")
228
+ print(json.dumps(debug_json, indent=2))
229
+
230
+ return jsonify(debug_json)
231
 
232
  # ๐Ÿ’ฌ Text Mode
 
233
  data = request.get_json(force=True)
234
  prompt = data.get("prompt", "")
235
  history = data.get("history", [])
 
 
 
236
 
237
  keywords = ["hotel", "mall", "resort", "villa", "tempat wisata", "restaurant", "cafe"]
238
  has_keyword = any(k in prompt.lower() for k in keywords)
 
239
  if has_keyword:
 
240
  serp = serpapi_search(prompt)
 
 
 
 
 
 
241
  text = "\n".join([f"{r['title']} โ€” {r['snippet']} โ€” {r['link']}" for r in serp["results"]])
242
  imgs = " ".join(serp["images"])
243
  prompt = f"{prompt}\n\nGoogle Results:\n{text}\n\nImages: {imgs}\n\nExplain & recommend."
 
 
 
 
 
244
 
245
  def generate():
246
  for chunk in stream_chat(prompt, history):
247
  yield chunk
 
248
 
249
  return Response(generate(), mimetype="text/plain")
250