generated from kgod/ai-review-template
feat: initialize resume agent with OfferPai sync
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
"""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),
|
||||
)
|
||||
Reference in New Issue
Block a user