Rodger-Wang
|
8aa2c9bef7
|
清理:第 4 批,本地插件与原生层的空壳插件、未链接二进制与残留配置(约 12MB)
- 整个插件:local_plugins/test(模板插件,agent_service 的 Package.swift 声明了却没 import)、
local_plugins/bytedance_speech(不在任何 pubspec,Kotlin 零 import);连带改 pubspec、
agent_service 的 Package.swift 两行、android/settings.gradle.kts 两行、agent_service build.gradle.kts 一行
- 不再链接:device_jieli/android(pubspec 只剩 ios)、根目录 SpeexKit.xcframework、
ble_service 里注释写明已移除的 JLAudioUnitKit.xcframework、app res/raw 三个无引用的 mp3、
两份多余的 GoogleService-Info.plist、swift_sdk_local/Tests(连同 Package.swift 的 testTarget)
- 示例/模板残留:qq_music 的 ApiSample.kt / PcmExampleActivityNew.kt、azure_speech/lib/main.dart、
floating_ui_plugin 的模板测试、recorder_holder/sdk/example
- azure_speech Android:Dart 从不使用的 azure_speech/translation 方法通道与 translation_events 事件通道、
TranslationMethodHandler,以及因此失去引用的 MicrosoftTranslationAndTtsService 与两个字段
(MicrosoftTranslationServiceImpl 仍被 AzureAsrToAsr 使用,保留)
- agent_service Dart 包装里 13 个业务层零调用的方法(原生侧不动)
- 原生配置:Facebook 登录残留(Android meta-data/strings、iOS Info.plist 键、URL scheme 与 15 个查询 scheme)、
无对应代码的 NSMotionUsageDescription、已无依赖的火山引擎 Maven 仓库
验证:dart analyze 无 error;flutter test 221 全过;flutter build ios --no-codesign 通过。
⚠️ Android 编译本机未验证:azure_speech 的 generateDebugProto 需要执行 protoc-gen-grpc-java 1.57.2,
其 osx-aarch_64 制品实为 x86_64,本机未装 Rosetta 无法运行。已确认在本批改动之前的提交上同样失败,
与本次清理无关;装好 Rosetta 后需补跑一次 flutter build apk。
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 86df62086dc029ed2b2c7199dccc2d8a6e7a340d)
|
2 weeks ago |
Rodger-Wang
|
4ec8932aef
|
车载香薰 AI 对话:唤醒问候、按键插话、自动回连、退出聊天、前后台与状态同步(均只对香薰生效,恒玄耳机流程不变)
- 会话:服务端放弃回复(requestAccepted)时停播解门控,修掉互等 90s 的卡死;会话中再按唤醒键=打断重听;
唤醒后用应用音色随机回一句「我在」;退出(0x07 03)无应答不再干等 2s;设备上线复位 AI 状态,
防 App 被杀后设备停在 AI 模式、再唤醒 0 帧上行;Android 会话期间开前台服务,防切后台被冻结断 WS
- 指令:extra_info.commands 为 JSON 字符串时也能解出 quit(新车载应用下发形状)
- 连接:香薰断线/冷启动自动回连(带退避、OTA 与主动断开不回连);回连带上记住的 MAC;
设备断开后界面显示最后连接的那台(DeviceHub 落盘 lastUsedVendor)
- iOS 经典蓝牙判断按 MAC 首字节±1/设备名匹配,连着就不再弹配对提示
- Android 播放器:车载会话(playbackOnly)回复间垫静音,防 A2DP 流挂起吞掉「我在」
- 聊天页:设备对话中底部按钮可「改用手机」;离开正显示香薰对话的页面时结束会话并通知设备
- 车载助手百炼应用 ID 改为 mm_127ddb82ba1244a99d2feaef0c1f
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
2 weeks ago |
Rodger-Wang
|
16ba488341
|
client(android):打包修复同步到 along——去掉 azure_speech 的 gRPC 代码生成、钉住 firebase 版本
- 与 along-test 的 1b7a8cbe 相同:protoc-gen-grpc-java 标为 osx-aarch_64 的制品其实是 x86_64,
苹果芯片 Mac 不装 Rosetta 编不过;它产出的 ASTServiceGrpc 全项目零引用,豆包 AST 只用 protoc 生成的消息类
- firebase_core / firebase_auth 钉在 4.13.0 / 6.5.7:锁文件与 pubspec 早已对不上,pub get 重解析会升到
firebase_auth 6.7.0,其原生库要求 Kotlin 2.3,工程是 2.1.10,Android 编不过(与 along-test 第 3 批同一处理)
验证:flutter build apk --release 通过。
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
2 weeks ago |
Rodger-Wang
|
5036ab4c3f
|
client: 修通话翻译「德语/意大利语一开就卡死、只有中英正常」——并发初始化+默认参数兜底
不是语种问题,是竞态。原生阿里初始化天然 >=1.2s(A 路 init → delay(1200) →
B 路 init),期间只要再来一次 initialize/dispose,「代数」就变了,前一次返回
false;Dart 拿到 false 把 _isInitialized 清掉;接着 recognizeCallback() 看到
「未初始化」就调**无参** initialize()——默认值 provider=azure + [zh-CN,en-US],
把刚握手成功的阿里 zh→de 会话整个换成 Azure 中英三段拼装。此后原生 provider
停在 azure、Azure 识别器一直在跑,每次 dispose 都慢几秒,下一轮更容易撞进
1.2s 窗口,**退出重进也不会好**。中英「正常」只是因为默认值恰好是中英。
修在三层,缺一层都会复发:
- azure_ast_service.dart:initialize() 串行化(_initInFlight);记住最近一次的
provider/语言表;recognizeCallback / startContinuousTranslation 走
_ensureInitialized——先等在途初始化,仍没成就**按上次参数**补一次,
永远不用默认值,没有可复用参数就直接报错。
- translation_controller.dart:_initializeCallModeTranslationService 串行链;
isPreparing 期间忽略重复点开始;_attachBesCallTranslationBridge 开桥前先等
初始化真正落地(10s 上限)——原来靠 _modeInitFuture 3s 超时硬往下走,
桥开在原生初始化之前。
- AzureSpeechPlugin.kt/.swift:被新一代取代时打出阶段与代数、A/B 任一失败打
结果,排查先找这两行。iOS 另修一处独有差异:原先 A/B 无论成败都回 true,
Dart 以为就绪、桥照开而实际一路是空的,现在按真实结果回。
Redmi K90 Pro Max 验证:连开 9 场(it/de/en/ja/fr/ko×2/en,含切语言、关闭重开、
退出重进)全部阿里 3.5,初始化各 1.2s,87 句译文,0 错误,断粮 0 次。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
ace92c9ea1
|
client: 通话翻译耳机杂音——四个独立原因逐个修掉(Android 定性,iOS 同步)
六轮真机定位出四个叠加的原因,每修掉一个概率降一档:
1. 发包定时器系统性漂移:scheduleWithFixedDelay 从任务**结束**起算,WSOLA+G.722+
写 socket 的 1~3ms 全叠进周期,"20ms"实测 21~23ms、只有 0.9 倍速。改成
scheduleAtFixedRate 固定节拍且永不重排。
2. 起播缓冲在句中重新生效(杂音落在句中的真凶):队列空了就要求再攒 120ms,而
变速追赶时队列中途归零很常见,等于句中硬插 120ms 静音。加 playing 标志让
起播缓冲只在句首用一次;真正的断粮单独计数并打「句中空洞」日志。
3. 恢复发包时从空缓冲起播(杂音落在句首):两路都空就停发、耳机缓冲被榨干。
现在先塞 4 包编码静音垫底再发真音频,两路空后再续 500ms 静音才停。
4. 24k→16k 重采样是逐块独立的线性插值、无抗混叠、每块相位从零重算。换成
64 阶低通 FIR + 跨块连续(Resampler24kTo16k.kt/.swift,Python 复刻校验
1k/3k/6k 正弦)。
顺带:耳机 0xD6 帧 data[6] 的语义是「补一包」不是「改速率」,按此重写
onHeadsetPace(01 补 1 包、00 补 2 包、03 扣 1 包);空闲那一路的静音帧改用该路
自己的编码器编零(G.722 是自适应差分,固定码流会让解码器状态跳);裁静音加
滞回(300 进 / 600 出)+ 3ms 淡入;速率每帧最多变 0.03;150ms 内有新数据不补零
收尾;HARD_CAP_SEC 补回 30s 纯兜底。DEEPVOICE_PARITY 对照开关保持 false。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
d1db3e5951
|
client(android): 通话翻译三处修复——同页第二场聋、call.stop 偶发丢失、译文积压追赶
全部在 Android 原生(azure_speech / bluetooth_manager 的 Kotlin),iOS 一行未动。
2026-09-22 ALN-AL80 + Echo-one 真机,配合协议栈 RFCOMM 日志逐条定位与复验。
同页第二次开始没反应(azure_speech)
- AST 就绪状态记在插件上(astSessionReady,与 iOS 同义),建桥与重新 enable 时都继承;
BesCallPcmBridge.disable() 不再把 ready 打回 false。
- 原因:markReady 只在 initialize 末尾发一次,同页面再开始只走 startContinuousTranslation,
disable() 清掉的 ready 再也没人置真,上行帧全扣在环形缓冲里。实测进页面第一场好、
之后每场 ready:false / downlinkFrames:0,退出重进又好一场。
结束指令偶发没到耳机(bluetooth_manager)
- 控制命令走单线程队列:距上一条命令 ≥30ms、距上一个实时音频包 ≥500ms 才写;
下行音频改走 writeRealtime 直发。
- 原因:BluetoothSocket 写入经本地管道,协议栈按信用一次把管道里攒着的字节合成一帧
(PORT_WriteData p_len=4 / 172 / 256),耳机一帧只解开头一条命令。8 次收尾丢 3 次,
耳机不回 BB D2、继续推音频,下一次 call.start 应答 BB D1 07 01(已在通话模式)。
修后 8 轮 0 丢,边播译文边点结束也在 0.5s 内收到 D2。
译文积压越说越慢(bluetooth_manager CallTranslationDownlink 重写)
- 积压 >1s 裁掉超过 150ms 的静音;>2s 起 WSOLA 变速不变调,4s 达 1.3x;不丢内容
(兜底丢弃常量默认关)。新增 getCallDownlinkStats 与收尾总账日志。
- 原因:译文音频突发产出、只能 1 倍速播,说话人不停顿时源时长≈原话时长,队列只涨不缩,
实测 A 路积压 6.2s。修后同量压测最大 3.2s,绝大部分时间 <1.5s,光裁静音就省了 10%,
变速最高只用到 1.11x。
其它
- translation_controller 收尾那几行日志提到 warn(release 包能看到 call.stop 有没有发)。
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
7ce56f693d
|
client: 通话翻译音频链路修复(iOS GATT 写入、后台保活、状态竞态)
iOS 上恒玄走的是 GATT over BR/EDR 而非 BLE,之前按 BLE 模型处理导致一连串问题。
本次改动都有真机数据支撑(2026-09-21 压测)。
GATT 写入(bluetooth_manager)
- 写类型改为优先 .withoutResponse。ATT 是请求-响应协议,带应答写每包等 ACK,
追不上下行 50 包/秒,表现为音频越听越滞后。
- canSendWriteWithoutResponse 只作观测、不作门槛。它是 CoreBluetooth 为 BLE
设计的提示,在 BR/EDR GATT 上不反映真实能力(实测 100% 为 false 却零丢弃);
拿它当闸门会死锁:不写就不回调,不回调就永不翻真,实测 548 包只出去 11 个。
- 控制命令无条件直发、不排队。排到积压音频后面会让 AA 09/AA 06/queryCallState
全部发不出去,曾被误判成「固件换了命令号」。
- 不再对标准电池服务 0x180F 做任何 ATT 操作:它在 Echo-one 上是空壳(值恒为 0),
而挂在它上面的读/订阅会把整条 ATT 通道堵死。
后台存活(translation)
- 通话翻译期间持有 BackgroundKeepalive。两路音频全走耳机 GATT,手机侧没有
AVAudioSession 的实际 I/O,UIBackgroundModes=audio 不成立,切后台几十秒后
上行被掐断:WebSocket 还连着,但服务端收不到语音,靠默认 VAD 每 30 秒强切一句,
吐出空译文或幻觉 —— 表现为「切后台后只剩译文、原文全没」。
- BackgroundKeepalive 不再无条件把音频类别改成 .playback,避免踩掉通话翻译
正在跑的 .playAndRecord 录音链路。
状态竞态(azure_speech / device_hub)
- markReady 的就绪状态记在插件上、建桥时继承。建桥与 AST 异步初始化是两条独立
路径,初始化先完成时那句 optional chaining 打在 nil 上静默丢失,之后 ready
恒为 false、上行帧全积在环形缓冲里,表现为「打开通话翻译没反应,再开一次才好」。
- DeviceHub.inCall 改以会话快照为准。事件会随 worker 在断连时被 dispose 而丢失,
重连后 ever 又不回调当前值,且后续重复赋同值不触发,永远不会自愈。
可观测性
- 下行发送器与 GATT 写入的日志从 NSLog 改为 os_log(release/profile 包里
idevicesyslog 只收得到 os_log),并经 DeviceSession.diagnostics() 暴露给 Dart,
写入文件日志后可用 devicectl 直接拉取,不依赖 usbmuxd。
- 新增 inCall 变化、闸门拦截、通话状态翻转、前后台切换四处观测点。
其它
- DeviceSession 新增 diagnostics()(默认空表);SmartcarSession 因是 implements
而非 extends,同步补了实现。
- CLAUDE.md 记录本次全部实测结论,含 BB 8E 为通话状态权威、BB 02/03 是噪声
(已知问题,本次未改判定)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
8b50e52572
|
client: 通话翻译字幕错位/总结残留/退不出去/切后台被冻结,及 B 路说话人门限
真机实测(Android,恒玄耳机)逐条定位后修,原生能改的都在原生层改。
字幕乱(AliyunBailianE2EHelper,Android/iOS 同改)
- 原文流与译文流各自按到达顺序自己发号,两条流的切句本来就不一致,off-by-one
一旦发生就一路错到底。改成认服务端的 item_id:译文帧的 item_id 经 itemParent
(response item → input item)映射回原文那条,取不到才退回本地发号。
- response.audio_transcript 的 text 是累计值、delta 才是增量,此前一律当增量
append,于是出现「Hello,Hello,Hello,」。改成按字段名分支:有 delta 就追加,
只有 text 就整段替换。
- connectionGeneration 守住 onOpen/onMessage/onFailure/onClosed(iOS 用 activeTask
弱引用按任务身份判),旧 socket 的迟到回调不再打进新会话;stopContinuousConversation
同步清 webSocket/isStarted。
翻译结束后「总结内容」还留在屏幕上
- AliyunAstCallback.onSessionFinished 会把整场累计文本当作一条 translated 再发
一次,表现就是一大坨总结。不再发;原文缓存改为按 utteranceId 存,上限 32 条。
结束后无法再翻译、返回按钮像被遮挡
- 退出时那颗延时 Get.delete 会误杀刚重新进来的页面。按 tag 记活跃页面数
(_PageAliveMarker + _aliveCount),还有人用就跳过销毁。
重进页面提示「未在通话中」
- 耳机对 0xD1/0xD2(进/出通话模式)的应答被当成通话状态上报,把 isCallOngoing
改掉了。这两个 type 改为只记日志,不动通话状态。
切后台功能被关掉
- 前台服务类型加 phoneCall:microphone|phoneCall (132),ROM 的进程冻结不再掐断
通话翻译。startForeground 带类型失败时回退到仅 microphone。stopService 改用
context.stopService,后台也能调。
- AST 掉线自动重连(1s/2s/4s,最多 3 次),回到前台按 _astHealthy 补一次;
重连后的新会话用 800ms 宽限期,否则会被原来的 2s 窗口吞掉重试。
B 路说话人门限(PeerSpeechGate,新增 + 11 个单测)
- 声音复刻配的是 frequency=once,只在会话开头刻一次音色。B 路会话一启动就建立,
此时对端多半还没开口,先收到的是机主的串音(实测 B 路 ASR 配 language=en 却
识别出机主刚说的中文),于是把机主音色刻成了「对端音色」,两个人听起来一样。
- 未开门期间音频进环形缓冲,开门瞬间整段补发——对端先开口时第一句的开头一个字
都不能丢。fallbackFrames 到时强行开门:门限太严会让对端整通电话不被翻译,
太松只是音色可能刻错,后者轻得多。
- 每次会话重建(含断线重连)都 reset,否则重连后照样刻到串音。
已知未尽:Android 14+ 会拒绝 phoneCall 这个前台服务类型并回退成仅 microphone,
那里的冻结保护不生效;rmsThreshold=600 尚未在真机上标定(上一轮跑到了兜底强开)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
f9b9c8c72d
|
client: 翻译默认归档进语音纪要;列表改本地优先;登录按包收敛;EMAI 走 A2DP
## 通话/同声/面对面翻译 → 语音纪要
三种翻译模式默认边翻边录,结束时把音频**连同已有转写**一起归档
(rtype=VOICETRANSLAT),服务端跳过识别、直接用智能模板(General-Autopilot)总结,
在会议纪要里就能看到。转写段的构造见 translation_export.dart(纯函数,带金测试):
- 时间是**相对录音起点的毫秒**并扣掉暂停区间——面对面是逐句按住说话、松开就暂停的,
不扣的话越往后偏得越多;写成绝对时间戳会让点一句跳到音频末尾之外;
- 说话人用 Speaker_0/Speaker_1,与服务端转写同一口径(转写页直接把这个字段当文案显示,
裸 0/1 会和别的纪要长得不一样,喂给 LLM 抽待办时也会混出 Speaker2 这种负责人);
- AST socket 断开后 _terminateCallOnError 会取消事件订阅,重开时收不到任何转写
(真机上表现为「有日志但转写 0 段」),改成重新订阅。
## 语音纪要列表:服务端是真源、本地 sqlite 是缓存
列表接口改回骨架字段后(服务端同批),客户端改成本地优先渲染 + 后台对齐:
- Synchrodata 重写:拉骨架 → upsert → 删掉「本地有服务端没有」的记录(连本地音频、
上传队列、轮询任务一起清)。**业务错误时 data 是 null 不是空列表**,判空错了
会把本地整个清空;
- 详情进页面时才拉整条;离线操作队列那套上行是死代码(服务端接口整个注释掉了),删除。
## 登录按包收敛
苹果包只留苹果+游客、安卓包只留微信+游客、谷歌包只留邮箱+游客。
判定抽成 resolveLoginMethods 纯函数(login_methods.dart + 8 条测试),
邮箱包还要锁死国家区号选择。
## EMAI 与其它
- 手机侧触发的对话走 A2DP 而不是语音处理通道:iOS 上 A2DP 输出与 voiceChat 模式
互斥,开了后者蓝牙耳机会当场切到手机扬声器。按当前实际输出路由决定要不要开
voiceProcessing/回声消除;
- EMAI「开始对话」闪退:探测输入格式时 new 了一个一次性 AVAudioEngine 去读 inputNode,
配置变更时崩在 AVAudioIONodeImpl(EXC_BAD_ACCESS)。改成直接问 AVAudioSession;
- 语音纪要文件名可改:每行右侧加铅笔图标,复用已有的重命名弹窗(原来只有长按菜单,
实际入口已不可达);
- 拾忆上报 IANA 时区名:DateTime.now().timeZoneName 给的是「CST」这种缩写,
服务端 LoadLocation 解析不了、静默退回容器时区,海外用户的提醒时刻会全按北京时间算。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
3 weeks ago |
Rodger-Wang
|
46ebf28d64
|
闹钟改成只在 App 内提示;通话翻译/通话录音挂前台服务;复刻档位日志提到 warn
1) 拾忆提醒不再发系统通知
改成进程内 Timer + App 内弹窗。代价必须说清楚:**App 不在前台就不会提示**,
它是「打开 App 时告诉你有什么要做」,不是系统闹钟。
- 一个 Timer 只指向队首那条,响完武装下一条;定时器最长压 30 分钟,
超过就到期重算(长定时器在移动端本来就不可靠)。
- 错过的不补弹,否则早上打开 App 会糊一串昨天的提醒。
- 仍保留 flutter_local_notifications,只用来撤老版本排进系统的那些排期
(装过老包的机器上还留着,不撤的话改口径之后仍会收到、且没法关)。
只撤自己的 id 区间,绝不 cancelAll(会干掉录音的前台通知)。
- 顺带删掉上一版加的「通知权限未开启」提示条,不再需要。
2) 通话翻译 / 通话录音 切后台继续工作
两条链路原先都没有前台服务:
- 通话翻译走 AliyunBailianE2EHelper,与 AzureAsrHelper 不是同一条路,
后者的前台服务管不到它;
- 通话录音的音频来自耳机 SPP 流,压根不经过识别插件。
没有前台服务时切后台会发生两件事且都不报错:国内 ROM(荣耀/华为尤其)
冻结或回收进程,WebSocket 断、PCM 流停摆;Android 9+ 后台拿不到麦克风。
→ AST 的 start/stopContinuousTranslation 里起停 AudioRecordingForegroundService;
另开两个 method channel 口子(startAudioForegroundService/stop…)给
通话录音用。三条链路互斥使用,暂不做引用计数,注释里写明并存时要改。
⚠️ 前台服务自带常驻通知,用户关掉通知权限后它不显示但服务照常跑——
所以第 1 条「不要系统通知」和这一条不冲突。
3) 声音复刻的档位日志提到 warn 级
[TRANS-INIT] 命中哪一档、[STS] initialize 的 voiceClone 开关,原先是 info,
release 包里看不到。而「有没有复刻」完全取决于命中的是 alibaba35 还是旧版档
(旧版模型静默忽略 enable_voice_clone),不看这两行只能靠猜。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
Rodger-Wang
|
24e17b3434
|
收拢积压改动:恒玄 OTA、发版配置拆表、实名认证、芯片厂商/代工厂管理等
把工作区里积压的多轮改动一次性入库。主要几块:
客户端
- 恒玄 OTA 打通:新增 local_plugins/bes_ota_manager(自包含 BES SDK,
Android Java + iOS ObjC,SPP OTA 2.0),路由切到 BesOtaUpgradeView /
BesOtaUpgradeController,配套下载服务;杰理那套文件保留但已不挂路由。
- 通话翻译新增阿里 3.5 档(alibaba35_language_config.dart,
qwen3.5-livetranslate-flash-realtime + 实时声音复刻)。
- 实名认证接入、游客登录改走服务端 api_sgin 的 Tourists 分支、
功能闸门由 GuestGuard 改为 IdVerifyGuard。
- 41 个语种文案同步(OTA 新增 28 个 key 等)。
- 默认主题改为浅色,不跟随系统。
服务端
- 发版类配置拆表:app_release(版本控制 / 游客显隐,一应用一行)与
channel_app(渠道级下载地址 / 上架状态 / 支付渠道)分家,
新增 comm/apprelease.go 与 console/api_apprelease.go。
- 授权码字符串整体移除:删除 utils/license 包,新增 utils/devcode
(MAC 规范化与 PID 反解),配套迁移 SQL 在 docs/migrations/。
- console 新增芯片厂商、代工厂、用户管理接口与对应 admin 页面。
- 身份证实名核验(sys/idverify)与第三方服务的服务端专用类别。
其它
- .gitignore 补挡 apps/services/lego/sys/gin/log-*.log:gin 子系统跑起来
会按时间戳滚动生成日志(多为 0 字节),与 apps/services/comm/log 同一
性质,不进版本管理。已跟踪的 log-2026-08-20 那个仍在库里,未动。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
Rodger-Wang
|
946204cc3c
|
翻译延迟优化:接上阿里增量文本、面对面/同传去掉固定等待
通话翻译:阿里百炼端到端协议本来就是流式的(音频 response.audio.delta
一直在逐帧回灌),但增量文本订阅的事件名是错的——代码监听
response.audio_transcript.delta(字段 delta),而实时语音翻译
audio+text 模态实际发的是 response.audio_transcript.text(字段 text),
.delta 是 OpenAI Realtime / 通义 Omni 的写法。于是 onPartialText 一次
都不触发,译文只在 .done 时整句蹦出来,看着像"等说完才翻"。
现在两套名字都认、两个字段都取,并按首次出现的事件名锁定,防止服务端
兼容层双发导致文本累计两遍。Android / iOS 两端同改。
面对面 / 同声翻译(走 ASR → HTTP 机器翻译 → TTS 三段串行):
- 补上 Speech_SegmentationSilenceTimeoutMs=300,原来一行没设走 Azure
默认 500ms,这是"说完到出译文"里唯一一段纯等待;
- 同传 / 音视频改单语 ASR,关掉连续语种识别(它要缓冲够音频、给候选
语言逐个打分才敢出 final)。只有面对面需要判断"谁在说",仍保持双语;
- 中间结果翻译从"每 300ms 无条件发"改成 700ms + 至少多 4 个字 +
CancelToken 撤旧请求 + 序号丢弃过期结果。中间译文只上屏不播报,
原来一句 5 秒的话要打十几次真实服务商调用,还会跟 final 抢链路;
- TTS 提到 _updateExistingHistoryItem 最前,不再排在浮窗 / 写历史 /
记统计那串 await 之后;
- startRecognition 先 await onInit 那次 changeTranslationMode,堵掉
"进页面立刻点开始 → 落到默认 zh-CN/en-US"的竞态。
AuthInterceptor 的 DioExceptionType.cancel 分支不再弹红色"请求已取消"
——取消永远是客户端自己发起的,不改的话中间结果一接上就会一路狂弹。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |
Rodger-Wang
|
2d1ee0b783
|
apps/client 首次入库(Flutter 移动端)
从 /Users/yunyanzhineng/work/eaimar_client-main 搬入,未带原 .git,历史留在原仓库。
3215 个文件 / 约 118MB,其中约 40MB 是构建必需的预编译 SDK(azure_speech 的
MicrosoftCognitiveServicesSpeech.xcframework、device_jieli 的 JL_BLEKit 等)。
build/ (5.2G)、ios/Pods/ (311M)、android/.gradle/ (120M) 已由 .gitignore 挡掉。
本次入库的代码包含两项刚做完的改动:
1) 游客登录入口接上服务端开关。此前 _checkGuestLoginConfig() 恒定写死 true,
入口根本不读配置。现改为取服务端算好的结论,并把入口所在的 Builder 改成 Obx
——配置是异步拿到的,Builder 只渲染 onInit 时的初值 false,入口再也不会出现。
拿不到配置时按隐藏处理:默认显示会在送审期把不该露的入口露给审核员。
⚠️ 已发布的老客户端关不掉(写死 true),只对本版及以后生效。
2) iOS 上架合规修复:
- 移除 ATT/IDFA:删掉 Info.plist 的 NSUserTrackingUsageDescription、
SKAdNetworkItems、NSAdvertisingAttributionReportEndpoint,删掉 splash 里的
授权请求与 app_tracking_transparency 依赖。本 App 从不读取 IDFA,也没有任何
广告/归因 SDK,弹框纯粹劝退用户,还要在 App Store Connect 申报追踪数据类型。
- ios/Podfile 里那段 config.build_settings.delete('NSUserTrackingUsageDescription')
是无效代码(该 key 在 Info.plist 里,不是 build setting),换成注释说明。
- 通讯录符号(ITMS-90683 被拒原因)随之一并解决:permission_handler 走 SPM 后
按 Info.plist 有无对应 key 决定编不编,判定结果被 SwiftPM 按内容哈希缓存,
改完 plist 必须清 DerivedData 与 manifests 缓存才会重新求值。
另附 GOOGLE_PLAY_RELEASE_CHECKLIST.md:Google Play 上架阻塞项的实测梳理
(targetSdk 36 与 Billing 8 的 2026-08-31 期限、16KB 页对齐不合规的两个 .so、
支付回退逻辑的下架风险)。
⚠️ android/app/sign/ 下的 eaimar.keystore 与 Eaimar.properties(含明文签名密码)
随本次提交入库,与本仓库"私有仓库下接受真实凭据"的既有取舍一致。
仓库若要公开,这两个必须先摘出去。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
1 month ago |