feat(#391): add base TTS provider and factory classes
All checks were successful
ci/woodpecker/push/api Pipeline was successful
All checks were successful
ci/woodpecker/push/api Pipeline was successful
Add the BaseTTSProvider abstract class and TTS provider factory that were part of the tiered TTS architecture but missed from the previous commit. - BaseTTSProvider: abstract base with synthesize(), listVoices(), isHealthy() - tts-provider.factory: creates Kokoro/Chatterbox/Piper providers from config - 30 tests (22 base provider + 8 factory) Refs #391
This commit is contained in:
112
apps/api/src/speech/providers/tts-provider.factory.ts
Normal file
112
apps/api/src/speech/providers/tts-provider.factory.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 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 { BaseTTSProvider } from "./base-tts.provider";
|
||||
import type { ITTSProvider } from "../interfaces/tts-provider.interface";
|
||||
import type { SpeechTier, AudioFormat } from "../interfaces/speech-types";
|
||||
import type { SpeechConfig } from "../speech.config";
|
||||
|
||||
// ==========================================
|
||||
// Concrete provider classes
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* Kokoro TTS provider (default tier).
|
||||
* CPU-based, always available, Apache 2.0 license.
|
||||
*/
|
||||
class KokoroProvider extends BaseTTSProvider {
|
||||
readonly name = "kokoro";
|
||||
readonly tier: SpeechTier = "default";
|
||||
}
|
||||
|
||||
/**
|
||||
* Chatterbox TTS provider (premium tier).
|
||||
* GPU required, voice cloning capable, MIT license.
|
||||
*/
|
||||
class ChatterboxProvider extends BaseTTSProvider {
|
||||
readonly name = "chatterbox";
|
||||
readonly tier: SpeechTier = "premium";
|
||||
|
||||
constructor(baseURL: string) {
|
||||
super(baseURL, "default", "mp3");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Piper TTS provider via OpenedAI Speech (fallback tier).
|
||||
* Ultra-lightweight CPU, GPL license.
|
||||
*/
|
||||
class PiperProvider extends BaseTTSProvider {
|
||||
readonly name = "piper";
|
||||
readonly tier: SpeechTier = "fallback";
|
||||
|
||||
constructor(baseURL: string) {
|
||||
super(baseURL, "alloy", "mp3");
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 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 KokoroProvider(
|
||||
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 ChatterboxProvider(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 PiperProvider(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;
|
||||
}
|
||||
Reference in New Issue
Block a user