Raiquia commited on
Commit
01c339e
·
1 Parent(s): b42c1aa

refine handling of unknown questions by improving user follow-up prompts and notification logic

Browse files
Files changed (1) hide show
  1. implementation/chat.py +67 -19
implementation/chat.py CHANGED
@@ -119,9 +119,9 @@ Keep replies concise.
119
 
120
  UNKNOWN_SYSTEM_PROMPT = """
121
  You are acting as Kharisma Rizki Wijanarko (Rizki)'s assistant.
122
- If you cannot answer confidently, say you don't know then ask the user to provide name and email so rizki can follow up directly.
123
- Then, use record_unknown_question to record the user's question and send the notification to rizki.
124
- Send the notification only if the user provided their user details.
125
  Keep replies concise.
126
  """
127
 
@@ -286,13 +286,47 @@ def record_unknown_question(question: str, user_details: str | None = None) -> s
286
  if user_details:
287
  entry["user_details"] = user_details
288
  _append_to_json(UNKNOWN_QUESTIONS_PATH, entry)
289
- # For unknown questions we want a Telegram ping so Rizki can follow up.
290
- # If we don't have user details, still send the question.
291
- details_line = f"User Details: {user_details}" if user_details else "User Details: (not provided)"
292
- send_telegram_notification(f"New Unknown Question: {question}\n{details_line}")
293
  return "Question recorded successfully."
294
 
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  def _extract_name_email(history: list[dict]) -> tuple[str | None, str | None]:
297
  """
298
  Best-effort extraction of user's name/email from conversation text.
@@ -503,6 +537,31 @@ def answer_question(question: str, history: list[dict] = []) -> tuple[str, list[
503
  Handles multi-turn tool calls in a loop until the model produces a final text response.
504
  """
505
  t0 = time.time()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  action = route_action(question, history)
507
  logger.info(f"[ROUTER] action={action!r}")
508
 
@@ -523,18 +582,7 @@ def answer_question(question: str, history: list[dict] = []) -> tuple[str, list[
523
  return answer, []
524
 
525
  if action == "unknown":
526
- name, email = _extract_name_email(history + [{"role": "user", "content": question}])
527
- user_details_parts = []
528
- if name:
529
- user_details_parts.append(f"Name: {name}")
530
- if email:
531
- user_details_parts.append(f"Email: {email}")
532
- user_details = "\n".join(user_details_parts) if user_details_parts else None
533
-
534
- # Deterministic: always record + notify so Rizki can follow up.
535
- record_unknown_question(question, user_details=user_details)
536
-
537
- # Respond to the user (no need for tools here).
538
  response = completion(
539
  model=MODEL,
540
  messages=[{"role": "system", "content": UNKNOWN_SYSTEM_PROMPT}] + history + [
 
119
 
120
  UNKNOWN_SYSTEM_PROMPT = """
121
  You are acting as Kharisma Rizki Wijanarko (Rizki)'s assistant.
122
+ If you cannot answer confidently, say you don't know.
123
+ Then ask the user to share their name and email so Rizki can follow up directly.
124
+ Do not claim you already notified Rizki until the user provides their details.
125
  Keep replies concise.
126
  """
127
 
 
286
  if user_details:
287
  entry["user_details"] = user_details
288
  _append_to_json(UNKNOWN_QUESTIONS_PATH, entry)
289
+ if user_details:
290
+ send_telegram_notification(f"New Unknown Question: {question}\nUser Details: {user_details}")
 
 
291
  return "Question recorded successfully."
292
 
293
 
294
+ def _looks_like_unknown_followup_request(history: list[dict]) -> bool:
295
+ """
296
+ Detect whether the assistant previously asked for name+email due to an unknown question.
297
+ We keep this heuristic intentionally simple and robust to minor prompt changes.
298
+ """
299
+ last_assistant = next((m for m in reversed(history) if m.get("role") == "assistant"), None)
300
+ if not last_assistant:
301
+ return False
302
+ text = str(last_assistant.get("content", "")).lower()
303
+ return (
304
+ ("i don't know" in text or "i do not know" in text)
305
+ and ("name" in text)
306
+ and ("email" in text)
307
+ and ("follow up" in text or "follow-up" in text or "follow up directly" in text)
308
+ )
309
+
310
+
311
+ def _find_previous_user_question_before_followup(history: list[dict]) -> str | None:
312
+ """
313
+ When the assistant asks for name/email after an unknown question, the unknown question is
314
+ typically the latest user message before that assistant response.
315
+ """
316
+ assistant_idx = None
317
+ for i in range(len(history) - 1, -1, -1):
318
+ if history[i].get("role") == "assistant":
319
+ assistant_idx = i
320
+ break
321
+ if assistant_idx is None:
322
+ return None
323
+ for j in range(assistant_idx - 1, -1, -1):
324
+ if history[j].get("role") == "user":
325
+ q = str(history[j].get("content", "")).strip()
326
+ return q or None
327
+ return None
328
+
329
+
330
  def _extract_name_email(history: list[dict]) -> tuple[str | None, str | None]:
331
  """
332
  Best-effort extraction of user's name/email from conversation text.
 
537
  Handles multi-turn tool calls in a loop until the model produces a final text response.
538
  """
539
  t0 = time.time()
540
+
541
+ # If we previously couldn't answer and asked for name/email, treat the next user message
542
+ # as the follow-up details and send Telegram once we have an email.
543
+ if _looks_like_unknown_followup_request(history):
544
+ prev_unknown_q = _find_previous_user_question_before_followup(history)
545
+ name, email = _extract_name_email(history + [{"role": "user", "content": question}])
546
+ if not email:
547
+ return (
548
+ "Thanks — could you share your email address as well? (And your name, if you haven’t already.)",
549
+ [],
550
+ )
551
+
552
+ details_lines = []
553
+ if name:
554
+ details_lines.append(f"Name: {name}")
555
+ details_lines.append(f"Email: {email}")
556
+ if question.strip():
557
+ details_lines.append(f"Follow-up: {question.strip()}")
558
+
559
+ record_unknown_question(prev_unknown_q or "(unknown question not found in history)", user_details="\n".join(details_lines))
560
+ return (
561
+ "Thanks — I’ve shared your details with Rizki so he can follow up.",
562
+ [],
563
+ )
564
+
565
  action = route_action(question, history)
566
  logger.info(f"[ROUTER] action={action!r}")
567
 
 
582
  return answer, []
583
 
584
  if action == "unknown":
585
+ # Respond to the user (ask for name + email so Rizki can follow up).
 
 
 
 
 
 
 
 
 
 
 
586
  response = completion(
587
  model=MODEL,
588
  messages=[{"role": "system", "content": UNKNOWN_SYSTEM_PROMPT}] + history + [