srilakshu012456 commited on
Commit
f06288d
·
verified ·
1 Parent(s): 0703877

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +44 -16
main.py CHANGED
@@ -43,6 +43,12 @@ GEMINI_URL = (
43
  )
44
  os.environ["POSTHOG_DISABLED"] = "true"
45
 
 
 
 
 
 
 
46
 
47
  def safe_str(e: Any) -> str:
48
  try:
@@ -535,9 +541,6 @@ def _build_clarifying_message() -> str:
535
  "or should I raise a ServiceNow ticket for you?")
536
 
537
 
538
-
539
-
540
-
541
  def _build_tracking_descriptions(issue_text: str, resolved_text: str) -> Tuple[str, str]:
542
  """
543
  ShortDescription must always be the original user query / process heading / error text.
@@ -547,7 +550,7 @@ def _build_tracking_descriptions(issue_text: str, resolved_text: str) -> Tuple[s
547
  resolved = (resolved_text or "").strip()
548
 
549
  # Strict: only the original issue/query goes into ShortDescription
550
- short_desc = issue[:100] # If empty, stays empty—frontend should provide last_issue
551
 
552
  # DetailedDescription documents both the original issue and the user's resolution confirmation
553
  long_desc = (
@@ -559,7 +562,6 @@ def _build_tracking_descriptions(issue_text: str, resolved_text: str) -> Tuple[s
559
  return short_desc, long_desc
560
 
561
 
562
-
563
  def _is_incident_intent(msg_norm: str) -> bool:
564
  intent_phrases = [
565
  "create ticket", "create a ticket", "raise ticket", "raise a ticket", "open ticket", "open a ticket",
@@ -662,7 +664,15 @@ async def chat_with_ai(input_data: ChatInput):
662
  is_llm_resolved = False
663
  if (not _has_negation_resolved(msg_norm)) and (_is_resolution_ack_heuristic(msg_norm) or is_llm_resolved):
664
  try:
665
- short_desc, long_desc = _build_tracking_descriptions(input_data.last_issue, input_data.user_message)
 
 
 
 
 
 
 
 
666
  result = create_incident(short_desc, long_desc)
667
  if isinstance(result, dict) and not result.get("error"):
668
  inc_number = result.get("number", "<unknown>")
@@ -902,6 +912,7 @@ async def chat_with_ai(input_data: ChatInput):
902
  next_step_applied = False
903
  next_step_info: Dict[str, Any] = {}
904
  context_preformatted = False
 
905
 
906
  if best_doc and detected_intent == "steps":
907
  # prefer exact section of the top hit; fallback to all steps
@@ -976,10 +987,8 @@ async def chat_with_ai(input_data: ChatInput):
976
  filt_info = {'mode': None, 'matched_count': None, 'all_sentences': None}
977
  context_found = True
978
 
979
-
980
-
981
  elif best_doc and detected_intent == "errors":
982
- # --- NEW: detect explicit "not resolved" phrases ---
983
  said_not_resolved = (
984
  _has_negation_resolved(msg_norm) or
985
  bool(re.search(
@@ -990,9 +999,9 @@ async def chat_with_ai(input_data: ChatInput):
990
  )
991
 
992
  if said_not_resolved:
993
- # Suppress the long error bullets reply; let the frontend card handle this flow.
994
  return {
995
- "bot_response": "\u00A0", # zero-width space → no visible bubble; no "No response text"
996
  "status": "OK",
997
  "context_found": False,
998
  "ask_resolved": False,
@@ -1005,19 +1014,17 @@ async def chat_with_ai(input_data: ChatInput):
1005
  "debug": {
1006
  "intent": "errors_not_resolved",
1007
  "best_doc": best_doc,
1008
- },
1009
  }
1010
 
1011
  # Build errors context
1012
  full_errors = get_best_errors_section_text(best_doc)
1013
- steps_override_applied = False
1014
  if full_errors:
1015
  ctx_err = _extract_errors_only(full_errors, max_lines=30)
1016
 
1017
  # If it's a permissions query, trim to permission lines
1018
  if is_perm_query:
1019
  context = _filter_permission_lines(ctx_err, max_lines=6)
1020
-
1021
  else:
1022
  # Treat domain-only messages (e.g., "putaway error") as specific queries
1023
  # so we filter errors to the most relevant lines instead of dumping entire heading.
@@ -1075,7 +1082,6 @@ async def chat_with_ai(input_data: ChatInput):
1075
  # Non-fatal; keep errors context
1076
  pass
1077
 
1078
-
1079
  elif best_doc and detected_intent == "prereqs":
1080
  full_prereqs = _find_prereq_section_text(best_doc)
1081
  if full_prereqs:
@@ -1159,6 +1165,28 @@ Return ONLY the rewritten guidance."""
1159
 
1160
  options = [{"type": "yesno", "title": "Share details or raise a ticket?"}] if status == "PARTIAL" else []
