"""Turn and card builders for the Builder conversation.""" from __future__ import annotations from typing import Any from ..fsm import anchor_field_specs, assistant_turn, component from ..models import ComposerMode from .constants import SECTION_HEADINGS, SECTION_PRIORITY, u from .state import _completed_sections, _set_stream_phases, ensure_builder_state def recommended_section(profile: dict[str, Any], resume_content: dict[str, Any] | None = None) -> str: priorities = SECTION_PRIORITY.get(str(profile.get("job_type") or "campus"), SECTION_PRIORITY["campus"]) completed = _completed_sections(resume_content or {}) return next((section for section in priorities if section not in completed), priorities[0]) def welcome_turn( profile: dict[str, Any], resume_id: str | None, *, imported: bool = False, resume_content: dict[str, Any] | None = None, ) -> tuple[dict[str, Any], dict[str, Any]]: state = ensure_builder_state(profile) state["imported"] = imported if imported: turn = assistant_turn("简历已经导入。你想先修改哪一段经历,还是补充一段新的内容?", [], mode=ComposerMode.CHAT) _set_stream_phases(profile, "suggesting_next") return profile, turn turn = _next_step_turn(recommended_section(profile, resume_content)) _set_stream_phases(profile, "suggesting_next") return profile, turn def _next_step_turn(section: str, *, prefix: str = "") -> dict[str, Any]: lead = f"{prefix} " if prefix else "" return assistant_turn( f"{lead}接下来建议补充{SECTION_HEADINGS[section]}。你想继续这类经历,还是改选其他经历类型?", [_section_choice_card(section)], mode=ComposerMode.CHAT, ) def _section_choice_card(recommended: str) -> dict[str, Any]: return component( "ChoiceChips", module="builder_next_section", title=u("选择下一步"), description=f"{u('建议先补充')}{SECTION_HEADINGS[recommended]}{u(',也可以换一种经历、推荐岗位技能,或直接完成。')}", options=[ *({"value": kind, "label": heading} for kind, heading in SECTION_HEADINGS.items()), {"value": "builder_recommend_skills", "label": u("推荐岗位技能")}, {"value": "builder_finish", "label": u("完成并生成个人总结")}, ], value=recommended, ) def _entry_choice_card(matches: list[tuple[dict[str, Any], dict[str, Any]]]) -> dict[str, Any]: options = [{"value": str(entry.get("id") or ""), "label": _entry_label(entry, str(section.get("kind") or ""))} for section, entry in matches] return component("ChoiceChips", module="builder_entry_select", title="选择要修改的经历", options=options) def _record_card(section: str, *, title: str, value: dict[str, Any] | None = None, entry_id: Any = None, skippable: bool = False) -> dict[str, Any]: props: dict[str, Any] = { "module": "builder_identity", "record_type": section, "title": title, "fields": anchor_field_specs(section), "show_description": False, "require_description": False, "skippable": skippable, "skip_label": "稍后补充", } if value: props["value"] = value if entry_id: props["entry_id"] = entry_id return component("RecordFields", **props) def _fact_prompt(section: str) -> str: prompts = { "education": "请补充这段教育经历的真实信息,例如课程项目、竞赛、实践或学习成果;没有也可以直接说没有。", "campus_experience": "请补充你实际承担的职责,或规模和结果中的一两项;没有也可以直接说没有。", "project_experience": "请补充个人动作、方法或工具,以及交付物、规模或量化结果中的一两项;没有也可以直接说没有。", "work_experience": "请补充个人动作、方法或工具,以及交付物、规模或量化结果中的一两项;没有也可以直接说没有。", "internship_experience": "请补充个人动作、方法或工具,以及交付物、规模或量化结果中的一两项;没有也可以直接说没有。", } return prompts[section] def _entry_label(entry: dict[str, Any], kind: str) -> str: identity = next((str(entry.get(key) or "").strip() for key in ("school", "company", "project_name", "organization") if str(entry.get(key) or "").strip()), SECTION_HEADINGS.get(kind, "经历")) role = next((str(entry.get(key) or "").strip() for key in ("major", "position", "project_role", "role") if str(entry.get(key) or "").strip()), "") return f"{identity} · {role}" if role else identity