Initial commit: audio2text 双语字幕生成服务

- 音频/视频转双语(英/中)SRT 字幕,Docker 容器化,CPU 开发/GPU 生产同一份代码
- faster-whisper ASR(词级时间戳) + 断句时间戳重算 + NLLB 翻译(模型不共驻)
- 分片上传(断点续传) + SQLite 持久化 + 主页/历史/日志页面
- 历史页文件名搜索;缓存定时清理(默认保留7天,可配置)
- 双 Dockerfile(cpu/gpu) + setup/start/stop 脚本
This commit is contained in:
2026-07-06 06:54:19 +00:00
commit 00e2a95fb7
44 changed files with 4110 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
"""分片上传路由:建会话 / 查状态 / 传分片 / 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_idenqueue 幂等无副作用)
from ..services.pipeline import enqueue_task
enqueue_task(resp.task_id)
return resp