1161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1162
  return {
1163
  "bot_response": bot_text,
1164
  "status": status,
@@ -1282,7 +1310,7 @@ def _classify_resolution_llm(user_message: str) -> bool:
1282
  Return only 'true' or 'false'.
1283
  Message: {user_message}"""
1284
  headers = {"Content-Type": "application/json"}
1285
- payload = {"contents": [{"parts": [{"text": prompt}]}]}
1286
  try:
1287
  resp = requests.post(GEMINI_URL, headers=headers, json=payload, timeout=12, verify=GEMINI_SSL_VERIFY)
1288
  data = resp.json()
 
43
  )
44
  os.environ["POSTHOG_DISABLED"] = "true"
45
 
46
+ # ---------------------------------------------------------------------
47
+ # Minimal server-side cache to remember last issue text shown to user
48
+ # (Used when user says "issue resolved" but frontend doesn't send last_issue)
49
+ # ---------------------------------------------------------------------
50
+ LAST_ISSUE_HINT: str = ""
51
+
52
 
53
  def safe_str(e: Any) -> str:
54
  try:
 
541
  "or should I raise a ServiceNow ticket for you?")
542
 
543
 
 
 
 
544
  def _build_tracking_descriptions(issue_text: str, resolved_text: str) -> Tuple[str, str]:
545
  """
546
  ShortDescription must always be the original user query / process heading / error text.
 
550
  resolved = (resolved_text or "").strip()
551
 
552
  # Strict: only the original issue/query goes into ShortDescription
553
+ short_desc = issue[:100] # If empty, stays empty—backend now tries to fill from cache
554
 
555
  # DetailedDescription documents both the original issue and the user's resolution confirmation
556
  long_desc = (
 
562
  return short_desc, long_desc
563
 
564
 
 
565
  def _is_incident_intent(msg_norm: str) -> bool:
566
  intent_phrases = [
567
  "create ticket", "create a ticket", "raise ticket", "raise a ticket", "open ticket", "open a ticket",
 
664
  is_llm_resolved = False
665
  if (not _has_negation_resolved(msg_norm)) and (_is_resolution_ack_heuristic(msg_norm) or is_llm_resolved):
666
  try:
667
+ # Prefer server-side cached hint if frontend didn't pass last_issue
668
+ issue_hint = (input_data.last_issue or "").strip()
669
+ if not issue_hint:
670
+ try:
671
+ issue_hint = LAST_ISSUE_HINT.strip()
672
+ except Exception:
673
+ issue_hint = ""
674
+
675
+ short_desc, long_desc = _build_tracking_descriptions(issue_hint, input_data.user_message)
676
  result = create_incident(short_desc, long_desc)
677
  if isinstance(result, dict) and not result.get("error"):
678
  inc_number = result.get("number", "<unknown>")
 
912
  next_step_applied = False
913
  next_step_info: Dict[str, Any] = {}
914
  context_preformatted = False
915
+ steps_override_applied = False # for Gemini paraphrase gating
916
 
917
  if best_doc and detected_intent == "steps":
918
  # prefer exact section of the top hit; fallback to all steps
 
987
  filt_info = {'mode': None, 'matched_count': None, 'all_sentences': None}
988
  context_found = True
989
 
 
 
990
  elif best_doc and detected_intent == "errors":
991
+ # --- Detect explicit "not resolved" phrases ---
992
  said_not_resolved = (
993
  _has_negation_resolved(msg_norm) or
994
  bool(re.search(
 
999
  )
1000
 
1001
  if said_not_resolved:
1002
+ # Keep only the card; avoid duplicate text or dots in bubble.
1003
  return {
1004
+ "bot_response": "Select an option below.", # short, non-duplicated helper line
1005
  "status": "OK",
1006
  "context_found": False,
1007
  "ask_resolved": False,
 
1014
  "debug": {
1015
  "intent": "errors_not_resolved",
1016
  "best_doc": best_doc,
1017
+ },
1018
  }
1019
 
1020
  # Build errors context
1021
  full_errors = get_best_errors_section_text(best_doc)
 
1022
  if full_errors:
1023
  ctx_err = _extract_errors_only(full_errors, max_lines=30)
1024
 
1025
  # If it's a permissions query, trim to permission lines
1026
  if is_perm_query:
1027
  context = _filter_permission_lines(ctx_err, max_lines=6)
 
1028
  else:
1029
  # Treat domain-only messages (e.g., "putaway error") as specific queries
1030
  # so we filter errors to the most relevant lines instead of dumping entire heading.
 
1082
  # Non-fatal; keep errors context
1083
  pass
1084
 
 
1085
  elif best_doc and detected_intent == "prereqs":
1086
  full_prereqs = _find_prereq_section_text(best_doc)
1087
  if full_prereqs:
 
1165
 
1166
  options = [{"type": "yesno", "title": "Share details or raise a ticket?"}] if status == "PARTIAL" else []
1167
 
1168
+ # ----- Cache last issue hint (used if user later says "issue resolved thanks")
1169
+ try:
1170
+ global LAST_ISSUE_HINT
1171
+ if detected_intent == "steps":
1172
+ # Prefer section heading if present; else user's query
1173
+ section_heading = ((top_meta or {}).get("section") or "").strip()
1174
+ LAST_ISSUE_HINT = (section_heading or input_data.user_message or "").strip()[:100]
1175
+ elif detected_intent == "errors":
1176
+ shown_lines = [ln.strip() for ln in (bot_text or "").splitlines() if ln.strip()]
1177
+ top_error_line = ""
1178
+ for ln in shown_lines:
1179
+ if re.match(r"^\s*[\-\*\u2022]\s*", ln) or ":" in ln:
1180
+ top_error_line = ln
1181
+ break
1182
+ base = (input_data.user_message or "").strip()
1183
+ if top_error_line:
1184
+ LAST_ISSUE_HINT = f"{base} — {top_error_line}".strip()[:100]
1185
+ else:
1186
+ LAST_ISSUE_HINT = base[:100]
1187
+ except Exception:
1188
+ pass
1189
+
1190
  return {
1191
  "bot_response": bot_text,
1192
  "status": status,
 
1310
  Return only 'true' or 'false'.
1311
  Message: {user_message}"""
1312
  headers = {"Content-Type": "application/json"}
1313
+ payload = {"contents": [{"parts": [{"text": prompt}]}]} # noqa: E501
1314
  try:
1315
  resp = requests.post(GEMINI_URL, headers=headers, json=payload, timeout=12, verify=GEMINI_SSL_VERIFY)
1316
  data = resp.json()