Merge remote-tracking branch 'origin/main' into fix/dependabot-security
This commit is contained in:
@@ -44,6 +44,7 @@ The bundled TTS model package (`pyproject.toml`) is versioned independently.
|
||||
- Patched dependency releases now cover 35 Python and Rust security advisories without weakening VoiceStudio's GPU or offline-runtime compatibility. (#1456, #1472, #1473, #1474, #1475, #1476, #1477)
|
||||
- YouTube imports that require a signed-in session can now use an explicitly selected `cookies.txt` export for one import; VoiceStudio never reads browser cookies silently and makes two best-effort attempts to delete its temporary copy. (#1429, #1432) — thanks @dongqing1968-sudo and @phamvandu9595-tech!
|
||||
- First-run source builds no longer stop after uv was successfully downloaded just because its installer failed during a later shell-profile step; app-private uv installs no longer touch shell profiles at all. (#1438) — thanks @AdrianoCahete!
|
||||
- ROCm Docker now installs and starts the backend with the same Python whose AMD torch build was validated, instead of launching a second CUDA-only environment and silently running on CPU. (#1274) — thanks @simmessa and @spicchio72!
|
||||
- An error whose text merely contained the digits 401 — a file path, a byte count, a job id — no longer tells you to fix your Hugging Face token. (#1427)
|
||||
- Custom MLX model IDs and saved voice instructions are now validated in bounded time, so malformed input cannot stall the backend. (#1446)
|
||||
- Streaming and provider failures now return stable recovery guidance without exposing exception details. (#1462)
|
||||
|
||||
+13
-7
@@ -32,7 +32,6 @@ WORKDIR /app
|
||||
# Enable unbuffered logs and optimizations
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV UV_SYSTEM_PYTHON=1
|
||||
ENV HF_HOME=/app/omnivoice_data/huggingface
|
||||
# Allow bare imports (from core.config, from services.*, etc.) when
|
||||
# uvicorn is started as `backend.main:app` from WORKDIR /app.
|
||||
@@ -54,9 +53,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# PEP 668: the ROCm base (Ubuntu 24.04) marks its system Python
|
||||
# EXTERNALLY-MANAGED, which would refuse `pip install` / `uv pip install
|
||||
# --system`. Inside a single-purpose container image installing into the
|
||||
# base env is exactly what we want. No-ops on the conda-based CUDA image.
|
||||
# EXTERNALLY-MANAGED, which would refuse installing into the selected base
|
||||
# interpreter. Inside a single-purpose container image that is exactly what
|
||||
# we want. No-ops on the conda-based CUDA image.
|
||||
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
||||
ENV UV_BREAK_SYSTEM_PACKAGES=1
|
||||
|
||||
@@ -71,6 +70,11 @@ COPY deploy/torch-constraints.txt ./deploy/torch-constraints.txt
|
||||
# Install the project (non-editable — no need for -e in containers).
|
||||
# Uses `uv` for exponentially faster resolution than plain pip.
|
||||
#
|
||||
# Target the exact interpreter selected by the base image. The ROCm image has
|
||||
# both /opt/venv/bin/python3 (ROCm torch) and /usr/bin/python (a CUDA-default
|
||||
# environment); `--system` used the latter while the build guard used the
|
||||
# former, so a green image launched a CPU-only backend on AMD (#1274).
|
||||
#
|
||||
# NOTE: `uv pip install` (without --upgrade) keeps already-installed packages
|
||||
# that satisfy the requirements, so the base image's GPU-built torch/torchaudio
|
||||
# (2.8.0, satisfying our `torch>=2.4`) survive this step instead of being
|
||||
@@ -83,7 +87,8 @@ COPY deploy/torch-constraints.txt ./deploy/torch-constraints.txt
|
||||
# stays put — an ABI mismatch at import (#1357). The pins carry no local
|
||||
# segment, so they match the base image's +cu128 / +rocm6.4 builds rather than
|
||||
# replacing them.
|
||||
RUN uv pip install --system --no-cache --constraint deploy/torch-constraints.txt .
|
||||
RUN uv pip install --python "$(command -v python3)" --no-cache \
|
||||
--constraint deploy/torch-constraints.txt .
|
||||
|
||||
# Guard (fails the build, not the user at runtime): assert the dependency
|
||||
# install did NOT replace the base image's GPU torch. A future dep bump that
|
||||
@@ -121,5 +126,6 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=120s --retries=5 \
|
||||
# Mount points for persistent data (sqlite db, user voices, huggingface cache)
|
||||
VOLUME ["/app/omnivoice_data"]
|
||||
|
||||
# Bind to 0.0.0.0 for external access
|
||||
ENTRYPOINT ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "3900"]
|
||||
# Bind to 0.0.0.0 for external access. `python3 -m` keeps runtime imports on
|
||||
# the same interpreter whose torch flavor the build guard validated (#1274).
|
||||
ENTRYPOINT ["python3", "-m", "uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "3900"]
|
||||
|
||||
+13
-3
@@ -109,16 +109,26 @@ the CUDA tags exactly.
|
||||
Verify the container sees the GPU:
|
||||
|
||||
```bash
|
||||
docker exec omnivoice python3 -c \
|
||||
"import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
|
||||
docker exec <container> python3 -c \
|
||||
"import torch; ok = torch.cuda.is_available(); print(ok, torch.cuda.get_device_name(0) if ok else 'unavailable')"
|
||||
```
|
||||
|
||||
Use `omnivoice` for the `docker run` examples above. Docker Compose names the
|
||||
ROCm container `omnivoice-studio-rocm` (CPU: `omnivoice-studio`, NVIDIA:
|
||||
`omnivoice-studio-gpu`); `docker compose ps` shows the exact active name.
|
||||
|
||||
(ROCm-built PyTorch reports through `torch.cuda.*` — `True` plus your card's
|
||||
name means torch can see the GPU.) That check alone isn't proof the app is
|
||||
using it: **Settings → System** shows the device VoiceStudio actually resolved.
|
||||
If it reads `cpu` while the command above prints `True`, the backend log line
|
||||
starting `Falling back to CPU:` names the architecture mismatch it hit.
|
||||
|
||||
The image installs and launches VoiceStudio through that same `python3`
|
||||
interpreter. To verify this invariant on an older or custom image, compare
|
||||
`docker exec <container> python3 -c "import sys, torch; print(sys.executable,
|
||||
torch.version.hip)"` with `docker exec <container> sh -c 'tr "\\0" " "
|
||||
</proc/1/cmdline'`; PID 1 must begin with `python3 -m uvicorn`.
|
||||
|
||||
If the command prints `False`, **Settings → System** now says why, and the
|
||||
three answers need different fixes:
|
||||
|
||||
@@ -203,7 +213,7 @@ Two paths are worth persisting across container restarts:
|
||||
pushes. Pull the image again after the fix is merged: `docker pull ghcr.io/debpalash/omnivoice-studio:latest`.
|
||||
The running version is now shown in **Settings → About → Version** (read live
|
||||
from the backend), so the web UI no longer displays a dash in Docker.
|
||||
- **Checking which version is running:** `docker exec omnivoice python -c "import importlib.metadata; print(importlib.metadata.version('omnivoice'))"`, or hit the `/health` endpoint — it returns `{"status": "ok", "device": ..., "version": "0.3.x"}`.
|
||||
- **Checking which version is running:** `docker exec <container> python3 -c "import importlib.metadata; print(importlib.metadata.version('omnivoice'))"`, or hit the `/health` endpoint — it returns `{"status": "ok", "device": ..., "version": "0.3.x"}`. Use the container name listed by `docker compose ps` (or `omnivoice` for the `docker run` examples).
|
||||
- **"Loopback origin required" errors (and a blank version):** the desktop
|
||||
build restricts the `/system/*` and `/api/settings/*` routes to a loopback
|
||||
origin, but Docker's NAT makes every request look non-loopback, so the gate
|
||||
|
||||
@@ -6,7 +6,7 @@ The coupling lives in `[tool.uv] constraint-dependencies`.
|
||||
|
||||
That setting is part of the **project** API — `uv sync`, `uv lock`, `uv run`.
|
||||
`uv pip install` is the pip-compatible interface and ignores it. Both install
|
||||
paths that use `uv pip install --system` (the Colab notebook and the Docker
|
||||
paths that use `uv pip install` (the Colab notebook and the Docker
|
||||
image) therefore resolved the trio on its bare lower bounds, free to upgrade
|
||||
torch while leaving a torchvision built against an older ABI in place:
|
||||
|
||||
@@ -99,13 +99,33 @@ def test_the_pins_carry_no_local_version(file_constraints):
|
||||
|
||||
def test_the_dockerfile_passes_the_constraint():
|
||||
text = _DOCKERFILE.read_text(encoding="utf-8")
|
||||
install = [ln for ln in text.splitlines() if "uv pip install" in ln and "--system" in ln]
|
||||
assert install, "no `uv pip install --system` line found in the Dockerfile"
|
||||
for line in install:
|
||||
assert "--constraint" in line and "torch-constraints.txt" in line, (
|
||||
f"Docker installs without the torch constraint, so the trio can "
|
||||
f"drift again:\n {line.strip()}"
|
||||
)
|
||||
install_start = text.index("RUN uv pip install")
|
||||
install_end = text.index("\n\n", install_start)
|
||||
install = text[install_start:install_end]
|
||||
assert "--constraint" in install and "torch-constraints.txt" in install, (
|
||||
"Docker installs without the torch constraint, so the trio can "
|
||||
f"drift again:\n{install}"
|
||||
)
|
||||
|
||||
|
||||
def test_docker_install_and_runtime_use_the_guarded_python():
|
||||
"""#1274: ROCm's `python3` had HIP torch, while `--system` installed and
|
||||
bare `uvicorn` launched through `/usr/bin/python` with CUDA torch."""
|
||||
text = _DOCKERFILE.read_text(encoding="utf-8")
|
||||
install_start = text.index("RUN uv pip install")
|
||||
install_end = text.index("\n\n", install_start)
|
||||
install = text[install_start:install_end]
|
||||
assert '--python "$(command -v python3)"' in install
|
||||
assert "--system" not in install
|
||||
assert 'ENTRYPOINT ["python3", "-m", "uvicorn"' in text
|
||||
|
||||
|
||||
def test_docker_docs_do_not_assume_the_run_name_for_compose():
|
||||
docs = (_ROOT / "docs" / "install" / "docker.md").read_text(encoding="utf-8")
|
||||
assert "docker exec <container> python3" in docs
|
||||
assert "torch.cuda.get_device_name(0) if ok else 'unavailable'" in docs
|
||||
for compose_name in ("omnivoice-studio", "omnivoice-studio-gpu", "omnivoice-studio-rocm"):
|
||||
assert compose_name in docs
|
||||
|
||||
|
||||
def test_the_dockerfile_copies_the_constraints_file():
|
||||
|
||||
Reference in New Issue
Block a user