generated from kgod/ai-review-template
feat: initialize resume agent with OfferPai sync
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"""Builder 个人总结再生入口:finish 按钮与对话指令统一走"显式请求即重生成"。
|
||||
|
||||
agent 侧只在总结缺失或 stale 时才生成(避免自动覆盖用户手工文本);用户的显式
|
||||
请求必须先把现有总结标记为 stale,让既有闸门放行。对话路径无法直接写简历
|
||||
(add_message 不合并 resume_content),所以走"生成候选 → ChoiceChips 确认 →
|
||||
组件事件写入"的既有 Builder 模式。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from ..fsm import FSMError, Transition, assistant_turn, component
|
||||
from ..models import ComposerMode, Stage
|
||||
from ..resume_document import mark_profile_summary_stale, set_generated_profile_summary
|
||||
from .constants import u
|
||||
from .state import _set_stream_phases, ensure_builder_state
|
||||
|
||||
SUMMARY_APPLY_MODULE = "builder_summary_apply"
|
||||
_REGEN_VERB = re.compile(r"(重新|再次|再来|重写|更新|刷新|换|再).{0,6}总结")
|
||||
_ASK_GENERATE = re.compile(r"(?:帮我|请|我要|我想|给我).{0,6}生成.{0,4}总结|^生成.{0,4}总结")
|
||||
|
||||
|
||||
def requests_summary_regen(content: str) -> bool:
|
||||
""""重新生成个人总结"类指令;提供总结原文或陈述事实的消息不算。"""
|
||||
normalized = re.sub(r"[\s,,。;;!!??]", "", content.casefold())
|
||||
if "总结" not in normalized or "总结是" in normalized:
|
||||
return False
|
||||
return bool(_REGEN_VERB.search(normalized) or _ASK_GENERATE.search(normalized))
|
||||
|
||||
|
||||
def finish_transition(profile: dict[str, Any], resume_content: dict[str, Any]) -> Transition:
|
||||
""""完成并生成个人总结":已有总结也强制重生成(先标记 stale 放行闸门)。"""
|
||||
_set_stream_phases(profile, "saving")
|
||||
return Transition(
|
||||
Stage.BUILDER_CONVERSATION,
|
||||
profile,
|
||||
assistant_turn(
|
||||
u("好的,已根据当前简历预览信息生成个人总结,内容仍可在右侧预览中编辑。"),
|
||||
[],
|
||||
mode=ComposerMode.CHAT,
|
||||
),
|
||||
resume_content=mark_profile_summary_stale(resume_content),
|
||||
generate_profile_summary=True,
|
||||
)
|
||||
|
||||
|
||||
def summary_regen_turn(agent: Any, profile: dict[str, Any], resume_content: dict[str, Any]) -> Transition:
|
||||
"""对话"重新生成个人总结":立即生成候选文本,确认后经组件事件写入简历。"""
|
||||
try:
|
||||
proposal = agent.profile_summary_generator.generate(resume_content)
|
||||
except Exception:
|
||||
return Transition(
|
||||
Stage.BUILDER_CONVERSATION,
|
||||
profile,
|
||||
assistant_turn(u("个人总结生成失败,请稍后重试。"), [], mode=ComposerMode.CHAT),
|
||||
)
|
||||
ensure_builder_state(profile)["pending_summary_proposal"] = proposal
|
||||
card = component(
|
||||
"ChoiceChips",
|
||||
module=SUMMARY_APPLY_MODULE,
|
||||
options=[
|
||||
{"value": "apply", "label": u("写入简历")},
|
||||
{"value": "dismiss", "label": u("暂不写入")},
|
||||
],
|
||||
)
|
||||
return Transition(
|
||||
Stage.BUILDER_CONVERSATION,
|
||||
profile,
|
||||
assistant_turn(u("好的,已根据当前简历内容重新生成个人总结:\n") + proposal, [card], mode=ComposerMode.CHAT),
|
||||
)
|
||||
|
||||
|
||||
def apply_summary_proposal(
|
||||
profile: dict[str, Any], action: str, payload: dict[str, Any], resume_content: dict[str, Any]
|
||||
) -> Transition:
|
||||
"""确认卡事件:apply 写入候选总结(随组件事件合并进简历),否则丢弃。"""
|
||||
if action != "select":
|
||||
raise FSMError("invalid_builder_choice", "Choose whether to apply the summary", status_code=422)
|
||||
proposal = str(ensure_builder_state(profile).pop("pending_summary_proposal", "") or "").strip()
|
||||
if str(payload.get("value") or "") != "apply" or not proposal:
|
||||
return Transition(
|
||||
Stage.BUILDER_CONVERSATION,
|
||||
profile,
|
||||
assistant_turn(u("好的,保留当前个人总结。"), [], mode=ComposerMode.CHAT),
|
||||
)
|
||||
content = set_generated_profile_summary(mark_profile_summary_stale(resume_content), proposal, replace_stale=True)
|
||||
return Transition(
|
||||
Stage.BUILDER_CONVERSATION,
|
||||
profile,
|
||||
assistant_turn(u("已写入新的个人总结,仍可在右侧预览中编辑。"), [], mode=ComposerMode.CHAT),
|
||||
lifecycle="confirmed",
|
||||
resume_content=content,
|
||||
)
|
||||
Reference in New Issue
Block a user