Files
resume-agent/backend/app/enrichment.py
T
2026-07-20 14:48:41 +08:00

111 lines
3.6 KiB
Python

from __future__ import annotations
from copy import deepcopy
from dataclasses import dataclass
from typing import Any
from .fsm import FSMError, assistant_turn, component
from .models import ComposerMode, Stage
from .services import ExtractedExperience
@dataclass(slots=True)
class RewriteConfirmationTransition:
stage: Stage
profile: dict[str, Any]
turn: dict[str, Any]
lifecycle: str = "submitted"
create_draft: bool = False
resume_content: dict[str, Any] | None = None
def prepare_rewrite_confirmation(
profile: dict[str, Any],
extraction: ExtractedExperience,
rewritten: dict[str, Any],
) -> tuple[dict[str, Any], dict[str, Any]]:
updated = deepcopy(profile)
updated["pending_experience"] = extraction.to_dict()
updated["pending_resume_content"] = rewritten
summary = _confirmation_summary(extraction, rewritten)
turn = assistant_turn(
"我已把这段事实整理成正式简历语言,请确认后再写入简历。",
[
component(
"ExperienceConfirmCard",
title="确认 AI 改写",
description="只在内容准确时加入简历;需要调整可返回继续描述。",
value=summary,
confirmation_kind="rewrite",
)
],
mode=ComposerMode.UI_ONLY,
)
return updated, turn
def process_rewrite_confirmation(
profile: dict[str, Any], action: str
) -> RewriteConfirmationTransition:
updated = deepcopy(profile)
normalized = action.strip().lower()
if normalized in {"edit", "revise", "edit_anchor"}:
updated.pop("pending_experience", None)
updated.pop("pending_resume_content", None)
return RewriteConfirmationTransition(
Stage.RESUME_ENRICHING,
updated,
assistant_turn(
"这版暂不写入。请补充或纠正事实,我会重新整理。",
[],
mode=ComposerMode.CHAT,
),
)
if normalized not in {"confirm", "confirm_anchor", "confirm_rewrite"}:
raise FSMError("invalid_action", "Confirm or revise the proposed rewrite")
experience = updated.pop("pending_experience", None)
resume_content = updated.pop("pending_resume_content", None)
if not isinstance(experience, dict) or not isinstance(resume_content, dict):
raise FSMError("rewrite_not_pending", "No proposed rewrite is waiting for confirmation")
updated.setdefault("experiences", []).append(experience)
updated["ai_rewrites_confirmed"] = True
return RewriteConfirmationTransition(
Stage.CONTENT_READY,
updated,
assistant_turn(
"已确认并写入简历。",
[
component(
"ContentReadyCard",
formal_content_ready=True,
actions=["continue_enriching", "finish_enrichment"],
)
],
mode=ComposerMode.HYBRID,
),
lifecycle="confirmed",
resume_content=resume_content,
)
def _confirmation_summary(
extraction: ExtractedExperience, rewritten: dict[str, Any]
) -> dict[str, Any]:
bullets: list[str] = []
section = next(
(
item
for item in rewritten.get("sections", [])
if item.get("kind") == "additional_experience"
),
None,
)
if section and section.get("items"):
bullets = section["items"][-1].get("resume_bullets") or []
return {
"title": extraction.title,
"organization": extraction.organization,
"role": extraction.role,
"highlights": bullets or extraction.highlights,
}