Files
tps-dashboard/docs/doco/doco_xfyun_integration_notes.md
T

6.0 KiB
Raw Blame History

讯飞 ASR 集成踩坑笔记

demo 期间累积的所有讯飞接入坑点。建议入 TPS 知识库,作为未来接入新 ASR 供应商时的对照。


选型坑

坑 1:不要用"大模型版"

  • 讯飞开放平台有两个录音转写产品:
    • 「录音文件转写(标准版)」← 用这个
    • 「录音文件转写(大模型版)」← 不要用
  • 大模型版的免费包阉割了 language 参数,调用时会报 language verify fail
  • 这个错误信息严重误导:看上去是语种没设对,实际是免费包没开通该参数权限
  • 排查耗时:约 30 分钟

坑 2:消费端和开发端密钥不通

  • 「讯飞听见 App」属于消费端,给最终用户做人工转写用
  • 「讯飞开放平台」属于开发端,给开发者调 API 用
  • 两套密钥互不相通——开发端的 APP_ID 在消费端没用,反之亦然
  • 如果只在讯飞听见 App 注册了账号,没有 APP_ID 和 SecretKey,必须再去开放平台注册一次

坑 3:免费额度不会自动激活

  • 开放平台首页显示"5 小时免费试用包",但只有走 0 元购买流程才会激活
  • 看到额度但没下单 → 调用时会报余额不足
  • 流程:商品页 → 0 元下单 → 支付(实际免费)→ 额度到账

音频规格坑

坑 4:必须是 16kHz / 单声道 / 16bit WAV

  • 其他规格讯飞会报错(且错误信息可能误导成"language verify fail"或"audio decode error"
  • MP3 在标准版也支持,但保险起见统一转 WAV
  • 转码命令(ffmpeg):
    ffmpeg -i input.mp3 -ac 1 -ar 16000 -sample_fmt s16 output_16k_mono.wav
    
    • -ac 1 = 单声道
    • -ar 16000 = 16kHz 采样率
    • -sample_fmt s16 = 16bit 位深

坑 5:时长字段不严格校验但建议传准

  • API 要求传 duration(毫秒)
  • 实测哪怕传 0 也能上传成功,但官方文档建议传准确值
  • WAV 从文件头读:n_frames / sample_rate * 1000
  • MP3 用 mutagen.mp3.MP3

接口坑

坑 6:签名算法是老式 HmacSHA1,不是常见的 HmacSHA256

# signa = base64(HmacSHA1(MD5(appid + ts), secretKey))
md5_str = hashlib.md5((appid + ts).encode("utf-8")).hexdigest()  # 32 位小写 hex
mac = hmac.new(secret_key.encode("utf-8"), md5_str.encode("utf-8"),
               digestmod=hashlib.sha1)
signa = base64.b64encode(mac.digest()).decode("utf-8")

注意:

  • MD5 输出是32 位小写 hex 字符串,不是 16 字节 raw bytes
  • HMAC 的 key 是 secretKey,data 是 MD5 字符串本身(不是其字节)
  • 最后做 base64 编码

坑 7:参数全部走 URL query,不是 form-data 或 JSON body

  • 上传接口:POST https://raasr.xfyun.cn/v2/api/upload?appId=...&signa=...&ts=...&...
  • Content-Type: application/json,但请求体是音频原始字节流(不是 JSON
  • 所有业务参数(fileSize fileName duration language pd hotWord …)都在 URL query 里
  • 中文热词必须做 URL encodequote(hot_word_str, safe='')

坑 8:热词用 | 分隔,不是逗号

hot_word_str = "|".join(HOT_WORDS)  # 萨德|爱国者|标准-6|...
params["hotWord"] = hot_word_str

限制:

  • 最多 200 个热词
  • 每个热词 216 字
  • 整个 hotWord 参数 URL encode 后不能超过某个长度(实测 35 个常规军事术语没问题)

异步查询坑

坑 9:轮询用 POST 不是 GET

  • 查询结果接口:POST https://raasr.xfyun.cn/v2/api/getResult?...
  • 即便没有 body 也是 POST
  • 用 GET 会报方法不允许

坑 10status 状态码语义

status 含义
0 待处理
1 处理中
4 完成
-1 失败

完成是 4,不是 2 也不是 200

坑 11:轮询间隔与超时

  • 26 分钟音频实测转写耗时约 5 分钟
  • 推荐轮询间隔 30 秒(taskEstimateTime 返回的预估值仅供参考)
  • 超时上限设 30 分钟比较保险

结果解析坑

坑 12:返回结果是双层嵌套 JSON 字符串

# 外层
data = response.json()
order_result_str = data["content"]["orderResult"]  # 这是 JSON 字符串

# 中间还有一层反斜杠转义
cleaned = re.sub(r"\\\\", r"\\", order_result_str)
outer = json.loads(cleaned)

# 句子在 outer["lattice"] 里
for item in outer["lattice"]:
    inner_str = item["json_1best"]    # 又是 JSON 字符串
    inner = json.loads(inner_str)
    # 句子时间在 inner["st"]["bg"] / inner["st"]["ed"]
    # 句子内容在 inner["st"]["rt"][..]["ws"][..]["cw"][..]["w"]

每个 cw 是一个字 / 词;要拼接所有 cw["w"](跳过 wp == "g" 的空白标记)。

坑 13:时间戳单位是毫秒(不是秒、不是百分秒)

  • bg ed 都是毫秒(int
  • 与 B 稿的 [Nm Ns] 对齐时记得换算

业务参数坑

坑 14pd=mil 对军事术语显著加分

  • 不开 pd:默认通用领域,军事术语会被识别成同音常见词
  • pd=mil:军事领域专用模型介入,配合热词效果叠加

坑 15eng_smoothproc + eng_colloqproc 让 ASR 接近书面

  • eng_smoothproc=true:去掉"嗯""那个""呃"
  • eng_colloqproc=true:口语规整("咱们"→"我们"等)
  • 两个都开后,输出已经非常接近书面文稿
  • 不会清理"那么""呢""啊""这个"——这些保留与否需要在融合层决定

凭证与配额(demo 阶段使用)

APP_ID: 84eff996
SECRET_KEY: d37fb0c77e7f4b4f4398e6a8834d1017
免费包: 5 小时(已激活),有效期至 2027 年 5 月

⚠️ 正式上线时替换为生产凭证,并把 SECRET_KEY 从代码移到环境变量 / 密钥管理服务。


一句话总结

讯飞 ASR 标准版能用、好用,但接入文档稀少且错误信息误导性强;以上 15 个坑全部踩完后,单次调用的成功率接近 100%。后续接入新 ASR 供应商时,建议按本笔记的结构(选型 / 音频 / 接口 / 异步 / 解析 / 业务参数 / 凭证)做同样的整理。