Futuresony commited on
Commit
56f8ae3
·
verified ·
1 Parent(s): 1a2f4c5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -55
app.py CHANGED
@@ -256,12 +256,14 @@ def perform_duckduckgo_search(query: str, max_results: int = 5): # Reduced max_r
256
  # Define the new semantic date/time detection and calculation function using dateparser
257
  def perform_date_calculation(query: str) -> str or None:
258
  """
259
- Analyzes query for date/time information using dateparser.
260
- If dateparser finds a date, it returns a human-friendly response string.
261
- Otherwise, it returns None.
262
- It is designed to handle multiple languages and provide the time for East Africa (Tanzania).
 
263
  """
264
  print(f"Executing Tool: perform_date_calculation with query='{query}') using dateparser.search_dates")
 
265
 
266
  try:
267
  eafrica_tz = pytz.timezone('Africa/Dar_es_Salaam')
@@ -270,35 +272,68 @@ def perform_date_calculation(query: str) -> str or None:
270
  print("Error: Unknown timezone 'Africa/Dar_es_Salaam'. Using default system time.")
271
  now = datetime.now()
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  try:
274
- # Try parsing with Swahili first, then English
275
  found = search_dates(
276
  query,
277
  settings={
278
  "PREFER_DATES_FROM": "future",
279
  "RELATIVE_BASE": now
280
  },
281
- languages=['sw', 'en'] # Prioritize Swahili
282
  )
283
 
284
  if not found:
285
- print("dateparser.search_dates could not parse any date/time.")
286
- return None
287
 
288
  text_snippet, parsed = found[0]
289
  print(f"dateparser.search_dates found: text='{text_snippet}', parsed='{parsed}'")
290
 
291
- is_swahili = any(swahili_phrase in query.lower() for swahili_phrase in ['tarehe', 'siku', 'saa', 'muda', 'leo', 'kesho', 'jana', 'ngapi', 'gani', 'mwezi', 'mwaka'])
292
 
293
- # Handle timezone information
294
  if now.tzinfo is not None and parsed.tzinfo is None:
295
  parsed = now.tzinfo.localize(parsed)
296
  elif now.tzinfo is None and parsed.tzinfo is not None:
297
  parsed = parsed.replace(tzinfo=None)
298
 
299
- # Check if the parsed date is today and time is close to now or midnight
300
  if parsed.date() == now.date():
301
- # Consider it "now" if within a small time window or if no specific time was parsed (midnight)
302
  if abs((parsed - now).total_seconds()) < 60 or parsed.time() == datetime.min.time():
303
  print("Query parsed to today's date and time is close to 'now' or midnight, returning current time/date.")
304
  if is_swahili:
@@ -336,43 +371,15 @@ def perform_date_calculation(query: str) -> str or None:
336
  def determine_tool_usage(query: str) -> str:
337
  """
338
  Analyzes the query to determine if a specific tool is needed.
339
- Returns the name of the tool ('duckduckgo_search', 'business_info_retrieval',
340
- 'date_calculation') or 'none' if no specific tool is clearly indicated.
341
- Prioritizes specific tools based on keywords and LLM judgment, then business info.
342
  """
343
  query_lower = query.lower()
344
 
