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 in app/services/voice.py routes requests to Azure, SiliconFlow, or Gemini based on voice name parsing.
  • Configuration requires API keys in config.toml loaded by app/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 SubMaker object containing subtitle timings that can be exported to SRT format using create_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →