Files
resume-agent/backend/app/resume_routes.py
T
hypandClaude ae2d9b128d feat: builder 简历生成 + 轻度优化 + 简历导入交付副本
自内部仓库剥离深度优化与 RAG 知识库后的交付版本:
- Builder 对话式简历生成(FSM + 意图路由 LLM 兜底增强)
- 条目级轻度优化:事实覆盖门禁 + STAR/bullet 修复链,功能/简介/成果与技术栈同级保护
- 简历导入:DOCX/PDF 解析、结构归一、手机号脱敏
- PostgreSQL 运行时 + Alembic 迁移链

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 11:08:30 +08:00

141 lines
5.4 KiB
Python

"""FastAPI route registration for resume editing and optimization."""
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from .agent import ResumeAgent
from .fsm import FSMError
from .models import ActionResponse, OptimizeEntryRequest, OptimizeRequest, ResumePatchRequest
from .optimization_models import (
OptimizationRunView,
OptimizationStartRequest,
TargetPositionRequest,
)
from .resume_api_models import SkillRecommendationRequest, SkillRecommendationResponse
def register_resume_routes(application: FastAPI, agent: ResumeAgent, prefix: str) -> None:
@application.patch(
f"{prefix}/sessions/{{session_id}}/resume",
response_model=ActionResponse,
tags=["resume-agent"],
)
def patch_resume(session_id: str, request: ResumePatchRequest) -> ActionResponse:
return agent.patch_resume(session_id, request)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/profile-summary/generate",
response_model=ActionResponse,
tags=["resume-agent"],
)
def generate_profile_summary(session_id: str) -> ActionResponse:
return agent.generate_profile_summary(session_id)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/profile-summary/confirm",
response_model=ActionResponse,
tags=["resume-agent"],
)
def confirm_profile_summary(session_id: str) -> ActionResponse:
return agent.confirm_profile_summary(session_id)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/profile-summary/reject",
response_model=ActionResponse,
tags=["resume-agent"],
)
def reject_profile_summary(session_id: str) -> ActionResponse:
return agent.reject_profile_summary(session_id)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/skills/recommend",
response_model=SkillRecommendationResponse,
tags=["resume-agent"],
)
def recommend_skills(
session_id: str, request: SkillRecommendationRequest
) -> SkillRecommendationResponse:
return SkillRecommendationResponse(
candidates=agent.recommend_skills(session_id, request.question)
)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize",
response_model=ActionResponse,
tags=["resume-agent"],
)
def optimize_entry(session_id: str, request: OptimizeRequest) -> ActionResponse:
return agent.optimize_entry(session_id, request)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/confirm",
response_model=ActionResponse,
tags=["resume-agent"],
)
def confirm_optimize(session_id: str, request: OptimizeEntryRequest) -> ActionResponse:
return agent.confirm_optimize(session_id, request)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/reject",
response_model=ActionResponse,
tags=["resume-agent"],
)
def reject_optimize(session_id: str, request: OptimizeEntryRequest) -> ActionResponse:
return agent.reject_optimize(session_id, request)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/undo",
response_model=ActionResponse,
tags=["resume-agent"],
)
def undo_optimize(session_id: str, request: OptimizeEntryRequest) -> ActionResponse:
return agent.undo_optimize(session_id, request)
@application.post(
f"{prefix}/sessions/{{session_id}}/target-position",
tags=["resume-agent"],
)
def set_session_target_position(
session_id: str, request: TargetPositionRequest
) -> dict[str, object]:
return agent.set_target_position(session_id, request.target_position)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/light",
response_model=OptimizationRunView,
tags=["resume-agent"],
)
def optimize_light(session_id: str, request: OptimizationStartRequest) -> OptimizationRunView:
limiter = getattr(application.state, "light_opt_limiter", None)
if limiter is not None and not limiter.allow(session_id):
raise FSMError(
"rate_limited",
"操作过于频繁,请稍后再试(轻度优化每小时最多 20 次)。",
status_code=429,
)
return agent.optimize_light(session_id, request)
@application.get(
f"{prefix}/sessions/{{session_id}}/resume/optimize/runs/active",
response_model=list[OptimizationRunView],
tags=["resume-agent"],
)
def list_active_optimization_runs(session_id: str) -> list[OptimizationRunView]:
return agent.list_active_optimization_runs(session_id)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/runs/{{run_id}}/confirm",
response_model=OptimizationRunView,
tags=["resume-agent"],
)
def confirm_deep_optimization(session_id: str, run_id: str) -> OptimizationRunView:
return agent.confirm_deep_optimization(session_id, run_id)
@application.post(
f"{prefix}/sessions/{{session_id}}/resume/optimize/runs/{{run_id}}/reject",
response_model=OptimizationRunView,
tags=["resume-agent"],
)
def reject_optimization(session_id: str, run_id: str) -> OptimizationRunView:
return agent.reject_optimization(session_id, run_id)