diff --git a/docs/setup.md b/docs/setup.md index 53a6fb28c..e17276f7b 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -415,10 +415,19 @@ A grab-bag of small gotchas that otherwise turn into long debugging sessions. | Package | Feature unlocked | |---------|-----------------| | `faster-whisper` | Local speech-to-text (microphone -> text) via the "local" STT provider. | +| `kokoro`, `soundfile` | Local Kokoro-82M text-to-speech on a CUDA GPU. The pinned Kokoro release supports Odysseus installs on Python 3.11-3.12; these packages are intentionally skipped on Python 3.13+ (including the Python 3.14 container image). | | `ddgs` | DuckDuckGo as a search provider option. | | `PyMuPDF` | PDF page rendering in the side viewer panel and form-filling. (Note: AGPL-3.0) | | `markitdown` | Office/EPUB document text extraction (converts .docx/.xlsx/.pptx/.xls/.epub to Markdown). | +Install the optional set only when you need these features: + +```bash +pip install -r requirements-optional.txt +``` + +The default Docker image currently uses Python 3.14, while Kokoro 0.9.4 declares Python `>=3.10,<3.13`. Odysseus itself continues to support Python 3.11+, but this pinned optional local-TTS feature requires a native Python 3.11 or 3.12 environment. Kokoro declares `torch`, but the local provider only activates when that torch build has CUDA and a GPU is visible; install the CUDA build appropriate for your host. Browser and configured endpoint TTS remain available on Python 3.13+ and in the container image. + ### Faster, reproducible installs with uv (optional) [uv](https://docs.astral.sh/uv/) works as a drop-in replacement for the venv + pip steps in the native install guides, no project changes are needed but this change results in faster installs along with a lockfile for reproducible environments. After [installing `uv`](https://docs.astral.sh/uv/getting-started/installation/), use: diff --git a/requirements-optional.txt b/requirements-optional.txt index ab21e81ee..d2117432f 100644 --- a/requirements-optional.txt +++ b/requirements-optional.txt @@ -12,6 +12,16 @@ # GPU-accelerated transcription — it's auto-detected, CPU is used otherwise. faster-whisper +# Local text-to-speech via Kokoro-82M for the "local" TTS provider. +# Kokoro 0.9.4 declares Python >=3.10,<3.13; Odysseus itself requires 3.11+, +# so pip installs these extras on 3.11-3.12 and deliberately skips them on +# Python 3.13+ (including the Python 3.14 container image). Kokoro declares +# torch; the local provider still +# requires a CUDA-enabled torch build and GPU at runtime. SoundFile is separate +# in Kokoro's official install instructions and is not a transitive dependency. +kokoro==0.9.4; python_version >= "3.11" and python_version < "3.13" +soundfile; python_version >= "3.11" and python_version < "3.13" + # DuckDuckGo as a search provider option. # Install if you want DDG in the search-provider dropdown. # Alternatives: SearXNG, Brave, Tavily, Serper, Google PSE. diff --git a/tests/test_kokoro_optional_requirements.py b/tests/test_kokoro_optional_requirements.py new file mode 100644 index 000000000..53e670a03 --- /dev/null +++ b/tests/test_kokoro_optional_requirements.py @@ -0,0 +1,40 @@ +from pathlib import Path + +import pytest +from packaging.requirements import Requirement + + +ROOT = Path(__file__).resolve().parents[1] + + +def _optional_requirement(name): + lines = (ROOT / "requirements-optional.txt").read_text(encoding="utf-8").splitlines() + return Requirement(next(line for line in lines if line.startswith(name))) + + +def test_kokoro_optional_dependency_pins_the_verified_release(): + kokoro = _optional_requirement("kokoro") + + assert str(kokoro.specifier) == "==0.9.4" + + +@pytest.mark.parametrize( + ("python_version", "selected"), + (("3.11", True), ("3.12", True), ("3.13", False), ("3.14", False)), +) +def test_kokoro_feature_markers_match_supported_python_range(python_version, selected): + for name in ("kokoro", "soundfile"): + requirement = _optional_requirement(name) + assert requirement.marker is not None + assert requirement.marker.evaluate({"python_version": python_version}) is selected + + +def test_setup_documents_container_constraint_and_install_command(): + setup = (ROOT / "docs" / "setup.md").read_text(encoding="utf-8") + + assert "pip install -r requirements-optional.txt" in setup + assert "default Docker image currently uses Python 3.14" in setup + assert "Python `>=3.10,<3.13`" in setup + assert "native Python 3.11 or 3.12" in setup + assert "skipped on Python 3.13+" in setup + assert "torch build has CUDA" in setup