srilakshu012456 commited on
Commit
2592788
·
verified ·
1 Parent(s): 7c52deb

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +18 -26
main.py CHANGED
@@ -97,7 +97,10 @@ def _normalize_lines(text: str) -> List[str]:
97
  return [ln.strip() for ln in (text or "").splitlines() if ln.strip()]
98
 
99
  def _ensure_numbering(text: str) -> str:
100
- lines = _normalize_lines(text)
 
 
 
101
  if not lines:
102
  return text or ""
103
  normalized = []
@@ -108,7 +111,7 @@ def _ensure_numbering(text: str) -> str:
108
  parts = [p.strip() for p in re.split(r"\.\s+(?=[A-Z0-9])", normalized[0]) if p.strip()]
109
  if len(parts) > 1:
110
  normalized = parts
111
- return "\n".join([f"{i+1}. {ln}" for i, ln in enumerate(normalized)]).strip()
112
 
113
  def _friendly_permission_reply(raw: str) -> str:
114
  line = (raw or "").strip()
@@ -123,10 +126,9 @@ def _friendly_permission_reply(raw: str) -> str:
123
 
124
  # ---------------- Language detection (Tamil/Hindi mirror) ----------------
125
  def _detect_language_hint(msg: str) -> Optional[str]:
126
- # Tamil range: \u0B80-\u0BFF ; Devanagari (Hindi): \u0900-\u097F
127
- if re.search(r"[\u0B80-\u0BFF]", msg or ""):
128
  return "Tamil"
129
- if re.search(r"[\u0900-\u097F]", msg or ""):
130
  return "Hindi"
131
  return None
132
 
@@ -474,10 +476,8 @@ async def chat_with_ai(input_data: ChatInput):
474
  score = distances[i] if i < len(distances) else None
475
  comb = combined[i] if i < len(combined) else None
476
  m = dict(meta)
477
- if score is not None:
478
- m["distance"] = score
479
- if comb is not None:
480
- m["combined"] = comb
481
  items.append({"text": text, "meta": m})
482
  selected = items[:max(1, 2)]
483
  context_raw = "\n\n---\n\n".join([s["text"] for s in selected]) if selected else ""
@@ -487,7 +487,6 @@ async def chat_with_ai(input_data: ChatInput):
487
  best_distance = min([d for d in distances if d is not None], default=None) if distances else None
488
  best_combined = max([c for c in combined if c is not None], default=None) if combined else None
489
  detected_intent = kb_results.get("user_intent", "neutral")
490
- actions = kb_results.get("actions", [])
491
  best_doc = kb_results.get("best_doc")
492
  top_meta = (metadatas or [{}])[0] if metadatas else {}
493
 
@@ -502,15 +501,13 @@ async def chat_with_ai(input_data: ChatInput):
502
  full_steps = get_best_steps_section_text(best_doc)
503
  if not full_steps:
504
  sec = (top_meta or {}).get("section")
505
- if sec:
506
- full_steps = get_section_text(best_doc, sec)
507
  if full_steps:
508
  context = _ensure_numbering(full_steps)
509
  elif detected_intent == "errors":
510
  full_errors = get_best_errors_section_text(best_doc)
511
  if full_errors:
512
  context = _extract_errors_only(full_errors, max_lines=12)
513
- # user-friendly sentence if it's only one line
514
  lines = _normalize_lines(context)
515
  if len(lines) == 1:
516
  context = _friendly_permission_reply(lines[0])
@@ -536,7 +533,7 @@ async def chat_with_ai(input_data: ChatInput):
536
  lang_line = f"Respond in {language_hint}." if language_hint else "Respond in a clear, polite tone."
537
  enhanced_prompt = f"""You are a helpful support assistant. Rewrite the provided context ONLY into clear, user-friendly guidance.
538
  - Do not add any information that is not present in the context.
539
- - If the content describes a procedure or steps, format as a strictly numbered list: 1., 2., 3., ...
540
  - If the content is an error/access/permission note, paraphrase it into a helpful sentence users can understand.
541
  - {lang_line}
542
 
@@ -565,8 +562,8 @@ Return ONLY the rewritten guidance."""
565
  bot_text = ""
566
  http_code = getattr(resp, "status_code", 0)
567
 
 
568
  if not bot_text.strip() or http_code == 429:
569
- # Fallback to local formatting
570
  if detected_intent == "steps":
571
  bot_text = _ensure_numbering(context)
572
  elif detected_intent == "errors":
@@ -575,11 +572,11 @@ Return ONLY the rewritten guidance."""
575
  else:
576
  bot_text = context
577
 
578
- # force numbering for steps
579
  if detected_intent == "steps":
580
  bot_text = _ensure_numbering(bot_text)
581
 
582
- # status compute
583
  short_query = len((input_data.user_message or "").split()) <= 4
584
  gate_combined_ok = 0.60 if short_query else 0.55
585
  status = "OK" if (best_combined is not None and best_combined >= gate_combined_ok) else "PARTIAL"
@@ -588,7 +585,6 @@ Return ONLY the rewritten guidance."""
588
  if ("partial" in lower) or ("may be partial" in lower) or ("closest" in lower) or ("may not fully" in lower):
589
  status = "PARTIAL"
590
 
591
- # For PARTIAL: show Yes/No card
592
  options = [{"type":"yesno","title":"Share details or raise a ticket?"}] if status == "PARTIAL" else []
593
 
594
  return {
@@ -644,8 +640,7 @@ def _set_incident_resolved(sys_id: str) -> bool:
644
  except Exception as e:
645
  print(f"[SN PATCH progress] exception={safe_str(e)}")
646
 
647
- def clean(d: dict) -> dict:
648
- return {k: v for k, v in d.items() if v is not None}
649
 
650
  payload_A = clean({
651
  "state": "6",
@@ -658,8 +653,7 @@ def _set_incident_resolved(sys_id: str) -> bool:
658
  "assignment_group": assign_group,
659
  })
660
  respA = requests.patch(url, headers=headers, json=payload_A, verify=VERIFY_SSL, timeout=25)
661
- if respA.status_code in (200, 204):
662
- return True
663
  print(f"[SN PATCH resolve A] status={respA.status_code} body={respA.text[:500]}")
664
 
665
  payload_B = clean({
@@ -673,8 +667,7 @@ def _set_incident_resolved(sys_id: str) -> bool:
673
  "assignment_group": assign_group,
674
  })
675
  respB = requests.patch(url, headers=headers, json=payload_B, verify=VERIFY_SSL, timeout=25)
676
- if respB.status_code in (200, 204):
677
- return True
678
  print(f"[SN PATCH resolve B] status={respB.status_code} body={respB.text[:500]}")
679
 
680
  code_field = os.getenv("SERVICENOW_RESOLUTION_CODE_FIELD", "close_code")
@@ -690,8 +683,7 @@ def _set_incident_resolved(sys_id: str) -> bool:
690
  "assignment_group": assign_group,
691
  })
692
  respC = requests.patch(url, headers=headers, json=payload_C, verify=VERIFY_SSL, timeout=25)
693
- if respC.status_code in (200, 204):
694
- return True
695
  print(f"[SN PATCH resolve C] status={respC.status_code} body={respC.text[:500]}")
696
  return False
697
  except Exception as e:
 
97
  return [ln.strip() for ln in (text or "").splitlines() if ln.strip()]
98
 
99
  def _ensure_numbering(text: str) -> str:
100
+ """
101
+ Force plain-text numbering: 1) 2) 3) so it renders in any bubble.
102
+ """
103
+ lines = [ln.strip() for ln in (text or "").splitlines() if ln.strip()]
104
  if not lines:
105
  return text or ""
106
  normalized = []
 
111
  parts = [p.strip() for p in re.split(r"\.\s+(?=[A-Z0-9])", normalized[0]) if p.strip()]
112
  if len(parts) > 1:
113
  normalized = parts
114
+ return "\n".join([f"{i+1}) {ln}" for i, ln in enumerate(normalized)])
115
 
116
  def _friendly_permission_reply(raw: str) -> str:
117
  line = (raw or "").strip()
 
126
 
127
  # ---------------- Language detection (Tamil/Hindi mirror) ----------------
128
  def _detect_language_hint(msg: str) -> Optional[str]:
129
+ if re.search(r"[\u0B80-\u0BFF]", msg or ""): # Tamil
 
130
  return "Tamil"
131
+ if re.search(r"[\u0900-\u097F]", msg or ""): # Hindi
132
  return "Hindi"
133
  return None
134
 
 
476
  score = distances[i] if i < len(distances) else None
477
  comb = combined[i] if i < len(combined) else None
478
  m = dict(meta)
