Update TTS providers and story markup

This commit is contained in:
2026-05-20 22:13:31 +02:00
parent b911c40d89
commit 8258ea2321
36 changed files with 1482 additions and 197 deletions
+32 -9
View File
@@ -18,7 +18,8 @@ class TTSFactoryModule extends BaseModule {
'browser-tts', // Browser TTS handler
'kokoro-tts', // Kokoro TTS handler
'elevenlabs-tts',// ElevenLabs TTS handler
'openai-tts' // OpenAI TTS handler
'openai-tts', // OpenAI TTS handler
'local-openai-tts' // Local OpenAI-compatible TTS handler
];
this.handlers = {};
this.initStatus = {};
@@ -356,7 +357,7 @@ class TTSFactoryModule extends BaseModule {
}
// Add placeholder entries for important API handlers that might not be registered yet
const apiHandlerIds = ['elevenlabs-tts', 'openai-tts'];
const apiHandlerIds = ['elevenlabs-tts', 'openai-tts', 'local-openai-tts'];
for (const id of apiHandlerIds) {
// Only add if not already in the list
if (!this.handlers[id] && !availableHandlers.some(h => h.id === id)) {
@@ -407,10 +408,24 @@ class TTSFactoryModule extends BaseModule {
'voice': '', // Empty default - will be selected based on handler
'language': 'en_US', // Legacy stored value; game metadata now owns active TTS language
'volume': 1.0, // Default volume
'browser-tts_timeout_ms': 60000,
'kokoro-tts_timeout_ms': 60000,
'elevenlabs_api_key': '', // Empty API key by default
'elevenlabs_api_url': 'https://api.elevenlabs.io/v1', // Default ElevenLabs API URL
'openai_api_key': '', // Empty API key by default
'openai_api_url': 'https://api.openai.com/v1' // Default OpenAI API URL
'openai_api_url': 'https://api.openai.com/v1', // Default OpenAI API URL
'elevenlabs-tts_api_key': '',
'elevenlabs-tts_api_url': 'https://api.elevenlabs.io/v1',
'elevenlabs-tts_timeout_ms': 60000,
'openai-tts_api_key': '',
'openai-tts_api_url': 'https://api.openai.com/v1',
'openai-tts_model': 'tts-1-hd',
'openai-tts_timeout_ms': 60000,
'local-openai-tts_api_key': '',
'local-openai-tts_api_url': 'http://localhost:8000/v1',
'local-openai-tts_voice': 'alloy',
'local-openai-tts_model': 'tts-1',
'local-openai-tts_timeout_ms': 60000
};
// Ensure all defaults are set in persistence if they don't exist
@@ -475,7 +490,8 @@ class TTSFactoryModule extends BaseModule {
{ id: 'kokoro-tts', displayName: 'Kokoro TTS' },
{ id: 'browser-tts', displayName: 'Browser TTS' },
{ id: 'elevenlabs-tts', displayName: 'ElevenLabs TTS' },
{ id: 'openai-tts', displayName: 'OpenAI TTS' }
{ id: 'openai-tts', displayName: 'OpenAI TTS' },
{ id: 'local-openai-tts', displayName: 'Local OpenAI TTS' }
];
// Register each handler
@@ -780,7 +796,7 @@ class TTSFactoryModule extends BaseModule {
}
// Check if we have this speech cached
const hash = await this.generateSpeechHash(text);
const hash = await this.generateSpeechHash(text, options);
const cached = await this.getCachedSpeech(hash);
if (cached && cached.success) {
@@ -845,7 +861,7 @@ class TTSFactoryModule extends BaseModule {
try {
// Generate a hash for this speech request
const hash = await this.generateSpeechHash(text);
const hash = await this.generateSpeechHash(text, options);
// Check if we have this speech cached
const cached = await this.getCachedSpeech(hash);
@@ -1097,6 +1113,7 @@ class TTSFactoryModule extends BaseModule {
getHandlerStatusMessage(id, handler) {
if (!handler) return 'Not registered';
if (handler.isReady === true) return 'Ready';
if (handler.unsupportedReason) return handler.unsupportedReason;
if (id === 'kokoro-tts') return handler.state === 'INITIALIZING' ? 'Loading model' : 'Not loaded';
if (handler.apiKey === '') return 'API key missing';
if (handler.apiKey && handler.isReady !== true) return 'API unavailable or invalid settings';
@@ -1234,7 +1251,7 @@ class TTSFactoryModule extends BaseModule {
let generationStarted = false;
try {
// Generate a hash for this speech request
hash = await this.generateSpeechHash(text);
hash = await this.generateSpeechHash(text, options);
// Check if we have this audio in cache
const cachedData = await this.getCachedSpeech(hash);
@@ -1286,17 +1303,23 @@ class TTSFactoryModule extends BaseModule {
* @param {string} text - Text to generate hash for
* @returns {Promise<string>} - Hash string
*/
async generateSpeechHash(text) {
async generateSpeechHash(text, options = {}) {
const handler = this.getActiveHandler();
const provider = this.activeHandler || 'none';
const voiceInfo = this.getEffectiveVoiceId(handler);
const model = handler?.voiceOptions?.model || handler?.model || '';
const speed = this.speed || 1.0;
const language = this.language || 'en-us';
const ttsInstruction = handler && typeof handler.getRequestInstructions === 'function'
? handler.getRequestInstructions(options)
: '';
const key = JSON.stringify({
provider,
voice: voiceInfo,
model,
speed,
language,
ttsInstruction,
text
});
@@ -1933,7 +1956,7 @@ class TTSFactoryModule extends BaseModule {
const handler = this.handlers[id];
const isInitialized = !!this.initStatus[id];
const isReady = handler && handler.isReady;
const isApiHandler = ['elevenlabs', 'openai', 'kokoro'].includes(id);
const isApiHandler = ['elevenlabs-tts', 'openai-tts', 'local-openai-tts', 'kokoro-tts'].includes(id);
console.log(`Handler ID: ${id}`);
console.log(` - Handler Exists: ${!!handler}`);