Files
stack/apps/api/src/speech/providers/tts-provider.factory.ts
Jason Woltje 6c465566f6
All checks were successful
ci/woodpecker/push/api Pipeline was successful
feat(#395): implement Piper TTS provider via OpenedAI Speech
Add fallback-tier TTS provider using Piper via OpenedAI Speech for
ultra-lightweight CPU-only synthesis. Maps 6 standard OpenAI voice
names (alloy, echo, fable, onyx, nova, shimmer) to Piper voices.
Update factory to use the new PiperTtsProvider class, replacing the
inline stub. Includes 37 unit tests covering provider identity,
voice mapping, and voice listing.

Fixes #395

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:39:20 -06:00

76 lines
2.7 KiB
TypeScript

/**
* TTS Provider Factory
*
* Creates and registers TTS providers based on speech configuration.
* Reads enabled flags and URLs from config and instantiates the appropriate
* provider for each tier.
*
* Each tier maps to a specific TTS engine:
* - default: Kokoro-FastAPI (CPU, always available)
* - premium: Chatterbox (GPU, voice cloning)
* - fallback: Piper via OpenedAI Speech (ultra-lightweight CPU)
*
* Issue #391
*/
import { Logger } from "@nestjs/common";
import { ChatterboxTTSProvider } from "./chatterbox-tts.provider";
import { KokoroTtsProvider } from "./kokoro-tts.provider";
import { PiperTtsProvider } from "./piper-tts.provider";
import type { ITTSProvider } from "../interfaces/tts-provider.interface";
import type { SpeechTier, AudioFormat } from "../interfaces/speech-types";
import type { SpeechConfig } from "../speech.config";
// ==========================================
// Factory function
// ==========================================
const logger = new Logger("TTSProviderFactory");
/**
* Create and register TTS providers based on the speech configuration.
*
* Only creates providers for tiers that are enabled in the config.
* Returns a Map keyed by SpeechTier for use with the TTS_PROVIDERS injection token.
*
* @param config - Speech configuration with TTS tier settings
* @returns Map of enabled TTS providers keyed by tier
*/
export function createTTSProviders(config: SpeechConfig): Map<SpeechTier, ITTSProvider> {
const providers = new Map<SpeechTier, ITTSProvider>();
// Default tier: Kokoro
if (config.tts.default.enabled) {
const provider = new KokoroTtsProvider(
config.tts.default.url,
config.tts.default.voice,
config.tts.default.format as AudioFormat
);
providers.set("default", provider);
logger.log(`Registered default TTS provider: kokoro at ${config.tts.default.url}`);
}
// Premium tier: Chatterbox
if (config.tts.premium.enabled) {
const provider = new ChatterboxTTSProvider(config.tts.premium.url);
providers.set("premium", provider);
logger.log(`Registered premium TTS provider: chatterbox at ${config.tts.premium.url}`);
}
// Fallback tier: Piper
if (config.tts.fallback.enabled) {
const provider = new PiperTtsProvider(config.tts.fallback.url);
providers.set("fallback", provider);
logger.log(`Registered fallback TTS provider: piper at ${config.tts.fallback.url}`);
}
if (providers.size === 0) {
logger.warn("No TTS providers are enabled. TTS synthesis will not be available.");
} else {
const tierNames = Array.from(providers.keys()).join(", ");
logger.log(`TTS providers ready: ${tierNames} (${String(providers.size)} total)`);
}
return providers;
}