All files / src tts-provider.ts

100% Statements 84/84
100% Branches 19/19
100% Functions 11/11
100% Lines 84/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 851x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 25x 25x 25x 25x 25x 1x 1x 25x 25x 25x 25x 1x 1x 16x 15x 15x 16x 1x 1x 1x 1x 1x 13x 13x 16x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 1x 1x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 1x 1x 2x 2x 2x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 2x 2x 2x 1x 1x 1x 3x 3x  
/**
 * TTS Provider Implementation
 */
 
import { TTSClient } from './tts-client.js';
import { ServiceManager } from './service-manager.js';
import { mergeConfig, type TTSProviderConfig } from './config.js';
import type { TTSRequest, TTSResponse, Voice, ServiceHealth } from './types.js';
 
export class TTSProvider {
  readonly name = 'tts';
 
  private config: Required<TTSProviderConfig>;
  private client: TTSClient;
  private serviceManager: ServiceManager;
  private initialized = false;
 
  constructor(config?: Partial<TTSProviderConfig>) {
    this.config = mergeConfig(config);
    this.client = new TTSClient(this.config);
    this.serviceManager = new ServiceManager(this.config);
  }
 
  async initialize(): Promise<void> {
    if (this.initialized) return;
 
    const ready = await this.serviceManager.ensureRunning();
    if (!ready) {
      throw new Error(
        'Speech synthesis service not available. ' +
        `Start it manually: cd ${this.config.servicePath} && npm run dev`
      );
    }
 
    this.initialized = true;
  }
 
  async synthesize(request: TTSRequest): Promise<TTSResponse> {
    if (!this.initialized) {
      await this.initialize();
    }
 
    return this.client.synthesize({
      text: request.text,
      voice: request.voice || this.config.defaultVoice,
      speed: request.speed || this.config.defaultSpeed,
      format: request.format || this.config.defaultFormat,
    });
  }
 
  async speak(text: string, voice?: string): Promise<Buffer> {
    const result = await this.synthesize({ text, voice });
    return result.audio;
  }
 
  async getVoices(): Promise<Voice[]> {
    if (!this.initialized) {
      await this.initialize();
    }
    return this.client.getVoices();
  }
 
  async isAvailable(): Promise<boolean> {
    const health = await this.client.checkHealth(this.config.healthCheckTimeout);
    return health.healthy;
  }
 
  async checkHealth(): Promise<ServiceHealth> {
    return this.client.checkHealth(this.config.healthCheckTimeout);
  }
 
  getConfig(): TTSProviderConfig {
    return { ...this.config };
  }
 
  async cleanup(): Promise<void> {
    await this.serviceManager.stop();
    this.initialized = false;
  }
}
 
export function createTTSProvider(config?: Partial<TTSProviderConfig>): TTSProvider {
  return new TTSProvider(config);
}