feat(tts): serve all TTS from the RunPod Orpheus-3B deployment#242
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the RunPod Orpheus-3B endpoint the only TTS inference serving point. POST /tasks/audio/speech (+ batch, speakers, url) now route exclusively to RunPod Orpheus; spark-tts, Modal, and the legacy per-provider TTS routes are removed. - integrations: add OrpheusClient (repoint of the retired Modal client) with Bearer auth, long cold-start timeouts, and a stream_speech() method for /v1/audio/speech; delete orpheus_modal.py. - services: Orpheus-only SpeechService (drop model/platform matrix + spark); add stream() and surface synthesized audio_bytes for response_mode='both'. - router: create_speech supports response_mode url | stream | both (both streams bytes with the signed URL in X-Audio-Url); batch capped at 16 (RunPod limit). - schema: drop model, platform, max_new_audio_tokens; batch max 128 -> 16. - whatsapp: message_processor voice replies synthesize via the shared Orpheus SpeechService using the returned bytes directly. - config: ORPHEUS_BASE_URL (+ timeouts) replace orpheus_modal_* and whatsapp_tts_backend; bearer reuses RUNPOD_API_KEY. - remove: tts.py, runpod_tts.py, orpheus_tts.py routers, legacy /tasks/tts, tts_service.py, runpod_tts_service.py, and their tests/wiring. - tests: new client unit tests; rewrite speech/batch/voice/tags/deps tests for the Orpheus-only contract. - docs: docs.py, tutorial.md, Tutorial.tsx updated (breaking change). BREAKING CHANGE: /tasks/audio/speech rejects model/platform/max_new_audio_tokens and no longer offers spark-tts; the legacy /tasks/modal/tts, /tasks/runpod/tts, /tasks/modal/orpheus/*, /tasks/tts routes are removed. ORPHEUS_BASE_URL must be set for TTS to function. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reuse the existing TTS_API_URL setting (default the RunPod Orpheus endpoint https://gfg8z4dvexiz85.api.runpod.ai/v1) as the single TTS base URL instead of a separate ORPHEUS_BASE_URL. The client accepts the URL with or without a '/v1' suffix and derives both the root (custom /tts, /tts/batch, /speakers, /health) and the /v1 base (/v1/audio/speech). Add ORPHEUS_MODEL_NAME (default 'sunbird-orpheus-tts'), the model identifier sent to /v1/audio/speech, replacing the hardcoded string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Removing the (module-unused) settings import broke the pre-existing dedup test that monkeypatches mp.settings.whatsapp_dedup_backend. Restore it at module scope with a noqa so tests can target mp.settings.*. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes the RunPod Orpheus-3B deployment the only TTS inference serving point.
POST /tasks/audio/speech(and its batch/speakers/url siblings) now route exclusively to RunPod Orpheus; spark-tts, Modal, and the legacy per-provider TTS routes are removed.Net −4,576 lines (mostly deletions). Design spec:
docs/superpowers/specs/2026-07-25-tts-runpod-orpheus-only-design.md.Key finding
The RunPod
server.pyis a port of the former Modal app with the identical route table (/tts,/tts/batch,/speakers,/health), so this is a repoint + teardown, not a new client. The Modal client's retry/backoff logic was generalized intoOrpheusClient, pointed at RunPod withBearerauth and long cold-start timeouts.What changed
New
app/integrations/orpheus_runpod.py—OrpheusClient(Bearer auth, long timeouts,stream_speech()for/v1/audio/speech).app/tests/test_orpheus_runpod_client.py— client unit tests (MockTransport).Core
speech_service.py— Orpheus-only; addsstream(); surfacesaudio_bytesforresponse_mode='both'.routers/audio.py—create_speech:url(signed GCS URL) ·stream(RunPod byte passthrough) ·both(bytes +X-Audio-Urlheader). Batch capped at 16.schemas/speech.py— dropmodel,platform,max_new_audio_tokens; batch max 128→16.message_processor.py— WhatsApp voice replies synthesize via the shared OrpheusSpeechService(uses returned bytes directly).config.py/.env.example—TTS_API_URL(defaulthttps://gfg8z4dvexiz85.api.runpod.ai/v1,/v1optional) is the TTS base URL;ORPHEUS_MODEL_NAME(defaultsunbird-orpheus-tts) is the/v1/audio/speechmodel id; bearer reusesRUNPOD_API_KEY.Removed —
tts.py,runpod_tts.py,orpheus_tts.pyrouters, legacy/tasks/tts,tts_service.py,runpod_tts_service.py,orpheus_modal.py, and their tests.Docs —
docs.py,docs/tutorial.md,frontend/src/pages/Tutorial.tsx.Breaking changes
/tasks/audio/speechrejectsmodel/platform/max_new_audio_tokensand no longer offersspark-tts./tasks/modal/tts*,/tasks/runpod/tts,/tasks/modal/orpheus/*,/tasks/tts.response_mode='both'now returns raw audio bytes with the signed URL in theX-Audio-Urlheader (was SSE).Config
TTS_API_URLis the RunPod endpoint (defaulthttps://gfg8z4dvexiz85.api.runpod.ai/v1; the/v1suffix is optional). The client derives both the root (custom routes) and the/v1base (/v1/audio/speech). If set to empty, TTS 503s at request time.ORPHEUS_MODEL_NAME=sunbird-orpheus-tts(model id for/v1/audio/speech).RUNPOD_API_KEY.Test plan
pytest app/tests/→ 1126 passed; 6 failures are pre-existing.env-leak failures (ga_*,qwen_endpoint_id) unrelated to TTS.black/isort/flake8onapp/→ clean.frontend/ npm run build(tsc + vite) → clean.Not verified here
/ttsheaders and/tts/batchbase64 shape — if the port diverged, client parsing is where to adjust.frontend npm run lint— the repo's ESLint config predates ESLint 10 and errors before linting (pre-existing). Type coverage viatsc.🤖 Generated with Claude Code