345
- # 1. Check for Date Calculation first, as it's a specific function call
346
- date_time_check_result = perform_date_calculation(query)
347
- if date_time_check_result is not None:
348
- print(f"Detected as date/time calculation query based on dateparser result for: '{query}'")
349
- return "date_calculation"
350
-
351
- # 2. Use LLM to determine if DuckDuckGo search is needed
352
- messages_tool_determination_search = [{"role": "user", "content": f"Does the following query require searching the web for current or general knowledge information (e.g., news, facts, definitions, current events)? Respond ONLY with 'duckduckgo_search' or 'none'. Query: {query}"}]
353
- try:
354
- search_determination_response = client.chat_completion(
355
- messages=messages_tool_determination_search,
356
- max_tokens=20,
357
- temperature=0.1,
358
- top_p=0.9
359
- ).choices[0].message.content or ""
360
- response_lower = search_determination_response.strip().lower()
361
-
362
- if "duckduckgo_search" in response_lower:
363
- print(f"Model-determined tool for '{query}': 'duckduckgo_search'")
364
- return "duckduckgo_search"
365
- else:
366
- print(f"Model-determined tool for '{query}': 'none' (for search)")
367
-
368
- except Exception as e:
369
- print(f"Error during LLM call for search tool determination for query '{query}': {e}")
370
- print(traceback.format_exc())
371
- print(f"Proceeding without search tool check for query '{query}' due to error.")
372
-
373
-
374
- # 3. If neither date calculation nor DuckDuckGo search, check for Business Info Retrieval if RAG is available
375
  if business_info_available:
 
376
  messages_business_check = [{"role": "user", "content": f"Does the following query ask about a specific person, service, offering, or description that would likely be found in a business's knowledge base? Answer only 'yes' or 'no'. Query: {query}"}]
377
  try:
378
  business_check_response = client.chat_completion(
@@ -380,8 +387,7 @@ def determine_tool_usage(query: str) -> str:
380
  max_tokens=10,
381
  temperature=0.1
382
  ).choices[0].message.content.strip().lower()
383
- # Ensure the response explicitly contains "yes" and is not just a substring match
384
- if business_check_response == "yes":
385
  print(f"Detected as business info query based on LLM check: '{query}'")
386
  return "business_info_retrieval"
387
  else:
@@ -391,9 +397,40 @@ def determine_tool_usage(query: str) -> str:
391
  print(traceback.format_exc())
392
  print(f"Proceeding without business info check for query '{query}' due to error.")
393
 
394
- # 4. If none of the specific tools are determined, default to 'none'
395
- print(f"No specific tool determined for '{query}'. Defaulting to 'none'.")
396
- return "none"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
 
399
  # Function to generate text using the LLM, incorporating tool results if available
@@ -432,8 +469,7 @@ def generate_text(prompt: str, tool_results: dict = None) -> str:
432
  else:
433
  full_prompt_builder.append(f"{results}\n\n") # Handle single string results (like date calculation)
434
 
435
- full_prompt_builder.append("Based on the provided tool results, answer the user's original query. If a question was answered by a tool, use the tool's result directly in your response.")
436
- print("Added tool results and instruction to final prompt.")
437
  else:
438
  print("No tool results to add to final prompt.")
439
 
@@ -590,6 +626,5 @@ if __name__ == "__main__":
590
  iface.launch(debug=True)
591
  except Exception as e:
592
  print(f"Error launching Gradio interface: {e}")
593
- print(traceback. format_exc())
594
- print("Please check the console output for more details on the error.")
595
-
 
256
  # Define the new semantic date/time detection and calculation function using dateparser
257
  def perform_date_calculation(query: str) -> str or None:
258
  """
259
+ Analyzes query for explicit date/time calculation requests and performs the calculation.
260
+ Returns a human-friendly response string if a calculation is clearly requested,
261
+ otherwise returns None to indicate the LLM should handle the query.
262
+ Uses dateparser.search_dates but is more selective about returning a result.
263
+ It is also designed to handle multiple languages and provide the time for East Africa (Tanzania).
264
  """
265
  print(f"Executing Tool: perform_date_calculation with query='{query}') using dateparser.search_dates")
266
+ query_lower = query.lower()
267
 
268
  try:
269
  eafrica_tz = pytz.timezone('Africa/Dar_es_Salaam')
 
272
  print("Error: Unknown timezone 'Africa/Dar_es_Salaam'. Using default system time.")
273
  now = datetime.now()
274
 
