srilakshu012456 commited on
Commit
2470a1f
·
verified ·
1 Parent(s): bd05313

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +98 -2
main.py CHANGED
@@ -202,6 +202,92 @@ def _ensure_numbering(text: str) -> str:
202
  out.append(f"{marker} {seg}")
203
  return "\n".join(out)
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  def _filter_error_lines_by_query(text: str, query: str, max_lines: int = 1) -> str:
206
  """
207
  Pick the most relevant 'Common Errors & Resolution' bullet(s) for the user's message.
@@ -906,8 +992,18 @@ async def chat_with_ai(input_data: ChatInput):
906
  sec = (top_meta or {}).get("section")
907
  if sec: full_steps = get_section_text(best_doc, sec)
908
  if full_steps:
909
- context = _ensure_numbering(full_steps)
910
-
 
 
 
 
 
 
 
 
 
 
911
  elif detected_intent == "errors":
912
  full_errors = get_best_errors_section_text(best_doc)
913
  #assist_followup = None # collect a helpful follow-up for generic cases
 
202
  out.append(f"{marker} {seg}")
203
  return "\n".join(out)
204
 
205
+ # --- Next-step helpers (generic; SOP-agnostic) ---
206
+
207
+ def _norm_text(s: str) -> str:
208
+ import re
209
+ s = (s or "").lower()
210
+ s = re.sub(r"[^\w\s]", " ", s)
211
+ s = re.sub(r"\s+", " ", s).strip()
212
+ return s
213
+
214
+ def _split_sop_into_steps(numbered_text: str) -> list:
215
+ """
216
+ Split a numbered/bulleted SOP block (already passed through _ensure_numbering)
217
+ into atomic steps. Returns a list of raw step strings (order preserved).
218
+ Safe for circled digits, '1.' styles, and bullets.
219
+ """
220
+ lines = [ln.strip() for ln in (numbered_text or "").splitlines() if ln.strip()]
221
+ steps = []
222
+ for ln in lines:
223
+ # Strip circled/number/bullet marker
224
+ cleaned = ln
225
+ cleaned = re.sub(r"^\s*(?:[\u2460-\u2473]|\d+[.)]|[-*•])\s*", "", cleaned)
226
+ if cleaned:
227
+ steps.append(cleaned)
228
+ return steps
229
+
230
+ def _soft_match_score(a: str, b: str) -> float:
231
+ # Simple Jaccard-like score on tokens for fuzzy matching
232
+ ta = set(_norm_text(a).split())
233
+ tb = set(_norm_text(b).split())
234
+ if not ta or not tb:
235
+ return 0.0
236
+ inter = len(ta & tb)
237
+ union = len(ta | tb)
238
+ return inter / union if union else 0.0
239
+
240
+ def _detect_next_intent(user_query: str) -> bool:
241
+ q = _norm_text(user_query)
242
+ # Conservative rules to avoid false triggers
243
+ keys = [
244
+ "after", "after this", "what next", "whats next", "next step",
245
+ "then what", "following step", "continue", "subsequent", "proceed"
246
+ ]
247
+ return any(k in q for k in keys)
248
+
249
+ def _resolve_next_steps(user_query: str, numbered_text: str, max_next: int = 6, min_score: float = 0.35):
250
+ """
251
+ If 'what's next' intent is detected and we can reliably match the user's
252
+ referenced line to a SOP step, return ONLY the subsequent steps.
253
+ Else return None to preserve current behavior.
254
+ """
255
+ if not _detect_next_intent(user_query):
256
+ return None
257
+
258
+ steps = _split_sop_into_steps(numbered_text)
259
+ if not steps:
260
+ return None
261
+
262
+ q = user_query or ""
263
+ best_idx, best_score = -1, -1.0
264
+ for idx, step in enumerate(steps):
265
+ # Exact substring match gets max score; else use soft match
266
+ score = 1.0 if _norm_text(step) in _norm_text(q) else _soft_match_score(q, step)
267
+ if score > best_score:
268
+ best_score, best_idx = score, idx
269
+
270
+ if best_idx < 0 or best_score < min_score:
271
+ return None # fallback to full SOP
272
+
273
+ start = best_idx + 1
274
+ if start >= len(steps):
275
+ return [] # user is at final step
276
+
277
+ end = min(start + max_next, len(steps))
278
+ return steps[start:end]
279
+
280
+ def _format_steps_as_numbered(steps: list) -> str:
281
+ """
282
+ Render a small list of steps with circled numbers for visual continuity.
283
+ """
284
+ circled = {1:"\u2460",2:"\u2461",3:"\u2462",4:"\u2463",5:"\u2464",6:"\u2465",7:"\u2466",8:"\u2467",9:"\u2468",10:"\u2469",
285
+ 11:"\u246a",12:"\u246b",13:"\u246c",14:"\u246d",15:"\u246e",16:"\u246f",17:"\u2470",18:"\u2471",19:"\u2472",20:"\u2473"}
286
+ out = []
287
+ for i, s in enumerate(steps, start=1):
288
+ out.append(f"{circled.get(i, str(i))} {s}")
289
+ return "\n".join(out)
290
+
291
  def _filter_error_lines_by_query(text: str, query: str, max_lines: int = 1) -> str:
292
  """
293
  Pick the most relevant 'Common Errors & Resolution' bullet(s) for the user's message.
 
992
  sec = (top_meta or {}).get("section")
993
  if sec: full_steps = get_section_text(best_doc, sec)
994
  if full_steps:
995
+
996
+ numbered = _ensure_numbering(full_steps) # keep your existing formatting
997
+ # NEW: return only subsequent steps when user asks "what's next"
998
+ next_only = _resolve_next_steps(input_data.user_message, numbered, max_next=6, min_score=0.35)
999
+ if next_only is not None:
1000
+ if len(next_only) == 0:
1001
+ context = "You are at the final step of this SOP. No further steps."
1002
+ else:
1003
+ context = _format_steps_as_numbered(next_only)
1004
+ else:
1005
+ context=numbered
1006
+
1007
  elif detected_intent == "errors":
1008
  full_errors = get_best_errors_section_text(best_doc)
1009
  #assist_followup = None # collect a helpful follow-up for generic cases