* Phase 3 Plan 03-01: Supertonic-3 engine on SubprocessBackend
Adds Supertonic-3 as a 7th opt-in TTS engine on the Phase 2
SubprocessBackend primitive. Closes TTS-01..06 (REQUIREMENTS.md):
* TTS-01 — _REGISTRY["supertonic3"] resolves to Supertonic3Backend,
a SubprocessBackend subclass.
* TTS-02 — `supertonic==1.3.1` lives under [project.optional-dependencies];
default `uv sync --no-dev` does NOT install it. Exactly one
`onnxruntime` row in `uv pip list` after `--extra supertonic`.
* TTS-03 — Model revision pinned by 40-char commit SHA
(724fb5abbf5502583fb520898d45929e62f02c0b — the "Initial
Supertonic 3 release" SHA, same as the SDK's own pin).
Resolver script for intentional bumps:
scripts/resolve_supertonic3_sha.py.
* TTS-04 — Honest CPU-only reporting. `is_available()` message says
"ready (CPU-only via onnxruntime)" and never mentions
"cuda" or "mps". `gpu_compat = ("cpu",)`.
* TTS-05 — License gate via settings_store helpers
(get/set_license_accepted) + Loopback-only
/api/settings/license endpoint + SupertonicLicenseDialog
frontend modal showing MIT (code) and OpenRAIL-M (model).
Wired into EngineCompatibilityMatrix as an "Accept license"
button on rows whose `reason` mentions "license not
accepted".
* TTS-06 — 3 langs (en/ja/ru) × 3 sec smoke test in
tests/test_supertonic3.py::test_smoke_3langs_3sec
(OMNIVOICE_SMOKE-gated; asserts no onnxruntime-gpu row
post-synthesize).
Package legitimacy gate (Task 1 in plan): supertonic on PyPI verified
to be published by Supertone Inc. (ato@supertone.ai), repo
github.com/supertone-inc/supertonic, wheel is pure-Python with no
postinstall scripts. Same publisher ships supertonic-js on npm under
the same maintainer email.
Test results:
* tests/test_supertonic3.py — 10 passed, 3 skipped (network-gated).
* tests/smoke/ — 4 passed.
* tests/ (full, --ignore=tests/manual) — 412 passed, 0 failed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci(tests): uv sync --all-extras so optional-engine tests can import their package
Phase 3 added `supertonic` as an optional dependency. The CI Tests job
runs `uv sync` (no extras), so `test_cpu_only_honest` and `test_license_gate`
in tests/test_supertonic3.py hit the "supertonic package not installed"
fallback instead of the real import path, and fail.
Bare `uv sync` is the right default for users (engines are opt-in), but
the test environment should exercise the full surface. `--all-extras`
keeps the smoke job lean (still bare `uv sync`) while letting Tests
verify the integrated behavior of every optional engine.
Future-proofs against the same failure mode in Phase 4 (GGUF) and any
later optional engines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
36 lines
1.6 KiB
Python
36 lines
1.6 KiB
Python
"""Supertonic-3 sidecar package (Phase 3 Plan 03-01).
|
|
|
|
Supertonic-3 runs in its own long-lived subprocess via Phase 2's
|
|
``SubprocessBackend`` primitive. Unlike IndexTTS it shares the OmniVoice
|
|
parent venv ‑‑ the SDK's deps (``onnxruntime``, ``numpy``, ``soundfile``,
|
|
``huggingface_hub``) already live there.
|
|
|
|
Three public entry points live in this package:
|
|
|
|
* :class:`Supertonic3Backend` (in ``backend.py``) ‑‑ the
|
|
SubprocessBackend subclass that
|
|
``services.tts_backend._LAZY_REGISTRY`` resolves on first access.
|
|
Defined in a separate module rather than inside
|
|
``services.tts_backend`` to avoid the import cycle:
|
|
``services.tts_backend`` finishes loading before anything here is
|
|
imported. (Same indirection pattern as ``engines.indextts``.)
|
|
* ``sidecar.py`` ‑‑ the subprocess entry point. Stdlib-only at import
|
|
time; loads the supertonic SDK lazily on the first synthesize op so
|
|
the ``ready`` handshake fits inside
|
|
``SubprocessBackend.SPAWN_READY_TIMEOUT_S``.
|
|
* ``constants.py`` ‑‑ pinned model revision SHA (TTS-03), voice
|
|
presets, license URLs.
|
|
|
|
Do NOT import ``sidecar.py`` from the parent process. The sidecar must
|
|
run as a subprocess so the parent's tts_backend module stays
|
|
import-cycle-free and the SDK's onnxruntime initialization can't
|
|
contaminate the parent's interpreter state.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
# Re-export the backend class for convenience. ``_LAZY_REGISTRY`` in
|
|
# ``services.tts_backend`` resolves ``"supertonic3"`` to this attribute.
|
|
from engines.supertonic3.backend import Supertonic3Backend
|
|
|
|
__all__ = ["Supertonic3Backend"]
|