@elizaos/plugin-elevenlabs 2.0.3-beta.5 → 2.0.3-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.browser.js +4 -0
- package/dist/browser/index.browser.js.map +11 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.node.cjs +521 -0
- package/dist/cjs/index.node.cjs.map +11 -0
- package/dist/index.browser.d.ts +3 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.node.d.ts +3 -0
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.node.js +487 -0
- package/dist/node/index.node.js.map +11 -0
- package/package.json +3 -3
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.ts", "../../src/index.node.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { ElevenLabsClient } from \"@elevenlabs/elevenlabs-js\";\nimport type {\n BodySpeechToTextV1SpeechToTextPost,\n MultichannelSpeechToTextResponseModel,\n SpeechToTextChunkResponseModel,\n SpeechToTextConvertRequestModelId,\n SpeechToTextConvertRequestTimestampsGranularity,\n TextToSpeechStreamRequestOutputFormat,\n} from \"@elevenlabs/elevenlabs-js/api\";\nimport {\n SpeechToTextConvertRequestModelId as SttModelIdEnum,\n SpeechToTextConvertRequestTimestampsGranularity as SttTimestampsGranularityEnum,\n TextToSpeechStreamRequestOutputFormat as TtsOutputFormatEnum,\n} from \"@elevenlabs/elevenlabs-js/api\";\nimport {\n type IAgentRuntime,\n logger,\n ModelType,\n type Plugin,\n parseBooleanFromText,\n} from \"@elizaos/core\";\n\nfunction parseTtsOutputFormat(\n format: string,\n): TextToSpeechStreamRequestOutputFormat {\n for (const allowed of Object.values(TtsOutputFormatEnum)) {\n if (allowed === format) return allowed;\n }\n throw new Error(`Unsupported ElevenLabs TTS output format: ${format}`);\n}\n\nfunction parseSttModelId(id: string): SpeechToTextConvertRequestModelId {\n for (const allowed of Object.values(SttModelIdEnum)) {\n if (allowed === id) return allowed;\n }\n throw new Error(`Unsupported ElevenLabs STT model: ${id}`);\n}\n\nfunction parseSttTimestampsGranularity(\n value: string,\n): SpeechToTextConvertRequestTimestampsGranularity {\n for (const allowed of Object.values(SttTimestampsGranularityEnum)) {\n if (allowed === value) return allowed;\n }\n throw new Error(\n `Unsupported ElevenLabs STT timestamps granularity: ${value}`,\n );\n}\n\nfunction extractTranscript(\n response:\n | SpeechToTextChunkResponseModel\n | MultichannelSpeechToTextResponseModel,\n): string {\n if (\"transcripts\" in response) {\n return response.transcripts.map((t) => t.text).join(\"\\n\");\n }\n return response.text;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction nonEmptyString(value: unknown): string {\n return typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction normalizeTtsInput(\n input:\n | string\n | {\n text: string;\n model?: string;\n voiceId?: string;\n format?: string;\n instructions?: string;\n },\n): {\n text: string;\n model?: string;\n voiceId?: string;\n format?: string;\n instructions?: string;\n} {\n const options = typeof input === \"string\" ? { text: input } : input;\n if (!isRecord(options) || !nonEmptyString(options.text)) {\n throw new Error(\"ElevenLabs TTS text is required\");\n }\n if (options.model !== undefined && !nonEmptyString(options.model)) {\n throw new Error(\"ElevenLabs TTS model must be a non-empty string\");\n }\n if (options.voiceId !== undefined && !nonEmptyString(options.voiceId)) {\n throw new Error(\"ElevenLabs TTS voiceId must be a non-empty string\");\n }\n if (options.format !== undefined && !nonEmptyString(options.format)) {\n throw new Error(\"ElevenLabs TTS format must be a non-empty string\");\n }\n return {\n ...options,\n text: options.text.trim(),\n model: options.model === undefined ? undefined : options.model.trim(),\n voiceId: options.voiceId === undefined ? undefined : options.voiceId.trim(),\n format: options.format === undefined ? undefined : options.format.trim(),\n };\n}\n\nfunction validateAudioUrl(value: unknown): string {\n const url = nonEmptyString(value);\n if (!url) {\n throw new Error(\"ElevenLabs transcription audioUrl is required\");\n }\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new Error(\"ElevenLabs transcription audioUrl must be a valid URL\");\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\"ElevenLabs transcription audioUrl must use http or https\");\n }\n return parsed.toString();\n}\n\n/**\n * Voice settings configuration for ElevenLabs API\n */\ninterface VoiceSettings {\n apiKey: string;\n voiceId: string;\n model: string;\n stability: string;\n latency: string;\n outputFormat: string;\n similarity: string;\n style: string;\n speakerBoost: boolean;\n}\n\ninterface TranscriptionSettings {\n apiKey: string;\n modelId: string;\n languageCode?: string;\n timestampsGranularity: string;\n diarize: boolean;\n numSpeakers?: number;\n tagAudioEvents: boolean;\n}\n\nfunction isBrowser(): boolean {\n return typeof globalThis.document !== \"undefined\";\n}\n\nfunction getSetting(runtime: IAgentRuntime, key: string): string | undefined;\nfunction getSetting(\n runtime: IAgentRuntime,\n key: string,\n fallback: string,\n): string;\nfunction getSetting(\n runtime: IAgentRuntime,\n key: string,\n fallback?: string,\n): string | undefined {\n const rawRuntime = runtime.getSetting(key);\n const fromRuntime =\n rawRuntime === null || rawRuntime === undefined\n ? undefined\n : String(rawRuntime);\n\n const envValue =\n typeof process !== \"undefined\" &&\n process.env &&\n typeof process.env[key] === \"string\"\n ? process.env[key]\n : undefined;\n\n return fromRuntime ?? envValue ?? fallback;\n}\n\nfunction getBaseURL(runtime: IAgentRuntime): string {\n const browserRaw = runtime.getSetting(\"ELEVENLABS_BROWSER_URL\");\n const browserURL =\n browserRaw === null || browserRaw === undefined\n ? undefined\n : String(browserRaw);\n if (isBrowser() && browserURL) return browserURL;\n return \"https://api.elevenlabs.io/v1\";\n}\n\nfunction getApiKey(runtime: IAgentRuntime): string | undefined {\n const raw = runtime.getSetting(\"ELEVENLABS_API_KEY\");\n const fromRuntime =\n raw === null || raw === undefined ? undefined : String(raw);\n const fromEnv =\n typeof process !== \"undefined\" &&\n process.env &&\n typeof process.env.ELEVENLABS_API_KEY === \"string\"\n ? process.env.ELEVENLABS_API_KEY\n : undefined;\n return fromRuntime ?? fromEnv;\n}\n\nfunction getElevenLabsClientConfig(runtime: IAgentRuntime): {\n apiKey?: string;\n baseUrl: string;\n} {\n const apiKey = getApiKey(runtime)?.trim();\n const baseUrl = getBaseURL(runtime);\n if (apiKey) return { apiKey, baseUrl };\n if (isBrowser() && baseUrl !== \"https://api.elevenlabs.io/v1\") {\n return { baseUrl };\n }\n throw new Error(\n \"ELEVENLABS_API_KEY is required unless ELEVENLABS_BROWSER_URL is configured in browser mode\",\n );\n}\n\n/**\n * Function to retrieve voice settings based on runtime and environment variables.\n * @param {IAgentRuntime} runtime - The agent runtime object.\n * @returns {VoiceSettings} - Object containing various voice settings.\n */\nfunction getVoiceSettings(runtime: IAgentRuntime): VoiceSettings {\n return {\n apiKey: getApiKey(runtime) || \"\",\n voiceId: getSetting(runtime, \"ELEVENLABS_VOICE_ID\", \"EXAVITQu4vr4xnSDxMaL\"),\n model: getSetting(runtime, \"ELEVENLABS_MODEL_ID\", \"eleven_monolingual_v1\"),\n stability: getSetting(runtime, \"ELEVENLABS_VOICE_STABILITY\", \"0.5\"),\n latency: getSetting(runtime, \"ELEVENLABS_OPTIMIZE_STREAMING_LATENCY\", \"0\"),\n // Use mp3 by default to be browser-safe and align with OpenAI plugin behavior\n outputFormat: getSetting(\n runtime,\n \"ELEVENLABS_OUTPUT_FORMAT\",\n \"mp3_44100_128\",\n ),\n similarity: getSetting(\n runtime,\n \"ELEVENLABS_VOICE_SIMILARITY_BOOST\",\n \"0.75\",\n ),\n style: getSetting(runtime, \"ELEVENLABS_VOICE_STYLE\", \"0\"),\n speakerBoost: parseBooleanFromText(\n `${getSetting(runtime, \"ELEVENLABS_VOICE_USE_SPEAKER_BOOST\", \"true\") ?? \"true\"}`,\n ),\n };\n}\n\nfunction getTranscriptionSettings(\n runtime: IAgentRuntime,\n): TranscriptionSettings {\n const languageCode = getSetting(runtime, \"ELEVENLABS_STT_LANGUAGE_CODE\");\n const numSpeakersStr = getSetting(runtime, \"ELEVENLABS_STT_NUM_SPEAKERS\");\n const numSpeakers = numSpeakersStr ? Number(numSpeakersStr) : undefined;\n if (\n numSpeakers !== undefined &&\n (!Number.isInteger(numSpeakers) || numSpeakers < 1 || numSpeakers > 32)\n ) {\n throw new Error(\n \"ELEVENLABS_STT_NUM_SPEAKERS must be an integer between 1 and 32\",\n );\n }\n\n return {\n apiKey: getApiKey(runtime) || \"\",\n modelId: getSetting(runtime, \"ELEVENLABS_STT_MODEL_ID\", \"scribe_v1\"),\n languageCode: languageCode || undefined,\n timestampsGranularity: getSetting(\n runtime,\n \"ELEVENLABS_STT_TIMESTAMPS_GRANULARITY\",\n \"word\",\n ),\n diarize: parseBooleanFromText(\n `${getSetting(runtime, \"ELEVENLABS_STT_DIARIZE\", \"false\") ?? \"false\"}`,\n ),\n numSpeakers,\n tagAudioEvents: parseBooleanFromText(\n `${getSetting(runtime, \"ELEVENLABS_STT_TAG_AUDIO_EVENTS\", \"false\") ?? \"false\"}`,\n ),\n };\n}\n\nfunction isBufferInput(input: unknown): input is Buffer {\n return (\n typeof Buffer !== \"undefined\" &&\n typeof Buffer.isBuffer === \"function\" &&\n Buffer.isBuffer(input)\n );\n}\n\nasync function responseToAudioFile(response: Response): Promise<Buffer | Blob> {\n if (isBrowser()) {\n if (typeof response.blob === \"function\") {\n return response.blob();\n }\n const arrayBuffer = await response.arrayBuffer();\n return new Blob([arrayBuffer]);\n }\n const arrayBuffer = await response.arrayBuffer();\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(arrayBuffer);\n }\n return new Blob([arrayBuffer]);\n}\n\n/**\n * Fetch speech from ElevenLabs API using official SDK.\n * Returns an in-memory binary payload to satisfy the core TTS contract.\n * @param {IAgentRuntime} runtime - The runtime interface containing necessary data for the API call.\n * @param {string} text - The text to be converted into speech.\n * @returns {Promise<Uint8Array>}\n */\nasync function readStreamToUint8Array(\n stream: ReadableStream<Uint8Array>,\n): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n chunks.push(value);\n totalLength += value.byteLength;\n }\n\n const output = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n output.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return output;\n}\n\nasync function fetchSpeech(\n runtime: IAgentRuntime,\n params: {\n text: string;\n voiceId: string;\n modelId: string;\n outputFormat: string;\n stability: string;\n similarity: string;\n style: string;\n speakerBoost: boolean;\n latency: string;\n },\n): Promise<Uint8Array> {\n try {\n const client = new ElevenLabsClient(getElevenLabsClientConfig(runtime));\n\n const stream = await client.textToSpeech.stream(params.voiceId, {\n text: params.text,\n modelId: params.modelId,\n outputFormat: parseTtsOutputFormat(params.outputFormat),\n optimizeStreamingLatency: Number(params.latency) || 0,\n voiceSettings: {\n stability: Number(params.stability) || 0,\n similarityBoost: Number(params.similarity) || 0,\n style: Number(params.style) || 0,\n useSpeakerBoost: !!params.speakerBoost,\n },\n });\n\n if (!stream) {\n throw new Error(\"Empty response body from ElevenLabs SDK\");\n }\n\n return readStreamToUint8Array(stream);\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.error(`ElevenLabs fetchSpeech error: ${msg}`);\n throw error instanceof Error ? error : new Error(msg);\n }\n}\n\nasync function fetchTranscription(\n runtime: IAgentRuntime,\n params: {\n audioFile: File | Buffer | Blob;\n modelId: string;\n languageCode?: string;\n timestampsGranularity: string;\n diarize: boolean;\n numSpeakers?: number;\n tagAudioEvents: boolean;\n },\n): Promise<string> {\n try {\n const client = new ElevenLabsClient(getElevenLabsClientConfig(runtime));\n\n const body: BodySpeechToTextV1SpeechToTextPost = {\n modelId: parseSttModelId(params.modelId),\n file: params.audioFile,\n };\n\n if (params.languageCode) {\n body.languageCode = params.languageCode;\n }\n\n body.timestampsGranularity = parseSttTimestampsGranularity(\n params.timestampsGranularity,\n );\n\n if (params.diarize) {\n body.diarize = true;\n if (params.numSpeakers !== undefined) {\n body.numSpeakers = params.numSpeakers;\n }\n }\n\n if (params.tagAudioEvents) {\n body.tagAudioEvents = true;\n }\n\n const response = await client.speechToText.convert(body);\n\n if (!response) {\n throw new Error(\"Empty response from ElevenLabs STT API\");\n }\n\n return extractTranscript(response);\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.error(`ElevenLabs fetchTranscription error: ${msg}`);\n throw error instanceof Error ? error : new Error(msg);\n }\n}\n\n// Note: WAV header utilities removed to ensure browser safety. Prefer mp3 output.\n\n/**\n * Represents the ElevenLabs plugin.\n * This plugin provides text-to-speech and speech-to-text functionality using the ElevenLabs API.\n *\n * Features:\n * - High-quality voice synthesis (TTS)\n * - High-accuracy speech transcription (STT) with Scribe v1 model\n * - Support for multiple voice models and settings\n * - Configurable voice parameters (stability, similarity, style)\n * - Stream-based audio output for efficient memory usage\n * - Speaker diarization (up to 32 speakers)\n * - Multi-language support (99 languages for STT)\n * - Audio event detection (laughter, applause, etc.)\n *\n * Required environment variables:\n * - ELEVENLABS_API_KEY: Your ElevenLabs API key\n *\n * Optional TTS environment variables:\n * - ELEVENLABS_VOICE_ID: Voice ID to use (default: EXAVITQu4vr4xnSDxMaL)\n * - ELEVENLABS_MODEL_ID: Model to use (default: eleven_monolingual_v1)\n * - ELEVENLABS_VOICE_STABILITY: Voice stability 0-1 (default: 0.5)\n * - ELEVENLABS_VOICE_SIMILARITY_BOOST: Voice similarity 0-1 (default: 0.75)\n * - ELEVENLABS_VOICE_STYLE: Voice style 0-1 (default: 0)\n * - ELEVENLABS_VOICE_USE_SPEAKER_BOOST: Enable speaker boost (default: true)\n * - ELEVENLABS_OPTIMIZE_STREAMING_LATENCY: Latency optimization 0-4 (default: 0)\n * - ELEVENLABS_OUTPUT_FORMAT: Output format (default: mp3_44100_128)\n *\n * Optional STT environment variables:\n * - ELEVENLABS_STT_MODEL_ID: STT model ID (default: scribe_v1)\n * - ELEVENLABS_STT_LANGUAGE_CODE: Language code for transcription (auto-detect if not set)\n * - ELEVENLABS_STT_TIMESTAMPS_GRANULARITY: Timestamp level (default: word)\n * - ELEVENLABS_STT_DIARIZE: Enable speaker diarization (default: false)\n * - ELEVENLABS_STT_NUM_SPEAKERS: Expected number of speakers (1-32)\n * - ELEVENLABS_STT_TAG_AUDIO_EVENTS: Tag audio events (default: false)\n *\n * @type {Plugin}\n */\nexport const elevenLabsPlugin: Plugin = {\n name: \"elevenLabs\",\n description:\n \"High-quality text-to-speech synthesis and speech-to-text transcription using ElevenLabs API with support for multiple voices, languages, and speaker diarization\",\n models: {\n [ModelType.TEXT_TO_SPEECH]: async (\n runtime: IAgentRuntime,\n input:\n | string\n | {\n text: string;\n model?: string;\n voiceId?: string;\n format?: string;\n instructions?: string;\n },\n ) => {\n const options = normalizeTtsInput(input);\n const settings = getVoiceSettings(runtime);\n const resolvedModel = options.model || settings.model;\n // Prefer explicit ElevenLabs voiceId param; fall back to configured voiceId.\n const resolvedVoiceId = options.voiceId ?? settings.voiceId;\n // Honor explicit caller-provided format (e.g., \"pcm_16000\", \"mp3_22050_64\").\n // Gracefully map generic \"mp3\" to a valid ElevenLabs enum, otherwise pass through.\n // Only default to settings.outputFormat when absent.\n const outputFormat = options.format\n ? options.format === \"mp3\"\n ? \"mp3_44100_128\"\n : (options.format as string)\n : settings.outputFormat;\n\n logger.log(`[ElevenLabs] Using TEXT_TO_SPEECH model: ${resolvedModel}`);\n try {\n const stream = await fetchSpeech(runtime, {\n text: options.text,\n voiceId: resolvedVoiceId,\n modelId: resolvedModel,\n outputFormat,\n stability: settings.stability,\n similarity: settings.similarity,\n style: settings.style,\n speakerBoost: settings.speakerBoost,\n latency: settings.latency,\n });\n return stream;\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.error(`ElevenLabs model error: ${msg}`);\n throw error instanceof Error ? error : new Error(msg);\n }\n },\n [ModelType.TRANSCRIPTION]: async (\n runtime: IAgentRuntime,\n input: string | Buffer | { audioUrl: string; prompt?: string },\n ) => {\n const settings = getTranscriptionSettings(runtime);\n\n logger.log(`[ElevenLabs] Using TRANSCRIPTION model: ${settings.modelId}`);\n\n try {\n let audioFile: Buffer | File | Blob;\n\n if (typeof input === \"string\") {\n const audioUrl = validateAudioUrl(input);\n const response = await fetch(audioUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch audio from URL: ${audioUrl}`);\n }\n audioFile = await responseToAudioFile(response);\n } else if (isBufferInput(input)) {\n audioFile = input;\n } else if (isRecord(input) && \"audioUrl\" in input) {\n const audioUrl = validateAudioUrl(input.audioUrl);\n const response = await fetch(audioUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch audio from URL: ${audioUrl}`);\n }\n audioFile = await responseToAudioFile(response);\n } else {\n throw new Error(\"Invalid input type for TRANSCRIPTION model\");\n }\n\n const transcript = await fetchTranscription(runtime, {\n audioFile,\n modelId: settings.modelId,\n languageCode: settings.languageCode,\n timestampsGranularity: settings.timestampsGranularity,\n diarize: settings.diarize,\n numSpeakers: settings.numSpeakers,\n tagAudioEvents: settings.tagAudioEvents,\n });\n\n return transcript;\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.error(`ElevenLabs transcription error: ${msg}`);\n throw error instanceof Error ? error : new Error(msg);\n }\n },\n },\n tests: [\n {\n name: \"test eleven labs\",\n tests: [\n {\n name: \"Eleven Labs API key validation\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getVoiceSettings(runtime);\n if (!settings.apiKey) {\n throw new Error(\n \"Missing API key: Please provide a valid Eleven Labs API key.\",\n );\n }\n },\n },\n {\n name: \"Voice settings validation\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getVoiceSettings(runtime);\n\n // Validate that all required settings are present\n if (!settings.voiceId) {\n throw new Error(\"Missing voice ID configuration\");\n }\n\n // Validate numeric settings\n const stability = Number.parseFloat(settings.stability);\n if (Number.isNaN(stability) || stability < 0 || stability > 1) {\n throw new Error(\"Voice stability must be between 0 and 1\");\n }\n\n const similarity = Number.parseFloat(settings.similarity);\n if (Number.isNaN(similarity) || similarity < 0 || similarity > 1) {\n throw new Error(\"Voice similarity boost must be between 0 and 1\");\n }\n\n logger.success(\"Voice settings validated successfully\");\n },\n },\n // WAV header generation test removed; we favor mp3 streaming for browser safety\n {\n name: \"Eleven Labs API connectivity\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getVoiceSettings(runtime);\n if (!settings.apiKey) {\n logger.warn(\n \"Skipping API connectivity test - no API key provided\",\n );\n return;\n }\n\n try {\n await fetchSpeech(runtime, {\n text: \"test\",\n voiceId: settings.voiceId,\n modelId: settings.model,\n outputFormat: settings.outputFormat,\n stability: settings.stability,\n similarity: settings.similarity,\n style: settings.style,\n speakerBoost: settings.speakerBoost,\n latency: settings.latency,\n });\n logger.success(\"API connectivity test passed\");\n } catch (error: unknown) {\n const msg =\n error instanceof Error ? error.message : String(error);\n if (msg.includes(\"QUOTA_EXCEEDED\")) {\n logger.warn(\"API quota exceeded - test skipped\");\n return;\n }\n logger.error(`API connectivity test failed: ${msg}`);\n throw new Error(`API connectivity test failed: ${msg}`);\n }\n },\n },\n {\n name: \"ElevenLabs TTS Generation (stream exists)\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getVoiceSettings(runtime);\n if (!settings.apiKey && !isBrowser()) {\n logger.warn(\"Skipping TTS generation test - no API key provided\");\n return;\n }\n\n const testText = \"Hello from ElevenLabs test.\";\n try {\n const audio = await runtime.useModel(\n ModelType.TEXT_TO_SPEECH,\n testText,\n );\n\n const bytes: Uint8Array | null =\n audio instanceof Uint8Array\n ? audio\n : Buffer.isBuffer(audio)\n ? new Uint8Array(audio)\n : audio instanceof ArrayBuffer\n ? new Uint8Array(audio)\n : null;\n\n if (!bytes || bytes.byteLength === 0) {\n throw new Error(\n \"TTS output must be non-empty Uint8Array, Buffer, or ArrayBuffer\",\n );\n }\n logger.success(\"Received TTS binary payload successfully\");\n } catch (error: unknown) {\n const msg =\n error instanceof Error ? error.message : String(error);\n if (msg.includes(\"QUOTA_EXCEEDED\")) {\n logger.warn(\n \"[ElevenLabs Test] API quota exceeded - test skipped\",\n );\n return;\n }\n logger.error(\n \"[ElevenLabs Test] TTS Generation test failed:\",\n msg,\n );\n throw new Error(`TTS Generation test failed: ${msg}`);\n }\n },\n },\n {\n name: \"Output format handling\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getVoiceSettings(runtime);\n\n // Test supported formats list includes common entries\n const pcmFormats = [\n \"mp3_44100_128\",\n \"pcm_16000\",\n \"pcm_22050\",\n \"pcm_24000\",\n \"pcm_44100\",\n ];\n for (const format of pcmFormats) {\n if (format.startsWith(\"pcm_\")) {\n const sampleRate = Number.parseInt(format.slice(4), 10);\n if (Number.isNaN(sampleRate) || sampleRate <= 0) {\n throw new Error(`Invalid PCM format: ${format}`);\n }\n }\n }\n\n // Test current output format\n logger.success(`Output format validated: ${settings.outputFormat}`);\n },\n },\n ],\n },\n {\n name: \"test eleven labs STT\",\n tests: [\n {\n name: \"STT settings validation\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getTranscriptionSettings(runtime);\n\n if (!settings.modelId) {\n throw new Error(\"Missing STT model ID configuration\");\n }\n\n const validGranularities = [\"none\", \"word\", \"character\"];\n if (!validGranularities.includes(settings.timestampsGranularity)) {\n throw new Error(\n `Invalid timestamps granularity: ${settings.timestampsGranularity}`,\n );\n }\n\n if (\n settings.numSpeakers !== undefined &&\n (settings.numSpeakers < 1 || settings.numSpeakers > 32)\n ) {\n throw new Error(\"Number of speakers must be between 1 and 32\");\n }\n\n logger.success(\"STT settings validated successfully\");\n },\n },\n {\n name: \"STT configuration defaults\",\n fn: async (runtime: IAgentRuntime) => {\n const settings = getTranscriptionSettings(runtime);\n\n if (settings.modelId !== \"scribe_v1\") {\n logger.warn(`Using non-default STT model: ${settings.modelId}`);\n }\n\n if (settings.timestampsGranularity !== \"word\") {\n logger.warn(\n `Using non-default timestamps granularity: ${settings.timestampsGranularity}`,\n );\n }\n\n logger.success(\"STT configuration defaults checked\");\n },\n },\n {\n name: \"STT input handling validation\",\n fn: async (_runtime: IAgentRuntime) => {\n const testCases = [\n { type: \"string URL\", valid: true },\n { type: \"Buffer\", valid: true },\n { type: \"object with audioUrl\", valid: true },\n ];\n\n for (const testCase of testCases) {\n if (!testCase.valid) {\n throw new Error(\n `Invalid test case should not be valid: ${testCase.type}`,\n );\n }\n }\n\n logger.success(\"STT input handling validation passed\");\n },\n },\n ],\n },\n ],\n};\nexport default elevenLabsPlugin;\n",
|
|
6
|
+
"export * from \"./index\";\n\nimport elevenLabsPlugin from \"./index\";\n\nexport default elevenLabsPlugin;\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "AFADBC5F6E97695364756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Plugin } from "@elizaos/core";
|
|
2
|
+
/**
|
|
3
|
+
* Represents the ElevenLabs plugin.
|
|
4
|
+
* This plugin provides text-to-speech and speech-to-text functionality using the ElevenLabs API.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - High-quality voice synthesis (TTS)
|
|
8
|
+
* - High-accuracy speech transcription (STT) with Scribe v1 model
|
|
9
|
+
* - Support for multiple voice models and settings
|
|
10
|
+
* - Configurable voice parameters (stability, similarity, style)
|
|
11
|
+
* - Stream-based audio output for efficient memory usage
|
|
12
|
+
* - Speaker diarization (up to 32 speakers)
|
|
13
|
+
* - Multi-language support (99 languages for STT)
|
|
14
|
+
* - Audio event detection (laughter, applause, etc.)
|
|
15
|
+
*
|
|
16
|
+
* Required environment variables:
|
|
17
|
+
* - ELEVENLABS_API_KEY: Your ElevenLabs API key
|
|
18
|
+
*
|
|
19
|
+
* Optional TTS environment variables:
|
|
20
|
+
* - ELEVENLABS_VOICE_ID: Voice ID to use (default: EXAVITQu4vr4xnSDxMaL)
|
|
21
|
+
* - ELEVENLABS_MODEL_ID: Model to use (default: eleven_monolingual_v1)
|
|
22
|
+
* - ELEVENLABS_VOICE_STABILITY: Voice stability 0-1 (default: 0.5)
|
|
23
|
+
* - ELEVENLABS_VOICE_SIMILARITY_BOOST: Voice similarity 0-1 (default: 0.75)
|
|
24
|
+
* - ELEVENLABS_VOICE_STYLE: Voice style 0-1 (default: 0)
|
|
25
|
+
* - ELEVENLABS_VOICE_USE_SPEAKER_BOOST: Enable speaker boost (default: true)
|
|
26
|
+
* - ELEVENLABS_OPTIMIZE_STREAMING_LATENCY: Latency optimization 0-4 (default: 0)
|
|
27
|
+
* - ELEVENLABS_OUTPUT_FORMAT: Output format (default: mp3_44100_128)
|
|
28
|
+
*
|
|
29
|
+
* Optional STT environment variables:
|
|
30
|
+
* - ELEVENLABS_STT_MODEL_ID: STT model ID (default: scribe_v1)
|
|
31
|
+
* - ELEVENLABS_STT_LANGUAGE_CODE: Language code for transcription (auto-detect if not set)
|
|
32
|
+
* - ELEVENLABS_STT_TIMESTAMPS_GRANULARITY: Timestamp level (default: word)
|
|
33
|
+
* - ELEVENLABS_STT_DIARIZE: Enable speaker diarization (default: false)
|
|
34
|
+
* - ELEVENLABS_STT_NUM_SPEAKERS: Expected number of speakers (1-32)
|
|
35
|
+
* - ELEVENLABS_STT_TAG_AUDIO_EVENTS: Tag audio events (default: false)
|
|
36
|
+
*
|
|
37
|
+
* @type {Plugin}
|
|
38
|
+
*/
|
|
39
|
+
export declare const elevenLabsPlugin: Plugin;
|
|
40
|
+
export default elevenLabsPlugin;
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
|
|
3
|
+
import {
|
|
4
|
+
SpeechToTextConvertRequestModelId as SttModelIdEnum,
|
|
5
|
+
SpeechToTextConvertRequestTimestampsGranularity as SttTimestampsGranularityEnum,
|
|
6
|
+
TextToSpeechStreamRequestOutputFormat as TtsOutputFormatEnum
|
|
7
|
+
} from "@elevenlabs/elevenlabs-js/api";
|
|
8
|
+
import {
|
|
9
|
+
logger,
|
|
10
|
+
ModelType,
|
|
11
|
+
parseBooleanFromText
|
|
12
|
+
} from "@elizaos/core";
|
|
13
|
+
function parseTtsOutputFormat(format) {
|
|
14
|
+
for (const allowed of Object.values(TtsOutputFormatEnum)) {
|
|
15
|
+
if (allowed === format)
|
|
16
|
+
return allowed;
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`Unsupported ElevenLabs TTS output format: ${format}`);
|
|
19
|
+
}
|
|
20
|
+
function parseSttModelId(id) {
|
|
21
|
+
for (const allowed of Object.values(SttModelIdEnum)) {
|
|
22
|
+
if (allowed === id)
|
|
23
|
+
return allowed;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Unsupported ElevenLabs STT model: ${id}`);
|
|
26
|
+
}
|
|
27
|
+
function parseSttTimestampsGranularity(value) {
|
|
28
|
+
for (const allowed of Object.values(SttTimestampsGranularityEnum)) {
|
|
29
|
+
if (allowed === value)
|
|
30
|
+
return allowed;
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Unsupported ElevenLabs STT timestamps granularity: ${value}`);
|
|
33
|
+
}
|
|
34
|
+
function extractTranscript(response) {
|
|
35
|
+
if ("transcripts" in response) {
|
|
36
|
+
return response.transcripts.map((t) => t.text).join(`
|
|
37
|
+
`);
|
|
38
|
+
}
|
|
39
|
+
return response.text;
|
|
40
|
+
}
|
|
41
|
+
function isRecord(value) {
|
|
42
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43
|
+
}
|
|
44
|
+
function nonEmptyString(value) {
|
|
45
|
+
return typeof value === "string" ? value.trim() : "";
|
|
46
|
+
}
|
|
47
|
+
function normalizeTtsInput(input) {
|
|
48
|
+
const options = typeof input === "string" ? { text: input } : input;
|
|
49
|
+
if (!isRecord(options) || !nonEmptyString(options.text)) {
|
|
50
|
+
throw new Error("ElevenLabs TTS text is required");
|
|
51
|
+
}
|
|
52
|
+
if (options.model !== undefined && !nonEmptyString(options.model)) {
|
|
53
|
+
throw new Error("ElevenLabs TTS model must be a non-empty string");
|
|
54
|
+
}
|
|
55
|
+
if (options.voiceId !== undefined && !nonEmptyString(options.voiceId)) {
|
|
56
|
+
throw new Error("ElevenLabs TTS voiceId must be a non-empty string");
|
|
57
|
+
}
|
|
58
|
+
if (options.format !== undefined && !nonEmptyString(options.format)) {
|
|
59
|
+
throw new Error("ElevenLabs TTS format must be a non-empty string");
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...options,
|
|
63
|
+
text: options.text.trim(),
|
|
64
|
+
model: options.model === undefined ? undefined : options.model.trim(),
|
|
65
|
+
voiceId: options.voiceId === undefined ? undefined : options.voiceId.trim(),
|
|
66
|
+
format: options.format === undefined ? undefined : options.format.trim()
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function validateAudioUrl(value) {
|
|
70
|
+
const url = nonEmptyString(value);
|
|
71
|
+
if (!url) {
|
|
72
|
+
throw new Error("ElevenLabs transcription audioUrl is required");
|
|
73
|
+
}
|
|
74
|
+
let parsed;
|
|
75
|
+
try {
|
|
76
|
+
parsed = new URL(url);
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error("ElevenLabs transcription audioUrl must be a valid URL");
|
|
79
|
+
}
|
|
80
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
81
|
+
throw new Error("ElevenLabs transcription audioUrl must use http or https");
|
|
82
|
+
}
|
|
83
|
+
return parsed.toString();
|
|
84
|
+
}
|
|
85
|
+
function isBrowser() {
|
|
86
|
+
return typeof globalThis.document !== "undefined";
|
|
87
|
+
}
|
|
88
|
+
function getSetting(runtime, key, fallback) {
|
|
89
|
+
const rawRuntime = runtime.getSetting(key);
|
|
90
|
+
const fromRuntime = rawRuntime === null || rawRuntime === undefined ? undefined : String(rawRuntime);
|
|
91
|
+
const envValue = typeof process !== "undefined" && process.env && typeof process.env[key] === "string" ? process.env[key] : undefined;
|
|
92
|
+
return fromRuntime ?? envValue ?? fallback;
|
|
93
|
+
}
|
|
94
|
+
function getBaseURL(runtime) {
|
|
95
|
+
const browserRaw = runtime.getSetting("ELEVENLABS_BROWSER_URL");
|
|
96
|
+
const browserURL = browserRaw === null || browserRaw === undefined ? undefined : String(browserRaw);
|
|
97
|
+
if (isBrowser() && browserURL)
|
|
98
|
+
return browserURL;
|
|
99
|
+
return "https://api.elevenlabs.io/v1";
|
|
100
|
+
}
|
|
101
|
+
function getApiKey(runtime) {
|
|
102
|
+
const raw = runtime.getSetting("ELEVENLABS_API_KEY");
|
|
103
|
+
const fromRuntime = raw === null || raw === undefined ? undefined : String(raw);
|
|
104
|
+
const fromEnv = typeof process !== "undefined" && process.env && typeof process.env.ELEVENLABS_API_KEY === "string" ? process.env.ELEVENLABS_API_KEY : undefined;
|
|
105
|
+
return fromRuntime ?? fromEnv;
|
|
106
|
+
}
|
|
107
|
+
function getElevenLabsClientConfig(runtime) {
|
|
108
|
+
const apiKey = getApiKey(runtime)?.trim();
|
|
109
|
+
const baseUrl = getBaseURL(runtime);
|
|
110
|
+
if (apiKey)
|
|
111
|
+
return { apiKey, baseUrl };
|
|
112
|
+
if (isBrowser() && baseUrl !== "https://api.elevenlabs.io/v1") {
|
|
113
|
+
return { baseUrl };
|
|
114
|
+
}
|
|
115
|
+
throw new Error("ELEVENLABS_API_KEY is required unless ELEVENLABS_BROWSER_URL is configured in browser mode");
|
|
116
|
+
}
|
|
117
|
+
function getVoiceSettings(runtime) {
|
|
118
|
+
return {
|
|
119
|
+
apiKey: getApiKey(runtime) || "",
|
|
120
|
+
voiceId: getSetting(runtime, "ELEVENLABS_VOICE_ID", "EXAVITQu4vr4xnSDxMaL"),
|
|
121
|
+
model: getSetting(runtime, "ELEVENLABS_MODEL_ID", "eleven_monolingual_v1"),
|
|
122
|
+
stability: getSetting(runtime, "ELEVENLABS_VOICE_STABILITY", "0.5"),
|
|
123
|
+
latency: getSetting(runtime, "ELEVENLABS_OPTIMIZE_STREAMING_LATENCY", "0"),
|
|
124
|
+
outputFormat: getSetting(runtime, "ELEVENLABS_OUTPUT_FORMAT", "mp3_44100_128"),
|
|
125
|
+
similarity: getSetting(runtime, "ELEVENLABS_VOICE_SIMILARITY_BOOST", "0.75"),
|
|
126
|
+
style: getSetting(runtime, "ELEVENLABS_VOICE_STYLE", "0"),
|
|
127
|
+
speakerBoost: parseBooleanFromText(`${getSetting(runtime, "ELEVENLABS_VOICE_USE_SPEAKER_BOOST", "true") ?? "true"}`)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function getTranscriptionSettings(runtime) {
|
|
131
|
+
const languageCode = getSetting(runtime, "ELEVENLABS_STT_LANGUAGE_CODE");
|
|
132
|
+
const numSpeakersStr = getSetting(runtime, "ELEVENLABS_STT_NUM_SPEAKERS");
|
|
133
|
+
const numSpeakers = numSpeakersStr ? Number(numSpeakersStr) : undefined;
|
|
134
|
+
if (numSpeakers !== undefined && (!Number.isInteger(numSpeakers) || numSpeakers < 1 || numSpeakers > 32)) {
|
|
135
|
+
throw new Error("ELEVENLABS_STT_NUM_SPEAKERS must be an integer between 1 and 32");
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
apiKey: getApiKey(runtime) || "",
|
|
139
|
+
modelId: getSetting(runtime, "ELEVENLABS_STT_MODEL_ID", "scribe_v1"),
|
|
140
|
+
languageCode: languageCode || undefined,
|
|
141
|
+
timestampsGranularity: getSetting(runtime, "ELEVENLABS_STT_TIMESTAMPS_GRANULARITY", "word"),
|
|
142
|
+
diarize: parseBooleanFromText(`${getSetting(runtime, "ELEVENLABS_STT_DIARIZE", "false") ?? "false"}`),
|
|
143
|
+
numSpeakers,
|
|
144
|
+
tagAudioEvents: parseBooleanFromText(`${getSetting(runtime, "ELEVENLABS_STT_TAG_AUDIO_EVENTS", "false") ?? "false"}`)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function isBufferInput(input) {
|
|
148
|
+
return typeof Buffer !== "undefined" && typeof Buffer.isBuffer === "function" && Buffer.isBuffer(input);
|
|
149
|
+
}
|
|
150
|
+
async function responseToAudioFile(response) {
|
|
151
|
+
if (isBrowser()) {
|
|
152
|
+
if (typeof response.blob === "function") {
|
|
153
|
+
return response.blob();
|
|
154
|
+
}
|
|
155
|
+
const arrayBuffer2 = await response.arrayBuffer();
|
|
156
|
+
return new Blob([arrayBuffer2]);
|
|
157
|
+
}
|
|
158
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
159
|
+
if (typeof Buffer !== "undefined") {
|
|
160
|
+
return Buffer.from(arrayBuffer);
|
|
161
|
+
}
|
|
162
|
+
return new Blob([arrayBuffer]);
|
|
163
|
+
}
|
|
164
|
+
async function readStreamToUint8Array(stream) {
|
|
165
|
+
const reader = stream.getReader();
|
|
166
|
+
const chunks = [];
|
|
167
|
+
let totalLength = 0;
|
|
168
|
+
while (true) {
|
|
169
|
+
const { done, value } = await reader.read();
|
|
170
|
+
if (done)
|
|
171
|
+
break;
|
|
172
|
+
if (!value)
|
|
173
|
+
continue;
|
|
174
|
+
chunks.push(value);
|
|
175
|
+
totalLength += value.byteLength;
|
|
176
|
+
}
|
|
177
|
+
const output = new Uint8Array(totalLength);
|
|
178
|
+
let offset = 0;
|
|
179
|
+
for (const chunk of chunks) {
|
|
180
|
+
output.set(chunk, offset);
|
|
181
|
+
offset += chunk.byteLength;
|
|
182
|
+
}
|
|
183
|
+
return output;
|
|
184
|
+
}
|
|
185
|
+
async function fetchSpeech(runtime, params) {
|
|
186
|
+
try {
|
|
187
|
+
const client = new ElevenLabsClient(getElevenLabsClientConfig(runtime));
|
|
188
|
+
const stream = await client.textToSpeech.stream(params.voiceId, {
|
|
189
|
+
text: params.text,
|
|
190
|
+
modelId: params.modelId,
|
|
191
|
+
outputFormat: parseTtsOutputFormat(params.outputFormat),
|
|
192
|
+
optimizeStreamingLatency: Number(params.latency) || 0,
|
|
193
|
+
voiceSettings: {
|
|
194
|
+
stability: Number(params.stability) || 0,
|
|
195
|
+
similarityBoost: Number(params.similarity) || 0,
|
|
196
|
+
style: Number(params.style) || 0,
|
|
197
|
+
useSpeakerBoost: !!params.speakerBoost
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
if (!stream) {
|
|
201
|
+
throw new Error("Empty response body from ElevenLabs SDK");
|
|
202
|
+
}
|
|
203
|
+
return readStreamToUint8Array(stream);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
206
|
+
logger.error(`ElevenLabs fetchSpeech error: ${msg}`);
|
|
207
|
+
throw error instanceof Error ? error : new Error(msg);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function fetchTranscription(runtime, params) {
|
|
211
|
+
try {
|
|
212
|
+
const client = new ElevenLabsClient(getElevenLabsClientConfig(runtime));
|
|
213
|
+
const body = {
|
|
214
|
+
modelId: parseSttModelId(params.modelId),
|
|
215
|
+
file: params.audioFile
|
|
216
|
+
};
|
|
217
|
+
if (params.languageCode) {
|
|
218
|
+
body.languageCode = params.languageCode;
|
|
219
|
+
}
|
|
220
|
+
body.timestampsGranularity = parseSttTimestampsGranularity(params.timestampsGranularity);
|
|
221
|
+
if (params.diarize) {
|
|
222
|
+
body.diarize = true;
|
|
223
|
+
if (params.numSpeakers !== undefined) {
|
|
224
|
+
body.numSpeakers = params.numSpeakers;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (params.tagAudioEvents) {
|
|
228
|
+
body.tagAudioEvents = true;
|
|
229
|
+
}
|
|
230
|
+
const response = await client.speechToText.convert(body);
|
|
231
|
+
if (!response) {
|
|
232
|
+
throw new Error("Empty response from ElevenLabs STT API");
|
|
233
|
+
}
|
|
234
|
+
return extractTranscript(response);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
237
|
+
logger.error(`ElevenLabs fetchTranscription error: ${msg}`);
|
|
238
|
+
throw error instanceof Error ? error : new Error(msg);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
var elevenLabsPlugin = {
|
|
242
|
+
name: "elevenLabs",
|
|
243
|
+
description: "High-quality text-to-speech synthesis and speech-to-text transcription using ElevenLabs API with support for multiple voices, languages, and speaker diarization",
|
|
244
|
+
models: {
|
|
245
|
+
[ModelType.TEXT_TO_SPEECH]: async (runtime, input) => {
|
|
246
|
+
const options = normalizeTtsInput(input);
|
|
247
|
+
const settings = getVoiceSettings(runtime);
|
|
248
|
+
const resolvedModel = options.model || settings.model;
|
|
249
|
+
const resolvedVoiceId = options.voiceId ?? settings.voiceId;
|
|
250
|
+
const outputFormat = options.format ? options.format === "mp3" ? "mp3_44100_128" : options.format : settings.outputFormat;
|
|
251
|
+
logger.log(`[ElevenLabs] Using TEXT_TO_SPEECH model: ${resolvedModel}`);
|
|
252
|
+
try {
|
|
253
|
+
const stream = await fetchSpeech(runtime, {
|
|
254
|
+
text: options.text,
|
|
255
|
+
voiceId: resolvedVoiceId,
|
|
256
|
+
modelId: resolvedModel,
|
|
257
|
+
outputFormat,
|
|
258
|
+
stability: settings.stability,
|
|
259
|
+
similarity: settings.similarity,
|
|
260
|
+
style: settings.style,
|
|
261
|
+
speakerBoost: settings.speakerBoost,
|
|
262
|
+
latency: settings.latency
|
|
263
|
+
});
|
|
264
|
+
return stream;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
267
|
+
logger.error(`ElevenLabs model error: ${msg}`);
|
|
268
|
+
throw error instanceof Error ? error : new Error(msg);
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
[ModelType.TRANSCRIPTION]: async (runtime, input) => {
|
|
272
|
+
const settings = getTranscriptionSettings(runtime);
|
|
273
|
+
logger.log(`[ElevenLabs] Using TRANSCRIPTION model: ${settings.modelId}`);
|
|
274
|
+
try {
|
|
275
|
+
let audioFile;
|
|
276
|
+
if (typeof input === "string") {
|
|
277
|
+
const audioUrl = validateAudioUrl(input);
|
|
278
|
+
const response = await fetch(audioUrl);
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
throw new Error(`Failed to fetch audio from URL: ${audioUrl}`);
|
|
281
|
+
}
|
|
282
|
+
audioFile = await responseToAudioFile(response);
|
|
283
|
+
} else if (isBufferInput(input)) {
|
|
284
|
+
audioFile = input;
|
|
285
|
+
} else if (isRecord(input) && "audioUrl" in input) {
|
|
286
|
+
const audioUrl = validateAudioUrl(input.audioUrl);
|
|
287
|
+
const response = await fetch(audioUrl);
|
|
288
|
+
if (!response.ok) {
|
|
289
|
+
throw new Error(`Failed to fetch audio from URL: ${audioUrl}`);
|
|
290
|
+
}
|
|
291
|
+
audioFile = await responseToAudioFile(response);
|
|
292
|
+
} else {
|
|
293
|
+
throw new Error("Invalid input type for TRANSCRIPTION model");
|
|
294
|
+
}
|
|
295
|
+
const transcript = await fetchTranscription(runtime, {
|
|
296
|
+
audioFile,
|
|
297
|
+
modelId: settings.modelId,
|
|
298
|
+
languageCode: settings.languageCode,
|
|
299
|
+
timestampsGranularity: settings.timestampsGranularity,
|
|
300
|
+
diarize: settings.diarize,
|
|
301
|
+
numSpeakers: settings.numSpeakers,
|
|
302
|
+
tagAudioEvents: settings.tagAudioEvents
|
|
303
|
+
});
|
|
304
|
+
return transcript;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
307
|
+
logger.error(`ElevenLabs transcription error: ${msg}`);
|
|
308
|
+
throw error instanceof Error ? error : new Error(msg);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
tests: [
|
|
313
|
+
{
|
|
314
|
+
name: "test eleven labs",
|
|
315
|
+
tests: [
|
|
316
|
+
{
|
|
317
|
+
name: "Eleven Labs API key validation",
|
|
318
|
+
fn: async (runtime) => {
|
|
319
|
+
const settings = getVoiceSettings(runtime);
|
|
320
|
+
if (!settings.apiKey) {
|
|
321
|
+
throw new Error("Missing API key: Please provide a valid Eleven Labs API key.");
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: "Voice settings validation",
|
|
327
|
+
fn: async (runtime) => {
|
|
328
|
+
const settings = getVoiceSettings(runtime);
|
|
329
|
+
if (!settings.voiceId) {
|
|
330
|
+
throw new Error("Missing voice ID configuration");
|
|
331
|
+
}
|
|
332
|
+
const stability = Number.parseFloat(settings.stability);
|
|
333
|
+
if (Number.isNaN(stability) || stability < 0 || stability > 1) {
|
|
334
|
+
throw new Error("Voice stability must be between 0 and 1");
|
|
335
|
+
}
|
|
336
|
+
const similarity = Number.parseFloat(settings.similarity);
|
|
337
|
+
if (Number.isNaN(similarity) || similarity < 0 || similarity > 1) {
|
|
338
|
+
throw new Error("Voice similarity boost must be between 0 and 1");
|
|
339
|
+
}
|
|
340
|
+
logger.success("Voice settings validated successfully");
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: "Eleven Labs API connectivity",
|
|
345
|
+
fn: async (runtime) => {
|
|
346
|
+
const settings = getVoiceSettings(runtime);
|
|
347
|
+
if (!settings.apiKey) {
|
|
348
|
+
logger.warn("Skipping API connectivity test - no API key provided");
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
await fetchSpeech(runtime, {
|
|
353
|
+
text: "test",
|
|
354
|
+
voiceId: settings.voiceId,
|
|
355
|
+
modelId: settings.model,
|
|
356
|
+
outputFormat: settings.outputFormat,
|
|
357
|
+
stability: settings.stability,
|
|
358
|
+
similarity: settings.similarity,
|
|
359
|
+
style: settings.style,
|
|
360
|
+
speakerBoost: settings.speakerBoost,
|
|
361
|
+
latency: settings.latency
|
|
362
|
+
});
|
|
363
|
+
logger.success("API connectivity test passed");
|
|
364
|
+
} catch (error) {
|
|
365
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
366
|
+
if (msg.includes("QUOTA_EXCEEDED")) {
|
|
367
|
+
logger.warn("API quota exceeded - test skipped");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
logger.error(`API connectivity test failed: ${msg}`);
|
|
371
|
+
throw new Error(`API connectivity test failed: ${msg}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "ElevenLabs TTS Generation (stream exists)",
|
|
377
|
+
fn: async (runtime) => {
|
|
378
|
+
const settings = getVoiceSettings(runtime);
|
|
379
|
+
if (!settings.apiKey && !isBrowser()) {
|
|
380
|
+
logger.warn("Skipping TTS generation test - no API key provided");
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const testText = "Hello from ElevenLabs test.";
|
|
384
|
+
try {
|
|
385
|
+
const audio = await runtime.useModel(ModelType.TEXT_TO_SPEECH, testText);
|
|
386
|
+
const bytes = audio instanceof Uint8Array ? audio : Buffer.isBuffer(audio) ? new Uint8Array(audio) : audio instanceof ArrayBuffer ? new Uint8Array(audio) : null;
|
|
387
|
+
if (!bytes || bytes.byteLength === 0) {
|
|
388
|
+
throw new Error("TTS output must be non-empty Uint8Array, Buffer, or ArrayBuffer");
|
|
389
|
+
}
|
|
390
|
+
logger.success("Received TTS binary payload successfully");
|
|
391
|
+
} catch (error) {
|
|
392
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
393
|
+
if (msg.includes("QUOTA_EXCEEDED")) {
|
|
394
|
+
logger.warn("[ElevenLabs Test] API quota exceeded - test skipped");
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
logger.error("[ElevenLabs Test] TTS Generation test failed:", msg);
|
|
398
|
+
throw new Error(`TTS Generation test failed: ${msg}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
name: "Output format handling",
|
|
404
|
+
fn: async (runtime) => {
|
|
405
|
+
const settings = getVoiceSettings(runtime);
|
|
406
|
+
const pcmFormats = [
|
|
407
|
+
"mp3_44100_128",
|
|
408
|
+
"pcm_16000",
|
|
409
|
+
"pcm_22050",
|
|
410
|
+
"pcm_24000",
|
|
411
|
+
"pcm_44100"
|
|
412
|
+
];
|
|
413
|
+
for (const format of pcmFormats) {
|
|
414
|
+
if (format.startsWith("pcm_")) {
|
|
415
|
+
const sampleRate = Number.parseInt(format.slice(4), 10);
|
|
416
|
+
if (Number.isNaN(sampleRate) || sampleRate <= 0) {
|
|
417
|
+
throw new Error(`Invalid PCM format: ${format}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
logger.success(`Output format validated: ${settings.outputFormat}`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
name: "test eleven labs STT",
|
|
428
|
+
tests: [
|
|
429
|
+
{
|
|
430
|
+
name: "STT settings validation",
|
|
431
|
+
fn: async (runtime) => {
|
|
432
|
+
const settings = getTranscriptionSettings(runtime);
|
|
433
|
+
if (!settings.modelId) {
|
|
434
|
+
throw new Error("Missing STT model ID configuration");
|
|
435
|
+
}
|
|
436
|
+
const validGranularities = ["none", "word", "character"];
|
|
437
|
+
if (!validGranularities.includes(settings.timestampsGranularity)) {
|
|
438
|
+
throw new Error(`Invalid timestamps granularity: ${settings.timestampsGranularity}`);
|
|
439
|
+
}
|
|
440
|
+
if (settings.numSpeakers !== undefined && (settings.numSpeakers < 1 || settings.numSpeakers > 32)) {
|
|
441
|
+
throw new Error("Number of speakers must be between 1 and 32");
|
|
442
|
+
}
|
|
443
|
+
logger.success("STT settings validated successfully");
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
name: "STT configuration defaults",
|
|
448
|
+
fn: async (runtime) => {
|
|
449
|
+
const settings = getTranscriptionSettings(runtime);
|
|
450
|
+
if (settings.modelId !== "scribe_v1") {
|
|
451
|
+
logger.warn(`Using non-default STT model: ${settings.modelId}`);
|
|
452
|
+
}
|
|
453
|
+
if (settings.timestampsGranularity !== "word") {
|
|
454
|
+
logger.warn(`Using non-default timestamps granularity: ${settings.timestampsGranularity}`);
|
|
455
|
+
}
|
|
456
|
+
logger.success("STT configuration defaults checked");
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "STT input handling validation",
|
|
461
|
+
fn: async (_runtime) => {
|
|
462
|
+
const testCases = [
|
|
463
|
+
{ type: "string URL", valid: true },
|
|
464
|
+
{ type: "Buffer", valid: true },
|
|
465
|
+
{ type: "object with audioUrl", valid: true }
|
|
466
|
+
];
|
|
467
|
+
for (const testCase of testCases) {
|
|
468
|
+
if (!testCase.valid) {
|
|
469
|
+
throw new Error(`Invalid test case should not be valid: ${testCase.type}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
logger.success("STT input handling validation passed");
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
]
|
|
476
|
+
}
|
|
477
|
+
]
|
|
478
|
+
};
|
|
479
|
+
var src_default = elevenLabsPlugin;
|
|
480
|
+
// src/index.node.ts
|
|
481
|
+
var index_node_default = src_default;
|
|
482
|
+
export {
|
|
483
|
+
elevenLabsPlugin,
|
|
484
|
+
index_node_default as default
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
//# debugId=6150E9F1F6217AD364756E2164756E21
|