Files
ai.interactive.fiction/public/js/tts-handler-module.js

203 lines
5.7 KiB
JavaScript

/**
* TTSHandlerModule Base Class
* Base class for all TTS handler modules
*/
import { BaseModule } from './base-module.js';
export class TTSHandlerModule extends BaseModule {
constructor(id, name) {
super(id, name);
// Common TTS handler properties
this.isReady = false;
this.isSpeaking = false;
this.currentUtterance = null;
this.voices = [];
this.currentVoice = null;
this.defaultVoice = null;
this.speechRate = 1.0;
this.pitch = 1.0;
this.volume = 1.0;
// Common dependencies for TTS handlers
this.dependencies = ['persistence-manager', 'localization'];
// Bind common methods
this.bindMethods([
'speak',
'stop',
'getVoices',
'setVoice',
'configure',
'generateSpeech'
]);
}
/**
* Get the handler ID
* @returns {string} - The handler ID
*/
getId() {
return this.id;
}
/**
* Initialize the TTS handler
* @returns {Promise<boolean>} - Resolves with success status
*/
async initialize() {
try {
this.reportProgress(20, `Initializing ${this.name}`);
// Check for required dependencies
const persistenceManager = this.getModule('persistence-manager');
if (!persistenceManager) {
console.error(`${this.name}: Persistence Manager dependency not found`);
return false;
}
// Load preferences
this.loadPreferences(persistenceManager);
// Set up event listeners
this.setupEventListeners();
return true;
} catch (error) {
console.error(`${this.name}: Initialization error`, error);
return false;
}
}
/**
* Load preferences from persistence manager
* @param {Object} persistenceManager - The persistence manager module
*/
loadPreferences(persistenceManager) {
// Load common preferences
this.speechRate = persistenceManager.getPreference('tts', 'rate', 1.0);
this.pitch = persistenceManager.getPreference('tts', 'pitch', 1.0);
this.volume = persistenceManager.getPreference('tts', 'volume', 1.0);
}
/**
* Set up common event listeners
*/
setupEventListeners() {
// To be implemented by subclasses if needed
}
/**
* Check if the handler is ready
* @returns {boolean} - Whether the handler is ready
*/
isHandlerReady() {
return this.isReady;
}
/**
* Check if the handler is currently speaking
* @returns {boolean} - Whether the handler is speaking
*/
isSpeakingNow() {
return this.isSpeaking;
}
/**
* Get available voices
* @returns {Promise<Array>} - Resolves with array of voice objects
*/
async getVoices() {
return this.voices;
}
/**
* Set the voice to use
* @param {string} voiceId - Voice identifier
* @returns {boolean} - Success status
*/
setVoice(voiceId) {
// To be implemented by subclasses
return false;
}
/**
* Configure TTS parameters
* @param {Object} options - Configuration options
* @returns {boolean} - Success status
*/
configure(options) {
let changed = false;
if (options.voice && options.voice !== this.currentVoice) {
this.setVoice(options.voice);
changed = true;
}
if (options.speed && options.speed !== this.speechRate) {
this.speechRate = options.speed;
changed = true;
}
if (options.pitch && options.pitch !== this.pitch) {
this.pitch = options.pitch;
changed = true;
}
if (options.volume && options.volume !== this.volume) {
this.volume = options.volume;
changed = true;
}
// Save preferences if changed
if (changed) {
const persistenceManager = this.getModule('persistence-manager');
if (persistenceManager) {
persistenceManager.updatePreference('tts', 'rate', this.speechRate);
persistenceManager.updatePreference('tts', 'pitch', this.pitch);
persistenceManager.updatePreference('tts', 'volume', this.volume);
if (this.currentVoice) {
persistenceManager.updatePreference('tts', `${this.id}_voice`, this.currentVoice);
}
}
}
return changed;
}
/**
* Speak text
* @param {string} text - Text to speak
* @param {Function} callback - Callback for when speech completes
* @returns {boolean} - Success status
*/
speak(text, callback) {
// To be implemented by subclasses
console.error(`${this.name}: speak() method not implemented`);
if (callback) {
setTimeout(() => callback({ success: false, reason: 'not_implemented' }), 0);
}
return false;
}
/**
* Stop speaking
* @returns {boolean} - Success status
*/
stop() {
// To be implemented by subclasses
return false;
}
/**
* Generate speech audio data
* @param {string} text - Text to generate speech for
* @param {Object} options - Generation options
* @returns {Promise<Object>} - Resolves with audio data
*/
async generateSpeech(text, options = {}) {
// To be implemented by subclasses
return { success: false, reason: 'not_implemented' };
}
}