# How to Use Voice Synthesis (TTS) in MoneyPrinterTurbo: A Complete Guide

> Learn how to use voice synthesis (TTS) in MoneyPrinterTurbo with our complete guide. Integrate Azure Speech, SiliconFlow, or Gemini for audio generation and synchronized subtitles.

- Repository: [Harry/MoneyPrinterTurbo](https://github.com/harry0703/MoneyPrinterTurbo)
- Tags: how-to-guide
- Published: 2026-03-23

---

**MoneyPrinterTurbo provides a unified text-to-speech interface in [`app/services/voice.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/config.toml) (copied from [`config.example.toml`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/config.example.toml)). The configuration is loaded by [`app/config/config.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/config/config.py) and exposed as the `config` object throughout the voice module.

```toml
[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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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:

```python
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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/test/services/test_voice.py).

### Direct Azure v2 Implementation

For direct access to Azure's multilingual capabilities without the abstraction layer:

```python
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:

```python
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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/services/voice.py) routes requests to Azure, SiliconFlow, or Gemini based on voice name parsing.
- Configuration requires API keys in [`config.toml`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/config.toml) loaded by [`app/config/config.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/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`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/config.toml) (copied from [`config.example.toml`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/config.example.toml)) with specific sections for `[azure]`, `[siliconflow]`, and `[gemini]`. These settings are loaded at runtime by [`app/config/config.py`](https://github.com/harry0703/MoneyPrinterTurbo/blob/main/app/config/config.py) and accessed throughout the voice service module via the imported `config` object.