# 科大讯飞 SparkChain —— 真机自测与回改 配合 [科大讯飞SparkChain-全面替换第三方-落地文档.md](科大讯飞SparkChain-全面替换第三方-落地文档.md)。 客户端 `1.0.3+45` 起,连着 `ym-dev.ymaikj.com` 时 AI 不再调用微软、阿里、字节、谷歌、灵犀:文本和同声优先走端上 SparkChain,密钥还没配时这些能力直接失败,不再退回旧服务。面对面、通话、音视频、EMAI、会议转写还没接到讯飞,所以在这把锁下也不可用。测试后台还没填 `sparkchain` 密钥时,init 不会被调用。测试服容器要有 `AI_ONLY_IFLYTEK=1`,正式服不要设。 2026-10-15 电脑上已经连着的两台,下面的命令都用这两台,不要换别的机器对日志: | | 设备 | 标识 | |---|---|---| | 安卓 | 华为 ALN-AL80,Android 12 | 序列号 `2MM0223B09017126` | | 苹果 | 李蒙蒙的 iPhone,iPhone 12 | UDID `00008101-001C684A2651003A` | 服务器只连测试服 `https://ym-dev.ymaikj.com`。`.env` 的 `SERVER_URL` 保持这个。不要装到连着 `ym.ymaikj.com` 的包上测,也不要上架。 耳机用 Echo-one。没戴耳机的用例用手机麦,两套都要测,不要只测一种。 --- ## 1. 每一轮怎么装 改完代码再升 `apps/client/pubspec.yaml` 的构建号,日志里要能对上是哪一轮。 安卓(在 `apps/client` 下): ```bash export GRADLE_USER_HOME="$HOME/.gradle" ~/flutter/bin/flutter build apk --release --no-pub --obfuscate --split-debug-info=./build/app/outputs/symbols adb -s 2MM0223B09017126 install -r build/app/outputs/flutter-apk/app-release.apk ``` 苹果: ```bash ./ios/sync_spm_platform.sh ~/flutter/bin/flutter build ipa --release --no-pub --obfuscate --split-debug-info=./build/ios/symbols --export-method development xcrun devicectl device install app --device 00008101-001C684A2651003A build/ios/ipa/EAIMAR.ipa ``` `flutter build ipa` 会改 `ios/Runner.xcodeproj/project.pbxproj`,那是本地噪声,不要提交。 装完先看关于页或日志里的构建号,对不上就不要开始用例。 --- ## 2. 日志怎么拿 安卓。`*:S` 在 zsh 里必须加引号,否则会被当成通配符: ```bash adb -s 2MM0223B09017126 logcat -c adb -s 2MM0223B09017126 logcat -v time 'EmaiFocus:I' 'flutter:I' '*:S' ``` 苹果不靠 syslog。App 自己的文件在 Documents/logs/: ```bash xcrun devicectl device info files --device 00008101-001C684A2651003A \ --domain-type appDataContainer --domain-identifier com.yimai.eaimar | grep logs xcrun devicectl device copy from --device 00008101-001C684A2651003A \ --domain-type appDataContainer --domain-identifier com.yimai.eaimar \ --source Documents/logs/<刚列出来的最新文件> --destination /tmp/eaimar.log ``` `copy from` 不要加 `--username`。 日志里允许出现 init 返回码和 `sid`。出现 `apiKey`、`apiSecret`、`ast_apisecret` 的原文,这一轮算失败,先把打印删掉再测功能。 --- ## 3. 测之前确认 1. 手机网络正常,打开 App 后请求的是 `ym-dev`,不是 `ym.ymaikj.com`。 2. 测试后台应用是 `ym`,`sparkchain` 已启用,三个密钥非空。`sparkchain` 的类别不是端到端(类别 4)。 3. 旧的微软/阿里语音服务先还留着,等第 9 步全部用例过了再在测试服停用。 4. 杀进程冷启动一次再测。热重载看不出原生 SDK 有没有 init。 init 失败时先看这三行,不要改业务页面: | 日志 | 含义 | 改哪里 | |---|---|---| | 返回码 `18400` 或 `18105` | 工作目录不可写 | `workDir` 改到应用私有目录 | | 配置为空、init 没被调用 | 没拿到 v3 密钥 | 测试后台、白名单 `user_getappconfig_v3`、客户端是否连的 ym-dev | | 只有一路有识别 | 第二路回调被释放,或两路同时 start | 回调改强引用;A 起来约 1.2 秒再起 B | --- ## 4. 用例 每一条都要在华为和 iPhone 上各做一次。结果记在第 6 节的表里。没写「通过」的不要进入下一条的代码修改,先把失败的这一条收掉。 耳机相关的条目前提是 Echo-one 已连接。日志里要能看到对应的麦,而不是手机麦。 ### 4.1 插件冒烟(不进业务页也能看日志) | 编号 | 做什么 | 通过 | |---|---|---| | S1 | 冷启动 | 日志有 init 成功,节点是新加坡(欧洲账号未加白时,人在欧洲也是新加坡)。无私钥 | | S2 | 中文说一句短句 | 听写出中文 | | S3 | 文本「你好」译成英文 | 安卓走 `GTRANS`。iOS 四个翻译类型里,把能返回英文的那个类型写进第 6 节 | | S4 | 文本「你好」译成爱尔兰语 | 译文是爱尔兰语,语种码 `ga`。iOS 实际用的 `TransType` 写进第 6 节 | | S5 | 把 S4 的爱尔兰语再合成 | 安卓出声,音色是 `ga-IE-OrlaNeural`。iOS 不出声就停在这一条,不要装进同声翻译冒充已支持 | S3 到 S5 没过,不要测同声和通话。后面全靠这三步。 ### 4.2 同声翻译 | 编号 | 做什么 | 通过 | 失败先看 | |---|---|---|---| | M1 | 连耳机,中文→英文 | 日志是「同声翻译收音:耳机麦」,有首帧;译文从耳机出 | 麦走错了看 `_attachSimultaneousHeadsetMic`。声音在手机扬声器看 `pinSpeaker` 是不是被改成 true,以及 SDK 有没有自己开麦 | | M2 | 不连耳机,中文→英文 | 手机麦能出字、出声 | SDK 自己开麦会和现有采集抢,改成只 `write` 现有 PCM | | M3 | M1 进行中按 Home 切后台,继续说 | 还能出字 | 前台服务 `keepalive: true, pinSpeaker: false`,iOS `BackgroundKeepalive('simultaneous')` | | M4 | 连耳机,中文→爱尔兰语 | 文字和声音都是爱尔兰语,不走 `AST` | 安卓:识别 `ga-IE`,翻译 `GTRANS`/`ga`,合成 `ga-IE-OrlaNeural`。iOS 用 S4/S5 记下来的参数 | ### 4.3 面对面 | 编号 | 做什么 | 通过 | |---|---|---| | F1 | 双耳戴上,左中文、右英文 | 方向相反,两边都有声音。协议帧没有改 | | F2 | 右耳改说爱尔兰语 | 本端有中文译文。iOS 若 S5 没过,这条只要求出字,出声标成「等音色」 | | F3 | 摘掉耳机再开 | 手机麦仍能翻,不要退回成失败 | | F4 | 翻译中来电 | 现有文案还在,会话停 | 安卓面对面不要顺手加上同声那种静音保活。 ### 4.4 音视频 | 编号 | 做什么 | 通过 | |---|---|---| | V1 | 安卓:允许悬浮窗和录屏,切到别的 App 播一段中文 | 悬浮窗有英文译文,原视频声音还在,没有被译文盖住 | | V2 | 安卓:拒绝悬浮窗 | 不开始识别 | | V3 | iPhone:开始广播,切后台 | 小窗有字,原视频声音还在 | | V4 | 从音视频切到同声 | 小窗关掉 | ### 4.5 通话翻译 不退出通话翻译页,按顺序做。A 是近端(自己),B 是远端(对方)。 | 编号 | 做什么 | 通过 | 失败先看 | |---|---|---|---| | C1 | 中文↔英文,双方各说一句 | 两边都有字,声音在耳机里 | `pinSpeaker: false`。PCM 走 `callPcmTap` / `com.eaimar.bes.callpcm.uplink`,不要接成面对面那条 | | C2 | 停掉,不退出页面,再开一场中英 | 仍有识别和声音 | `ready` 被 `disable` 清掉了。只在会话销毁时清 | | C3 | 中文→爱尔兰语。自己说中文 | 自己这边有爱尔兰语文字,对方耳机里听到爱尔兰语 | A 路合成。iOS 依赖 S5 | | C4 | 接着对方说爱尔兰语 | 自己这边有爱尔兰语原文、中文译文、耳机里的中文。不要做中文/爱尔兰语自动检测 | B 路回调是不是强引用。日志里 B 路有帧但没有识别,就是回调被释放 | C1 里如果只有近端有字、远端完全没有,先看 B 路回调和 1.2 秒间隔,不要改语种码。 ### 4.6 EMAI 手机里按住说话的那一页不测。 | 编号 | 做什么 | 通过 | |---|---|---| | E1 | 耳机按键唤醒 | 听到「我在 / 回来了 / 有什么可以帮到你」里的一句,不等用户先说话 | | E2 | 问一句 | 有文字和声音。说完再答,不要按百炼那种边听边说来判失败 | | E3 | 「明天下午三点提醒我开会」 | 能进待办。进不去就只记「工具未通」,不要改待办解析 | | E4 | 对话中切后台 | 不断开 | | E5 | 没在播音乐时唤醒再结束 | 不要自己把音乐播出来 | | E6 | 有音乐在播时唤醒 | 音乐变小或暂停;结束后恢复。香薰也做这一条 | | E7 | 密钥配错或 init 失败时按唤醒 | 设备退出聆听,不空等 | 声音发飘、像慢放或快放:合成没有按 16 kHz 送进喇叭,百炼的 24000 被套过来了。 ### 4.7 文本页、图片、纪要 | 编号 | 做什么 | 通过 | |---|---|---| | T1 | 文本页中英、中文→爱尔兰语 | 出字。断网或端上失败时,请求打到测试服 `user_translate`,不是微软直连 | | P1 | 图片翻译一张带字的图 | 有原文和译文。没有把译文贴回原图,这是现状 | | R1 | 同声或通话翻完进语音纪要 | 有音频、端上那份转写、总结。服务端没有把这段再转写一遍 | | R2 | 纪要首页新录一条中文、一条英文 | 测试服日志里的转写服务是 `asrfile_iflytek`,总结是 `llm_iflytek`。失败退算力只退一次 | R2 依赖测试服已经按落地文档第 6 节发过 home,并且会议配置里讯飞的优先级高于旧服务。正式服不会有这条数据。 --- ## 5. 一轮失败了怎么改 一次只改失败表里指出的那一处,然后两台都重装,重测失败的那一条,再加一条已经通过的相邻用例,防止改坏。 | 现象 | 只改 | |---|---| | 安卓有、iOS 没有,或相反 | 该端原生枚举。不要改 Dart 的 `zh` / `en` / `ga`,也不要把另一端的枚举抄过来 | | 有识别文字、没有声音 | 合成回调有没有把 PCM 交给现有播放器或 `CallTranslationDownlink`。不要在插件里新开 `AudioTrack` | | 声音从耳机跑到手机喇叭 | `pinSpeaker` 和 SDK 是否自己开了麦、改了音频会话 | | 同页第二场通话没声音 | `ready` | | 切后台没反应 | 保活调用点。不要改音乐焦点那一套 | | 没播的音乐被拉起来 | 设备对话的焦点。没在播就不要抢焦点、不要发播放键 | | 爱尔兰语走成了中英同传 | 选路把 `ga` 送进了 `AST`。`ga` 强制三段 | | 纪要仍是字节/阿里/微软 | 测试服会议配置的优先级,或 home 镜像还是旧的。不要去正式服改 | iOS 爱尔兰语翻译类型、识别 region、音色名,一旦真机确定,写回落地文档第 4.5 节,把「先试四个类型」改成确定值。没确定之前不要在文档里写成已经支持。 --- ## 6. 记录 每轮测完填一行。构建号和日志对不上的结果不算。 | 日期 | 构建号 | 端 | 用例 | 结果 | 日志里的一句 | 下一轮只改 | |---|---|---|---|---|---|---| | | | 华为 / iPhone | | 过 / 不过 | | | iOS 爱尔兰语定下来之后补这一行,后面的用例都用它: | 项 | 真机确定的值 | |---|---| | 翻译 `TransType` | | | 识别 region 和语种码 | | | 合成 region 和音色 | | | 是否出声 | |