generated from kgod/ai-review-template
288 lines
9.7 KiB
Python
288 lines
9.7 KiB
Python
"""FastAPI route registration for resume editing and optimization."""
|
|
|
|
from typing import Any, Callable
|
|
|
|
from fastapi import FastAPI, Header
|
|
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,
|
|
*,
|
|
authorize_session_request: Callable[[str, str | None], str | None] | None = None,
|
|
) -> None:
|
|
authorize_session_request = authorize_session_request or (
|
|
lambda _session_id, _authorization: None
|
|
)
|
|
|
|
def mutate_with_sync(
|
|
session_id: str,
|
|
external_token: str | None,
|
|
operation: Callable[[], Any],
|
|
*,
|
|
allow_pulled_resume: bool = False,
|
|
) -> Any:
|
|
if external_token is None:
|
|
return operation()
|
|
return agent.mutate_with_offerpai_sync(
|
|
session_id,
|
|
external_token,
|
|
operation,
|
|
allow_pulled_resume=allow_pulled_resume,
|
|
)
|
|
|
|
@application.patch(
|
|
f"{prefix}/sessions/{{session_id}}/resume",
|
|
response_model=ActionResponse,
|
|
tags=["resume-agent"],
|
|
)
|
|
def patch_resume(
|
|
session_id: str,
|
|
request: ResumePatchRequest,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: agent.patch_resume(session_id, request),
|
|
allow_pulled_resume=True,
|
|
)
|
|
|
|
@application.post(
|
|
f"{prefix}/sessions/{{session_id}}/resume/profile-summary/generate",
|
|
response_model=ActionResponse,
|
|
tags=["resume-agent"],
|
|
)
|
|
def generate_profile_summary(
|
|
session_id: str,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> SkillRecommendationResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
if external_token is not None:
|
|
agent.reconcile_resume_with_offerpai(session_id, external_token)
|
|
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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> ActionResponse:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> dict[str, object]:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> OptimizationRunView:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
|
|
def mutate() -> 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)
|
|
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
mutate,
|
|
)
|
|
|
|
@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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> list[OptimizationRunView]:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
if external_token is not None:
|
|
agent.reconcile_resume_with_offerpai(session_id, external_token)
|
|
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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> OptimizationRunView:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: 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,
|
|
authorization: str | None = Header(default=None),
|
|
) -> OptimizationRunView:
|
|
external_token = authorize_session_request(session_id, authorization)
|
|
return mutate_with_sync(
|
|
session_id,
|
|
external_token,
|
|
lambda: agent.reject_optimization(session_id, run_id),
|
|
)
|