generated from kgod/ai-review-template
78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
"""Builder profile-state helpers: drafts, gap tracking, and text utilities."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from copy import deepcopy
|
|
import re
|
|
from typing import Any
|
|
|
|
|
|
def ensure_builder_state(profile: dict[str, Any]) -> dict[str, Any]:
|
|
state = profile.setdefault("builder", {})
|
|
state.setdefault("active_section", None)
|
|
state.setdefault("identity_draft", {})
|
|
state.setdefault("pending_entry", None)
|
|
state.setdefault("editing_entry_id", None)
|
|
state.setdefault("editing_base_entry", None)
|
|
state.setdefault("selection_candidates", [])
|
|
state.setdefault("gap_state", {"asked": [], "skipped": [], "rounds": 0})
|
|
state.setdefault("revision_mode", False)
|
|
state.setdefault("last_confirmed_entry", None)
|
|
state.setdefault("pending_skill_candidates", [])
|
|
state.setdefault("last_stream_phases", [])
|
|
state.setdefault("imported", False)
|
|
return state
|
|
|
|
|
|
def _gap_state(state: dict[str, Any]) -> dict[str, Any]:
|
|
raw = state.setdefault("gap_state", {"asked": [], "skipped": [], "rounds": 0})
|
|
raw["asked"] = [str(value) for value in raw.get("asked") or []]
|
|
raw["skipped"] = [str(value) for value in raw.get("skipped") or []]
|
|
raw["rounds"] = int(raw.get("rounds") or 0)
|
|
return raw
|
|
|
|
|
|
def _reset_gap_state(state: dict[str, Any]) -> None:
|
|
state["gap_state"] = {"asked": [], "skipped": [], "rounds": 0}
|
|
|
|
|
|
def _set_stream_phases(profile: dict[str, Any], *phases: str) -> None:
|
|
ensure_builder_state(profile)["last_stream_phases"] = list(dict.fromkeys(phases))
|
|
|
|
|
|
def _clear_draft(state: dict[str, Any]) -> None:
|
|
state["revision_mode"] = False
|
|
state["active_section"] = None
|
|
state["identity_draft"] = {}
|
|
state["pending_entry"] = None
|
|
state["editing_entry_id"] = None
|
|
state["editing_base_entry"] = None
|
|
state["selection_candidates"] = []
|
|
_reset_gap_state(state)
|
|
|
|
|
|
def _public_entry(entry: dict[str, Any]) -> dict[str, Any]:
|
|
return {key: deepcopy(value) for key, value in entry.items() if not key.startswith("_")}
|
|
|
|
|
|
def _dedupe_strings(values: list[str]) -> list[str]:
|
|
return list(dict.fromkeys(values))
|
|
|
|
|
|
def _highlights(text: str) -> list[str]:
|
|
return [part.strip() for part in re.split(r"[。;;\n]+", text) if part.strip()][:5]
|
|
|
|
|
|
def _merge_fact_text(original: str, detail: str, *, skip_no_information: bool = False) -> str:
|
|
if not detail.strip():
|
|
return original
|
|
if not original or original == detail:
|
|
return detail or original
|
|
if skip_no_information:
|
|
return original
|
|
return f"{original}\n{detail}"
|
|
|
|
|
|
def _completed_sections(resume_content: dict[str, Any]) -> set[str]:
|
|
return {str(section.get("kind") or "") for section in resume_content.get("sections") or [] if isinstance(section, dict) and any(isinstance(entry, dict) for entry in section.get("items") or [])}
|