275
+ calculation_phrases = [
276
+ r"\b(what is|what'?s|tell me|do you know|can you tell me)?\s*the\s*date\s+(of|for)?\s*(today|today'?s)?\b", # "what is today's date" (English)
277
+ r'\b(\d+)\s+(days?|weeks?|months?|years?)\s+(ago|from now)\b', # "3 days ago", "2 weeks from now" (English)
278
+ r'\bwhat day is it\b', # "what day is it" (English)
279
+ r'\bwhat is the time\b', # "what is the time" (English)
280
+ r'\bwhen is\s+', # "when is..." (English)
281
+ r'\bon\s+what\s+date\s+did\s+', # "on what date did..." (English)
282
+ r'\btarehe\s+ya\s+leo\b', # "date of today" (Swahili)
283
+ r'\bsaa\s+ngapi\b', # "what time" (Swahili)
284
+ r'\bmuda\s+gani\b', # "what time" (Swahili)
285
+ r'\btarehe\s+gani\b', # "what date" (Swahili)
286
+ r'\bni\s+saa\s+ngapi\b', # "it is what time" (Swahili)
287
+ r'\bni\s+tarehe\s+gani\b', # "it is what date" (Swahili)
288
+ r'\btarehe\s+ya\s+kesho\b', # "date of tomorrow" (Swahili)
289
+ r'\btarehe\s+ya\s+jana\b', # "date of yesterday" (Swahili)
290
+ r'\bsiku\s+ya\s+leo\b', # "day of today" (Swahili)
291
+ r'\bsiku\s+gani\b', # "what day" (Swahili)
292
+ r'\bmwezi\s+gani\b', # "what month" (Swahili)
293
+ r'\b(mwaka|mwaka\s+gani)\b', # "year" or "what year" (Swahili)
294
+ r'\bsaa\s+za\s+sasa\b', # "current time" (Swahili)
295
+ r'\btarehe\s+ngapi\s+leo\b', # "date how much today" (Swahili - common phrasing)
296
+ r'\bni\s+tarehe\s+ngapi\s+leo\b', # "it is date how much today" (Swahili - common phrasing)
297
+ r'\bsiku\s+ngapi\s+leo\b', # "day how much today" (Swahili - common phrasing)
298
+ r'\bni\s+siku\s+ngapi\s+leo\b', # "it is day how much today" (Swahili - common phrasing)
299
+ r'\b(leo|leo\s+hii)\b.*?\b(tarehe|siku|saa|muda)\b', # "today" followed by date/day/time (Swahili)
300
+ ]
301
+
302
+ is_calculation_query = False
303
+ for phrase in calculation_phrases:
304
+ if re.search(phrase, query_lower):
305
+ is_calculation_query = True
306
+ break
307
+
308
+ if not is_calculation_query:
309
+ print("Query does not contain explicit date/time calculation phrases. Returning None.")
310
+ return None
311
+
312
  try:
 
313
  found = search_dates(
314
  query,
315
  settings={
316
  "PREFER_DATES_FROM": "future",
317
  "RELATIVE_BASE": now
318
  },
319
+ languages=['en', 'sw']
320
  )
321
 
322
  if not found:
323
+ print("Explicit date/time phrase found, but dateparser.search_dates could not parse it.")
324
+ return "Sorry, I couldn’t understand that date/time. Could you rephrase?"
325
 
326
  text_snippet, parsed = found[0]
327
  print(f"dateparser.search_dates found: text='{text_snippet}', parsed='{parsed}'")
328
 
329
+ is_swahili = any(swahili_phrase in query_lower for swahili_phrase in ['tarehe', 'siku', 'saa', 'muda', 'leo', 'kesho', 'jana', 'ngapi', 'gani', 'mwezi', 'mwaka'])
330
 
 
331
  if now.tzinfo is not None and parsed.tzinfo is None:
332
  parsed = now.tzinfo.localize(parsed)
333
  elif now.tzinfo is None and parsed.tzinfo is not None:
334
  parsed = parsed.replace(tzinfo=None)
335
 
 
336
  if parsed.date() == now.date():
 
337
  if abs((parsed - now).total_seconds()) < 60 or parsed.time() == datetime.min.time():
338
  print("Query parsed to today's date and time is close to 'now' or midnight, returning current time/date.")
339
  if is_swahili:
 
371
  def determine_tool_usage(query: str) -> str:
372
  """
373
  Analyzes the query to determine if a specific tool is needed.
374
+ Returns the name of the tool ('duckduckgo_search', 'business_info_retrieval')
375
+ or 'none' if no specific tool is clearly indicated or if it's a date/time query
376
+ (as date/time is handled by semantic detection first).
377
  """
378
  query_lower = query.lower()
379
 
380
+ # 1. Prioritize Business Info Retrieval if RAG is available
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  if business_info_available:
382
+ # Use a more direct prompt to encourage "yes" for relevant queries
383
  messages_business_check = [{"role": "user", "content": f"Does the following query ask about a specific person, service, offering, or description that would likely be found in a business's knowledge base? Answer only 'yes' or 'no'. Query: {query}"}]
384
  try:
385
  business_check_response = client.chat_completion(
 
387
  max_tokens=10,
388
  temperature=0.1
389
  ).choices[0].message.content.strip().lower()
390
+ if "yes" in business_check_response:
 
391
  print(f"Detected as business info query based on LLM check: '{query}'")
392
  return "business_info_retrieval"
393
  else:
 
397
  print(traceback.format_exc())
398
  print(f"Proceeding without business info check for query '{query}' due to error.")
399
 
400
+ # 2. If not a business info query, check for date calculation
401
+ date_time_check_result = perform_date_calculation(query)
402
+ if date_time_check_result is not None and "Sorry, I couldn’t understand" not in date_time_check_result:
403
+ print(f"Detected as date/time calculation query: '{query}'")
404
+ return "date_calculation"
405
+
406
+ # 3. If neither business info nor date calculation, use LLM for other tool determination (DuckDuckGo or none)
407
+ messages_tool_determination = [{"role": "user", "content": f"Determine the most suitable tool for the following query from the options: 'duckduckgo_search', or 'none'. Respond ONLY with the tool name. Query: {query}"}]
408
+ try:
409
+ initial_response = client.chat_completion(
410
+ messages=messages_tool_determination,
411
+ max_tokens=20,
412
+ temperature=0.1,
413
+ top_p=0.9
414
+ ).choices[0].message.content or ""
415
+ response_lower = initial_response.strip().lower()
416
+
417
+ if "duckduckgo_search" in response_lower:
418
+ determined_tool = "duckduckgo_search"
419
+ elif "none" in response_lower:
420
+ # Allow the LLM to answer simple questions like "who are you" internally
421
+ # without a tool if it determines 'none'.
422
+ determined_tool = "none"
423
+ else:
424
+ print(f"Warning: LLM returned unexpected tool determination '{initial_response.strip()}'. Defaulting to 'none'.")
425
+ determined_tool = "none"
426
+ print(f"Model-determined tool: {determined_tool}")
427
+ return determined_tool
428
+
429
+ except Exception as e:
430
+ print(f"Error during LLM call for tool determination for query '{query}': {e}")
431
+ print(traceback.format_exc())
432
+ print(f"Defaulting to 'none' tool due to error for query '{query}'.")
433
+ return "none"
434
 
435
 
436
  # Function to generate text using the LLM, incorporating tool results if available
 
469
  else:
470
  full_prompt_builder.append(f"{results}\n\n") # Handle single string results (like date calculation)
471
 
472
+ print("Added tool results to final prompt.")
 
473
  else:
474
  print("No tool results to add to final prompt.")
475
 
 
626
  iface.launch(debug=True)
627
  except Exception as e:
628
  print(f"Error launching Gradio interface: {e}")
629
+ print(traceback. обзоr)
630
+ print("Please check the console output for more details on the error.")