"""Parse and normalize the field-assist model response. Pure module: no FastAPI imports and no HTTPException. """ from __future__ import annotations import re from job_assist.prompt import LIST_FIELDS, SINGLE_LINE_FIELDS MAX_SUGGESTION_CHARS = 6000 # Leading bullet/number markers the model may emit despite the prompt. _BULLET = re.compile(r"^\s*(?:[-*•·]+|\d+[.)])\s+") def parse_assist_response(data, field) -> str: """The suggestion string, normalized to the field's shape. Raises RuntimeError.""" if not isinstance(data, dict): raise RuntimeError("assist response is not an object") suggestion = data.get("suggestion") if not isinstance(suggestion, str) or not suggestion.strip(): raise RuntimeError("assist response has no suggestion") text = suggestion.replace("\r\n", "\n").replace("\r", "\n").strip() if field in SINGLE_LINE_FIELDS: text = " ".join(text.split()) elif field in LIST_FIELDS: # The form splits these on newline (Jobs.jsx splitLines), so strip any # bullet markers and keep one item per line. lines = [_BULLET.sub("", line).strip() for line in text.split("\n")] text = "\n".join(line for line in lines if line) if not text: raise RuntimeError("assist response emptied after normalization") else: text = re.sub(r"\n{3,}", "\n\n", text) return text[:MAX_SUGGESTION_CHARS].strip()