# How to Integrate Custom TTS Providers Beyond KittenTTS in MoneyPrinterV2

> Easily integrate custom TTS providers beyond KittenTTS in MoneyPrinterV2. Learn how to create a provider wrapper class and register it in the factory map for custom voice integration.

- Repository: [FujiwaraChoki/MoneyPrinterV2](https://github.com/FujiwaraChoki/MoneyPrinterV2)
- Tags: how-to-guide
- Published: 2026-03-20

---

**You can integrate custom TTS providers in MoneyPrinterV2 by creating a provider wrapper class that implements a `synthesize(text, output_file)` interface, registering it in the factory map inside [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py), and selecting it via the `tts_provider` key in [`config.json`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/config.json).**

MoneyPrinterV2 currently ships with a single TTS implementation based on KittenTTS, limiting users to one voice synthesis backend. If you want to integrate custom TTS providers beyond KittenTTS in MoneyPrinterV2, the architecture supports extension through a simple provider interface and factory pattern. This guide shows you exactly how to add support for services like Coqui TTS or Google Cloud TTS without breaking existing workflows.

## Add a Configuration Flag

The configuration file ([`config.json`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/config.json)) already stores the voice name (`tts_voice`). Add a new key to specify the provider:

```json
{
  "tts_voice": "Jasper",
  "tts_provider": "kitten"
}

```

Add a helper accessor in [`src/config.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/config.py) to read this value:

```python
import os
import json

from .constants import ROOT_DIR

def get_tts_provider() -> str:
    """
    Returns the configured TTS provider name.
    """
    with open(os.path.join(ROOT_DIR, "config.json"), "r") as file:
        return json.load(file).get("tts_provider", "kitten")

```

## Create Provider Wrappers

Create a new module at [`src/classes/tts_providers.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/tts_providers.py) that contains concrete classes for each backend. Each class must expose a `synthesize(text: str, output_file: str) -> str` method, returning the file path.

```python

# src/classes/tts_providers.py

import os
import soundfile as sf
from kittentts import KittenTTS as KittenModel

KITTEN_MODEL = "KittenML/kitten-tts-mini-0.8"
KITTEN_SAMPLE_RATE = 24000


class KittenProvider:
    """Thin wrapper around KittenTTS."""
    def __init__(self, voice: str):
        self._model = KittenModel(KITTEN_MODEL)
        self._voice = voice

    def synthesize(self, text: str, output_file: str) -> str:
        audio = self._model.generate(text, voice=self._voice)
        sf.write(output_file, audio, KITTEN_SAMPLE_RATE)
        return output_file


class CoquiProvider:
    """Wrapper for Coqui TTS (requires `coqui-tts` package)."""
    def __init__(self, voice: str):
        from TTS.api import TTS as CoquiTTS
        self._tts = CoquiTTS(model_name=voice, progress_bar=False, gpu=False)

    def synthesize(self, text: str, output_file: str) -> str:
        self._tts.tts_to_file(text=text, file_path=output_file)
        return output_file

```

## Refactor the TTS Factory

Replace the monolithic [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) with a thin factory that delegates to the selected provider. This maintains backward compatibility with existing code in [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) and [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py).

```python

# src/classes/Tts.py

import os
from config import ROOT_DIR, get_tts_voice, get_tts_provider
from .tts_providers import KittenProvider, CoquiProvider

_PROVIDER_MAP = {
    "kitten": KittenProvider,
    "coqui": CoquiProvider,
}


class TTS:
    """Factory that forwards synthesize calls to the configured provider."""
    def __init__(self) -> None:
        provider_name = get_tts_provider().lower()
        voice = get_tts_voice()
        provider_cls = _PROVIDER_MAP.get(provider_name)

        if provider_cls is None:
            raise ValueError(f"Unsupported TTS provider: {provider_name}")

        self._provider = provider_cls(voice)

    def synthesize(self, text, output_file=os.path.join(ROOT_DIR, ".mp", "audio.wav")):
        """
        Generate speech using the selected TTS backend.
        Returns the absolute path to the generated WAV file.
        """
        return self._provider.synthesize(text, output_file)

```

Key implementation details:

- **Factory pattern**: The `TTS` class reads `tts_provider` from the config, looks up the concrete class in `_PROVIDER_MAP`, and constructs it with the configured voice.
- **Unchanged public API**: The `synthesize(text, output_file)` method signature remains identical to the original implementation, ensuring [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) and the CLI in [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py) require zero changes.

## Install Additional Dependencies

If you add a provider that requires external packages (e.g., `coqui-tts` or `google-cloud-texttospeech`), add them to [`requirements.txt`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/requirements.txt) and run the standard setup:

```bash
pip install -r requirements.txt

```

Or execute the provided setup script:

```bash
bash scripts/setup_local.sh

```

## Update Documentation

Add the new configuration option to the user documentation. In [`docs/Configuration.md`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/docs/Configuration.md), include:

```markdown
- `tts_provider`: string – Choose the TTS backend. Supported values: `kitten` (default), `coqui`, `google`.

```

This ensures end-users understand how to switch providers without reading source code.

## Integration Examples

### Switching to Coqui TTS

1. **Edit [`config.json`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/config.json)**

```json
{
  "tts_voice": "tts_models/en/ljspeech/tacotron2",
  "tts_provider": "coqui"
}

```

2. **Run the workflow**

```bash
python3 src/main.py

```

Select any YouTube option; the system will now route calls to `CoquiProvider` under the hood.

### Adding a New Provider (Google Cloud TTS)

1. **Create `GoogleProvider` in [`src/classes/tts_providers.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/tts_providers.py)**

```python
from google.cloud import texttospeech

class GoogleProvider:
    def __init__(self, voice: str):
        self.client = texttospeech.TextToSpeechClient()
        self.voice = voice

    def synthesize(self, text: str, output_file: str) -> str:
        synthesis_input = texttospeech.SynthesisInput(text=text)
        voice = texttospeech.VoiceSelectionParams(name=self.voice, language_code="en-US")
        audio_config = texttospeech.AudioConfig(audio_encoding=texttospeech.AudioEncoding.LINEAR16)

        response = self.client.synthesize_speech(
            input=synthesis_input, voice=voice, audio_config=audio_config
        )
        with open(output_file, "wb") as out:
            out.write(response.audio_content)
        return output_file

```

2. **Register it in [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py)**

```python
from .tts_providers import GoogleProvider
_PROVIDER_MAP["google"] = GoogleProvider

```

3. **Set the config**

```json
{
  "tts_voice": "en-US-Wavenet-D",
  "tts_provider": "google"
}

```

All existing calls to `TTS().synthesize(...)` in [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) and [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py) will now produce speech via Google Cloud without any further code changes.

## Key Files

| File | Role | Path |
|------|------|------|
| [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) | Central TTS factory (updated to select a provider) | [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) |
| [`src/classes/tts_providers.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/tts_providers.py) | Concrete implementations for each TTS backend (new module) | [`src/classes/tts_providers.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/tts_providers.py) |
| [`src/config.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/config.py) | Configuration helpers – add `get_tts_provider()` here | [`src/config.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/config.py) |
| [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) | Consumes the `TTS` class to generate audio for videos | [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) |
| [`docs/Configuration.md`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/docs/Configuration.md) | User‑visible docs – include the new `tts_provider` option | [`docs/Configuration.md`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/docs/Configuration.md) |

## Summary

- **Abstract the backend**: Create a provider wrapper in [`src/classes/tts_providers.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/tts_providers.py) that implements `synthesize(text, output_file)`.
- **Expose via config**: Add `tts_provider` to [`config.json`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/config.json) and a reader in [`src/config.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/config.py).
- **Wire the factory**: Update [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) to map config values to provider classes in `_PROVIDER_MAP`.
- **Zero breaking changes**: Existing code in [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) and [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py) continues to call `TTS().synthesize()` without modification.

## Frequently Asked Questions

### Can I use multiple TTS providers simultaneously in the same project?

No, the current architecture selects one provider per session via the `tts_provider` configuration key. However, you can switch providers between runs by editing [`config.json`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/config.json) before launching [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py), or you could extend the factory to accept a provider override parameter in the `TTS` constructor if you need per-call switching.

### Do I need to modify YouTube.py or main.py to use a new provider?

No. The `TTS` class in [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) acts as a stable abstraction. Because [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) and [`src/main.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/main.py) only interact with the `synthesize()` method signature, switching providers happens entirely within the factory and configuration layers. You only need to edit [`src/classes/Tts.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/Tts.py) and create the provider wrapper.

### What audio format should the synthesize method return?

The `synthesize` method must return a string representing the absolute file path to a **WAV** file. The existing `KittenProvider` writes 24 kHz PCM WAV using `soundfile`, and the video generation pipeline in [`src/classes/YouTube.py`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/src/classes/YouTube.py) expects this format for concatenation with video tracks. If your provider outputs MP3 or other formats, convert to WAV inside the wrapper before returning the path.

### Is GPU acceleration supported for custom providers?

Yes, but implementation depends on the specific provider library. The `CoquiProvider` example accepts a `gpu` parameter in its constructor (set to `False` by default for CPU compatibility). If you are adding a provider that supports CUDA (e.g., Coqui TTS with GPU or `torch`-based models), modify the `__init__` method of your provider class to accept a `device` or `gpu` argument and pass it to the underlying library. Ensure your [`requirements.txt`](https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/main/requirements.txt) includes the correct GPU-enabled dependencies (e.g., `torch` with CUDA bindings).