- 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: 安装时预下载模型权重
58 lines
2.5 KiB
Python
58 lines
2.5 KiB
Python
"""Task ORM:一个上传完成的视频对应一个转写任务,承载状态机。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from datetime import datetime, timezone
|
||
|
||
from sqlalchemy import DateTime, Float, Integer, String, Text
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from ..database import Base
|
||
|
||
|
||
def _now() -> datetime:
|
||
return datetime.now(timezone.utc)
|
||
|
||
|
||
# 任务状态枚举(单一真源,供 scheduler / cache_cleaner / views 引用)
|
||
STATUS_UPLOADING = "uploading" # 虚拟状态:分片上传中(不在 Task 表,由 UploadSession 映射)
|
||
STATUS_QUEUED = "queued"
|
||
STATUS_EXTRACTING = "extracting"
|
||
STATUS_TRANSCRIBING = "transcribing"
|
||
STATUS_SEGMENTING = "segmenting"
|
||
STATUS_TRANSLATING = "translating"
|
||
STATUS_DONE = "done"
|
||
STATUS_FAILED = "failed"
|
||
|
||
|
||
class Task(Base):
|
||
__tablename__ = "task"
|
||
|
||
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
||
# 原始视频文件名(用户上传时的名字)
|
||
filename: Mapped[str] = mapped_column(String(512), nullable=False)
|
||
# 视频在 upload_dir 下的相对路径(提取音频前后可能被删)
|
||
source_path: Mapped[str] = mapped_column(String(1024), nullable=False)
|
||
# 状态机:queued → extracting → transcribing → segmenting → translating → done | failed
|
||
status: Mapped[str] = mapped_column(String(32), nullable=False, default=STATUS_QUEUED, index=True)
|
||
# 0-100 进度
|
||
progress: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
||
# 失败原因
|
||
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
# 输出字幕路径(双语合并 / 英文 / 中文)
|
||
bilingual_srt_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||
en_srt_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||
zh_srt_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||
|
||
# ---- 流水线阶段间传递的中间数据(scheduler 调度用)----
|
||
# ffmpeg 提取出的 wav 绝对路径(extract 阶段写,asr 阶段读)
|
||
wav_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
|
||
# ASR + 断句结果(asr 阶段写 JSON,translate 阶段读)。JSON 序列化的 list[Subtitle]
|
||
segments_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||
|
||
created_at: Mapped[datetime] = mapped_column(DateTime, default=_now, index=True)
|
||
updated_at: Mapped[datetime] = mapped_column(DateTime, default=_now, onupdate=_now)
|
||
|
||
def __repr__(self) -> str:
|
||
return f"<Task id={self.id} {self.filename} status={self.status}>"
|