FROM node:20-bookworm AS frontend WORKDIR /frontend COPY ./frontend/package*.json ./ RUN npm ci COPY ./frontend/index.html ./frontend/vite.config.js ./ COPY ./frontend/public ./public COPY ./frontend/src ./src RUN npm run build # ── PO Token provider (bgutil) ────────────────────────────────────────────── # YouTube chặn IP máy chủ ("bot check"). Provider này sinh Proof-of-Origin Token # để yt-dlp qua được — TỰ ĐỘNG, không cần cookies/tài khoản. Build sẵn ở đây. FROM node:20-bookworm AS potprovider WORKDIR /pot RUN git clone --depth 1 --single-branch --branch 1.3.1 \ https://github.com/Brainicism/bgutil-ytdlp-pot-provider.git . \ && cd server && npm ci && npx tsc FROM python:3.11-slim # libstdc++6: cần để chạy binary node copy từ tầng trên. # fontconfig: libass cần để nạp font ổn định (hết lỗi "Cannot load default config # file"); font phụ đề nhúng kèm ở backend/app/assets/fonts (nạp qua fontsdir). RUN apt-get update && apt-get install -y ffmpeg libstdc++6 fontconfig && rm -rf /var/lib/apt/lists/* # Node runtime + server provider (chạy nền cùng uvicorn, xem CMD) COPY --from=potprovider /usr/local/bin/node /usr/local/bin/node COPY --from=potprovider /pot/server /opt/bgutil/server ENV NUMBA_CACHE_DIR=/tmp/numba_cache ENV XDG_CACHE_HOME=/tmp/hf_cache ENV HF_HOME=/tmp/hf_cache WORKDIR /app # Cài torch/torchaudio bản CPU-ONLY (~200MB) TRƯỚC — mặc định `pip install torch` # (do demucs kéo vào) tải bản CUDA ~2.5GB vô dụng trên CPU Space, làm build cực chậm. # Cài CPU trước -> demucs thấy torch đã có, không tải bản CUDA nữa. RUN pip install --no-cache-dir torch torchaudio --index-url https://download.pytorch.org/whl/cpu COPY backend/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # ── OmniVoice (TTS clone giọng cho en/fil) ───────────────────────────────── # Cài TÁCH RIÊNG và --no-deps: metadata của `omnivoice` khai cả `gradio`, # `webdataset`, `tensorboardx` — chỉ dùng cho demo UI + huấn luyện, đường suy # luận KHÔNG import tới. Cài trọn bộ thì gradio kéo theo fastapi/starlette/ # uvicorn/pydantic bản khác ĐÈ LÊN web stack đang chạy (đã thử dựng cây phụ # thuộc: gradio 6 kéo starlette 1.x, fastapi 0.141 — nhảy cả major). # Các gói dưới đây là đúng những thứ omnivoice import lúc suy luận. RUN pip install --no-cache-dir "transformers>=5.3" accelerate soundfile pydub librosa && pip install --no-cache-dir --no-deps omnivoice # CHỐT AN TOÀN: gãy web stack thì HỎNG BUILD ở đây, đừng để chết lúc chạy. RUN python -c "import fastapi, pydantic, cv2, numpy, gradio_client, transformers, omnivoice; print('deps ok:', fastapi.__version__, pydantic.VERSION, numpy.__version__, transformers.__version__)" # Trọng số (~3.3GB) KHÔNG nhúng vào ảnh — tải lúc khởi động, chạy nền trong # warm_voice_previews (mạng nội bộ HF rất nhanh), nên job đầu tiên khỏi phải chờ. COPY ./backend ./backend # Cài font phụ đề nhúng vào hệ thống + cập nhật cache fontconfig -> libass tìm # được theo family name ("Be Vietnam Pro"...) trên server Linux (không có font # Microsoft). Đây là bộ font mà trình duyệt cũng nạp qua /fonts -> render KHỚP # xem trước. (burn() còn dùng thêm fontsdir cho môi trường dev.) RUN mkdir -p /usr/share/fonts/truetype/tnt \ && cp ./backend/app/assets/fonts/*.ttf /usr/share/fonts/truetype/tnt/ \ && fc-cache -f /usr/share/fonts/truetype/tnt COPY --from=frontend /frontend/dist ./frontend/dist ENV PORT=7860 EXPOSE 7860 # Chạy PO Token provider ở NỀN (cổng mặc định 4416) rồi mới chạy web. # Provider lỗi/không chạy -> uvicorn vẫn lên bình thường (chỉ mất PO Token). # # --timeout-keep-alive 120: KHÔNG phải tinh chỉnh vặt. Router của HF giữ sẵn một # nắm kết nối tới app rồi dùng lại. Mặc định uvicorn đóng kết nối rảnh sau 5 # GIÂY, nên router thường xuyên gửi request vào một kết nối vừa bị đóng -> nó # trả 502 kèm trang HTML của huggingface.co, request chưa hề tới app. Đo thực tế # trên Space: 5/20 lời gọi API dính 502 kiểu này, và chính nó đẻ ra lỗi # "Unexpected token '<'" mà người dùng gặp. Để ngưỡng cao hơn hẳn thời gian rảnh # của router thì bên đóng kết nối là router, đóng đàng hoàng từ phía nó. CMD ["sh", "-c", "node /opt/bgutil/server/build/main.js --port 4416 >/tmp/potprovider.log 2>&1 & exec uvicorn backend.app.main:app --host 0.0.0.0 --port 7860 --timeout-keep-alive 120"]