Merge remote-tracking branch 'origin/main' into fix/dependabot-security

This commit is contained in:
debpalash
2026-08-10 06:28:10 +00:00
4 changed files with 55 additions and 18 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+28 -8
View File
@@ -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():