开发者

语音转文字 API

通过排队作业转录完整音频文件,支持免费费用估算、幂等提交,以及两个 API 主机上的用量跟踪。

本页
  1. 端点
  2. 准备音频文件
  3. 提交转录作业
  4. 幂等键
  5. 不创建作业的费用估算
  6. 读取转录结果
  7. 使用 api.multitel.net

此 API 通过排队作业转录完整的音频文件。提交文件后,请保存返回的作业 ID,并持续获取作业信息,直到处理完成。所有请求均须通过 HTTPS 发送,并使用您的账户凭据:可使用示例中的 HTTP Basic 凭据,也可使用 API 令牌,详见身份验证。请将凭据保存在您的服务器上。

端点

两个 API 主机https://api.multi.tel和兼容主机https://api.multitel.net共享同一账户范围内的作业、幂等键、限制和计费。它们的上传编码和响应封装格式不同,因此请始终使用同一主机及与其匹配的解析器。

操作方法和路径
服务信息GET /v3/speech_to_text
提交作业POST /v3/speech_to_text
不创建作业的费用估算POST /v3/speech_to_text/estimate
读取作业GET /v3/speech_to_text/JOB_ID
结算待付款作业POST /v3/speech_to_text/JOB_ID/settle
用量GET /v3/speech_to_text/usage

在api.multi.tel上,所有路径还可以使用前缀/v1/speech-to-text替换/v3/speech_to_text,例如POST /v1/speech-to-text/estimate。在api.multitel.net上,请使用/v3/speech_to_text路径。

服务信息响应报告以下字段:mode(batch)、realtime(false)、paidEnabled(当前是否接受新的付费提交)、pricePerMinuteUsd(0.005)、billingUnit(audio_second)、maxAudioSeconds(7200)和maxUploadBytes(26214400),以及简短的description。读取该信息免费,即使付费提交已停用也可读取;仅在整个服务不可用时才返回 503 transcription_unavailable。

准备音频文件

请使用不超过 25 MiB(26,214,400 字节)且时长不超过 2 小时(7,200 秒)的完整音频文件。提交时,文件必须被识别为包含音频流的 MP3、WAV、Ogg、FLAC、MOV 或 Matroska 媒体,并且元数据中的时长必须大于零且不超过 7,200 秒。已识别但未通过这些检查的文件将被拒绝,返回 422 unsupported_audio。目前,无法以任何上述格式读取的文件可能会返回服务器错误(500);请勿原样重新提交此类文件。仅凭文件扩展名无法确定兼容性。

通过这些检查不保证音频能够解码。音频按单声道或双声道处理。超过两个音频声道的文件、解码后音频时长超过 2 小时的文件,或在处理期间发生其他解码失败的文件,最终都会成为failed作业,通常带有decode_failed,且不收费。提交前,请将多声道音频转换为单声道或立体声。

可选的语言提示为所说语言的小写两字母或三字母代码,例如en。不提供提示时,请省略该字段;api.multi.tel会拒绝空字符串。该提示用于引导处理,但不会根据支持的语言列表进行检查,因此请使用所说语言的有效代码。

提交转录作业

使用Content-Type: application/json将 JSON 发送至POST https://api.multi.tel/v3/speech_to_text。请求体最大为 35 MiB,可容纳经 base64 编码后的最大尺寸文件;更大的请求体会被拒绝,返回 413。

字段含义
audioBase64必填。使用标准 base64 编码的完整文件(A–Z, a–z, 0–9, +, /),必要时使用=填充。请勿添加 data-URL 前缀、换行或空格,也不要使用 URL 安全字符表。该值解码后的大小必须在 1 字节到 25 MiB 之间,且重新编码后必须与原文本完全一致。
language可选的语言提示,详见上文。

其他任何 JSON 属性(包括idempotency_key)都会被拒绝,返回 400 invalid_transcription_request。请通过请求头发送该键。

幂等键

