Skip to content

Add Edge-TTS as a third voiceover provider (free, no API key, incl. Vietnamese) - #46

Open
bin-bard wants to merge 8 commits into
digitalsamba:mainfrom
bin-bard:upstream/edge-tts-vietnamese
Open

Add Edge-TTS as a third voiceover provider (free, no API key, incl. Vietnamese)#46
bin-bard wants to merge 8 commits into
digitalsamba:mainfrom
bin-bard:upstream/edge-tts-vietnamese

Conversation

@bin-bard

Copy link
Copy Markdown

Summary

Adds Microsoft Edge TTS as a third voiceover.py backend alongside ElevenLabs and
Qwen3-TTS — free, no API key or account, ~300 voices including Vietnamese
(vi-VN-HoaiMyNeural, vi-VN-NamMinhNeural). Defaults to en-US-AriaNeural.

Changes

  • tools/edgetts.py — new module (single-utterance + list-voices), retries transient
    backend failures, distinguishes client-side param errors (fail fast) from
    transient ones (retry with backoff), never leaves a zero-byte file on failure
  • tools/voiceover.py — wires edge-tts into the existing per-scene / single-file
    dispatch, --rate/--pitch/--volume flags, honest per-scene failure
    reporting (exit 1 + [FAILED: ...] on any scene that didn't produce audio)
  • brands/default/voice.json — edgeTts config block
  • CLAUDE.md, .claude/commands/generate-voiceover.md, _internal/toolkit-registry.json
    — docs and registry entries

Testing

  • Verified live against the real edge-tts backend: default voice (English),
    explicit Vietnamese voice, malformed --rate (fails fast, no retry burned),
    valid-but-nonexistent voice (retries 3x then cleans up), per-scene batch run
    with a forced failure (exits 1, reports which scene failed, no stray files)

bin-bard and others added 8 commits July 14, 2026 14:39
…ices)

Standalone generate_audio()/list_voices() following the same result-dict
shape as qwen3_tts.py, so voiceover.py can adopt it as a third provider.
No API key or cloud GPU needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
argparse only runs %-substitution on epilog text when it contains
%(prog); this epilog does not, so the doubled %% rendered literally in
--help. The docstring already showed the correct single %. help= strings
keep %% (those ARE %-substituted).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds --provider edge-tts alongside elevenlabs/qwen3: argparse choices,
--rate/--pitch/--volume flags, a generate_single_audio_edge_tts()
wrapper, and a three-way branch through the scene-dir loop, single-file
generation, dry-run/JSON output, and brand voice-config resolution.
--speaker is reused as the Edge-TTS voice name (default vi-VN-HoaiMyNeural).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sets the default brand's Edge-TTS voice to vi-VN-HoaiMyNeural, matching
the toolkit-wide fallback added in voiceover.py.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… hints

The guided voiceover workflow only offered ElevenLabs and Qwen3-TTS —
neither of which supports Vietnamese — so the Edge-TTS provider added in
this branch was unreachable from the primary UX. Also adds Edge-TTS as
the easiest free fallback in both ElevenLabs failure messages (no API
key, no account, no GPU).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A per-scene run reported "success" and exited 0 even when scenes produced
no audio, and the serial loop printed failed scenes as if they had worked
("01.mp3 (?s)"). A silently-dropped scene ships a video with a silent gap.
This was pre-existing in the shared scene loop (it hit ElevenLabs and the
Qwen3 serial path too), but Edge-TTS makes it dangerous: its backend
intermittently returns no audio, so partial failures are routine — and a
failed save leaves a ZERO-BYTE .mp3 behind, which ffprobe reads as no
duration and Remotion renders as silence rather than erroring.

voiceover.py (shared, all providers):
  - serial loop prints [FAILED: <error>] instead of a bare filename
  - per_scene success is now "every scene produced audio"; adds
    failed_scenes; exits 1 when any scene failed

edgetts.py:
  - retry transient backend failures (3 attempts, 1s/2s backoff)
  - treat a zero-byte write as a failure, and remove the file when the
    attempts are exhausted
  - fail fast on ValueError (unknown voice, malformed rate/pitch/volume) —
    edge-tts validates those client-side, so retrying cannot help

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brands/default/voice.json and the "Ryan" speaker fallback both
defaulted new Edge-TTS scenes to vi-VN-HoaiMyNeural. Fine for this
fork's use case, but wrong as the shared default for a general-purpose
toolkit: anyone running the documented `--provider edge-tts` example
verbatim on English script text got Vietnamese-voice audio. Default is
now en-US-AriaNeural; vi-VN-HoaiMyNeural/vi-VN-NamMinhNeural remain
available and documented as explicit opt-ins.

Also closes registry drift: generate-voiceover's registry entry still
described ElevenLabs/Qwen3-TTS only despite the command doc already
covering Edge-TTS, and edgetts.py had no standalone tools.* entry.

Found via code-reviewer subagent pass ahead of the upstream PR.
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.

1 participant