@crvouga/mockingbird-service-elevenlabs (英语)
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
模拟器 十一Labs 文本为语音 测试套房: POST /v1/text-to-speech/{voice_id}
用音频回答,真的 output_format 说(可解码的 MPEG 第 三层框架,
无头 PCM 样本,或 WAV 文件),带有销售商的错误信封,以及精确的字节
测试队列。 无一物被模型合成,无一物被计费:默认的音频是a
音调,其音调和音长是请求的函数.
安装
npm install -D @crvouga/mockingbird-service-elevenlabs
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-elevenlabs serve, (中文(简体) ), createServer 从 ./server (节点),或 createRuntime
与任何获取服务器.
使用量
在模拟器上指向该应用的"11Labs"基础 URL(http://127.0.0.1:8841/v1 真实的
一个是 https://api.elevenlabs.io/v1并赋予它仿真者所接受的密钥.
npx mockingbird-elevenlabs serve --port 8841 \
--api-key "$ELEVENLABS_API_KEY" \
--voices "$ELEVENLABS_VOICE_ID" \
--models eleven_multilingual_v2,eleven_flash_v2_5
在进程中,通过模拟器作为 fetch 官方 SDK (中文(简体) )@elevenlabs/elevenlabs-js:
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js"
import {
createRuntime,
DEFAULT_API_KEY,
DEFAULT_VOICES,
mp3Audio,
} from "@crvouga/mockingbird-service-elevenlabs"
// Test setup. A reply the test controls: exact bytes for one text. Here they are a valid MP3,
// but any bytes are returned as given.
const scripted = mp3Audio(44_100, 128, 500, 9)
const emulator = createRuntime({
scripts: [{ match: { text: "Welcome back." }, audio: scripted }],
})
// The ElevenLabs SDK your application already uses. Only its fetch changes: requests reach
// the emulator in this process instead of api.elevenlabs.io.
const elevenlabs = new ElevenLabsClient({
apiKey: DEFAULT_API_KEY,
fetch: ((url: RequestInfo | URL, init?: RequestInit) =>
emulator.fetch(new Request(url, init))) as typeof fetch,
})
const voiceId = DEFAULT_VOICES[0]?.voice_id ?? ""
const welcome = await elevenlabs.textToSpeech
.convert(voiceId, { text: "Welcome back.", modelId: "eleven_multilingual_v2", outputFormat: "mp3_44100_128" })
.withRawResponse()
console.log(welcome.rawResponse.status, welcome.rawResponse.headers.get("content-type")) // 200 audio/mpeg
console.log((await new Response(welcome.data).arrayBuffer()).byteLength === scripted.length) // true
// Unscripted requests get generated audio: raw 16-bit mono samples for pcm_44100.
const pcm = await elevenlabs.textToSpeech.convert(voiceId, { text: "Anything else.", outputFormat: "pcm_44100" })
console.log((await new Response(pcm).arrayBuffer()).byteLength) // 61740
路线
| 路线 | 行为 |
|---|---|
POST /v1/text-to-speech/{voice_id}?output_format=… | 贾森 {text, model_id?} 与 xi-api-key答复 200 带音频和信头 character-cost (代码: text, (中文(简体) ), request-id 财务报告和审定财务报表 x-trace-id。 。 。 . output_format 默认为 mp3_44100_128 财务报告和审定财务报表 model_id 改为 eleven_multilingual_v2就像卖家一样 这个 Accept 页眉不读. |
该路径上的任何其他方法是: 405 {"detail": "Method Not Allowed"} 与 allow: POST; 任意
其他路径是 404 {"detail": "Not Found"}。 。 。 .
音频
请求由最老排队者回答 脚本 这匹配它。 没有一个人
模拟器生成一个音调: 每个字符50ms text (至少0.25 s, 最多5 s), 1
从请求中挑选的十二个投出 指纹。同样的
因此,无论何时,请求总是得到相同的字节,以及两个不同的请求
几乎总是得到不同的文本(两个相同长度的文本,当它们降落在
相同的投出; 当测试需要绝对不同的字节时排入脚本 .
output_format | 字节 | content-type |
|---|---|---|
mp3_44100_32, (中文(简体) ), _64, (中文(简体) ), _96, (中文(简体) ), _128, (中文(简体) ), _192 | MPEG-1 第III层,44.1 kHz,单相,常位速率. 每个字节都属于一个完整的1152个样板框架;被粘贴的比特保持了流的标称速率(417-和418个字节框架以128克比特/秒). 没有ID3标记,没有星头. | audio/mpeg |
mp3_22050_32, (中文(简体) ), mp3_24000_48 | MPEG-2 第III层,单相,576-样相框. | audio/mpeg |
pcm_8000 . pcm_48000 | Raw签下16位小endian单样. 没有容器和头:第一个字节是第一个样本. | audio/pcm (单位:千美元)未核实(中文(简体) ) |
wav_8000 . wav_48000 | 犬科44字节RIFF/WAVE头后面的同样样本. | audio/wav (单位:千美元)未核实(中文(简体) ) |
opus_48000_*, (中文(简体) ), ulaw_8000, (中文(简体) ), alaw_8000 | 未生成. 501 与 detail.type: "mockingbird_not_modelled" 直到脚本提供字节;然后 audio/opus, (中文(简体) ), audio/basic, (中文(简体) ), audio/x-alaw-basic (单位:千美元)未核实) (中文(简体) ). |
pcm_44100 不是WAV文件,不管请求是什么 Accept 信头写着: 发送的客户端
Accept: audio/wav 并将答案作为WAV从小贩那里得到的无头样本
从这个模范一样。 问 wav_44100 去拿货柜.
MP3帧携带真实的音频,而不是填充器前的页眉:每个颗粒Huffman-code
一个光谱线,和 ffmpeg, (中文(简体) ), mpg123 和 Core 音频解码流到稳定音调
大约四分之一的全尺寸. mp3Audio, (中文(简体) ), pcmAudio 财务报告和审定财务报表 wavAudio 为建筑物导出
属于有效音频的脚本定着.
销售商的参考文献说明和模拟者如下: 格式列表
mp3_44100_128 默认, audio/mpeg,而PCM作为S16LE,深度为16位. 没有说,
如此未经证实:除了 audio/mpeg;PCM和MP3是单体的(
引用时只表示拒绝“制作立体声”的效果 pcm_*页:1
页眉布局; 真实的 MP3 答案是否从 ID3 标记开始; 以及 character-cost 等于
每个模型的字符数.
错误
除了一个错误 422 是卖家的信封,与 x-trace-id 重复 request_id数字 :
{
"detail": {
"type": "authentication_error",
"code": "unauthorized",
"message": "Invalid API key",
"status": "invalid_api_key",
"request_id": "8d3fefe1da6d251e5b571c484eecdaad"
}
}
status 是遗留的标识符( 供应商仍然发送; 老客户端已读取)
detail.status 财务报告和审定财务报表 detail.message) (中文(简体) ). param 当一个请求参数出现过错时会添加.
A 类 422 是请求验证器的列表 : {"detail": [{"type", "loc", "msg", "input"}]}。 。 。 .
| 请求 | 答复 | 依据 |
|---|---|---|
| 身体不是JSON的,不是JSON | 422 json_invalid, (中文(简体) ), loc: ["body", 0], (中文(简体) ), msg: "JSON decode error" | 被观察. 卖家的 loc[1] 是解析器的字符偏移和 ctx.error 其信息;模拟者发送 0 财务报告和审定财务报表 "Invalid JSON"。 。 。 . |
没有尸体,非JSON媒体类型,或者没有 text | 422 missing, (中文(简体) ), loc: ["body", "text"], (中文(简体) ), msg: "Field required" | 被观察. 对于一个JSON阵列,供应商将每个体域列为缺失;模拟器列表 text。 。 。 . |
text 或者说 model_id 不是一个字符串 | 422 string_type, (中文(简体) ), msg: "Input should be a valid string", (中文(简体) ), input 值 | 被观察. |
没有 xi-api-key | 401 authentication_error 编号 : unauthorized, (中文(简体) ), status: "needs_authorization" | 观察,信息包含. |
| 命名空格没有按键 | 401 authentication_error 编号 : unauthorized, (中文(简体) ), status: "invalid_api_key" | 观察,信息包含. |
output_format 未列入供应商名单 | 400 validation_error 编号 : invalid_output_format, (中文(简体) ), param: "output_format" | 有记录的代码和类型. 未核实 在电线上. |
text 实值 "" | 400 validation_error 编号 : empty_text, (中文(简体) ), param: "text" | 有记录的代码和类型. 未核实 在电线上. |
| 未配置的声音 | 404 not_found 编号 : voice_not_found, (中文(简体) ), param: "voice_id" | 有记录的代码和类型. 未核实; 供应商的更年长的帮助文章文件 voice_not_found 在"400或401"下. |
| 未配置的模型 | 404 not_found 编号 : model_not_found, (中文(简体) ), param: "model_id" | 有记录的代码和类型. 未核实 在电线上. |
配置的模型 can_do_text_to_speech: false | 400 validation_error 编号 : unsupported_model | 有记录的代码和类型. 未核实 在电线上. |
"Observed"是指公众端点给出的请求没有API密钥的答案,或者一个
编成一,于2026-10-10查阅. 这些答案还确定了头两次检查的顺序:身体
在检查密钥之前验证( 带坏身体的无密钥请求是) 422页:1
键前 output_format,文本和语音(格式未知的无密钥请求为
401) (中文(简体) ). 钥匙后面的检查顺序是 未核实:格式,空文本,语音,
型号。 对于未经核实的行 message 是供应商错误中的描述
参考, status 重复 code,以及供应商是否发送 param 不详.
脚本
POST /__admin/scripts 请求的队列精确字节 a match 选择 :
{
"match": { "voice_id": "21m00Tcm4TlvDq8ikWAM", "output_format": "mp3_44100_128", "text": "Welcome back." },
"audio_base64": "//uQwAAAACALlACEIAAEAXKA…",
"content_type": "audio/mpeg",
"times": 1
}
match可能名称voice_id, (中文(简体) ),model_id, (中文(简体) ),output_format,准确的text联合国text_sha256),以及整个请求fingerprint。每个给定的字段必须匹配;空match回答每一个请求.text到达时就散了.times在许多答案后退出脚本;没有这些答案,脚本将回答每个 匹配请求,这是缓存测试想要的。 在最古老的剧本中 答题左取胜,所以在重复之前先排队一发答题.- 一个脚本只被一个否则会得到音频的请求所使用. 请求被驳回
4xx或因过错而失败 让它不受影响. content_type覆盖格式的内容类型.- 这个
scripts选项createRuntime形状一样audio: Uint8Array这些 脚本由POST /__admin/reset;在 HTTP 上排队的脚本被它丢出.
电话和指纹
仿真器每处理一个请求 保存一个记录 它处理过去的身体验证, 没有请求
文本 : GET /__admin/calls 答题 {count, by_fingerprint, calls}每次通话
{id, voice_id, model_id, output_format, text_sha256, text_characters, fingerprint, status, error, script_id, audio_bytes, audio_sha256, content_type, at}。 。 。 . ?fingerprint=<hex> 缩进
给一个请求.
text_sha256是 UTF-8 文本的 SHA-256(textFingerprint(text)) (中文(简体) ).fingerprint是 JSON 阵列的 SHA-256[voice_id, model_id, output_format, text_sha256]与已填入的缺省数(speechFingerprint({voice_id, model_id?, output_format?, text})) (中文(简体) ). 其他身体领域不是它的一部分.
请求因过失而失败,从未到达模拟者那里,所以他们没有通话记录
请求日记( e)GET /__admin/requests具有其地位和 faultId。 。 。 .
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
POST /__admin/scripts | 请回答(上). 201 与 {id, match, content_type, bytes, sha256, times, remaining, hits}· ; 400 与一个错误的脚本的原因. |
GET /__admin/scripts | 取名空间的脚本,最古老的第一,没有他们的音频. |
DELETE /__admin/scripts | 放下每个脚本. {deleted}。 。 。 . |
GET /__admin/calls | 调用记录和计数(上). |
PUT /__admin/voices | {voices: ["<id>", {voice_id, name?}]} 替换命名空间的声音. GET 列出他们. |
PUT /__admin/models | {models: ["<id>", {model_id, can_do_text_to_speech?}]} 替换命名空间的模型. GET 列出他们. |
PUT /__admin/keys | {keys: ["<key>"]} 替换命名空间接受的密钥. GET 列出他们的SHA -256, 从来没有键. |
名称空间从密钥开始 fixture-elevenlabs-key,声音 21m00Tcm4TlvDq8ikWAM (单位:千美元)
和模型 eleven_multilingual_v2, (中文(简体) ), eleven_flash_v2_5 财务报告和审定财务报表
eleven_turbo_v2_5,除非 keys, (中文(简体) ), voices 财务报告和审定财务报表 models 选项另作说明.
POST /__admin/reset 返回到这个位置,以及 POST /__admin/snapshots 及其恢复盖
脚本(并附有剩余答案)和呼叫记录.
错误预设( E)POST /__admin/faults/presets/<name>数字 {"count": n} 失败超过
下一个请求; GET /__admin/faults/presets) (中文(简体) ). 每个答案在模拟器前,所以
记录没有调用, 没有使用脚本 :
| 预设 | 答复 |
|---|---|
invalid_api_key | 401 authentication_error, (中文(简体) ), status: "invalid_api_key" |
quota_exceeded | 402 payment_required 编号 : insufficient_credits, (中文(简体) ), status: "quota_exceeded" |
rate_limited | 429 rate_limit_error 编号 : rate_limit_exceeded |
too_many_concurrent_requests | 429 rate_limit_error 编号 : concurrent_limit_exceeded, (中文(简体) ), status: "too_many_concurrent_requests" |
system_busy | 429 rate_limit_error 编号 : system_busy |
server_error | 500 internal_error |
service_unavailable | 503 service_unavailable |
network_reset | 无回答: 连接被丢弃( N)fetch 拒绝方式 TypeError) (中文(简体) ). |
slow_response | 请求在模拟者看到前被持有250毫秒. |
情况、类型和代码是供应商错误参考清单
未遵守(未核实) (中文(简体) ). 具体地说,该参考文献指出: 402, (中文(简体) ),
卖家年长的帮助文章文件 quota_exceeded 在"400或401"下。 对于任何其他
身份或机构,增加一条规则: POST /__admin/faults {"status": 401, "count": 1, "body": {…}}。 。 。 .
{"latencyMs": n} 请求由 n 毫秒; 通过 io: {sleep} 改为 createRuntime 改为
让它虚拟地等待。 当等待结束时, 请求被挡在后面时中止 .
命名空间
一个命名空间有自己的键,声音,模型,脚本和呼叫记录. 选择一个与
x-mockingbird-namespace 标题,带有 /__admin/ns/<name> 基础 URL 前缀
(单位:千美元)http://127.0.0.1:8841/__admin/ns/worker-1/v1),或用 API 键:
PUT /__admin/credentials {"credentials": {"<key>": "<namespace>"}},在将该密钥添加到
名称空间 PUT /__admin/keys。 。 。 .
存储什么
请求文本、 API 密钥和音频永远不能到达日记、 日志、 状态反省、 状态
管理路线或快照。 请求留下一份识别资料、长度和摘要的呼叫记录;
一个密钥作为SHA-256保存; 脚本音频被加密(AES-256-GCM在密钥下)
仅存在于此过程中; 通过 vaultKey 重开一个持续的数据库)
还有SHA-256 被否决的身体被记录为字段和原因,绝不是价值.
现场平等
bun run parity:service -- elevenlabs 比较模拟器和真实的 API。 这需要
ELEVENLABS_API_KEY 2号出口没有它。 默认情况下,它只发出供应商的请求
在合成前拒绝(无效的正文,一个不存在的语音),所以没有字符
计费; --include-unsafe 增加一条短线的转换 ELEVENLABS_VOICE_ID该
运行是解开上面标有的行.
故意不模拟
- 出自"语义"的语音:音是声调,从来不说. 需要特别测试 音频队列.
- 流言(
/stream, WebSockets),时间戳(/with-timestamps),文本为对话框. - 语音克隆和语音管理
/v1/voices),型号上市(/v1/models: 声音 模型是通过管理路线设置的固定装置. - 接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接接.
- 记帐,认购,定额和计划限额. 每个键都可以使用每一种格式
等级规则
mp3_44100_192和44.1 kHz PCM,每个模型字符限制和真实 费率限额不适用。 使用断层预设以故意失败请求 . - 请求字段以外的
text财务报告和审定财务报表model_id(单位:千美元)voice_settings, (中文(简体) ),seed, (中文(简体) ),language_code, (中文(简体) ),previous_text,(...)和enable_logging财务报告和审定财务报表optimize_streaming_latency查询 参数: 已接受,未验证,且对答案或指纹没有影响. Authorization作为替代xi-api-key,以及供应商的区域主机.- Opus、mu-law和A-law编码(仅标注,见 音频) (中文(简体) ).
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
ElevenLabsAPI | 类 | 进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), queue(script), (中文(简体) ), scripts(), (中文(简体) ), clearScripts(), (中文(简体) ), calls()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), keys, (中文(简体) ), voices, (中文(简体) ), models, (中文(简体) ), scripts, (中文(简体) ), vaultKey。 。 。 . |
createRuntime | 函数 | 全面服务合同的仿真器(保健、管理、命名空间、证书、预设和日记)。 备选方案: ElevenLabsAPI 加号 clock, (中文(简体) ), seed, (中文(简体) ), adminPrefix, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), io。 。 。 . |
ELEVENLABS_PRESETS | 对象 | 每个命名的断层预设. |
ELEVENLABS_NAMESPACE | 字符串 | 服务名称, "elevenlabs"。 。 。 . |
API_KEY_HEADER | 字符串 | "xi-api-key"。 。 。 . |
DEFAULT_API_KEY, (中文(简体) ), DEFAULT_VOICES, (中文(简体) ), DEFAULT_MODELS, (中文(简体) ), DEFAULT_MODEL_ID | 数值 | 命名空间始于什么, 当请求命名为无时所使用的模型 . |
OUTPUT_FORMATS, (中文(简体) ), DEFAULT_OUTPUT_FORMAT | 数值 | 每个 output_format 供应商名单,以及 "mp3_44100_128"。 。 。 . |
describeFormat | 函数 | (format) 改为 {codec, sampleRate, bitrate?, contentType, synthesized}。 。 。 . |
mp3Audio, (中文(简体) ), pcmAudio, (中文(简体) ), wavAudio | 函数 | 调子产生器: mp3Audio(sampleRate, bitrate, durationMs, line), (中文(简体) ), pcmAudio(sampleRate, durationMs, line), (中文(简体) ), wavAudio(sampleRate, durationMs, line)时 line 选择投出(line + 0.5) * 38.28 Hz in PCM and WAV)). 互联网档案馆的存檔,存档日期2013-12-21. |
speechFingerprint, (中文(简体) ), textFingerprint | 函数 | 文摘中包含一个脚本匹配和呼叫记录. |
createVaultKey | 函数 | 一个新鲜的32字节键 vaultKey 选项. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | OpenAPI合同及其操作代号. |
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务过来 node:http; 数据 serve CLI目标;出港8841. |
部分 嘲笑鸟。 。 。 .