每次提交都需要一个Idempotency-Key请求头,其长度为 1 到 190 个字符。请使用 ASCII 字母、数字、-, _, .和:,且不要带有前导或尾随空格:兼容主机会去除首尾空白,并以字节计量键的长度,因此其他字符在两个主机上的计数可能不同。缺少键或键长度为 191 个字符及以上时,将被拒绝并返回 400。

键的作用范围为您的账户和语音转文字服务,涵盖两个主机及该账户的所有凭据。使用相同键重新发送相同文件和语言时,会返回现有作业、HTTP 200 和duplicate: true,不论该作业处于何种状态,也不论处理版本在作业创建后是否更新,均不会再次收费。将同一键用于不同文件或语言时,会返回 409 idempotency_conflict。使用新键时,即使文件相同也会创建新作业,并在处理成功完成后另行收费。

API_USER="your-api-username"
API_PASSWORD="your-api-password"

node -e 'process.stdout.write(JSON.stringify({audioBase64:require("node:fs").readFileSync("completed-call.mp3").toString("base64"),language:"en"}))' > completed-call.json

curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: speech-call-001" \
  --data-binary @completed-call.json \
  -o speech-job.json \
  https://api.multi.tel/v3/speech_to_text

node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).data.id'

新作业返回 HTTP 202 和下方所示字段;重复提交则返回 HTTP 200 及读取转录结果中所述的完整作业对象。请从data.id中读取作业 ID(UUID)。新作业的响应如下(标识符和值均为示例):

{
  "status": "success",
  "data": {
    "id": "3f6c1b2e-8a4d-4e7f-9c21-5b0d7e4a9f13",
    "status": "queued",
    "mode": "batch",
    "realtime": false,
    "source": "api",
    "durationSeconds": 90.5,
    "billedSeconds": 91,
    "costUsd": "0.007583334",
    "pricePerMinuteUsd": "0.005"
  }
}

作业处于排队或运行状态时,durationSeconds, billedSeconds和costUsd是根据文件元数据得出的估算值。最终费用按解码后的时长计算。

提交还可能返回:402 insufficient_balance,表示预付余额不足以支付该作业及其他尚未结清作业的费用;429 transcription_queue_full,表示您的账户或服务有过多未完成作业;429 audio_validation_busy,表示文件验证已达到处理容量;以及 503 paid_transcription_not_enabled,表示付费转录已停用。收到 429 和 503 响应时,请稍后使用相同键重试。

不创建作业的费用估算

将相同的 JSON 请求体发送至POST https://api.multi.tel/v3/speech_to_text/estimate。不需要幂等键。费用估算会验证文件并测量时长,但不会转录文件、创建作业、预留资金、检查余额或向账户收费。可以提供language提示,但它不会影响估算。

估算成功时返回 HTTP 200,字段包括estimate: true, charged: false, mode, realtime, durationSeconds, billedSeconds, pricePerMinuteUsd和costUsd,均位于data下。估算使用文件元数据中的时长,而已完成作业按解码后的时长收费,两者可能不同。费用估算与提交执行相同的文件检查。只有启用付费转录时才可使用估算(否则返回 503 paid_transcription_not_enabled)。文件验证达到处理容量时,可能返回 429 audio_validation_busy;请稍等后重试。

读取转录结果

轮询GET /v3/speech_to_text/JOB_ID,具体参见作业流程指南。作业对象包含以下字段:

字段含义
id作业的 UUID。
statusqueued, running, completed, failed或awaiting_payment。
progress运行时如可获取,则为 0 到 99 的百分比;完成时为 100;其他情况为null。
durationSeconds, billedSeconds音频时长和计费的整数秒数。作业排队或运行时,这些值为元数据估算值;作业已完成或等待付款时,使用解码后的时长。
costUsd, costIsEstimate以美元表示的费用,为保留九位小数的十进制字符串。costIsEstimate在作业排队或运行时为true。失败的作业不收费,即使其costUsd仍显示估算值。
pricePerMinuteUsd0.005适用于 API 作业,而0.000适用于免费的 Hosted PBX 录音作业。
failureCode对于失败作业:decode_failed(音频无法解码,例如音频超过两个声道,或解码后时长超过 2 小时)、inference_timeout(处理时间过长)、service_error或worker_lease_lost(处理被中断)。此外还定义了代码unsupported_audio和quality_check_failed。等待付款的作业显示insufficient_balance,结算后该代码仍可能保留。
source, modelVersion, createdAtsource为api时,表示通过 API 提交的作业;为hpbx时,表示您账户中的 Hosted PBX 录音作业。modelVersion是不透明的处理版本字符串。createdAt为提交时间。
duplicatetrue用于返回现有作业的响应。
result仅当status为completed时才存在。
结果字段含义
text完整转录文本:按分段顺序,以换行连接所有分段文本。
segments按开始时间排序的分段数组。每个分段覆盖最长约 29 秒的一段音频。其start和end(从音频开头算起的秒数)标记的是该音频段,而非单个词或句子,相邻音频段最多可重叠 1 秒。每个分段还包含text和language(语言代码,可为空),双声道结果还包含channel。
channelCount1 或 2。当前结果中包含此字段;较早的结果可能省略。
audioDurationMs解码后的时长,以毫秒为单位。计费时向上取整到整数秒。
qualityFlags为空,或包含review_recommended以及repetition_detected(某个短语在一个音频段内异常频繁地重复)、no_speech(未转录出语音),或后两者同时出现。
pipelineVersion可能出现。不透明的处理标识符。

转录文本及其时间戳、语言标签和声道标签均自动生成,不保证准确。出现任何质量标记时均应复核结果,并将重要姓名、数字和承诺与原始音频核对。长时间静音和非常安静的片段会被跳过,不会生成分段。结果不会识别各个说话者。当结果报告的channelCount为 2 时,每个分段的channel为A(第一个,即左声道)或B(第二个,即右声道)。只有各说话者分别录制在不同声道时,这才能区分说话者。双声道音频按实际经过的时长计费一次,不按声道分别计费。单声道结果不带声道标签。

使用 api.multitel.net

兼容端点POST https://api.multitel.net/v3/speech_to_text接受multipart/form-data,其中包含一个audio文件部分和可选的language字段,而非 JSON audioBase64。空的language值视为未提供提示。请发送相同的Idempotency-Key请求头。若请求头不存在,此主机也接受idempotency_key表单字段。名为source, free, billing_source, realtime或stream的字段会被拒绝,返回 400 unsupported_transcription_option;其他表单字段会被忽略。此主机还会返回以下错误:

  • 400 idempotency_key_required:缺少键或键过长。
  • 400 audio_upload_required:未上传文件,或上传未完整接收。
  • 400 invalid_language:语言无效。
  • 413 invalid_audio_size:文件为空或过大。
  • 400 invalid_job:作业 ID 格式错误。

此主机的语音转文字服务响应采用封装格式{"status":{"code":HTTP_STATUS},"response":{...}}。注意,status是对象,不是字符串。成功时,response包含与主主机上data相同的对象,因此作业 ID 为response.id。出错时,response.code包含错误代码,不附带消息或请求 ID。身份验证失败(401)由此主机的通用登录检查返回,响应体可能不同,因此请在解析前检查 HTTP 状态。请勿在两个主机间混用上传编码或响应解析器。

在此主机上估算费用时,请将相同的 multipart 字段 POST 至/v3/speech_to_text/estimate。不需要幂等键,估算结果位于response中。

API_USER="your-api-username"
API_PASSWORD="your-api-password"

curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
  -H "Idempotency-Key: speech-call-001" \
  -F "audio=@completed-call.mp3" -F "language=en" \
  -o speech-job.json \
  https://api.multitel.net/v3/speech_to_text

node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).response.id'