Files
audio2text/app/models/upload_session.py
audio2text dev 73110848f4 feat: 调度器+并发管线+GPU优化+日志分级+前端修复
- 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: 安装时预下载模型权重
2026-07-06 21:59:59 +08:00

62 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""分片上传会话 ORM支撑断点续传。"""
from __future__ import annotations
import json
import logging
from datetime import datetime, timezone
from typing import Any
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, TypeDecorator
from sqlalchemy.orm import Mapped, mapped_column
from ..database import Base
logger = logging.getLogger("audio2text.models")
def _now() -> datetime:
return datetime.now(timezone.utc)
class _IntList(TypeDecorator):
"""把 list[int] 存成 JSON 字符串。SQLite 没有 ARRAY 类型。"""
impl = Text
cache_ok = True
def process_bind_param(self, value: Any, dialect) -> str | None:
return json.dumps(value) if value is not None else None
def process_result_value(self, value: Any, dialect) -> list[int]:
if not value:
return []
try:
return json.loads(value)
except (json.JSONDecodeError, TypeError):
# DB 脏数据(手工修改/并发写截断)不应让整行读取失败
logger.warning("uploaded_chunks JSON 解析失败,回退空列表:%r", value[:80])
return []
class UploadSession(Base):
__tablename__ = "upload_session"
upload_id: Mapped[str] = mapped_column(String(64), primary_key=True)
filename: Mapped[str] = mapped_column(String(512), nullable=False)
size_bytes: Mapped[int] = mapped_column(Integer, nullable=False)
chunk_size: Mapped[int] = mapped_column(Integer, nullable=False)
total_chunks: Mapped[int] = mapped_column(Integer, nullable=False)
uploaded_chunks: Mapped[list[int]] = mapped_column(_IntList, default=list)
# pending → completedcomplete 成功)| abandonedreaper 清理)
status: Mapped[str] = mapped_column(String(32), nullable=False, default="pending", index=True)
# 拼接完成后的视频相对 upload_dir 路径
final_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)
# complete 后关联的 Task.id。ondelete=SET NULLTask 被删时 session 保留task_id 置空)
task_id: Mapped[int | None] = mapped_column(
ForeignKey("task.id", ondelete="SET NULL"), nullable=True
)
created_at: Mapped[datetime] = mapped_column(DateTime, default=_now, index=True)
updated_at: Mapped[datetime] = mapped_column(DateTime, default=_now, onupdate=_now)