How to Use Voice Synthesis (TTS) in MoneyPrinterTurbo: A Complete Guide
MoneyPrinterTurbo provides a unified text-to-speech interface in app/services/voice.py that supports Azure Speech, SiliconFlow, and Gemini backends, automatically generating synchronized subtitles while requiring only a voice name and API configuration to produce audio files.
MoneyPrinterTurbo is an automated video generation framework that includes a powerful voice synthesis layer for creating narration. The TTS system abstracts multiple cloud providers behind a single Python API, allowing you to generate speech and subtitle files with minimal configuration while maintaining provider-specific optimizations for timing accuracy.
TTS Architecture and Backend Providers
The voice synthesis system implements three distinct backends in app/services/voice.py, each handling audio generation and subtitle timing differently.
Azure Speech Services
The Azure integration provides two implementations:
azure_tts_v1: Edge-TTS compatible endpoint that streams audio chunks while capturing word-boundary events to build precise subtitle timings.azure_tts_v2: Full Azure Cognitive Services SDK implementation that supports multilingual neural voices and returns detailed timing metadata for synchronization.
SiliconFlow Integration
The siliconflow_tts function calls the SiliconFlow /v1/audio/speech HTTP API, writes the returned MP3 file to disk, and creates approximate subtitles by proportionally splitting the input text according to the audio duration.
Gemini (Google) TTS
The gemini_tts function uses the Gemini-1.5-flash-preview-tts model via the google.generativeai SDK. It receives raw PCM audio data, converts it to MP3 format, and generates a single-segment subtitle covering the entire text duration.
Configuration Requirements
Before calling any backend, you must supply the required API keys in config.toml (copied from config.example.toml). The configuration is loaded by app/config/config.py and exposed as the config object throughout the voice module.
[azure]
speech_key = "<YOUR_AZURE_SPEECH_KEY>"
speech_region = "<YOUR_AZURE_REGION>"
[siliconflow]
api_key = "<YOUR_SILICONFLOW_API_KEY>"
[gemini]
gemini_api_key = "<YOUR_GEMINI_API_KEY>"
Voice Name Formats and Selection
The system parses voice names to determine which backend to invoke using helper functions like parse_voice_name(), is_azure_v2_voice(), is_siliconflow_voice(), and is_gemini_voice().
Voice names follow these specific formats:
- Azure (v1/v2):
zh-CN-XiaoyiNeural-Female - Azure v2 Multilingual:
zh-CN-XiaoxiaoMultilingualNeural-V2-Female - SiliconFlow:
siliconflow:FunAudioLLM/CosyVoice2-0.5B:alex-Male - Gemini:
gemini:Zephyr-Female
The helper functions get_all_azure_voices(), get_siliconflow_voices(), and get_gemini_voices() (lines 020-076 in voice.py) return complete lists suitable for UI dropdowns.
Implementing Voice Synthesis in Code
All backends share a common workflow: normalize the voice name, select the implementation, generate the audio file to your specified path, create a SubMaker object with timing data (stored in 100-nanosecond units), and optionally export to SRT format using create_subtitle() (lines 074-104).
Basic Usage with the Unified API
The tts() function provides a single entry point for all providers:
from app.services import voice as tts
from app.utils import utils
# Prepare output paths
out_dir = utils.storage_dir("temp", create=True)
audio_path = f"{out_dir}/demo.mp3"
subtitle_path = f"{out_dir}/demo.srt"
# Choose a voice (any supported format)
voice_name = "siliconflow:FunAudioLLM/CosyVoice2-0.5B:alex-Male"
# Call the unified TTS helper
sub_maker = tts.tts(
text="Hello, this is a demo of Money Printer Turbo's TTS service.",
voice_name=voice_name,
voice_rate=1.0, # normal speed
voice_file=audio_path,
voice_volume=1.0, # default gain
)
# Build the subtitle file
if sub_maker:
tts.create_subtitle(sub_maker, "Hello, this is a demo of Money Printer Turbo's TTS service.", subtitle_path)
print(f"Audio saved to {audio_path}")
print(f"Subtitle saved to {subtitle_path}")
else:
raise RuntimeError("TTS generation failed")
This mirrors the test implementation in test/services/test_voice.py.
Direct Azure v2 Implementation
For direct access to Azure's multilingual capabilities without the abstraction layer:
import asyncio
from app.services import voice as tts
from app.utils import utils
async def run():
out_dir = utils.storage_dir("temp", create=True)
audio_path = f"{out_dir}/azure_v2.mp3"
subtitle_path = f"{out_dir}/azure_v2.srt"
sub_maker = await tts.azure_tts_v2(
text="欢迎使用 Money Printer Turbo!",
voice_name="zh-CN-XiaoxiaoMultilingualNeural-V2-Female",
voice_file=audio_path,
)
tts.create_subtitle(sub_maker, "欢迎使用 Money Printer Turbo!", subtitle_path)
print("Done")
asyncio.run(run())
This corresponds to the test_azure_tts_v2 test case in the repository.
Runtime Backend Switching
You can switch providers dynamically by changing only the voice name parameter:
def synthesize(text, voice_name, out_dir):
audio_path = f"{out_dir}/out.mp3"
subtitle_path = f"{out_dir}/out.srt"
sub = tts.tts(
text=text,
voice_name=voice_name,
voice_rate=1.0,
voice_file=audio_path,
voice_volume=1.0,
)
if sub:
tts.create_subtitle(sub, text, subtitle_path)
return audio_path, subtitle_path
raise RuntimeError("Failed")
Pass any supported voice_name string; the tts() function internally selects the correct backend based on the naming prefix.
Working with Subtitles
Every backend returns a SubMaker object containing subtitle strings and their start/end offsets in 100-nanosecond units. While Azure provides word-level precision through boundary events, SiliconFlow approximates timing by text proportion, and Gemini returns a single segment covering the entire duration.
To export these timings to a standard SRT file, use the create_subtitle() function with your SubMaker instance, original text, and output path.
Summary
- The unified
tts()function inapp/services/voice.pyroutes requests to Azure, SiliconFlow, or Gemini based on voice name parsing. - Configuration requires API keys in
config.tomlloaded byapp/config/config.py, with sections for[azure],[siliconflow], and[gemini]. - Voice names follow specific prefixes (
siliconflow:,gemini:) or Azure neural naming patterns to trigger the correct backend. - All backends return a
SubMakerobject containing subtitle timings that can be exported to SRT format usingcreate_subtitle(). - Azure backends provide the most accurate word-level timing through boundary event capture, while other providers use approximation methods.
Frequently Asked Questions
Which TTS backend provides the most accurate word-level subtitles?
Azure Speech services (both v1 and v2) provide the most precise subtitle synchronization because they capture word-boundary events during audio streaming. According to the implementation in app/services/voice.py, Azure tracks these events to build exact timestamps, whereas SiliconFlow approximates timing by proportionally splitting text and Gemini creates a single-segment subtitle covering the entire duration.
How do I switch between different voice providers without changing my code structure?
Pass different voice_name strings to the unified tts() function. The system automatically detects the backend using helper functions like is_azure_v2_voice(), is_siliconflow_voice(), and is_gemini_voice() defined in app/services/voice.py. Simply change the voice name from siliconflow:FunAudioLLM/CosyVoice2-0.5B:alex-Male to gemini:Zephyr-Female or zh-CN-XiaoxiaoNeural-Female to switch providers.
What audio format does the TTS system generate?
All backends generate MP3 files regardless of the provider. Azure streams audio chunks directly to your specified voice_file path, SiliconFlow writes the MP3 returned from their HTTP API, and Gemini converts raw PCM data received from the Google Generative AI SDK to MP3 format before saving.
Where do I configure the API keys for voice synthesis?
API keys are configured in config.toml (copied from config.example.toml) with specific sections for [azure], [siliconflow], and [gemini]. These settings are loaded at runtime by app/config/config.py and accessed throughout the voice service module via the imported config object.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →