"""分片上传路由:建会话 / 查状态 / 传分片 / complete。 协议与 server 完全一致,区别仅在 complete 后创建的是转写 Task 而非 UploadedFile。 """ from __future__ import annotations from fastapi import APIRouter, Depends, Request from sqlalchemy.orm import Session from ..database import get_db from ..schemas.task import ( ChunkUploadResponse, CompleteResponse, CreateSessionRequest, CreateSessionResponse, SessionStatusResponse, ) from ..services.upload_service import UploadService router = APIRouter(prefix="/api/tasks/chunk-uploads", tags=["upload"]) def _service(db: Session = Depends(get_db)) -> UploadService: return UploadService(db) @router.post("", response_model=CreateSessionResponse, summary="创建分片上传会话") def create_session( body: CreateSessionRequest, service: UploadService = Depends(_service), ) -> CreateSessionResponse: return service.create_session(body) @router.get("/{upload_id}/status", response_model=SessionStatusResponse, summary="查询会话状态(断点续传)") def session_status( upload_id: str, service: UploadService = Depends(_service), ) -> SessionStatusResponse: return service.get_status(upload_id) @router.post("/{upload_id}/chunks/{index}", response_model=ChunkUploadResponse, summary="上传单个分片") async def upload_chunk( upload_id: str, index: int, request: Request, service: UploadService = Depends(_service), ) -> ChunkUploadResponse: uploaded = service.write_chunk(upload_id, index, await request.body()) return ChunkUploadResponse(upload_id=upload_id, index=index, uploaded_chunks=uploaded) @router.post("/{upload_id}/complete", response_model=CompleteResponse, summary="完成拼接并创建转写任务") def complete_session( upload_id: str, service: UploadService = Depends(_service), ) -> CompleteResponse: """拼接分片 + 创建转写任务 + 入队管线。 controller 负责编排:service.complete 只管存储(拼接 + 建 Task), 管线触发由 controller 调用,service 不依赖 pipeline(避免循环依赖)。 """ resp = service.complete(upload_id) # 仅新建任务时入队(幂等 complete 返回的也是同一 task_id,enqueue 幂等无副作用) from ..services.pipeline import enqueue_task enqueue_task(resp.task_id) return resp