Files
john 1aaef71f52 Initial commit: Happy Up monorepo through Sprint 5.
Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:42:40 +08:00

91 lines
2.9 KiB
Python

from fastapi import APIRouter, Depends, Request, Response
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session
from app.core.response import error, ok
from app.db.models import User
from app.db.session import get_db
from app.deps import get_current_user
from app.schemas.models import AnalysisTaskCreateRequest, AnalysisTaskWebhook
from app.services import analysis as analysis_service
router = APIRouter(prefix="/api/analysis", tags=["Analysis"])
@router.post("/tasks", status_code=201)
def create_task(
body: AnalysisTaskCreateRequest,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
idempotency_key = request.headers.get("Idempotency-Key")
task, err, duplicate = analysis_service.create_analysis_task(
db, current_user.id, body, idempotency_key
)
if err == "child_not_found":
return JSONResponse(
status_code=404,
content=error(10004, "child_not_found", request.state.request_id),
)
if err == "video_not_found":
return JSONResponse(
status_code=404,
content=error(10006, "video_not_found", request.state.request_id),
)
if err == "duplicate" and duplicate:
return JSONResponse(
status_code=409,
content=ok(
analysis_service.task_to_dict(duplicate),
message="duplicate_task",
request_id=request.state.request_id,
),
)
return ok(
analysis_service.task_to_dict(task),
message="created",
request_id=request.state.request_id,
)
@router.get("/tasks/{task_id}")
def get_task(
task_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
task = analysis_service.get_task_for_user(db, current_user.id, task_id)
if not task:
return JSONResponse(
status_code=404,
content=error(10007, "task_not_found", request.state.request_id),
)
return ok(analysis_service.task_to_dict(task), request_id=request.state.request_id)
@router.post("/tasks/{task_id}/cancel")
def cancel_task(
task_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
task = analysis_service.cancel_task(db, current_user.id, task_id)
if not task:
return JSONResponse(
status_code=404,
content=error(10007, "task_not_found", request.state.request_id),
)
return ok(
{"taskId": task_id, "status": task.status},
request_id=request.state.request_id,
)
@router.post("/webhook", status_code=204)
def analysis_webhook(body: AnalysisTaskWebhook, db: Session = Depends(get_db)):
analysis_service.handle_webhook(db, body.task_id, body.status.value)
return Response(status_code=204)