- scheduler: ffmpeg 异步线程 + GPU 串行调度 + 模型复用(2N→2 次加载) - pipeline: 阶段拆分(extract/asr/translate),中间数据存 Task 字段 - translate_service: 长度排序批处理,padding 浪费减少 91% - model_manager: ASR/翻译不共驻,BatchedInferencePipeline 批量解码 - 日志分级: INFO=任务流转里程碑,DEBUG=进度详情;默认 INFO - 前端: 日志最新在上+滚动感知+退避轮询;24h 时间;上传中状态显示 - /health: 返回完整 Whisper/NLLB 配置 - upload_service: 单事务 complete + 扩展名白名单 - task_router: 合并 UploadSession 虚拟任务到列表 - Dockerfile: CPU/GPU 独立构建链,deps 缓存稳定 - prefetch_models: 安装时预下载模型权重
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
"""分片上传路由:建会话 / 查状态 / 传分片 / complete。
|
||
|
||
complete 成功后创建转写 Task 并交由 scheduler 入队。
|
||
"""
|
||
|
||
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 调用 scheduler(ffmpeg 异步 + GPU 串行调度),service 不依赖
|
||
scheduler(避免循环依赖)。
|
||
"""
|
||
resp = service.complete(upload_id)
|
||
# 仅新建任务时入队(幂等 complete 返回的也是同一 task_id,enqueue 幂等无副作用)
|
||
from ..services.scheduler import enqueue_task
|
||
enqueue_task(resp.task_id)
|
||
return resp
|