| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- from __future__ import annotations
- from fastapi import FastAPI, HTTPException
- from fastapi.exceptions import RequestValidationError
- from fastapi.encoders import jsonable_encoder
- from fastapi.responses import JSONResponse
- from content_agent.errors import ErrorCode, error_response, sanitize_error_detail
- from content_agent.run_service import RunService
- from content_agent.schemas import (
- JsonFileResponse,
- RecordsResponse,
- RunStartRequest,
- RunStartResponse,
- RunSummaryResponse,
- ValidationResponse,
- )
- app = FastAPI(title="Content Agent V1")
- service = RunService.from_env()
- @app.exception_handler(RequestValidationError)
- async def validation_exception_handler(request, exc: RequestValidationError):
- return JSONResponse(
- status_code=422,
- content={
- "detail": error_response(
- ErrorCode.INVALID_REQUEST,
- "invalid request",
- {"errors": jsonable_encoder(sanitize_error_detail(exc.errors()))},
- )
- },
- )
- @app.post("/runs", response_model=RunStartResponse)
- def start_run(request: RunStartRequest) -> RunStartResponse:
- state = service.start_run(request)
- if state["status"] not in {"success", "partial_success"}:
- detail = error_response(
- state.get("error_code", ErrorCode.RUN_START_FAILED),
- state.get("error_message", "run failed"),
- state.get("error_detail", {"errors": state.get("errors", [])}),
- )
- raise HTTPException(status_code=state.get("http_status_code", 500), detail=detail)
- run_id = state["run_id"]
- return RunStartResponse(
- run_id=run_id,
- policy_run_id=state["policy_run_id"],
- status=state["status"],
- policy_bundle_id=state["policy_bundle_id"],
- strategy_version=state["strategy_version"],
- platform=state["platform"],
- platform_mode=state["platform_mode"],
- output_dir=str(service.runtime.run_dir(run_id)),
- )
- @app.get("/runs/{run_id}", response_model=RunSummaryResponse)
- def get_run(run_id: str) -> RunSummaryResponse:
- _ensure_run_exists(run_id)
- return RunSummaryResponse(**service.get_summary(run_id))
- @app.get("/runs/{run_id}/discovered-content-items", response_model=RecordsResponse)
- def get_discovered_content_items(run_id: str) -> RecordsResponse:
- return _jsonl_response(run_id, "discovered_content_items.jsonl")
- @app.get("/runs/{run_id}/rule-decisions", response_model=RecordsResponse)
- def get_rule_decisions(run_id: str) -> RecordsResponse:
- return _jsonl_response(run_id, "rule_decisions.jsonl")
- @app.get("/runs/{run_id}/source-path-records", response_model=RecordsResponse)
- def get_source_path_records(run_id: str) -> RecordsResponse:
- return _jsonl_response(run_id, "source_path_records.jsonl")
- @app.get("/runs/{run_id}/final-output", response_model=JsonFileResponse)
- def get_final_output(run_id: str) -> JsonFileResponse:
- return _json_response(run_id, "final_output.json")
- @app.get("/runs/{run_id}/strategy-review", response_model=JsonFileResponse)
- def get_strategy_review(run_id: str) -> JsonFileResponse:
- _ensure_run_exists(run_id)
- return JsonFileResponse(run_id=run_id, data=service.strategy_review(run_id))
- @app.post("/runs/{run_id}/strategy-review/regenerate", response_model=JsonFileResponse)
- def regenerate_strategy_review(run_id: str) -> JsonFileResponse:
- _ensure_run_exists(run_id)
- return JsonFileResponse(run_id=run_id, data=service.regenerate_strategy_review(run_id))
- @app.get("/runs/{run_id}/validation", response_model=ValidationResponse)
- def get_validation(run_id: str) -> ValidationResponse:
- _ensure_run_exists(run_id)
- return ValidationResponse(**service.validate_run(run_id))
- def _jsonl_response(run_id: str, filename: str) -> RecordsResponse:
- _ensure_run_exists(run_id)
- return RecordsResponse(run_id=run_id, records=service.read_jsonl(run_id, filename))
- def _json_response(run_id: str, filename: str) -> JsonFileResponse:
- _ensure_run_exists(run_id)
- return JsonFileResponse(run_id=run_id, data=service.read_json(run_id, filename))
- def _ensure_run_exists(run_id: str) -> None:
- if not service.runtime.run_dir(run_id).exists():
- raise HTTPException(
- status_code=404,
- detail=error_response(
- ErrorCode.RUN_NOT_FOUND,
- "run not found",
- {"run_id": run_id},
- ),
- )
|