virtual-class / Dockerfile
tourmii's picture
prebuild voice
2c27e53
Raw
History Blame Contribute Delete
4.13 kB
# Dockerfile cho Hugging Face Spaces (SDK: docker).
#
# HF Spaces build với context = gốc repo và đọc chính file Dockerfile này. Free
# tier: 16 GB RAM, 2 vCPU, đĩa KHÔNG bền (mất khi rebuild/restart) — nên mọi thứ
# nặng phải được nướng sẵn vào image, không trông chờ volume như docker-compose.
#
# Khác bản backend/Dockerfile ở đúng một chỗ: PREBUILD_AUDIO mặc định = 1, nên
# lúc build sẽ tải model VieNeu (~1 GB) và dựng sẵn toàn bộ giọng vào image. Nhờ
# vậy runtime không phải tải model hay chờ tổng hợp — câu đầu tiên nói ngay.
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /srv
# ffmpeg: nén audio về MP3 thay vì WAV 48 kHz, và đổi tốc độ đọc mà không lệch
# cao độ giọng. Thiếu nó vẫn chạy được, chỉ là mỗi câu nặng gấp ~50 lần.
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
&& rm -rf /var/lib/apt/lists/*
COPY backend/requirements.txt ./requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# torch + torchaudio bản CUDA cho đường GPU của VieNeu v3-Turbo. Wheel cu121 gói
# sẵn CUDA nên KHÔNG cần base image nvidia/cuda — chỉ cần driver của Space GPU.
# Runtime tự dò GPU (VIENEU_DEVICE=auto); lúc build không có GPU nên prebuild vẫn
# chạy đường ONNX/CPU bình thường.
COPY backend/requirements-gpu.txt ./requirements-gpu.txt
RUN pip install --no-cache-dir -r requirements-gpu.txt
COPY backend/app ./backend/app
COPY content ./content
COPY frontend ./frontend
COPY scripts ./scripts
# HF Spaces khuyến nghị chạy bằng user id 1000. Cả hai thư mục cache phải tồn tại
# và do chính user này sở hữu trước khi đổi USER, nếu không:
# - ~/.cache/huggingface: model VieNeu không tải về được.
# - /srv/content/.audio-cache: audio_cache.put() nuốt OSError rồi mọi câu bị
# tổng hợp lại từ đầu mãi mãi mà nhìn ngoài vẫn thấy "chạy bình thường".
RUN useradd --create-home --uid 1000 user \
&& mkdir -p /home/user/.cache/huggingface /srv/content/.audio-cache \
&& chown -R 1000:1000 /home/user /srv/content
USER user
ENV HOME=/home/user \
HF_HOME=/home/user/.cache/huggingface
# Nướng SẴN trọng số model (KHÔNG nướng audio). Tải sẵn trọng số PyTorch mà GPU
# dùng để cold-start khỏi kéo ~1 GB. Build không có GPU nên nạp trên CPU chỉ cốt
# kích hoạt tải về; lỗi cũng không sao — runtime sẽ tự tải.
ARG BAKE_MODEL=1
RUN if [ "$BAKE_MODEL" = "1" ]; then \
python -c "from vieneu import Vieneu; Vieneu(device='cpu', backend='pytorch')" \
|| echo "Bỏ qua nướng model — sẽ tải lúc chạy."; \
fi
# KHÔNG dựng audio ở build nữa: bước đó chậm và bắt buộc chạy CPU (build không có
# GPU). Thay vào đó PREBUILD_ON_BOOT=1 dựng 242 câu TRÊN GPU lúc khởi động, luồng
# nền, ~1-2 phút. Vẫn giữ đường nướng-lúc-build cho ai deploy CPU: --build-arg
# PREBUILD_AUDIO=1.
ARG PREBUILD_AUDIO=0
ARG SPEECH_PROVIDER=vieneu
ARG VIENEU_VOICE="Minh Đức"
RUN if [ "$PREBUILD_AUDIO" = "1" ]; then \
SPEECH_PROVIDER="$SPEECH_PROVIDER" VIENEU_VOICE="$VIENEU_VOICE" \
python scripts/prebuild_audio.py; \
fi
WORKDIR /srv/backend
# HF Spaces đặt cổng qua app_port trong README (ta chọn 7860). Vẫn nhận $PORT nếu
# host nào đó (Railway/Render) tự tiêm — cùng một image chạy được nhiều nơi.
ENV PORT=7860 \
SPEECH_PROVIDER=vieneu \
VIENEU_VOICE="Minh Đức" \
VIENEU_DEVICE=auto \
PREBUILD_ON_BOOT=1
EXPOSE 7860
# /api/health trả lời ngay cả khi model đang nạp (nạp chạy ở thread riêng).
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s \
CMD python -c "import os,urllib.request;urllib.request.urlopen(f\"http://127.0.0.1:{os.getenv('PORT','7860')}/api/health\")"
CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860}"]