Skip to content

Let another app read a whole video in one pinned voice - #211

Merged
davior merged 1 commit into
mainfrom
claude/funny-knuth-en5fly
Oct 16, 2026
Merged

davior merged 1 commit into
mainfrom
claude/funny-knuth-en5fly

Conversation

@davior

@davior davior commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Gecko Video Creator's renderer (M2) reads its narration through Notes' speech, one chunk per request, so voices, keys and the TTS cache stay in one place. It needs two things the endpoint couldn't give it:

  • The account's voice when none is chosen. TTSRequest.model defaults to a fal.ai voice, which isn't the same thing.
  • The engine and voice pinned after the first chunk. Notes' own render worker already does this: a Deepgram hiccup partway through must not read one chunk on fal.ai in a different voice.

What changes

  • New optional fields. POST /api/settings/speech/tts takes provider (auto | deepgram | fal) and voice, where null means the account's voice.
  • Shared resolution. With provider set, both are resolved by video/worker.resolve_render_speech, which is pulled out of _tts_caller so the worker and the endpoint pin the same way.
  • Echoed back. The response names the resolved pair in X-Speech-Provider and X-Speech-Voice, for GVC to send back on every later chunk.
  • Old requests unchanged. Without provider, a request means exactly what it did: read-aloud, export and the frontend are untouched.
  • Spec doc updated. docs/gecko-video-creator.md §9.1 marks this row done.

Tests

  • Three new tests in tests/test_video_voice.py, with providers faked as the existing tests do:
    • "auto" gives Deepgram in the account's voice, with the headers set;
    • a pinned engine and voice are kept;
    • a request without provider is unchanged, with no headers.
  • The worker's existing pinning tests still pass through the extracted helper.
  • pytest -q: 1351 passed, 1 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_016fiRJAt34ag62iPiuMkNhm


Generated by Claude Code

Gecko Video Creator renders through Notes' speech, one chunk per request,
and needs what Notes' own render worker does:
- the account's voice when none is chosen, where `model` defaults to a
  fal.ai voice;
- the engine pinned after the first chunk, so a Deepgram hiccup partway
  through cannot read one chunk on fal.ai in a different voice.

POST /speech/tts takes an optional `provider` and `voice`. With them,
both are resolved by resolve_render_speech, which is now shared with
the worker. The response names them in X-Speech-Provider and
X-Speech-Voice, for the caller to send back on every later chunk.
Without `provider`, a request means exactly what it did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fiRJAt34ag62iPiuMkNhm
@davior
davior marked this pull request as ready for review October 16, 2026 05:30
@davior
davior merged commit 410a23f into main Oct 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants