UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

150 lines (149 loc) • 6.21 kB
import { t as XAI_BASE_URL } from "./model-definitions-BejEvn8r.mjs"; import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input"; import { asFiniteNumberInRange, asOptionalObjectRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; //#region extensions/xai/speech-provider-metadata-factory.ts const XAI_SPEECH_RESPONSE_FORMATS = [ "mp3", "wav", "pcm", "mulaw", "alaw" ]; const XAI_TTS_FALLBACK_VOICES = [ "ara", "eve", "leo", "rex", "sal" ]; function normalizeXaiTtsBaseUrl(baseUrl) { return normalizeOptionalString(baseUrl)?.replace(/\/+$/, "") ?? XAI_BASE_URL; } function isValidXaiTtsVoice(voice) { return normalizeOptionalString(voice) !== void 0; } function normalizeXaiLanguageCode(value) { const normalized = normalizeOptionalString(value)?.toLowerCase(); if (!normalized) return; if (normalized === "auto" || /^[a-z]{2,3}(?:-[a-z]{2,4})?$/.test(normalized)) return normalized; throw new Error(`xAI language must be "auto" or a BCP-47 tag (e.g. "en", "pt-br", "zh-cn"); got: ${normalized}`); } function normalizeXaiSpeechSpeed(value) { return asFiniteNumberInRange(value, { min: .7, max: 1.5 }); } function normalizeXaiSpeechResponseFormat(value) { const next = normalizeLowercaseStringOrEmpty(value); if (!next) return; const format = XAI_SPEECH_RESPONSE_FORMATS.find((candidate) => candidate === next); if (format) return format; throw new Error(`Invalid xAI speech responseFormat: ${next}`); } function resolveXaiSpeechResponseFormat(target, configuredFormat) { return target === "voice-note" ? "mp3" : configuredFormat ?? "mp3"; } function xaiSpeechResponseFormatToFileExtension(format) { return format === "wav" || format === "pcm" || format === "mulaw" || format === "alaw" ? `.${format}` : ".mp3"; } function normalizeXaiSpeechProviderConfig(rawConfig) { const providers = asOptionalObjectRecord(rawConfig.providers); const xai = asOptionalObjectRecord(providers?.xai ?? rawConfig.xai ?? rawConfig) ?? {}; return { apiKey: normalizeResolvedSecretInputString({ value: xai.apiKey, path: "tts.providers.xai.apiKey" }), baseUrl: normalizeXaiTtsBaseUrl(normalizeOptionalString(xai.baseUrl) ?? normalizeOptionalString(process.env.XAI_BASE_URL) ?? XAI_BASE_URL), voiceId: normalizeOptionalString(xai.voiceId ?? xai.voice) ?? "eve", language: normalizeXaiLanguageCode(xai.language ?? xai.languageCode), speed: normalizeXaiSpeechSpeed(xai.speed), responseFormat: normalizeXaiSpeechResponseFormat(xai.responseFormat) }; } function readXaiSpeechProviderConfig(config) { const normalized = normalizeXaiSpeechProviderConfig({}); return { apiKey: normalizeOptionalString(config.apiKey), baseUrl: normalizeOptionalString(config.baseUrl) ?? normalized.baseUrl, voiceId: normalizeOptionalString(config.voiceId ?? config.voice) ?? normalized.voiceId, language: normalizeXaiLanguageCode(config.language ?? config.languageCode), speed: normalizeXaiSpeechSpeed(config.speed), responseFormat: normalizeXaiSpeechResponseFormat(config.responseFormat) }; } function readXaiSpeechOverrides(overrides) { if (!overrides) return {}; return { voiceId: normalizeOptionalString(overrides.voiceId ?? overrides.voice), language: normalizeXaiLanguageCode(overrides.language), speed: normalizeXaiSpeechSpeed(overrides.speed) }; } function resolveDirectXaiAudioApiKey(configApiKey) { return normalizeOptionalString(configApiKey) ?? normalizeOptionalString(process.env.XAI_API_KEY); } function parseXaiSpeechDirectiveToken(ctx) { switch (ctx.key) { case "voice": case "voice_id": case "voiceid": case "xai_voice": case "xaivoice": if (!ctx.policy.allowVoice) return { handled: true }; if (!isValidXaiTtsVoice(ctx.value)) return { handled: true, warnings: [`invalid xAI voice "${ctx.value}"`] }; return { handled: true, overrides: { voiceId: ctx.value } }; default: return { handled: false }; } } function createXaiSpeechProviderMetadata(context) { return { id: "xai", label: "xAI", autoSelectOrder: 25, models: [], voices: XAI_TTS_FALLBACK_VOICES, resolveConfig: ({ rawConfig }) => normalizeXaiSpeechProviderConfig(rawConfig), parseDirectiveToken: parseXaiSpeechDirectiveToken, resolveTalkConfig: ({ baseTtsConfig, talkProviderConfig }) => { const base = normalizeXaiSpeechProviderConfig(baseTtsConfig); const responseFormat = normalizeXaiSpeechResponseFormat(talkProviderConfig.responseFormat); const baseUrl = normalizeOptionalString(talkProviderConfig.baseUrl); return { ...base, apiKey: talkProviderConfig.apiKey === void 0 ? base.apiKey : normalizeResolvedSecretInputString({ value: talkProviderConfig.apiKey, path: "talk.providers.xai.apiKey" }), baseUrl: baseUrl === void 0 ? base.baseUrl : normalizeXaiTtsBaseUrl(baseUrl), voiceId: normalizeOptionalString(talkProviderConfig.voiceId) ?? base.voiceId, language: normalizeXaiLanguageCode(talkProviderConfig.language ?? talkProviderConfig.languageCode) ?? base.language, speed: normalizeXaiSpeechSpeed(talkProviderConfig.speed) ?? base.speed, responseFormat: responseFormat ?? base.responseFormat }; }, resolveTalkOverrides: ({ params }) => { const voiceId = normalizeOptionalString(params.voiceId ?? params.voice); const language = normalizeXaiLanguageCode(params.language ?? params.languageCode); const speed = normalizeXaiSpeechSpeed(params.speed); return { ...voiceId === void 0 ? {} : { voiceId }, ...language === void 0 ? {} : { language }, ...speed === void 0 ? {} : { speed } }; }, isConfigured: ({ providerConfig, cfg }) => Boolean(resolveDirectXaiAudioApiKey(readXaiSpeechProviderConfig(providerConfig).apiKey)) || context.isProviderAuthProfileConfigured({ provider: "xai", cfg }) }; } //#endregion export { normalizeXaiTtsBaseUrl as a, resolveDirectXaiAudioApiKey as c, normalizeXaiLanguageCode as i, resolveXaiSpeechResponseFormat as l, createXaiSpeechProviderMetadata as n, readXaiSpeechOverrides as o, isValidXaiTtsVoice as r, readXaiSpeechProviderConfig as s, XAI_TTS_FALLBACK_VOICES as t, xaiSpeechResponseFormatToFileExtension as u };