479
+ if score is not None: m["distance"] = score
480
+ if comb is not None: m["combined"] = comb
 
 
481
  items.append({"text": text, "meta": m})
482
  selected = items[:max(1, 2)]
483
  context_raw = "\n\n---\n\n".join([s["text"] for s in selected]) if selected else ""
 
487
  best_distance = min([d for d in distances if d is not None], default=None) if distances else None
488
  best_combined = max([c for c in combined if c is not None], default=None) if combined else None
489
  detected_intent = kb_results.get("user_intent", "neutral")
 
490
  best_doc = kb_results.get("best_doc")
491
  top_meta = (metadatas or [{}])[0] if metadatas else {}
492
 
 
501
  full_steps = get_best_steps_section_text(best_doc)
502
  if not full_steps:
503
  sec = (top_meta or {}).get("section")
504
+ if sec: full_steps = get_section_text(best_doc, sec)
 
505
  if full_steps:
506
  context = _ensure_numbering(full_steps)
507
  elif detected_intent == "errors":
508
  full_errors = get_best_errors_section_text(best_doc)
509
  if full_errors:
510
  context = _extract_errors_only(full_errors, max_lines=12)
 
511
  lines = _normalize_lines(context)
512
  if len(lines) == 1:
513
  context = _friendly_permission_reply(lines[0])
 
533
  lang_line = f"Respond in {language_hint}." if language_hint else "Respond in a clear, polite tone."
534
  enhanced_prompt = f"""You are a helpful support assistant. Rewrite the provided context ONLY into clear, user-friendly guidance.
535
  - Do not add any information that is not present in the context.
536
+ - If the content describes a procedure or steps, format as a strictly numbered list using plain text: 1), 2), 3), ...
537
  - If the content is an error/access/permission note, paraphrase it into a helpful sentence users can understand.
538
  - {lang_line}
539
 
 
562
  bot_text = ""
563
  http_code = getattr(resp, "status_code", 0)
564
 
565
+ # Fallback to local formatting
566
  if not bot_text.strip() or http_code == 429:
 
567
  if detected_intent == "steps":
568
  bot_text = _ensure_numbering(context)
569
  elif detected_intent == "errors":
 
572
  else:
573
  bot_text = context
574
 
575
+ # Force numbering for steps
576
  if detected_intent == "steps":
577
  bot_text = _ensure_numbering(bot_text)
578
 
579
+ # Status compute
580
  short_query = len((input_data.user_message or "").split()) <= 4
581
  gate_combined_ok = 0.60 if short_query else 0.55
582
  status = "OK" if (best_combined is not None and best_combined >= gate_combined_ok) else "PARTIAL"
 
585
  if ("partial" in lower) or ("may be partial" in lower) or ("closest" in lower) or ("may not fully" in lower):
586
  status = "PARTIAL"
587
 
 
588
  options = [{"type":"yesno","title":"Share details or raise a ticket?"}] if status == "PARTIAL" else []
589
 
590
  return {
 
640
  except Exception as e:
641
  print(f"[SN PATCH progress] exception={safe_str(e)}")
642
 
643
+ def clean(d: dict) -> dict: return {k: v for k, v in d.items() if v is not None}
 
644
 
645
  payload_A = clean({
646
  "state": "6",
 
653
  "assignment_group": assign_group,
654
  })
655
  respA = requests.patch(url, headers=headers, json=payload_A, verify=VERIFY_SSL, timeout=25)
656
+ if respA.status_code in (200, 204): return True
 
657
  print(f"[SN PATCH resolve A] status={respA.status_code} body={respA.text[:500]}")
658
 
659
  payload_B = clean({
 
667
  "assignment_group": assign_group,
668
  })
669
  respB = requests.patch(url, headers=headers, json=payload_B, verify=VERIFY_SSL, timeout=25)
670
+ if respB.status_code in (200, 204): return True
 
671
  print(f"[SN PATCH resolve B] status={respB.status_code} body={respB.text[:500]}")
672
 
673
  code_field = os.getenv("SERVICENOW_RESOLUTION_CODE_FIELD", "close_code")
 
683
  "assignment_group": assign_group,
684
  })
685
  respC = requests.patch(url, headers=headers, json=payload_C, verify=VERIFY_SSL, timeout=25)
686
+ if respC.status_code in (200, 204): return True
 
687
  print(f"[SN PATCH resolve C] status={respC.status_code} body={respC.text[:500]}")
688
  return False
689
  except Exception as e: