srilakshu012456 commited on
Commit
a2205f6
·
verified ·
1 Parent(s): 4500383

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +45 -33
main.py CHANGED
@@ -694,7 +694,7 @@ def _set_incident_resolved(sys_id: str) -> bool:
694
  notes_field = os.getenv("SERVICENOW_RESOLUTION_NOTES_FIELD", "close_notes")
695
  payload_C = clean({
696
  "state": "6",
697
- code_field: close_code_val,
698
  notes_field: close_notes_val,
699
  "caller_id": caller_sysid,
700
  "resolved_at": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
@@ -1030,8 +1030,9 @@ async def chat_with_ai(input_data: ChatInput):
1030
  },
1031
  }
1032
 
1033
- # ---------- Action-focused extraction + boilerplate cleanup (NEW) ----------
1034
- MONTH_TERMS = ("january","february","march","april","may","june","july","august","september","october","november","december")
 
1035
 
1036
  def _detect_action_from_query(q: str) -> Optional[str]:
1037
  qlow = (q or "").lower()
@@ -1049,7 +1050,6 @@ async def chat_with_ai(input_data: ChatInput):
1049
  is_change_hist = ("change history" in low) or ("initial draft" in low) or ("review" in low) or ("version" in low)
1050
  has_month_year = any(m in low for m in MONTH_TERMS) and bool(re.search(r"\b20\d{2}\b", low))
1051
  is_title_line = ("sop document" in low) or ("contents" in low)
1052
- # Drop lines that look like doc header/footer metadata
1053
  if is_change_hist or has_month_year or is_title_line:
1054
  continue
1055
  cleaned.append(ln)
@@ -1058,46 +1058,68 @@ async def chat_with_ai(input_data: ChatInput):
1058
  def _extract_action_block(raw_context: str, target_act: Optional[str]) -> str:
1059
  """
1060
  Extract the contiguous block of lines for the target action (create/update/delete).
1061
- Start when a line mentions the target action OR looks like the creation intro,
1062
- stop when a line mentions any other action.
 
 
1063
  """
1064
  if not raw_context.strip():
1065
  return raw_context
 
1066
  lines = _normalize_lines(raw_context)
1067
- if not target_act:
1068
  return raw_context
1069
 
 
 
 
 
 
 
 
1070
  other_terms: List[str] = []
1071
  for act, syns in ACTION_SYNONYMS_EXT.items():
1072
  if act != target_act:
1073
  other_terms.extend(syns)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1074
 
1075
  started = False
1076
  block: List[str] = []
 
1077
  for ln in lines:
1078
  low = ln.lower()
1079
- contains_target = any(s in low for s in ACTION_SYNONYMS_EXT.get(target_act, []))
1080
- contains_other = any(s in low for s in other_terms)
1081
 
1082
- # Heuristic: creation often starts with overview-like sentences; allow start on first procedural line if not yet started
1083
- is_procedural = any(k in low for k in ("select", "choose", "click", "open", "add", "assign", "save", "navigate"))
1084
- if not started and (contains_target or (target_act == "create" and is_procedural)):
1085
- started = True
 
 
 
 
 
1086
 
1087
- if started:
1088
- if contains_other:
1089
- break # end of target block
1090
- block.append(ln)
1091
 
1092
- # Fallback: if we never 'started', return original (minus boilerplate)
1093
  return "\n".join(block).strip() if block else raw_context
1094
 
1095
  def _filter_steps_by_action(raw_context: str, asked_act: Optional[str]) -> str:
1096
- # 1) strip boilerplate (title/date/author/change-history)
1097
  cleaned = _strip_boilerplate(raw_context)
1098
- # 2) extract the contiguous action block
1099
  block = _extract_action_block(cleaned, asked_act)
1100
- # 3) as a final guard, remove any stray lines that mention other actions
1101
  if asked_act:
1102
  other_terms: List[str] = []
1103
  for act, syns in ACTION_SYNONYMS_EXT.items():
@@ -1112,8 +1134,8 @@ async def chat_with_ai(input_data: ChatInput):
1112
  if is_perm_query:
1113
  detected_intent = "errors"
1114
 
1115
- escalation_line = None # SOP escalation candidate
1116
- full_errors = None # keep for possible escalation extraction
1117
  next_step_applied = False
1118
  next_step_info: Dict[str, Any] = {}
1119
 
@@ -1126,16 +1148,13 @@ async def chat_with_ai(input_data: ChatInput):
1126
  full_steps = get_section_text(best_doc, sec)
1127
 
1128
  if full_steps:
1129
- # Apply action-focused extraction & cleanup FIRST
1130
  asked_action = _detect_action_from_query(input_data.user_message)
1131
  full_steps = _filter_steps_by_action(full_steps, asked_action)
1132
 
1133
- # Use numbered form only for matching; keep raw for full output
1134
  numbered_full = _ensure_numbering(full_steps)
1135
  next_only = _resolve_next_steps(input_data.user_message, numbered_full, max_next=6, min_score=0.35)
1136
 
1137
  if next_only is not None:
1138
- # "what's next" mode
1139
  if len(next_only) == 0:
1140
  context = "You are at the final step of this SOP. No further steps."
1141
  next_step_applied = True
@@ -1147,8 +1166,6 @@ async def chat_with_ai(input_data: ChatInput):
1147
  next_step_info = {"count": len(next_only)}
1148
  context_preformatted = True
1149
  else:
1150
- # Normal mode: return the full SOP section (raw),
1151
- # and we'll number it below once.
1152
  context = full_steps
1153
  context_preformatted = False
1154
 
@@ -1159,7 +1176,6 @@ async def chat_with_ai(input_data: ChatInput):
1159
  if is_perm_query:
1160
  context = _filter_permission_lines(ctx_err, max_lines=6)
1161
  else:
1162
- # Decide specific vs generic:
1163
  is_specific_error = len(_detect_error_families(msg_low)) > 0
1164
  if is_specific_error:
1165
  context = _filter_error_lines_by_query(ctx_err, input_data.user_message, max_lines=1)
@@ -1173,7 +1189,6 @@ async def chat_with_ai(input_data: ChatInput):
1173
  )
1174
  escalation_line = _extract_escalation_line(full_errors)
1175
  else:
1176
- # Fallback when Errors section is missing: show steps
1177
  full_steps = get_best_steps_section_text(best_doc) or get_section_text(best_doc, sec_title or "")
1178
  if full_steps:
1179
  asked_action = _detect_action_from_query(input_data.user_message)
@@ -1187,7 +1202,6 @@ async def chat_with_ai(input_data: ChatInput):
1187
  if full_prereqs:
1188
  context = full_prereqs.strip()
1189
  else:
1190
- # Fallback when Prereqs section is missing: show steps
1191
  full_steps = get_best_steps_section_text(best_doc) or get_section_text(best_doc, sec_title or "")
1192
  if full_steps:
1193
  asked_action = _detect_action_from_query(input_data.user_message)
@@ -1230,8 +1244,6 @@ Return ONLY the rewritten guidance."""
1230
 
1231
  # Deterministic local formatting
1232
  if detected_intent == "steps":
1233
- # If we trimmed to next steps, 'context' is already formatted (or a sentence).
1234
- # Only number when returning full SOP raw text.
1235
  if ('context_preformatted' in locals()) and context_preformatted:
1236
  bot_text = context
1237
  else:
 
694
  notes_field = os.getenv("SERVICENOW_RESOLUTION_NOTES_FIELD", "close_notes")
695
  payload_C = clean({
696
  "state": "6",
697
+ code_field: close_notes_val, # (if you have custom fields, adjust here)
698
  notes_field: close_notes_val,
699
  "caller_id": caller_sysid,
700
  "resolved_at": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
 
1030
  },
1031
  }
1032
 
1033
+ # ---------- Action-focused extraction + boilerplate cleanup ----------
1034
+ MONTH_TERMS = ("january", "february", "march", "april", "may", "june",
1035
+ "july", "august", "september", "october", "november", "december")
1036
 
1037
  def _detect_action_from_query(q: str) -> Optional[str]:
1038
  qlow = (q or "").lower()
 
1050
  is_change_hist = ("change history" in low) or ("initial draft" in low) or ("review" in low) or ("version" in low)
1051
  has_month_year = any(m in low for m in MONTH_TERMS) and bool(re.search(r"\b20\d{2}\b", low))
1052
  is_title_line = ("sop document" in low) or ("contents" in low)
 
1053
  if is_change_hist or has_month_year or is_title_line:
1054
  continue
1055
  cleaned.append(ln)
 
1058
  def _extract_action_block(raw_context: str, target_act: Optional[str]) -> str:
1059
  """
1060
  Extract the contiguous block of lines for the target action (create/update/delete).
1061
+ Start when a line mentions the target action OR looks procedural for 'create',
1062
+ and stop ONLY when a line is a clear boundary:
1063
+ - inline heading for another topic (e.g., 'Appointment schedule updation', 'Appointment deletion'), OR
1064
+ - a line that strongly signals a different action (update/delete) via extended synonyms.
1065
  """
1066
  if not raw_context.strip():
1067
  return raw_context
1068
+
1069
  lines = _normalize_lines(raw_context)
1070
+ if not lines or not target_act:
1071
  return raw_context
1072
 
1073
+ INLINE_BOUNDARIES = (
1074
+ "appointment schedule updation",
1075
+ "schedule updation",
1076
+ "appointment deletion",
1077
+ "deletion",
1078
+ )
1079
+
1080
  other_terms: List[str] = []
1081
  for act, syns in ACTION_SYNONYMS_EXT.items():
1082
  if act != target_act:
1083
  other_terms.extend(syns)
1084
+ other_terms_low = set(t.lower() for t in other_terms)
1085
+
1086
+ def is_boundary_line(low: str) -> bool:
1087
+ if any(h in low for h in INLINE_BOUNDARIES):
1088
+ return True
1089
+ if any(t in low for t in other_terms_low):
1090
+ return True
1091
+ return False
1092
+
1093
+ PROCEDURAL_VERBS = ("select", "choose", "click", "open", "add", "assign", "save",
1094
+ "navigate", "tag", "displayed", "triggered")
1095
+ def is_procedural(low: str) -> bool:
1096
+ return any(v in low for v in PROCEDURAL_VERBS)
1097
+
1098
+ target_terms_low = set(t.lower() for t in ACTION_SYNONYMS_EXT.get(target_act, []))
1099
 
1100
  started = False
1101
  block: List[str] = []
1102
+
1103
  for ln in lines:
1104
  low = ln.lower()
 
 
1105
 
1106
+ contains_target = any(t in low for t in target_terms_low)
1107
+ if not started:
1108
+ if contains_target or (target_act == "create" and is_procedural(low)):
1109
+ started = True
1110
+ block.append(ln)
1111
+ continue
1112
+
1113
+ if is_boundary_line(low):
1114
+ break
1115
 
1116
+ block.append(ln)
 
 
 
1117
 
 
1118
  return "\n".join(block).strip() if block else raw_context
1119
 
1120
  def _filter_steps_by_action(raw_context: str, asked_act: Optional[str]) -> str:
 
1121
  cleaned = _strip_boilerplate(raw_context)
 
1122
  block = _extract_action_block(cleaned, asked_act)
 
1123
  if asked_act:
1124
  other_terms: List[str] = []
1125
  for act, syns in ACTION_SYNONYMS_EXT.items():
 
1134
  if is_perm_query:
1135
  detected_intent = "errors"
1136
 
1137
+ escalation_line = None
1138
+ full_errors = None
1139
  next_step_applied = False
1140
  next_step_info: Dict[str, Any] = {}
1141
 
 
1148
  full_steps = get_section_text(best_doc, sec)
1149
 
1150
  if full_steps:
 
1151
  asked_action = _detect_action_from_query(input_data.user_message)
1152
  full_steps = _filter_steps_by_action(full_steps, asked_action)
1153
 
 
1154
  numbered_full = _ensure_numbering(full_steps)
1155
  next_only = _resolve_next_steps(input_data.user_message, numbered_full, max_next=6, min_score=0.35)
1156
 
1157
  if next_only is not None:
 
1158
  if len(next_only) == 0:
1159
  context = "You are at the final step of this SOP. No further steps."
1160
  next_step_applied = True
 
1166
  next_step_info = {"count": len(next_only)}
1167
  context_preformatted = True
1168
  else:
 
 
1169
  context = full_steps
1170
  context_preformatted = False
1171
 
 
1176
  if is_perm_query:
1177
  context = _filter_permission_lines(ctx_err, max_lines=6)
1178
  else:
 
1179
  is_specific_error = len(_detect_error_families(msg_low)) > 0
1180
  if is_specific_error:
1181
  context = _filter_error_lines_by_query(ctx_err, input_data.user_message, max_lines=1)
 
1189
  )
1190
  escalation_line = _extract_escalation_line(full_errors)
1191
  else:
 
1192
  full_steps = get_best_steps_section_text(best_doc) or get_section_text(best_doc, sec_title or "")
1193
  if full_steps:
1194
  asked_action = _detect_action_from_query(input_data.user_message)
 
1202
  if full_prereqs:
1203
  context = full_prereqs.strip()
1204
  else:
 
1205
  full_steps = get_best_steps_section_text(best_doc) or get_section_text(best_doc, sec_title or "")
1206
  if full_steps:
1207
  asked_action = _detect_action_from_query(input_data.user_message)
 
1244
 
1245
  # Deterministic local formatting
1246
  if detected_intent == "steps":
 
 
1247
  if ('context_preformatted' in locals()) and context_preformatted:
1248
  bot_text = context
1249
  else: