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: 安装时预下载模型权重
This commit is contained in:
audio2text dev
2026-07-06 21:59:59 +08:00
parent 00e2a95fb7
commit 73110848f4
30 changed files with 1238 additions and 259 deletions

View File

@@ -1,44 +1,81 @@
# syntax=docker/dockerfile:1.7
# audio2text — 一份 DockerfileCPU(dev) / GPU(prod) 双形态。
# docker build --build-arg VARIANT=cpu -t audio2text:cpu .
# docker build --build-arg VARIANT=gpu -t audio2text:gpu .
# 区别仅在基础镜像与 torch 轮子Python 依赖列表完全一致。
# docker compose --profile dev up -d --build # 开发dev target + 源码挂载 + reload
#
# 分层目标:依赖层(deps)稳定固化,代码层(final/dev)在最末,改代码不重装依赖。
# BuildKit 缓存挂载(--mount=type=cache)pip wheel 跨构建复用,二次构建秒级。
#
# 安全约束PyTorch CPU wheel 与 GPU(CUDA) wheel 是两个不兼容二进制包。
# - CPU 版 torch.cuda.is_available()=FalseCPU 预期)
# - GPU 版 torch.cuda.is_available()=TrueGPU 可调度)
# 因此 torch 必须按 VARIANT 分叉装不同 wheel绝不能跨 variant 共享依赖层。
# deps 阶段用 FROM base-${VARIANT}CPU/GPU 是两条独立构建链,各自装对应 torch。
ARG VARIANT=cpu
# ---------------------------------------------------------------------------
# 1. 基础镜像分叉CPU 用 slim PythonGPU 用 CUDA runtime + 手动装 python3.12
# ---------------------------------------------------------------------------
FROM python:3.12-slim AS base-cpu
# GPU 基础镜像带 CUDA 运行时torch 可装 CUDA 轮子
FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04 AS base-gpu
# Ubuntu 22.04 默认源只有 python3.10/3.11,需加 deadsnakes PPA 才能装 python3.12。
# 注意:不能用 python3-pip那是 3.10 的系统 pip会把包装到 3.10 site-packages
# 用 python3.12 -m ensurepip 给 3.12 装 pip确保所有包进 3.12 目录。
# DEBIAN_FRONTEND=noninteractive 避免 tzdata 等包进入交互式配置卡住构建。
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y && apt-get install -y --no-install-recommends \
python3.12 python3.12-venv python3.12-dev python3-pip \
software-properties-common gnupg ca-certificates \
&& add-apt-repository -y ppa:deadsnakes/ppa \
&& apt-get update -y && apt-get install -y --no-install-recommends \
python3.12 python3.12-venv python3.12-dev \
&& rm -rf /var/lib/apt/lists/* \
&& ln -sf /usr/bin/python3.12 /usr/local/bin/python3 \
&& ln -sf /usr/bin/python3.12 /usr/local/bin/python
&& ln -sf /usr/bin/python3.12 /usr/local/bin/python \
&& python3 -m ensurepip \
&& python3 -m pip install --upgrade pip
FROM base-${VARIANT} AS final
# ---------------------------------------------------------------------------
# 2. deps系统依赖 + Python 依赖(含 torch。CPU/GPU 各自一条独立链。
# final / dev 都 FROM deps继承对应 variant 的 torch不串。
# ---------------------------------------------------------------------------
FROM base-${VARIANT} AS deps
ARG VARIANT
ENV VARIANT=${VARIANT} \
PYTHONUNBUFFERED=1 \
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
HF_HOME=/models/huggingface \
CT2_CACHE=/models/ctranslate2
# ffmpeg 是核心系统依赖,必须装
RUN apt-get update -y && apt-get install -y --no-install-recommends \
# ffmpeg 是核心系统依赖patchelf 用于修复 ctranslate2 可执行栈
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update -y && apt-get install -y --no-install-recommends \
ffmpeg ca-certificates patchelf \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt /app/requirements.txt
# CPU 装 CPU 版 torchGPU 走默认 index带 CUDA 的轮子)
RUN if [ "$VARIANT" = "cpu" ]; then \
pip install --upgrade pip && \
# 【顺序关键】必须先装 torch按 VARIANT 分叉),再装 requirements。
# 原因requirements 里的 transformers / accelerate 依赖 torch若先装 requirements
# pip 会从默认 PyPI 拉来 GPU 版 torch + nvidia-* 全家桶(~2GB即使后续覆盖装 CPU torch
# 那些无用的 nvidia 包仍残留在镜像里。先装 torch 让 pip 解析 requirements 时 torch 已满足。
#
# CPU 走 cpu index~200MB无 nvidia 依赖GPU 走默认 PyPI带 CUDA~2.5GB)。
# 两套 wheel 二进制不兼容CPU 版 cuda.is_available()=FalseGPU 版 =True。不可共享。
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install --upgrade pip && \
if [ "$VARIANT" = "cpu" ]; then \
pip install torch --index-url https://download.pytorch.org/whl/cpu ; \
else \
pip install --upgrade pip && \
pip install torch ; \
fi
RUN pip install -r /app/requirements.txt
# torch 已就位requirements 里的 transformers/accelerate 解析时复用已装 torch不重复拉
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install -r /app/requirements.txt
# ctranslate2 的 .so 带可执行栈标志PT_GNU_STACK X在某些内核 + Docker 组合下
# 会触发 "cannot enable executable stack as shared object requires"。用 patchelf
@@ -51,13 +88,37 @@ RUN for d in /usr/local/lib/python3.12/site-packages/ctranslate2.libs \
done; \
python -c "import ctranslate2; print('ctranslate2 stack fix verified', ctranslate2.__version__)"
# ---------------------------------------------------------------------------
# 3. dev从 deps 继承依赖,不 COPY 代码compose 用 volume 挂载源码)。
# 开启 uvicorn --reload改代码零重建、保存即生效。
# 注意dev 必须在 final 之前,保证 `docker build` 默认 target 是 final。
# ---------------------------------------------------------------------------
FROM deps AS dev
VOLUME ["/data", "/models"]
# ctranslate2/faster-whisper 用系统动态链接器找 cuDNN不走 torch 的库加载),
# 需把 torch wheel 自带的 nvidia 库目录加入 LD_LIBRARY_PATH否则 GPU 推理报
# "Unable to load libcudnn_ops.so.9"。放在 final/dev 而非 deps避免 ENV 变化
# 导致 deps 的 apt/pip 层缓存失效。CPU 镜像无此目录,路径被忽略不影响。
ENV CONFIG_PATH=/app/config.yaml \
LD_LIBRARY_PATH=/usr/local/lib/python3.12/site-packages/nvidia/cudnn/lib:/usr/local/lib/python3.12/dist-packages/nvidia/cudnn/lib:/usr/local/lib/python3.12/site-packages/nvidia/cublas/lib:/usr/local/lib/python3.12/dist-packages/nvidia/cublas/lib
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
# ---------------------------------------------------------------------------
# 4. finalprod从 deps 继承全部依赖,只加 app 代码。
# 放在最后 = `docker build` 默认 target。setup.sh / start.sh 依赖此默认行为。
# ---------------------------------------------------------------------------
FROM deps AS final
COPY app /app/app
COPY scripts /app/scripts
COPY config.example.yaml /app/config.example.yaml
# 运行时数据:上传 / 中间产物 / 输出字幕 / 模型缓存
# 全部走 volume镜像本身无状态、无敏感数据
VOLUME ["/data", "/models"]
ENV CONFIG_PATH=/app/config.yaml
ENV CONFIG_PATH=/app/config.yaml \
LD_LIBRARY_PATH=/usr/local/lib/python3.12/site-packages/nvidia/cudnn/lib:/usr/local/lib/python3.12/dist-packages/nvidia/cudnn/lib:/usr/local/lib/python3.12/site-packages/nvidia/cublas/lib:/usr/local/lib/python3.12/dist-packages/nvidia/cublas/lib
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]