Rodger-Wang
|
c12651e79c
|
语音纪要:录音语言自动识别、转写不翻译、翻译只作用于总结;可选总结模型;详情加 PPT 页签(仅界面)
客户端
- 首页标题「语音记录助手」→「语音纪要」,去掉顶栏右侧的算力摘要
- 「生成」弹窗:去掉录音语言(传空,交给识别服务自动判断);「目标语言」改为「翻译」,
默认「默认」= 不翻译、总结跟随录音语言,选了语言 = 总结/概览用该语言输出;
新增「总结模型」一行(echomeet_getsummaryservices 拉列表,记住上次选择,summary_svc_id 带进 starttask/summary)
- 重新总结选「默认」时传 tolanguage=auto(该接口空串历来表示沿用上次语言)
- 纪要详情在思维导图右边加「PPT」页签:示意图 + 「生成 PPT」按钮,点了提示即将上线
服务端(echomeet)
- 转写不再翻译:TranslateProcess 只做 Translate=Original;StartTask 不再选翻译服务
- 总结输出语言由 summaryLanguageInstruction 追加在模板 system prompt 末尾(空=跟随转写语言)
- 模板解析 ResolveSummaryTemplate:有目标语言先找该语种版本,否则用客户端选中的那条
- formlanguage / tolanguage 的 "auto" 与空串同义;Azure 批量转写不指定语言时带候选语种自动识别,被拒退回 en-US
- console「会议配置 → 会议总结」:默认模型之外可勾选「供用户选择的模型」,勾了即打开应用级「允许客户端选择」
⚠️ 行为变化:服务端部署后老版本 App 也不再翻译转写(原「英文录音→中文」现在是英文转写 + 中文总结)。
验证:dart analyze 无 error;flutter test 224 全过;go build/vet 通过,echomeet/console 测试通过;
admin npm run build 通过。已部署测试服(app/console/admin),release 包装到 ALN-AL80。
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
2 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
|
63634532ce
|
语音纪要等待态换成自绘动效;修 tasktype 存两张表导致重进后等待态消失
## 等待态
原来是 assets/lottie/meeting_wait.json —— 一张「JOIN」对话气泡插画,和本页在做的事
(把音频变成文稿)没有任何关系,配色也与全站的 222° 冷蓝灰不搭,深色主题下更是一块
突兀的白。改成自绘:上面一排声波表示音频正在被读,下面几条带流光的骨架行预告即将
生成的文稿形状,两者共用同一个 AnimationController。
自绘而不是再换一个 Lottie:① 不用为一个等待态再背一份 json 资源;② 颜色全部走
AppPalette,明暗主题自动跟随,插画做不到;③ 四个 tab(概览/发言/全文/思维导图)
共用同一个等待态,自绘好调。meeting_wait.json 一并删除(全仓零引用;assets/lottie/
在 pubspec 里是按目录声明的,不用改配置)。
## 重进后等待态消失 —— tasktype 在两张表里各存一份
真机上那条记录的实际状态是 meeting.tasktype=1 / meetingdetails.tasktype=0:
列表页读前者,显示「转写中」;详情页读后者,拿到 0,于是什么等待态都没有。
两张表分头写,而且中间态漏了:
- submitTask / refreshTask / readTask 只调 editMeetingTitle,**只写 meeting**
- _queryTask 里写 meetingdetails 的两次都藏在里程碑分支里(>=3、==5/6),
1→2(等待转写→转写中)这一跳、以及失败态 10002,meetingdetails 一次都不写
首次进入之所以有动画,靠的是详情控制器里那句内存赋值 meetingDetails.value.tasktype=1;
控制器一销毁,重进读库就是 0 —— 表现为「退出重进特效就不见了」。
改法:
1. SqfliteApi.setMeetingTaskType(id, type):一个事务同时写两张表,成为写 tasktype 的
**唯一入口**。⚠️ 别再直接 editMeetingTitle({'tasktype': x}),那只写一张。
2. 轮询里的状态推进从两个里程碑分支里提到分支之后无条件执行 —— 数据先落、状态最后推,
详情页的 ever(tasktype) 监听读到新状态时数据已经就位。tasktype.value 同样不再只在
分支里更新,1→2 这一跳现在也会通知 UI。
3. 详情页以 meeting 表那份为准(它是历史上唯一每次状态变化都会写的),给**存量**错位
数据兜底:不用等下一次状态跳变就能立刻正常。
真机验证(华为 ALN-AL80):用那条 details=0/meeting=1 的错位记录进详情,等待态正常
(改前是空白页);退出重进,等待态仍在;退出后查库两张表都是 1;轮询把状态推到失败态后
两张表都是 10002(改前 details 恒为 0);终态下等待态正确消失、显示「分析失败」。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
4 weeks 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 |