| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- from __future__ import annotations
- from datetime import datetime
- from typing import Any, Literal
- from fastapi import APIRouter, HTTPException, Query, Request
- from pydantic import BaseModel, Field
- from api.services.business_harness import (
- get_platform_demand_history,
- get_published_demand_package,
- )
- from supply_infra.business_harness.content_feedback import (
- ingest_content_performance_fact,
- )
- from supply_infra.business_harness.feedback import process_feedback
- from supply_infra.business_harness.strategy import (
- approve_strategy_proposal,
- create_strategy_proposal,
- preview_strategy_proposal,
- )
- router = APIRouter(prefix="/api/business-harness", tags=["business-harness"])
- class ProcessFeedbackBody(BaseModel):
- status: Literal["accepted", "rejected", "needs_evidence"]
- reason: str = Field(min_length=1, max_length=2000)
- impact: dict[str, Any] | None = None
- class ContentPerformanceBody(BaseModel):
- content_id: str = Field(min_length=1, max_length=128)
- biz_dt: str = Field(pattern=r"^\d{8}$")
- source: str = Field(min_length=1, max_length=64)
- raw_payload: dict[str, Any] = Field(default_factory=dict)
- observed_at: datetime
- exposure_count: int | None = Field(default=None, ge=0)
- sample_size: int | None = Field(default=None, ge=0)
- content_quality: float | None = Field(default=None, ge=0, le=1)
- rov: float | None = None
- vov: float | None = None
- class StrategyProposalBody(BaseModel):
- requested_change: dict[str, Any]
- reason: str = Field(min_length=1, max_length=2000)
- @router.get("/packages/latest")
- def latest_package(
- biz_dt: str | None = Query(default=None, pattern=r"^\d{8}$"),
- run_id: str | None = None,
- ) -> dict:
- result = get_published_demand_package(biz_dt=biz_dt, run_id=run_id)
- if result is None:
- raise HTTPException(status_code=404, detail="published demand package not found")
- return result
- @router.get("/demands/{platform_demand_id}/history")
- def demand_history(platform_demand_id: str) -> dict:
- result = get_platform_demand_history(platform_demand_id)
- if result is None:
- raise HTTPException(status_code=404, detail="platform demand not found")
- return result
- @router.post("/feedback/{feedback_id}/process")
- def review_feedback(
- feedback_id: int,
- body: ProcessFeedbackBody,
- request: Request,
- ) -> dict:
- try:
- return process_feedback(
- feedback_id,
- status=body.status,
- processor=str(request.state.current_user["username"]),
- reason=body.reason,
- impact=body.impact,
- )
- except LookupError as exc:
- raise HTTPException(status_code=404, detail=str(exc)) from exc
- except RuntimeError as exc:
- raise HTTPException(status_code=409, detail=str(exc)) from exc
- @router.post("/content-performance")
- def ingest_content_performance(body: ContentPerformanceBody) -> dict:
- return ingest_content_performance_fact(**body.model_dump())
- @router.post("/strategy/proposals")
- def propose_strategy(body: StrategyProposalBody, request: Request) -> dict:
- try:
- return create_strategy_proposal(
- requested_change=body.requested_change,
- reason=body.reason,
- created_by=str(request.state.current_user["username"]),
- )
- except (ValueError, RuntimeError) as exc:
- raise HTTPException(status_code=409, detail=str(exc)) from exc
- @router.post("/strategy/proposals/{proposal_id}/preview")
- def preview_strategy(proposal_id: str) -> dict:
- try:
- return preview_strategy_proposal(proposal_id)
- except LookupError as exc:
- raise HTTPException(status_code=404, detail=str(exc)) from exc
- except RuntimeError as exc:
- raise HTTPException(status_code=409, detail=str(exc)) from exc
- @router.post("/strategy/proposals/{proposal_id}/approve")
- def approve_strategy(proposal_id: str, request: Request) -> dict:
- try:
- return approve_strategy_proposal(
- proposal_id,
- approved_by=str(request.state.current_user["username"]),
- )
- except LookupError as exc:
- raise HTTPException(status_code=404, detail=str(exc)) from exc
- except RuntimeError as exc:
- raise HTTPException(status_code=409, detail=str(exc)) from exc
|