@tanstack/ai-elevenlabs 0.2.33 → 0.2.35

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.
@@ -1,143 +1,176 @@
1
+ import { createElevenLabsClient, dataUrlToBlob, generateId } from "../utils/client.js";
1
2
  import { BaseTranscriptionAdapter } from "@tanstack/ai/adapters";
2
- import { createElevenLabsClient, generateId, dataUrlToBlob } from "../utils/client.js";
3
- class ElevenLabsTranscriptionAdapter extends BaseTranscriptionAdapter {
4
- name = "elevenlabs";
5
- client;
6
- constructor(model, config) {
7
- super(model, config ?? {});
8
- this.client = createElevenLabsClient(config);
9
- }
10
- async transcribe(options) {
11
- const { logger } = options;
12
- logger.request(
13
- `activity=generateTranscription provider=elevenlabs model=${this.model}`,
14
- { provider: "elevenlabs", model: this.model }
15
- );
16
- try {
17
- const modelOpts = options.modelOptions ?? {};
18
- const audioInput = normalizeAudioInput(options.audio);
19
- const response = await this.client.speechToText.convert({
20
- modelId: this.model,
21
- ...audioInput.kind === "file" ? { file: audioInput.value } : { cloudStorageUrl: audioInput.value },
22
- ...options.language ? { languageCode: options.language } : {},
23
- ...modelOpts.tagAudioEvents != null ? { tagAudioEvents: modelOpts.tagAudioEvents } : {},
24
- ...modelOpts.numSpeakers != null ? { numSpeakers: modelOpts.numSpeakers } : {},
25
- ...modelOpts.timestampsGranularity ? { timestampsGranularity: modelOpts.timestampsGranularity } : {},
26
- ...modelOpts.diarize != null ? { diarize: modelOpts.diarize } : {},
27
- ...modelOpts.diarizationThreshold != null ? { diarizationThreshold: modelOpts.diarizationThreshold } : {},
28
- ...modelOpts.detectSpeakerRoles != null ? { detectSpeakerRoles: modelOpts.detectSpeakerRoles } : {},
29
- ...modelOpts.keyterms ? { keyterms: modelOpts.keyterms } : {},
30
- ...modelOpts.entityDetection ? { entityDetection: modelOpts.entityDetection } : {},
31
- ...modelOpts.entityRedaction ? { entityRedaction: modelOpts.entityRedaction } : {},
32
- ...modelOpts.entityRedactionMode ? { entityRedactionMode: modelOpts.entityRedactionMode } : {},
33
- ...modelOpts.noVerbatim != null ? { noVerbatim: modelOpts.noVerbatim } : {},
34
- ...modelOpts.temperature != null ? { temperature: modelOpts.temperature } : {},
35
- ...modelOpts.seed != null ? { seed: modelOpts.seed } : {},
36
- ...modelOpts.enableLogging != null ? { enableLogging: modelOpts.enableLogging } : {},
37
- ...modelOpts.useMultiChannel != null ? { useMultiChannel: modelOpts.useMultiChannel } : {},
38
- ...modelOpts.fileFormat ? { fileFormat: modelOpts.fileFormat } : {}
39
- });
40
- return this.transformResponse(response);
41
- } catch (error) {
42
- logger.errors("elevenlabs.generateTranscription fatal", {
43
- error,
44
- source: "elevenlabs.generateTranscription"
45
- });
46
- throw error;
47
- }
48
- }
49
- transformResponse(response) {
50
- const data = response;
51
- if (data.transcripts) {
52
- const joinedText = data.transcripts.map((t) => t.text ?? "").filter(Boolean).join("\n");
53
- const joinedWords = data.transcripts.flatMap((t) => t.words ?? []);
54
- const duration = data.transcripts.reduce(
55
- (max, t) => Math.max(max, t.audioDurationSecs ?? 0),
56
- 0
57
- );
58
- const firstLang = data.transcripts.find(
59
- (t) => t.languageCode
60
- )?.languageCode;
61
- return {
62
- id: generateId(this.name),
63
- model: this.model,
64
- text: joinedText,
65
- ...firstLang ? { language: firstLang } : {},
66
- ...duration ? { duration } : {},
67
- ...buildWordsAndSegments(joinedWords)
68
- };
69
- }
70
- return {
71
- id: generateId(this.name),
72
- model: this.model,
73
- text: data.text ?? "",
74
- ...data.languageCode ? { language: data.languageCode } : {},
75
- ...data.audioDurationSecs ? { duration: data.audioDurationSecs } : {},
76
- ...buildWordsAndSegments(data.words ?? [])
77
- };
78
- }
79
- generateId() {
80
- return generateId(this.name);
81
- }
82
- }
3
+ //#region src/adapters/transcription.ts
4
+ /**
5
+ * ElevenLabs speech-to-text adapter built on the official SDK's Scribe family.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const adapter = elevenlabsTranscription('scribe_v1')
10
+ * const result = await generateTranscription({
11
+ * adapter,
12
+ * audio: fileInput,
13
+ * language: 'en',
14
+ * })
15
+ * ```
16
+ */
17
+ var ElevenLabsTranscriptionAdapter = class extends BaseTranscriptionAdapter {
18
+ name = "elevenlabs";
19
+ client;
20
+ constructor(model, config) {
21
+ super(model, config ?? {});
22
+ this.client = createElevenLabsClient(config);
23
+ }
24
+ async transcribe(options) {
25
+ const { logger } = options;
26
+ logger.request(`activity=generateTranscription provider=elevenlabs model=${this.model}`, {
27
+ provider: "elevenlabs",
28
+ model: this.model
29
+ });
30
+ try {
31
+ const modelOpts = options.modelOptions ?? {};
32
+ const audioInput = normalizeAudioInput(options.audio);
33
+ const response = await this.client.speechToText.convert({
34
+ modelId: this.model,
35
+ ...audioInput.kind === "file" ? { file: audioInput.value } : { cloudStorageUrl: audioInput.value },
36
+ ...options.language ? { languageCode: options.language } : {},
37
+ ...modelOpts.tagAudioEvents != null ? { tagAudioEvents: modelOpts.tagAudioEvents } : {},
38
+ ...modelOpts.numSpeakers != null ? { numSpeakers: modelOpts.numSpeakers } : {},
39
+ ...modelOpts.timestampsGranularity ? { timestampsGranularity: modelOpts.timestampsGranularity } : {},
40
+ ...modelOpts.diarize != null ? { diarize: modelOpts.diarize } : {},
41
+ ...modelOpts.diarizationThreshold != null ? { diarizationThreshold: modelOpts.diarizationThreshold } : {},
42
+ ...modelOpts.detectSpeakerRoles != null ? { detectSpeakerRoles: modelOpts.detectSpeakerRoles } : {},
43
+ ...modelOpts.keyterms ? { keyterms: modelOpts.keyterms } : {},
44
+ ...modelOpts.entityDetection ? { entityDetection: modelOpts.entityDetection } : {},
45
+ ...modelOpts.entityRedaction ? { entityRedaction: modelOpts.entityRedaction } : {},
46
+ ...modelOpts.entityRedactionMode ? { entityRedactionMode: modelOpts.entityRedactionMode } : {},
47
+ ...modelOpts.noVerbatim != null ? { noVerbatim: modelOpts.noVerbatim } : {},
48
+ ...modelOpts.temperature != null ? { temperature: modelOpts.temperature } : {},
49
+ ...modelOpts.seed != null ? { seed: modelOpts.seed } : {},
50
+ ...modelOpts.enableLogging != null ? { enableLogging: modelOpts.enableLogging } : {},
51
+ ...modelOpts.useMultiChannel != null ? { useMultiChannel: modelOpts.useMultiChannel } : {},
52
+ ...modelOpts.fileFormat ? { fileFormat: modelOpts.fileFormat } : {}
53
+ });
54
+ return this.transformResponse(response);
55
+ } catch (error) {
56
+ logger.errors("elevenlabs.generateTranscription fatal", {
57
+ error,
58
+ source: "elevenlabs.generateTranscription"
59
+ });
60
+ throw error;
61
+ }
62
+ }
63
+ transformResponse(response) {
64
+ const data = response;
65
+ if (data.transcripts) {
66
+ const joinedText = data.transcripts.map((t) => t.text ?? "").filter(Boolean).join("\n");
67
+ const joinedWords = data.transcripts.flatMap((t) => t.words ?? []);
68
+ const duration = data.transcripts.reduce((max, t) => Math.max(max, t.audioDurationSecs ?? 0), 0);
69
+ const firstLang = data.transcripts.find((t) => t.languageCode)?.languageCode;
70
+ return {
71
+ id: generateId(this.name),
72
+ model: this.model,
73
+ text: joinedText,
74
+ ...firstLang ? { language: firstLang } : {},
75
+ ...duration ? { duration } : {},
76
+ ...buildWordsAndSegments(joinedWords)
77
+ };
78
+ }
79
+ return {
80
+ id: generateId(this.name),
81
+ model: this.model,
82
+ text: data.text ?? "",
83
+ ...data.languageCode ? { language: data.languageCode } : {},
84
+ ...data.audioDurationSecs ? { duration: data.audioDurationSecs } : {},
85
+ ...buildWordsAndSegments(data.words ?? [])
86
+ };
87
+ }
88
+ generateId() {
89
+ return generateId(this.name);
90
+ }
91
+ };
83
92
  function normalizeAudioInput(audio) {
84
- if (audio instanceof ArrayBuffer) {
85
- return { kind: "file", value: new Blob([audio]) };
86
- }
87
- if (typeof audio === "string") {
88
- const blob = dataUrlToBlob(audio);
89
- if (blob) return { kind: "file", value: blob };
90
- return { kind: "url", value: audio };
91
- }
92
- return { kind: "file", value: audio };
93
+ if (audio instanceof ArrayBuffer) return {
94
+ kind: "file",
95
+ value: new Blob([audio])
96
+ };
97
+ if (typeof audio === "string") {
98
+ const blob = dataUrlToBlob(audio);
99
+ if (blob) return {
100
+ kind: "file",
101
+ value: blob
102
+ };
103
+ return {
104
+ kind: "url",
105
+ value: audio
106
+ };
107
+ }
108
+ return {
109
+ kind: "file",
110
+ value: audio
111
+ };
93
112
  }
94
113
  function buildWordsAndSegments(words) {
95
- const timedWords = words.filter(
96
- (w) => typeof w.start === "number" && typeof w.end === "number" && w.type !== "spacing"
97
- );
98
- if (timedWords.length === 0) return {};
99
- const outWords = timedWords.map((w) => ({
100
- word: w.text,
101
- start: w.start,
102
- end: w.end
103
- }));
104
- const segments = [];
105
- let current = null;
106
- for (const w of timedWords) {
107
- if (!current) {
108
- current = {
109
- start: w.start,
110
- end: w.end,
111
- text: w.text,
112
- ...w.speakerId ? { speaker: w.speakerId } : {}
113
- };
114
- continue;
115
- }
116
- if (w.speakerId && current.speaker !== w.speakerId) {
117
- segments.push({ id: segments.length, ...current });
118
- current = {
119
- start: w.start,
120
- end: w.end,
121
- text: w.text,
122
- speaker: w.speakerId
123
- };
124
- continue;
125
- }
126
- current.end = w.end;
127
- current.text = current.text ? `${current.text} ${w.text}` : w.text;
128
- }
129
- if (current) segments.push({ id: segments.length, ...current });
130
- return { words: outWords, segments };
114
+ const timedWords = words.filter((w) => typeof w.start === "number" && typeof w.end === "number" && w.type !== "spacing");
115
+ if (timedWords.length === 0) return {};
116
+ const outWords = timedWords.map((w) => ({
117
+ word: w.text,
118
+ start: w.start,
119
+ end: w.end
120
+ }));
121
+ const segments = [];
122
+ let current = null;
123
+ for (const w of timedWords) {
124
+ if (!current) {
125
+ current = {
126
+ start: w.start,
127
+ end: w.end,
128
+ text: w.text,
129
+ ...w.speakerId ? { speaker: w.speakerId } : {}
130
+ };
131
+ continue;
132
+ }
133
+ if (w.speakerId && current.speaker !== w.speakerId) {
134
+ segments.push({
135
+ id: segments.length,
136
+ ...current
137
+ });
138
+ current = {
139
+ start: w.start,
140
+ end: w.end,
141
+ text: w.text,
142
+ speaker: w.speakerId
143
+ };
144
+ continue;
145
+ }
146
+ current.end = w.end;
147
+ current.text = current.text ? `${current.text} ${w.text}` : w.text;
148
+ }
149
+ if (current) segments.push({
150
+ id: segments.length,
151
+ ...current
152
+ });
153
+ return {
154
+ words: outWords,
155
+ segments
156
+ };
131
157
  }
158
+ /**
159
+ * Create an ElevenLabs transcription adapter using `ELEVENLABS_API_KEY` from env.
160
+ */
132
161
  function elevenlabsTranscription(model, config) {
133
- return new ElevenLabsTranscriptionAdapter(model, config);
162
+ return new ElevenLabsTranscriptionAdapter(model, config);
134
163
  }
164
+ /**
165
+ * Create an ElevenLabs transcription adapter with an explicit API key.
166
+ */
135
167
  function createElevenLabsTranscription(model, apiKey, config) {
136
- return new ElevenLabsTranscriptionAdapter(model, { apiKey, ...config });
168
+ return new ElevenLabsTranscriptionAdapter(model, {
169
+ apiKey,
170
+ ...config
171
+ });
137
172
  }
138
- export {
139
- ElevenLabsTranscriptionAdapter,
140
- createElevenLabsTranscription,
141
- elevenlabsTranscription
142
- };
143
- //# sourceMappingURL=transcription.js.map
173
+ //#endregion
174
+ export { ElevenLabsTranscriptionAdapter, createElevenLabsTranscription, elevenlabsTranscription };
175
+
176
+ //# sourceMappingURL=transcription.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcription.js","sources":["../../../src/adapters/transcription.ts"],"sourcesContent":["import { BaseTranscriptionAdapter } from '@tanstack/ai/adapters'\nimport {\n createElevenLabsClient,\n dataUrlToBlob,\n generateId,\n} from '../utils/client'\nimport type { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'\nimport type {\n TranscriptionOptions,\n TranscriptionResult,\n TranscriptionSegment,\n TranscriptionWord,\n} from '@tanstack/ai'\nimport type { ElevenLabsClientConfig } from '../utils/client'\nimport type { ElevenLabsTranscriptionModel } from '../model-meta'\n\n/**\n * Provider-specific options for ElevenLabs Scribe transcription. Fields map\n * 1:1 onto the SDK's `BodySpeechToTextV1SpeechToTextPost` — mirroring the\n * names so documentation stays useful.\n * @see https://elevenlabs.io/docs/api-reference/speech-to-text/convert\n */\nexport interface ElevenLabsTranscriptionProviderOptions {\n /** Annotate non-speech events like (laughter), (footsteps), …. */\n tagAudioEvents?: boolean\n /** Maximum number of speakers in the audio (1..32). */\n numSpeakers?: number\n /** Timestamp granularity for words. */\n timestampsGranularity?: 'word' | 'character' | 'none'\n /** Enable speaker diarization. */\n diarize?: boolean\n /** Diarization threshold (requires `diarize=true` and no `numSpeakers`). */\n diarizationThreshold?: number\n /** Detect speaker roles (agent/customer). Requires diarize=true. */\n detectSpeakerRoles?: boolean\n /** Bias the model towards these keyterms (max 1000). */\n keyterms?: Array<string>\n /**\n * Entity detection: `'all'`, a category (`'pii'`, `'phi'`, `'pci'`,\n * `'other'`, `'offensive_language'`), or a specific entity type.\n */\n entityDetection?: string\n /** Redact entities from the transcript text. Must be a subset of `entityDetection`. */\n entityRedaction?: string\n /** How redacted entities are formatted. */\n entityRedactionMode?: string\n /** Whether to skip filler words / non-speech sounds (scribe_v2 only). */\n noVerbatim?: boolean\n /** Sampling temperature (0..2). */\n temperature?: number\n /** Deterministic sampling seed (0..2147483647). */\n seed?: number\n /** Use `false` for zero-retention mode (enterprise only). */\n enableLogging?: boolean\n /** Multi-channel audio with one speaker per channel. Max 5 channels. */\n useMultiChannel?: boolean\n /**\n * Hint for audio format. Use `'pcm_s16le_16'` to skip encoding for 16-bit\n * PCM @ 16kHz mono little-endian inputs (lower latency).\n */\n fileFormat?: 'pcm_s16le_16' | 'other'\n}\n\n/**\n * ElevenLabs speech-to-text adapter built on the official SDK's Scribe family.\n *\n * @example\n * ```ts\n * const adapter = elevenlabsTranscription('scribe_v1')\n * const result = await generateTranscription({\n * adapter,\n * audio: fileInput,\n * language: 'en',\n * })\n * ```\n */\nexport class ElevenLabsTranscriptionAdapter<\n TModel extends ElevenLabsTranscriptionModel,\n> extends BaseTranscriptionAdapter<\n TModel,\n ElevenLabsTranscriptionProviderOptions\n> {\n readonly name = 'elevenlabs' as const\n\n private readonly client: ElevenLabsClient\n\n constructor(model: TModel, config?: ElevenLabsClientConfig) {\n super(model, config ?? {})\n this.client = createElevenLabsClient(config)\n }\n\n async transcribe(\n options: TranscriptionOptions<ElevenLabsTranscriptionProviderOptions>,\n ): Promise<TranscriptionResult> {\n const { logger } = options\n logger.request(\n `activity=generateTranscription provider=elevenlabs model=${this.model}`,\n { provider: 'elevenlabs', model: this.model },\n )\n try {\n const modelOpts = options.modelOptions ?? {}\n const audioInput = normalizeAudioInput(options.audio)\n\n const response = await this.client.speechToText.convert({\n modelId: this.model,\n ...(audioInput.kind === 'file'\n ? { file: audioInput.value }\n : { cloudStorageUrl: audioInput.value }),\n ...(options.language ? { languageCode: options.language } : {}),\n ...(modelOpts.tagAudioEvents != null\n ? { tagAudioEvents: modelOpts.tagAudioEvents }\n : {}),\n ...(modelOpts.numSpeakers != null\n ? { numSpeakers: modelOpts.numSpeakers }\n : {}),\n ...(modelOpts.timestampsGranularity\n ? { timestampsGranularity: modelOpts.timestampsGranularity }\n : {}),\n ...(modelOpts.diarize != null ? { diarize: modelOpts.diarize } : {}),\n ...(modelOpts.diarizationThreshold != null\n ? { diarizationThreshold: modelOpts.diarizationThreshold }\n : {}),\n ...(modelOpts.detectSpeakerRoles != null\n ? { detectSpeakerRoles: modelOpts.detectSpeakerRoles }\n : {}),\n ...(modelOpts.keyterms ? { keyterms: modelOpts.keyterms } : {}),\n ...(modelOpts.entityDetection\n ? { entityDetection: modelOpts.entityDetection }\n : {}),\n ...(modelOpts.entityRedaction\n ? { entityRedaction: modelOpts.entityRedaction }\n : {}),\n ...(modelOpts.entityRedactionMode\n ? { entityRedactionMode: modelOpts.entityRedactionMode }\n : {}),\n ...(modelOpts.noVerbatim != null\n ? { noVerbatim: modelOpts.noVerbatim }\n : {}),\n ...(modelOpts.temperature != null\n ? { temperature: modelOpts.temperature }\n : {}),\n ...(modelOpts.seed != null ? { seed: modelOpts.seed } : {}),\n ...(modelOpts.enableLogging != null\n ? { enableLogging: modelOpts.enableLogging }\n : {}),\n ...(modelOpts.useMultiChannel != null\n ? { useMultiChannel: modelOpts.useMultiChannel }\n : {}),\n ...(modelOpts.fileFormat ? { fileFormat: modelOpts.fileFormat } : {}),\n } as Parameters<ElevenLabsClient['speechToText']['convert']>[0])\n\n return this.transformResponse(response)\n } catch (error) {\n logger.errors('elevenlabs.generateTranscription fatal', {\n error,\n source: 'elevenlabs.generateTranscription',\n })\n throw error\n }\n }\n\n private transformResponse(\n response: Awaited<ReturnType<ElevenLabsClient['speechToText']['convert']>>,\n ): TranscriptionResult {\n // The SDK types this as a union of single- and multi-channel responses.\n // We treat multi-channel as \"join the channel transcripts\" — consumers\n // who care about per-channel detail can re-parse from `modelOptions`.\n // eslint-disable-next-line no-restricted-syntax -- bridges SpeechToTextConvertResponse union (incl. webhook variant with no text/words/transcripts) to a flattened duck-typed shape we discriminate at runtime\n const data = response as unknown as {\n text?: string\n languageCode?: string\n languageProbability?: number\n words?: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>\n audioDurationSecs?: number\n transcripts?: Array<{\n text?: string\n languageCode?: string\n words?: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>\n audioDurationSecs?: number\n }>\n }\n\n if (data.transcripts) {\n const joinedText = data.transcripts\n .map((t) => t.text ?? '')\n .filter(Boolean)\n .join('\\n')\n const joinedWords = data.transcripts.flatMap((t) => t.words ?? [])\n const duration = data.transcripts.reduce(\n (max, t) => Math.max(max, t.audioDurationSecs ?? 0),\n 0,\n )\n const firstLang = data.transcripts.find(\n (t) => t.languageCode,\n )?.languageCode\n return {\n id: generateId(this.name),\n model: this.model,\n text: joinedText,\n ...(firstLang ? { language: firstLang } : {}),\n ...(duration ? { duration } : {}),\n ...buildWordsAndSegments(joinedWords),\n }\n }\n\n return {\n id: generateId(this.name),\n model: this.model,\n text: data.text ?? '',\n ...(data.languageCode ? { language: data.languageCode } : {}),\n ...(data.audioDurationSecs ? { duration: data.audioDurationSecs } : {}),\n ...buildWordsAndSegments(data.words ?? []),\n }\n }\n\n protected override generateId(): string {\n return generateId(this.name)\n }\n}\n\ntype NormalizedAudio =\n | { kind: 'file'; value: Blob }\n | { kind: 'url'; value: string }\n\nfunction normalizeAudioInput(\n audio: TranscriptionOptions['audio'],\n): NormalizedAudio {\n if (audio instanceof ArrayBuffer) {\n return { kind: 'file', value: new Blob([audio]) }\n }\n if (typeof audio === 'string') {\n const blob = dataUrlToBlob(audio)\n if (blob) return { kind: 'file', value: blob }\n return { kind: 'url', value: audio }\n }\n // Blob or File both fit the SDK's `Uploadable` contract.\n return { kind: 'file', value: audio }\n}\n\nfunction buildWordsAndSegments(\n words: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>,\n): {\n words?: Array<TranscriptionWord>\n segments?: Array<TranscriptionSegment>\n} {\n const timedWords = words.filter(\n (w): w is typeof w & { start: number; end: number } =>\n typeof w.start === 'number' &&\n typeof w.end === 'number' &&\n w.type !== 'spacing',\n )\n if (timedWords.length === 0) return {}\n\n const outWords: Array<TranscriptionWord> = timedWords.map((w) => ({\n word: w.text,\n start: w.start,\n end: w.end,\n }))\n\n // Group contiguous words that share a speaker into segments. If no speaker\n // is ever set, we still emit one segment per sentence-ish grouping.\n const segments: Array<TranscriptionSegment> = []\n let current: {\n start: number\n end: number\n text: string\n speaker?: string\n } | null = null\n\n for (const w of timedWords) {\n if (!current) {\n current = {\n start: w.start,\n end: w.end,\n text: w.text,\n ...(w.speakerId ? { speaker: w.speakerId } : {}),\n }\n continue\n }\n if (w.speakerId && current.speaker !== w.speakerId) {\n segments.push({ id: segments.length, ...current })\n current = {\n start: w.start,\n end: w.end,\n text: w.text,\n speaker: w.speakerId,\n }\n continue\n }\n current.end = w.end\n current.text = current.text ? `${current.text} ${w.text}` : w.text\n }\n if (current) segments.push({ id: segments.length, ...current })\n\n return { words: outWords, segments }\n}\n\n/**\n * Create an ElevenLabs transcription adapter using `ELEVENLABS_API_KEY` from env.\n */\nexport function elevenlabsTranscription<\n TModel extends ElevenLabsTranscriptionModel,\n>(\n model: TModel,\n config?: ElevenLabsClientConfig,\n): ElevenLabsTranscriptionAdapter<TModel> {\n return new ElevenLabsTranscriptionAdapter(model, config)\n}\n\n/**\n * Create an ElevenLabs transcription adapter with an explicit API key.\n */\nexport function createElevenLabsTranscription<\n TModel extends ElevenLabsTranscriptionModel,\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<ElevenLabsClientConfig, 'apiKey'>,\n): ElevenLabsTranscriptionAdapter<TModel> {\n return new ElevenLabsTranscriptionAdapter(model, { apiKey, ...config })\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transcription.js","names":[],"sources":["../../../src/adapters/transcription.ts"],"sourcesContent":["import { BaseTranscriptionAdapter } from '@tanstack/ai/adapters'\nimport {\n createElevenLabsClient,\n dataUrlToBlob,\n generateId,\n} from '../utils/client'\nimport type { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'\nimport type {\n TranscriptionOptions,\n TranscriptionResult,\n TranscriptionSegment,\n TranscriptionWord,\n} from '@tanstack/ai'\nimport type { ElevenLabsClientConfig } from '../utils/client'\nimport type { ElevenLabsTranscriptionModel } from '../model-meta'\n\n/**\n * Provider-specific options for ElevenLabs Scribe transcription. Fields map\n * 1:1 onto the SDK's `BodySpeechToTextV1SpeechToTextPost` — mirroring the\n * names so documentation stays useful.\n * @see https://elevenlabs.io/docs/api-reference/speech-to-text/convert\n */\nexport interface ElevenLabsTranscriptionProviderOptions {\n /** Annotate non-speech events like (laughter), (footsteps), …. */\n tagAudioEvents?: boolean\n /** Maximum number of speakers in the audio (1..32). */\n numSpeakers?: number\n /** Timestamp granularity for words. */\n timestampsGranularity?: 'word' | 'character' | 'none'\n /** Enable speaker diarization. */\n diarize?: boolean\n /** Diarization threshold (requires `diarize=true` and no `numSpeakers`). */\n diarizationThreshold?: number\n /** Detect speaker roles (agent/customer). Requires diarize=true. */\n detectSpeakerRoles?: boolean\n /** Bias the model towards these keyterms (max 1000). */\n keyterms?: Array<string>\n /**\n * Entity detection: `'all'`, a category (`'pii'`, `'phi'`, `'pci'`,\n * `'other'`, `'offensive_language'`), or a specific entity type.\n */\n entityDetection?: string\n /** Redact entities from the transcript text. Must be a subset of `entityDetection`. */\n entityRedaction?: string\n /** How redacted entities are formatted. */\n entityRedactionMode?: string\n /** Whether to skip filler words / non-speech sounds (scribe_v2 only). */\n noVerbatim?: boolean\n /** Sampling temperature (0..2). */\n temperature?: number\n /** Deterministic sampling seed (0..2147483647). */\n seed?: number\n /** Use `false` for zero-retention mode (enterprise only). */\n enableLogging?: boolean\n /** Multi-channel audio with one speaker per channel. Max 5 channels. */\n useMultiChannel?: boolean\n /**\n * Hint for audio format. Use `'pcm_s16le_16'` to skip encoding for 16-bit\n * PCM @ 16kHz mono little-endian inputs (lower latency).\n */\n fileFormat?: 'pcm_s16le_16' | 'other'\n}\n\n/**\n * ElevenLabs speech-to-text adapter built on the official SDK's Scribe family.\n *\n * @example\n * ```ts\n * const adapter = elevenlabsTranscription('scribe_v1')\n * const result = await generateTranscription({\n * adapter,\n * audio: fileInput,\n * language: 'en',\n * })\n * ```\n */\nexport class ElevenLabsTranscriptionAdapter<\n TModel extends ElevenLabsTranscriptionModel,\n> extends BaseTranscriptionAdapter<\n TModel,\n ElevenLabsTranscriptionProviderOptions\n> {\n readonly name = 'elevenlabs' as const\n\n private readonly client: ElevenLabsClient\n\n constructor(model: TModel, config?: ElevenLabsClientConfig) {\n super(model, config ?? {})\n this.client = createElevenLabsClient(config)\n }\n\n async transcribe(\n options: TranscriptionOptions<ElevenLabsTranscriptionProviderOptions>,\n ): Promise<TranscriptionResult> {\n const { logger } = options\n logger.request(\n `activity=generateTranscription provider=elevenlabs model=${this.model}`,\n { provider: 'elevenlabs', model: this.model },\n )\n try {\n const modelOpts = options.modelOptions ?? {}\n const audioInput = normalizeAudioInput(options.audio)\n\n const response = await this.client.speechToText.convert({\n modelId: this.model,\n ...(audioInput.kind === 'file'\n ? { file: audioInput.value }\n : { cloudStorageUrl: audioInput.value }),\n ...(options.language ? { languageCode: options.language } : {}),\n ...(modelOpts.tagAudioEvents != null\n ? { tagAudioEvents: modelOpts.tagAudioEvents }\n : {}),\n ...(modelOpts.numSpeakers != null\n ? { numSpeakers: modelOpts.numSpeakers }\n : {}),\n ...(modelOpts.timestampsGranularity\n ? { timestampsGranularity: modelOpts.timestampsGranularity }\n : {}),\n ...(modelOpts.diarize != null ? { diarize: modelOpts.diarize } : {}),\n ...(modelOpts.diarizationThreshold != null\n ? { diarizationThreshold: modelOpts.diarizationThreshold }\n : {}),\n ...(modelOpts.detectSpeakerRoles != null\n ? { detectSpeakerRoles: modelOpts.detectSpeakerRoles }\n : {}),\n ...(modelOpts.keyterms ? { keyterms: modelOpts.keyterms } : {}),\n ...(modelOpts.entityDetection\n ? { entityDetection: modelOpts.entityDetection }\n : {}),\n ...(modelOpts.entityRedaction\n ? { entityRedaction: modelOpts.entityRedaction }\n : {}),\n ...(modelOpts.entityRedactionMode\n ? { entityRedactionMode: modelOpts.entityRedactionMode }\n : {}),\n ...(modelOpts.noVerbatim != null\n ? { noVerbatim: modelOpts.noVerbatim }\n : {}),\n ...(modelOpts.temperature != null\n ? { temperature: modelOpts.temperature }\n : {}),\n ...(modelOpts.seed != null ? { seed: modelOpts.seed } : {}),\n ...(modelOpts.enableLogging != null\n ? { enableLogging: modelOpts.enableLogging }\n : {}),\n ...(modelOpts.useMultiChannel != null\n ? { useMultiChannel: modelOpts.useMultiChannel }\n : {}),\n ...(modelOpts.fileFormat ? { fileFormat: modelOpts.fileFormat } : {}),\n } as Parameters<ElevenLabsClient['speechToText']['convert']>[0])\n\n return this.transformResponse(response)\n } catch (error) {\n logger.errors('elevenlabs.generateTranscription fatal', {\n error,\n source: 'elevenlabs.generateTranscription',\n })\n throw error\n }\n }\n\n private transformResponse(\n response: Awaited<ReturnType<ElevenLabsClient['speechToText']['convert']>>,\n ): TranscriptionResult {\n // The SDK types this as a union of single- and multi-channel responses.\n // We treat multi-channel as \"join the channel transcripts\" — consumers\n // who care about per-channel detail can re-parse from `modelOptions`.\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- bridges SpeechToTextConvertResponse union (incl. webhook variant with no text/words/transcripts) to a flattened duck-typed shape we discriminate at runtime\n const data = response as unknown as {\n text?: string\n languageCode?: string\n languageProbability?: number\n words?: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>\n audioDurationSecs?: number\n transcripts?: Array<{\n text?: string\n languageCode?: string\n words?: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>\n audioDurationSecs?: number\n }>\n }\n\n if (data.transcripts) {\n const joinedText = data.transcripts\n .map((t) => t.text ?? '')\n .filter(Boolean)\n .join('\\n')\n const joinedWords = data.transcripts.flatMap((t) => t.words ?? [])\n const duration = data.transcripts.reduce(\n (max, t) => Math.max(max, t.audioDurationSecs ?? 0),\n 0,\n )\n const firstLang = data.transcripts.find(\n (t) => t.languageCode,\n )?.languageCode\n return {\n id: generateId(this.name),\n model: this.model,\n text: joinedText,\n ...(firstLang ? { language: firstLang } : {}),\n ...(duration ? { duration } : {}),\n ...buildWordsAndSegments(joinedWords),\n }\n }\n\n return {\n id: generateId(this.name),\n model: this.model,\n text: data.text ?? '',\n ...(data.languageCode ? { language: data.languageCode } : {}),\n ...(data.audioDurationSecs ? { duration: data.audioDurationSecs } : {}),\n ...buildWordsAndSegments(data.words ?? []),\n }\n }\n\n protected override generateId(): string {\n return generateId(this.name)\n }\n}\n\ntype NormalizedAudio =\n | { kind: 'file'; value: Blob }\n | { kind: 'url'; value: string }\n\nfunction normalizeAudioInput(\n audio: TranscriptionOptions['audio'],\n): NormalizedAudio {\n if (audio instanceof ArrayBuffer) {\n return { kind: 'file', value: new Blob([audio]) }\n }\n if (typeof audio === 'string') {\n const blob = dataUrlToBlob(audio)\n if (blob) return { kind: 'file', value: blob }\n return { kind: 'url', value: audio }\n }\n // Blob or File both fit the SDK's `Uploadable` contract.\n return { kind: 'file', value: audio }\n}\n\nfunction buildWordsAndSegments(\n words: Array<{\n text: string\n start?: number\n end?: number\n type: string\n speakerId?: string\n }>,\n): {\n words?: Array<TranscriptionWord>\n segments?: Array<TranscriptionSegment>\n} {\n const timedWords = words.filter(\n (w): w is typeof w & { start: number; end: number } =>\n typeof w.start === 'number' &&\n typeof w.end === 'number' &&\n w.type !== 'spacing',\n )\n if (timedWords.length === 0) return {}\n\n const outWords: Array<TranscriptionWord> = timedWords.map((w) => ({\n word: w.text,\n start: w.start,\n end: w.end,\n }))\n\n // Group contiguous words that share a speaker into segments. If no speaker\n // is ever set, we still emit one segment per sentence-ish grouping.\n const segments: Array<TranscriptionSegment> = []\n let current: {\n start: number\n end: number\n text: string\n speaker?: string\n } | null = null\n\n for (const w of timedWords) {\n if (!current) {\n current = {\n start: w.start,\n end: w.end,\n text: w.text,\n ...(w.speakerId ? { speaker: w.speakerId } : {}),\n }\n continue\n }\n if (w.speakerId && current.speaker !== w.speakerId) {\n segments.push({ id: segments.length, ...current })\n current = {\n start: w.start,\n end: w.end,\n text: w.text,\n speaker: w.speakerId,\n }\n continue\n }\n current.end = w.end\n current.text = current.text ? `${current.text} ${w.text}` : w.text\n }\n if (current) segments.push({ id: segments.length, ...current })\n\n return { words: outWords, segments }\n}\n\n/**\n * Create an ElevenLabs transcription adapter using `ELEVENLABS_API_KEY` from env.\n */\nexport function elevenlabsTranscription<\n TModel extends ElevenLabsTranscriptionModel,\n>(\n model: TModel,\n config?: ElevenLabsClientConfig,\n): ElevenLabsTranscriptionAdapter<TModel> {\n return new ElevenLabsTranscriptionAdapter(model, config)\n}\n\n/**\n * Create an ElevenLabs transcription adapter with an explicit API key.\n */\nexport function createElevenLabsTranscription<\n TModel extends ElevenLabsTranscriptionModel,\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<ElevenLabsClientConfig, 'apiKey'>,\n): ElevenLabsTranscriptionAdapter<TModel> {\n return new ElevenLabsTranscriptionAdapter(model, { apiKey, ...config })\n}\n"],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -1,27 +1,10 @@
1
+ import { getElevenLabsApiKeyFromEnv } from "./utils/client.js";
1
2
  import { elevenlabsRealtimeToken } from "./realtime/token.js";
2
3
  import { elevenlabsRealtime } from "./realtime/adapter.js";
4
+ import "./realtime/index.js";
3
5
  import { ElevenLabsSpeechAdapter, createElevenLabsSpeech, elevenlabsSpeech } from "./adapters/speech.js";
6
+ import { ELEVENLABS_AUDIO_MODELS, ELEVENLABS_TRANSCRIPTION_MODELS, ELEVENLABS_TTS_MODELS, isElevenLabsMusicModel, isElevenLabsSoundEffectsModel } from "./model-meta.js";
4
7
  import { ElevenLabsAudioAdapter, createElevenLabsAudio, elevenlabsAudio } from "./adapters/audio.js";
5
8
  import { ElevenLabsTranscriptionAdapter, createElevenLabsTranscription, elevenlabsTranscription } from "./adapters/transcription.js";
6
- import { ELEVENLABS_AUDIO_MODELS, ELEVENLABS_TRANSCRIPTION_MODELS, ELEVENLABS_TTS_MODELS, isElevenLabsMusicModel, isElevenLabsSoundEffectsModel } from "./model-meta.js";
7
- import { getElevenLabsApiKeyFromEnv } from "./utils/client.js";
8
- export {
9
- ELEVENLABS_AUDIO_MODELS,
10
- ELEVENLABS_TRANSCRIPTION_MODELS,
11
- ELEVENLABS_TTS_MODELS,
12
- ElevenLabsAudioAdapter,
13
- ElevenLabsSpeechAdapter,
14
- ElevenLabsTranscriptionAdapter,
15
- createElevenLabsAudio,
16
- createElevenLabsSpeech,
17
- createElevenLabsTranscription,
18
- elevenlabsAudio,
19
- elevenlabsRealtime,
20
- elevenlabsRealtimeToken,
21
- elevenlabsSpeech,
22
- elevenlabsTranscription,
23
- getElevenLabsApiKeyFromEnv,
24
- isElevenLabsMusicModel,
25
- isElevenLabsSoundEffectsModel
26
- };
27
- //# sourceMappingURL=index.js.map
9
+ import "./utils/index.js";
10
+ export { ELEVENLABS_AUDIO_MODELS, ELEVENLABS_TRANSCRIPTION_MODELS, ELEVENLABS_TTS_MODELS, ElevenLabsAudioAdapter, ElevenLabsSpeechAdapter, ElevenLabsTranscriptionAdapter, createElevenLabsAudio, createElevenLabsSpeech, createElevenLabsTranscription, elevenlabsAudio, elevenlabsRealtime, elevenlabsRealtimeToken, elevenlabsSpeech, elevenlabsTranscription, getElevenLabsApiKeyFromEnv, isElevenLabsMusicModel, isElevenLabsSoundEffectsModel };
@@ -1,32 +1,47 @@
1
- const ELEVENLABS_TTS_MODELS = [
2
- "eleven_v3",
3
- "eleven_multilingual_v2",
4
- "eleven_flash_v2_5",
5
- "eleven_flash_v2",
6
- "eleven_turbo_v2_5",
7
- "eleven_turbo_v2",
8
- "eleven_monolingual_v1"
1
+ //#region src/model-meta.ts
2
+ /**
3
+ * ElevenLabs model identifiers. The lists below are the source of truth —
4
+ * callers are blocked from passing unknown model IDs. Keep them in sync with
5
+ * the ElevenLabs SDK via the automated update pipeline.
6
+ */
7
+ /**
8
+ * Text-to-speech models.
9
+ * @see https://elevenlabs.io/docs/models
10
+ */
11
+ var ELEVENLABS_TTS_MODELS = [
12
+ "eleven_v3",
13
+ "eleven_multilingual_v2",
14
+ "eleven_flash_v2_5",
15
+ "eleven_flash_v2",
16
+ "eleven_turbo_v2_5",
17
+ "eleven_turbo_v2",
18
+ "eleven_monolingual_v1"
9
19
  ];
10
- const ELEVENLABS_AUDIO_MODELS = [
11
- "music_v1",
12
- "eleven_text_to_sound_v2",
13
- "eleven_text_to_sound_v1"
20
+ /**
21
+ * Audio generation models — music (`music_v1`) + sound effects
22
+ * (`eleven_text_to_sound_v*`) share one `generateAudio` adapter.
23
+ * The adapter dispatches by model id so callers pick behavior via the model.
24
+ *
25
+ * @see https://elevenlabs.io/docs/overview/capabilities/music
26
+ * @see https://elevenlabs.io/docs/overview/capabilities/sound-effects
27
+ */
28
+ var ELEVENLABS_AUDIO_MODELS = [
29
+ "music_v1",
30
+ "eleven_text_to_sound_v2",
31
+ "eleven_text_to_sound_v1"
14
32
  ];
15
33
  function isElevenLabsMusicModel(model) {
16
- return model === "music_v1";
34
+ return model === "music_v1";
17
35
  }
18
36
  function isElevenLabsSoundEffectsModel(model) {
19
- return model.startsWith("eleven_text_to_sound_");
37
+ return model.startsWith("eleven_text_to_sound_");
20
38
  }
21
- const ELEVENLABS_TRANSCRIPTION_MODELS = [
22
- "scribe_v2",
23
- "scribe_v1"
24
- ];
25
- export {
26
- ELEVENLABS_AUDIO_MODELS,
27
- ELEVENLABS_TRANSCRIPTION_MODELS,
28
- ELEVENLABS_TTS_MODELS,
29
- isElevenLabsMusicModel,
30
- isElevenLabsSoundEffectsModel
31
- };
32
- //# sourceMappingURL=model-meta.js.map
39
+ /**
40
+ * Speech-to-text (transcription) models — Scribe family.
41
+ * @see https://elevenlabs.io/docs/overview/capabilities/speech-to-text
42
+ */
43
+ var ELEVENLABS_TRANSCRIPTION_MODELS = ["scribe_v2", "scribe_v1"];
44
+ //#endregion
45
+ export { ELEVENLABS_AUDIO_MODELS, ELEVENLABS_TRANSCRIPTION_MODELS, ELEVENLABS_TTS_MODELS, isElevenLabsMusicModel, isElevenLabsSoundEffectsModel };
46
+
47
+ //# sourceMappingURL=model-meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["import type { ElevenLabs } from '@elevenlabs/elevenlabs-js'\n\n/**\n * ElevenLabs model identifiers. The lists below are the source of truth —\n * callers are blocked from passing unknown model IDs. Keep them in sync with\n * the ElevenLabs SDK via the automated update pipeline.\n */\n\n/**\n * Text-to-speech models.\n * @see https://elevenlabs.io/docs/models\n */\nexport const ELEVENLABS_TTS_MODELS = [\n 'eleven_v3',\n 'eleven_multilingual_v2',\n 'eleven_flash_v2_5',\n 'eleven_flash_v2',\n 'eleven_turbo_v2_5',\n 'eleven_turbo_v2',\n 'eleven_monolingual_v1',\n] as const\n\nexport type ElevenLabsTTSModel = (typeof ELEVENLABS_TTS_MODELS)[number]\n\n/**\n * Audio generation models — music (`music_v1`) + sound effects\n * (`eleven_text_to_sound_v*`) share one `generateAudio` adapter.\n * The adapter dispatches by model id so callers pick behavior via the model.\n *\n * @see https://elevenlabs.io/docs/overview/capabilities/music\n * @see https://elevenlabs.io/docs/overview/capabilities/sound-effects\n */\nexport const ELEVENLABS_AUDIO_MODELS = [\n 'music_v1',\n 'eleven_text_to_sound_v2',\n 'eleven_text_to_sound_v1',\n] as const\n\nexport type ElevenLabsAudioModel = (typeof ELEVENLABS_AUDIO_MODELS)[number]\n\n/** Music models within the audio family. */\nexport type ElevenLabsMusicModel = 'music_v1'\n/** SFX models within the audio family. */\nexport type ElevenLabsSoundEffectsModel =\n | 'eleven_text_to_sound_v2'\n | 'eleven_text_to_sound_v1'\n\nexport function isElevenLabsMusicModel(\n model: string,\n): model is ElevenLabsMusicModel {\n return model === 'music_v1'\n}\n\nexport function isElevenLabsSoundEffectsModel(\n model: string,\n): model is ElevenLabsSoundEffectsModel {\n return model.startsWith('eleven_text_to_sound_')\n}\n\n/**\n * Speech-to-text (transcription) models — Scribe family.\n * @see https://elevenlabs.io/docs/overview/capabilities/speech-to-text\n */\nexport const ELEVENLABS_TRANSCRIPTION_MODELS = [\n 'scribe_v2',\n 'scribe_v1',\n] as const\n\nexport type ElevenLabsTranscriptionModel =\n (typeof ELEVENLABS_TRANSCRIPTION_MODELS)[number]\n\n/**\n * Supported `output_format` strings, encoded as `codec_samplerate[_bitrate]`.\n * Aliased to the SDK's `AllowedOutputFormats` so the list stays in sync\n * automatically whenever the `@elevenlabs/elevenlabs-js` dependency is bumped.\n *\n * @see https://elevenlabs.io/docs/api-reference/text-to-speech/convert\n */\nexport type ElevenLabsOutputFormat = ElevenLabs.AllowedOutputFormats\n"],"names":[],"mappings":"AAYO,MAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAYO,MAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF;AAWO,SAAS,uBACd,OAC+B;AAC/B,SAAO,UAAU;AACnB;AAEO,SAAS,8BACd,OACsC;AACtC,SAAO,MAAM,WAAW,uBAAuB;AACjD;AAMO,MAAM,kCAAkC;AAAA,EAC7C;AAAA,EACA;AACF;"}
1
+ {"version":3,"file":"model-meta.js","names":[],"sources":["../../src/model-meta.ts"],"sourcesContent":["import type { ElevenLabs } from '@elevenlabs/elevenlabs-js'\n\n/**\n * ElevenLabs model identifiers. The lists below are the source of truth —\n * callers are blocked from passing unknown model IDs. Keep them in sync with\n * the ElevenLabs SDK via the automated update pipeline.\n */\n\n/**\n * Text-to-speech models.\n * @see https://elevenlabs.io/docs/models\n */\nexport const ELEVENLABS_TTS_MODELS = [\n 'eleven_v3',\n 'eleven_multilingual_v2',\n 'eleven_flash_v2_5',\n 'eleven_flash_v2',\n 'eleven_turbo_v2_5',\n 'eleven_turbo_v2',\n 'eleven_monolingual_v1',\n] as const\n\nexport type ElevenLabsTTSModel = (typeof ELEVENLABS_TTS_MODELS)[number]\n\n/**\n * Audio generation models — music (`music_v1`) + sound effects\n * (`eleven_text_to_sound_v*`) share one `generateAudio` adapter.\n * The adapter dispatches by model id so callers pick behavior via the model.\n *\n * @see https://elevenlabs.io/docs/overview/capabilities/music\n * @see https://elevenlabs.io/docs/overview/capabilities/sound-effects\n */\nexport const ELEVENLABS_AUDIO_MODELS = [\n 'music_v1',\n 'eleven_text_to_sound_v2',\n 'eleven_text_to_sound_v1',\n] as const\n\nexport type ElevenLabsAudioModel = (typeof ELEVENLABS_AUDIO_MODELS)[number]\n\n/** Music models within the audio family. */\nexport type ElevenLabsMusicModel = 'music_v1'\n/** SFX models within the audio family. */\nexport type ElevenLabsSoundEffectsModel =\n | 'eleven_text_to_sound_v2'\n | 'eleven_text_to_sound_v1'\n\nexport function isElevenLabsMusicModel(\n model: string,\n): model is ElevenLabsMusicModel {\n return model === 'music_v1'\n}\n\nexport function isElevenLabsSoundEffectsModel(\n model: string,\n): model is ElevenLabsSoundEffectsModel {\n return model.startsWith('eleven_text_to_sound_')\n}\n\n/**\n * Speech-to-text (transcription) models — Scribe family.\n * @see https://elevenlabs.io/docs/overview/capabilities/speech-to-text\n */\nexport const ELEVENLABS_TRANSCRIPTION_MODELS = [\n 'scribe_v2',\n 'scribe_v1',\n] as const\n\nexport type ElevenLabsTranscriptionModel =\n (typeof ELEVENLABS_TRANSCRIPTION_MODELS)[number]\n\n/**\n * Supported `output_format` strings, encoded as `codec_samplerate[_bitrate]`.\n * Aliased to the SDK's `AllowedOutputFormats` so the list stays in sync\n * automatically whenever the `@elevenlabs/elevenlabs-js` dependency is bumped.\n *\n * @see https://elevenlabs.io/docs/api-reference/text-to-speech/convert\n */\nexport type ElevenLabsOutputFormat = ElevenLabs.AllowedOutputFormats\n"],"mappings":";;;;;;;;;;AAYA,IAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;AAYA,IAAa,0BAA0B;CACrC;CACA;CACA;AACF;AAWA,SAAgB,uBACd,OAC+B;CAC/B,OAAO,UAAU;AACnB;AAEA,SAAgB,8BACd,OACsC;CACtC,OAAO,MAAM,WAAW,uBAAuB;AACjD;;;;;AAMA,IAAa,kCAAkC,CAC7C,aACA,WACF"}