Spaces:
Paused
Paused
| import type { GatewayRequestHandlers } from "./types.js"; | |
| import { loadConfig } from "../../config/config.js"; | |
| import { | |
| OPENAI_TTS_MODELS, | |
| OPENAI_TTS_VOICES, | |
| getTtsProvider, | |
| isTtsEnabled, | |
| isTtsProviderConfigured, | |
| resolveTtsAutoMode, | |
| resolveTtsApiKey, | |
| resolveTtsConfig, | |
| resolveTtsPrefsPath, | |
| resolveTtsProviderOrder, | |
| setTtsEnabled, | |
| setTtsProvider, | |
| textToSpeech, | |
| } from "../../tts/tts.js"; | |
| import { ErrorCodes, errorShape } from "../protocol/index.js"; | |
| import { formatForLog } from "../ws-log.js"; | |
| export const ttsHandlers: GatewayRequestHandlers = { | |
| "tts.status": async ({ respond }) => { | |
| try { | |
| const cfg = loadConfig(); | |
| const config = resolveTtsConfig(cfg); | |
| const prefsPath = resolveTtsPrefsPath(config); | |
| const provider = getTtsProvider(config, prefsPath); | |
| const autoMode = resolveTtsAutoMode({ config, prefsPath }); | |
| const fallbackProviders = resolveTtsProviderOrder(provider) | |
| .slice(1) | |
| .filter((candidate) => isTtsProviderConfigured(config, candidate)); | |
| respond(true, { | |
| enabled: isTtsEnabled(config, prefsPath), | |
| auto: autoMode, | |
| provider, | |
| fallbackProvider: fallbackProviders[0] ?? null, | |
| fallbackProviders, | |
| prefsPath, | |
| hasOpenAIKey: Boolean(resolveTtsApiKey(config, "openai")), | |
| hasElevenLabsKey: Boolean(resolveTtsApiKey(config, "elevenlabs")), | |
| edgeEnabled: isTtsProviderConfigured(config, "edge"), | |
| }); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| "tts.enable": async ({ respond }) => { | |
| try { | |
| const cfg = loadConfig(); | |
| const config = resolveTtsConfig(cfg); | |
| const prefsPath = resolveTtsPrefsPath(config); | |
| setTtsEnabled(prefsPath, true); | |
| respond(true, { enabled: true }); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| "tts.disable": async ({ respond }) => { | |
| try { | |
| const cfg = loadConfig(); | |
| const config = resolveTtsConfig(cfg); | |
| const prefsPath = resolveTtsPrefsPath(config); | |
| setTtsEnabled(prefsPath, false); | |
| respond(true, { enabled: false }); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| "tts.convert": async ({ params, respond }) => { | |
| const text = typeof params.text === "string" ? params.text.trim() : ""; | |
| if (!text) { | |
| respond( | |
| false, | |
| undefined, | |
| errorShape(ErrorCodes.INVALID_REQUEST, "tts.convert requires text"), | |
| ); | |
| return; | |
| } | |
| try { | |
| const cfg = loadConfig(); | |
| const channel = typeof params.channel === "string" ? params.channel.trim() : undefined; | |
| const result = await textToSpeech({ text, cfg, channel }); | |
| if (result.success && result.audioPath) { | |
| respond(true, { | |
| audioPath: result.audioPath, | |
| provider: result.provider, | |
| outputFormat: result.outputFormat, | |
| voiceCompatible: result.voiceCompatible, | |
| }); | |
| return; | |
| } | |
| respond( | |
| false, | |
| undefined, | |
| errorShape(ErrorCodes.UNAVAILABLE, result.error ?? "TTS conversion failed"), | |
| ); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| "tts.setProvider": async ({ params, respond }) => { | |
| const provider = typeof params.provider === "string" ? params.provider.trim() : ""; | |
| if (provider !== "openai" && provider !== "elevenlabs" && provider !== "edge") { | |
| respond( | |
| false, | |
| undefined, | |
| errorShape( | |
| ErrorCodes.INVALID_REQUEST, | |
| "Invalid provider. Use openai, elevenlabs, or edge.", | |
| ), | |
| ); | |
| return; | |
| } | |
| try { | |
| const cfg = loadConfig(); | |
| const config = resolveTtsConfig(cfg); | |
| const prefsPath = resolveTtsPrefsPath(config); | |
| setTtsProvider(prefsPath, provider); | |
| respond(true, { provider }); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| "tts.providers": async ({ respond }) => { | |
| try { | |
| const cfg = loadConfig(); | |
| const config = resolveTtsConfig(cfg); | |
| const prefsPath = resolveTtsPrefsPath(config); | |
| respond(true, { | |
| providers: [ | |
| { | |
| id: "openai", | |
| name: "OpenAI", | |
| configured: Boolean(resolveTtsApiKey(config, "openai")), | |
| models: [...OPENAI_TTS_MODELS], | |
| voices: [...OPENAI_TTS_VOICES], | |
| }, | |
| { | |
| id: "elevenlabs", | |
| name: "ElevenLabs", | |
| configured: Boolean(resolveTtsApiKey(config, "elevenlabs")), | |
| models: ["eleven_multilingual_v2", "eleven_turbo_v2_5", "eleven_monolingual_v1"], | |
| }, | |
| { | |
| id: "edge", | |
| name: "Edge TTS", | |
| configured: isTtsProviderConfigured(config, "edge"), | |
| models: [], | |
| }, | |
| ], | |
| active: getTtsProvider(config, prefsPath), | |
| }); | |
| } catch (err) { | |
| respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); | |
| } | |
| }, | |
| }; | |