generated from kgod/ai-review-template
自内部仓库剥离深度优化与 RAG 知识库后的交付版本: - Builder 对话式简历生成(FSM + 意图路由 LLM 兜底增强) - 条目级轻度优化:事实覆盖门禁 + STAR/bullet 修复链,功能/简介/成果与技术栈同级保护 - 简历导入:DOCX/PDF 解析、结构归一、手机号脱敏 - PostgreSQL 运行时 + Alembic 迁移链 Co-Authored-By: Claude <noreply@anthropic.com>
141 lines
5.4 KiB
Python
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)
|