generated from kgod/ai-review-template
99 lines
4.6 KiB
Python
99 lines
4.6 KiB
Python
"""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
|