Hamdy005 commited on
Commit
2badbec
·
1 Parent(s): ae88f17

feat: improve chatbot search quality, implement refusal filtering.

Browse files
Files changed (3) hide show
  1. rag/constants.py +4 -2
  2. rag/rag.py +22 -3
  3. rag/routes.py +11 -2
rag/constants.py CHANGED
@@ -7,8 +7,10 @@ WARMUP_INTERVAL_S = 300
7
  # Web search configuration — Wiki + DDG for topics, DDG only for PDF/URL materials.
8
  WIKI_TOP_K_RESULTS = 1
9
  WIKI_DOC_CONTENT_CHARS_MAX = 1200 # max chars from Wikipedia result
10
- DUCKDUCKGO_NUM_RESULTS = 3 # number of DDG snippet results returned per search
11
- DUCKDUCKGO_DOC_CONTENT_CHARS_MAX = 1200 # max chars kept from the combined DDG result block
 
 
12
 
13
  RAG_PROMPT_TEMPLATE_BASE = """\
14
  <role>
 
7
  # Web search configuration — Wiki + DDG for topics, DDG only for PDF/URL materials.
8
  WIKI_TOP_K_RESULTS = 1
9
  WIKI_DOC_CONTENT_CHARS_MAX = 1200 # max chars from Wikipedia result
10
+
11
+ # DuckDuckGO Search
12
+ DUCKDUCKGO_NUM_RESULTS = 5 # number of DDG snippet results returned per search
13
+ DUCKDUCKGO_DOC_CONTENT_CHARS_MAX = 3000 # max chars kept from the combined DDG result block
14
 
15
  RAG_PROMPT_TEMPLATE_BASE = """\
16
  <role>
rag/rag.py CHANGED
@@ -337,7 +337,10 @@ def rag_answer(
337
  context_parts.append(f"Wikipedia Results:\n{wiki_snippets}")
338
 
339
  # --- DuckDuckGo search: ALL material types (topics, PDFs, URLs) ---
340
- ddg_snippets = direct_ddg_search(query)
 
 
 
341
  if ddg_snippets:
342
  context_parts.append(f"Web Search Results (DuckDuckGo):\n{ddg_snippets}")
343
 
@@ -352,6 +355,18 @@ def rag_answer(
352
  subject=subject_title,
353
  )
354
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  try:
356
  # All queries now use the simple LLM call (no agent loop).
357
  # DDG results are pre-fetched and injected into context above.
@@ -368,7 +383,9 @@ def rag_answer(
368
  })
369
 
370
  answer = response.content
371
- memory.save_context({"input": query}, {"output": answer})
 
 
372
  return answer, memory
373
  except Exception as e:
374
  logger.warning(f"Groq API call failed or rate-limited: {e}. Falling back to google/gemma-4-31b-it immediately.")
@@ -385,7 +402,9 @@ def rag_answer(
385
  "agent_scratchpad": "",
386
  })
387
  answer = response.content
388
- memory.save_context({"input": query}, {"output": answer})
 
 
389
  return answer, memory
390
  except Exception as fallback_err:
391
  logger.error(f"Fallback LLM call also failed: {fallback_err}")
 
337
  context_parts.append(f"Wikipedia Results:\n{wiki_snippets}")
338
 
339
  # --- DuckDuckGo search: ALL material types (topics, PDFs, URLs) ---
340
+ # Enrich the search query with the subject title so follow-up / short
341
+ subject_title = mat.get("title") if mat and mat.get("title") else ""
342
+ ddg_query = f"{query} {subject_title}".strip() if subject_title else query
343
+ ddg_snippets = direct_ddg_search(ddg_query)
344
  if ddg_snippets:
345
  context_parts.append(f"Web Search Results (DuckDuckGo):\n{ddg_snippets}")
346
 
 
355
  subject=subject_title,
356
  )
357
 
358
+ # Safety/refusal responses must NOT be saved to memory, otherwise the
359
+ _REFUSAL_PREFIXES = (
360
+ "I can't respond on a gibberish",
361
+ "I can't respond on a NSFW",
362
+ "I can't respond on a political",
363
+ "I can't respond on a religious",
364
+ )
365
+
366
+ def _is_refusal(text: str) -> bool:
367
+ t = text.strip()
368
+ return any(t.startswith(p) for p in _REFUSAL_PREFIXES)
369
+
370
  try:
371
  # All queries now use the simple LLM call (no agent loop).
372
  # DDG results are pre-fetched and injected into context above.
 
383
  })
384
 
385
  answer = response.content
386
+ # Only persist non-refusal answers to memory
387
+ if not _is_refusal(answer):
388
+ memory.save_context({"input": query}, {"output": answer})
389
  return answer, memory
390
  except Exception as e:
391
  logger.warning(f"Groq API call failed or rate-limited: {e}. Falling back to google/gemma-4-31b-it immediately.")
 
402
  "agent_scratchpad": "",
403
  })
404
  answer = response.content
405
+ # Only persist non-refusal answers to memory
406
+ if not _is_refusal(answer):
407
+ memory.save_context({"input": query}, {"output": answer})
408
  return answer, memory
409
  except Exception as fallback_err:
410
  logger.error(f"Fallback LLM call also failed: {fallback_err}")
rag/routes.py CHANGED
@@ -94,8 +94,17 @@ async def ask_tutor(
94
  cleaned_answer = clean_summary(answer)
95
  elapsed = time.time() - start
96
 
97
- # Persist assistant response
98
- if body.session_id:
 
 
 
 
 
 
 
 
 
99
  try:
100
  append_session_message(body.session_id, "assistant", cleaned_answer)
101
  except Exception:
 
94
  cleaned_answer = clean_summary(answer)
95
  elapsed = time.time() - start
96
 
97
+ # Safety/refusal responses must not be saved to DB history either.
98
+ _REFUSAL_PREFIXES = (
99
+ "I can't respond on a gibberish",
100
+ "I can't respond on a NSFW",
101
+ "I can't respond on a political",
102
+ "I can't respond on a religious",
103
+ )
104
+ is_refusal = any(cleaned_answer.strip().startswith(p) for p in _REFUSAL_PREFIXES)
105
+
106
+ # Persist assistant response (only if not a refusal)
107
+ if body.session_id and not is_refusal:
108
  try:
109
  append_session_message(body.session_id, "assistant", cleaned_answer)
110
  except Exception: