Tree:
811a008545
along
along-test
main
memory-center-impl-v1
memory-design-v0.2
${ noResults }
9 Commits (811a008545cc0b1fecd84fce0cd2ff8e8cab1429)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
41e3a023a3 |
client: 蓝牙名白名单(EaiRec/EaiCar);连接即按账号登记绑定;iOS 崩溃加固;弱网翻译超时
- 设备名闸门:支架只认 EaiRec/EAIMAR/Pad Note,车载香薰只认 EaiCar,固件名对不上直接不连; 一次性清掉此前被归一化名字污染的配对记录;Smartcar 资源与 agent 命名统一改为 EaiCar - 绑定登记:新增 DeviceBindRegistry(按 uid|MAC 去重),支架也进 verifyConnected, 登录态从无到有时补报一次,换账号不再漏切绑定 - iOS 崩溃加固:补 NSPhotoLibraryAddUsageDescription(保存思维导图/统计图必崩); StsAgent 先配音频会话再 installTap 并校验格式;支架录音两处 installTap 加 0Hz 守卫; AzureTtsHelper 播放队列改加锁队列(三线程裸改 Array,release 下崩); MicrophoneCapture 主线程不再用信号量等权限弹窗(看门狗误杀) - 网络:connectionError 给中文文案;实时翻译请求 12s 超时,不再跟 30s 默认值等 - 附:AI 助手中枢设计文档 v0.2(未动代码) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
4 weeks ago |
|
|
c14580d7db |
client: 设备默认图去背;AI 页编排跟随设备;香薰 AI 回复走蓝牙;OTA 状态如实显示
设备默认图 - default.png / default_icon.png 是 assets/images/devices 里仅有的两张**不透明带底图** (892×1152 竖版海报 + 浅蓝渐变底),而设备页展示区是 1.14:1 的横宽框, BoxFit.contain 后成了中间一条窄的蓝色卡片、左右大片留白,深色模式下尤其突兀。 改成去背透明(948×828 / 176×154),主体自己铺满框、周围就是页面背景,代码零适配。 - device_images.dart 记下这条约定,免得以后又丢一张竖版带底图进来。 AI 页按设备铺编排(连着香薰却显示全量功能) - _load() 的一次性迁移会改 enabledIds 却**不更新基线 _lastAppliedKey**, 尤其 _migrateDefaultLayout 会把 defaultEnabled 里缺的全部 append 回来 —— 香薰编排铺成 3 项,重启后被追加成 11 项,基线还停在 3 项, 于是 applyDeviceDefaults 判定「用户动过编排」,从此再也不铺,且怎么重连都恢复不了。 现在:当前编排若是自动铺的就整个跳过这些迁移;已经坏掉的装机由 _rebaseDeviceDefaultsBaseline 一次性把基线抬到现状(判据收紧到迁移留下的特征形态)。 - AgentDefaults.bind 补跑一次当前状态:GetX 的 ever 拿不到绑定那一刻已有的值, 而设备是被动回连的,完全可能赶在 bind 之前就绪。 - 断开设备后回退到 DeviceHub.lastKnownVendor:设备图和「设备管理」在断连后都显示 最近那台设备,AI 页却停在上一台铺的编排里,于是出现「图是耳机、功能是香薰」。 为此给 DeviceHub 加 lastKnownVendor,并把它与 lastKnownName 抽成同一个来源 —— 各算各的就还会自相矛盾。 - test/agent_module_defaults_test.dart 6 个用例守这条规则。 车载香薰唤醒 AI 后回复从手机扬声器出来 - 下行本来就设计成走经典蓝牙 A2DP,坏在共用的音频会话上:defaultToSpeaker 把输出 钉在内置扬声器,选项里只有 allowBluetooth(HFP)而没有 allowBluetoothA2dp (playAndRecord 下 A2DP 输出默认是关的)。而这条链路采音在设备上走 BLE opus, 手机压根不录音,用 playAndRecord 本身就是错配。 - EmaiAudioSession 分档:香薰走新的 playbackOnly(.playback 类别,输出跟随系统路由), EMAI 页「按住说话」仍是 playAndRecord(去掉 defaultToSpeaker 会退回听筒,更糟), 只补上 allowBluetoothA2dp。原生 PcmSpeakerPlayer 明确不碰 AVAudioSession,改这一处即可。 固件升级页 - 后台没给产品配过固件时,页面显示的是绿色的「已是最新」——这是假话,会让人以为 手上固件是最新的而不再去查。改成三态:找不到产品配置 / 服务端暂无固件版本 / 有新版本·已是最新。 新文案 otaNoServerVersion 已补齐 41 个语言文件(i18n_audit total_missing=0)。 - 产品找到但版本为空时打一条点名 warn,不再和「拉取失败」混在一起。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
e00b617025 |
services,admin,client: 服务配置按应用隔离、应用参数下线、客户端凭据走加密 v3
后台 - 服务配置去掉「全局默认」层,svc_config / svc_region_override / echomeet_orch / echomeet_orch_setting / echomeet_template 五张表统一按 app_name 隔离, 启动迁移 migrate_scope.go 幂等分配(首个应用原地改名保 id,其余拷贝); 写接口 app_name 必填(scope_check.go)。 - 类别落库 svc_category,可增删改;内置 11 个 id 不可改不可删,运行时语义仍只挂 comm.SvcCat*。 - 「应用参数」标签页下线:业务库 config 表不再随 user_getappconfig 下发, migrate_appparams.go 把 AGENT_TYPE / MOBILE_ELF_* 迁到服务 llm_mobile_elf、 iapCustomerServiceQQ 迁到 app_params,COMPUTE_*/NEWUSER_GIFT_* 留在 config 表不下发, 无人读的音乐/公码/导航/COS_*/MeetServers 删除,其余键保留并在启动日志告警。 - 删除 console appcfg/* 与 api 模块的 get/add/update/delconfig、唤醒音四个接口(无调用方)。 - 修 getmcpservers 仍查全局层导致 MCP 类服务永远读不到。 客户端 - 凭据改走结构化通道:user_getappconfig_v3 整体 AES-CBC 加密(api_crypto.dart, 拦截器须排在 AuthInterceptor 之前),AppConfig.cred(svcId, field, envKey) 取值, 老键名只作兜底;lib 内 AppConfig.env( 已降到 0 处调用。 - 图片翻译的 ALIBABA_VL_MODEL / ENDPOINT 改挂 ast_alibaba。 启动日志 - 删除 sys/auth/firebase(google_auth 的重复实现,零调用方,且同一错误刷两行)。 - api 模块不再每次启动无条件插入默认超管(Duplicate entry 'admin')。 - sys/auth/* 五个包的 logger 名从复制来的 sys.tavily 各改各名; google_auth 启动时即判断配置是否可用。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
4 weeks ago |
|
|
27cabe1bde |
client: 设备内核抽象、Smartcar 车载香薰接入与语音纪要等一批改动
工作区里累积的 Flutter 客户端改动,随本轮一并入库。主要涉及: - lib/devices/ 设备内核:DeviceHub / DevicePlugin / DeviceSession 抽象, 恒玄(bes)、EaiRec 支架(holder)、Smartcar 车载香薰(smartcar) 各自的插件实现, 业务层不再直接依赖任何厂商类;分层边界由 test/devices/ 下的测试守着 - local_plugins/device_plugin_interface、device_smartcar、recorder_holder: 纯 Dart 契约与原生侧实现 - lib/modules/ 能力模块注册表、语音纪要、OTA 升级等模块 - test/ 新增设备协议、Ogg Opus 时长、模块注册表、路由等金测试 - ios/sync_spm_platform.sh:修 Xcode 直接构建时 SPM 平台版本被打回 13.0 的问题 验证:dart analyze lib 无 error(264 条 warning 均为 HEAD 上既有的 unused_import / avoid_print 等 lint,非本次引入)。未跑真机与打包。 注:这批不是本次会话中由 Claude 编写的,此处仅做入库。 |
4 weeks ago |
|
|
abd0922d78 |
设备图改成按设备名从本地取;修同传页 GetX 报错遮挡与 AI 页 2px 溢出
## 设备图:关键字映射 → 按名字取图
原来是一张写死的映射表(名字里含 echo-one/deepvoice/buds… 就用 earphone.png),
加一个产品就要回代码里加一条。改成直接按设备名找
`assets/images/devices/<设备名>.png` 与 `<设备名>_icon.png`,
加新产品只要按这个命名把图丢进目录——pubspec 里该目录是**按目录**声明的,
新文件自动打包,代码和配置都不用动。
四个展示点统一到 DeviceImages:设备页主图、设备管理列表小图标、
恒玄固件升级页、杰理固件升级页。其中:
- 设备管理小图标原来是 Material 图标 + 紫色渐变块,现在换成产品实拍图,
底色仍区分连接状态(换成图之后原来靠渐变色传达的「这台连着」就没了)。
⚠️ 这一页取图用的是**服务端下发的 devicename** 而不是当前蓝牙广播名——
它列的是绑定关系,可能包含此刻没连上的设备,用当前连接名会让所有行显示成同一台。
- 杰理固件升级页原来拉服务端 productimage 网络图,一并去掉:产品图统一走本地,
留着会出现「同一台设备在设备页显示本地图、在升级页显示另一张网络图」。
匹配三级,从严到宽:完全相同 → 忽略大小写 → 最长前缀(兜 `Echo-one_L`
这类带后缀的广播名)。第三级必须取**最长**匹配,否则目录里同时有 `Echo` 和
`Echo-one` 时前者会把后者的设备抢走。
启动时读一次 AssetManifest(main.dart)记下目录里实际有哪些图。不做这一步就只能
靠 Image.asset 的 errorBuilder 在渲染失败时兜底,那是**静默**的——美术漏出一张图
或命名对不上,界面直接变通用图,没有任何地方看得出来。现在会打 warn。
资源侧:earphone.png → Echo-one.png(同一张耳机实拍图,只是改名以适配新规则),
补上缺失的 default_icon.png,删掉已无引用的 earphone*/record_card*(省约 1.6MB)。
## 修同传/面对面页「一层阴影盖住标题和返回键」
不是阴影,是 Flutter 的错误控件。translation_view 的 AppBar 里有个 Obx 写成
`Platform.isIOS && controller.currentMode.value == ...`,安卓上 && 短路,
右半边根本不执行,这个 Obx 一个可观测变量都没订阅到,GetX 判「用法不当」抛错,
错误控件顶替了整条 AppBar(debug 红框、release 灰框)。iOS 上 Platform.isIOS
为真会继续求值,所以只有安卓复现。把可观测变量提到平台判断之前读即可。
全仓扫过,同样写法只此一处。
## 修 AI 页三张卡片 RIGHT OVERFLOWED BY 2.0 PIXELS
VIP 区容器有一圈 Border.all()(默认宽 1.0),Border 画在 padding 内侧、左右各占
1px,而列宽计算只扣了 padding 没扣 border,于是正好多出 2px。把 border 宽度提成
具名常量与计算共用,免得改一处又错位。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
1 month ago |
|
|
5eeedf1013 |
修拾忆页看不到助手闹钟:换源时把本地那份的展示出口弄丢了
真机实测暴露的回归。设备上取到的证据: assistant_reminders: 2 条("南山会议" 16:00、"晚餐时间" 17:00),synced=false assistant_directives: 2 条 SET_clock,status=done memory_items_cache: 0 条 也就是说助手完全正常:听懂了、下发了指令、指令也落地了。但用户在拾忆页 什么都看不到。 ## 原因 _rebuildEvents 换成只读 MemoryService.items 之后,AssistantDirectiveService 的 reminders **全仓再没有任何消费者**(grep 可证)。后端还没部署 memory 模块, memory_add 必然失败,于是本地那两条既进不了 MemoryService、也没有展示出口。 我上一轮的提交说明写着「迁移期双写……即使上传失败,用户至少还能在本机看到 自己刚定的闹钟」——**那句话是错的**,双写的「本地」那一半当时已经没有出口了。 ## 改动 - CalendarController._rebuildEvents 补上 _localReminderEvents():把 **还没同步**的助手闹钟也投影进日历。已同步的跳过,否则 MemoryService 与 本地两边都投影会出现两条。 - 重新订阅 AssistantDirectiveService.reminders(_reminderWorker): 不订阅的话助手刚定完闹钟页面不会刷新,要退出重进才看得到。 - 「提醒 → 记忆项」的换算收敛成 AssistantReminderToMemory 扩展, 上传路径与日历投影共用同一份,删掉 service 里那份重复实现。 - 本地未同步项的 memoryId 是 0:点开编辑或勾完成时给明确提示 (memLocalOnlyHint,41 语言已补),不再静默无反应——它没有服务端 id, 改了也没处提交。 ## 另一个症状:EMAI 回复没声音(未修,不在本次改动范围) 同一份日志里: [ERROR][PcmStreamPlayer] 播放错误: PlatformException(-11850, Operation Stopped) [ERROR][PcmStreamPlayer] 启动播放失败: (-11850) Operation Stopped 反复几十次。EMAI 的回复音频走 BailianMultimodalService.audioOut → PcmStreamPlayer.feed,**整条链路不经过 TtsService**,也不在本次改动的文件里 (改动清单见 git diff --name-only)。-11850 是 AVFoundation 层的错误, 指向音频会话状态,需要单独排查。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
66463e53f6 |
记忆中心客户端:拾忆页接服务端 + 写操作 UI + 本地提醒 + 每日播报
dart analyze 零错误,flutter build apk --debug 通过。 零期修缮 - tabTodo 补齐 41 个语言。此前只有 11 个文件有这个 key,其中 8 个的值是 'Remin'(不是任何语言里的词,像 Reminisce 打了一半),缺 key 的 30 个经 GetX 回退到 en_US 同样显示 'Remin' —— 41 个语言里 38 个是坏的,只是不报错。 - i18n_audit.py 补「缺失 key」检查。它此前**结构上无法发现缺失的 key**:循环遍历 的是该文件已有的 key,且对 baseline 里没有的直接 continue。这正是 tabTodo 在 30 个语言里悄悄丢掉而没人发现的原因。现以 zh_cn 为基准,实测报出 7243 处历史缺失 (40 个语言只有 1 个不缺)。加了 --fail-on-missing/--allow-missing 给 CI 卡「只增 不减」,默认不开——一上来就红会让人直接把检查关掉。 - pubspec 引入 timezone + flutter_timezone。zonedSchedule 只接受 tz.TZDateTime, 没有这两个依赖,提醒功能一行都写不了。 拾忆页从纯展示改成可写(此前最大的工作量遗漏) 页面原来没有 RefreshIndicator、没有 FloatingActionButton、卡片没有 onTap, 于是服务端的 add/update/del/complete 四个写接口在客户端一个调用点都没有, user_edited 那套「保护用户修改」的机制完全空转。本次补齐: - MemoryEditSheet:新增/编辑弹层,按分类分流表单(统一表存储 ≠ 统一表单) - 卡片 onTap 打开编辑、左侧勾选框标记完成(灵感不给勾选框,它没有完成一说) - 右下角 + 新增、RefreshIndicator 下拉刷新、带引导的空态页 - date_certain=false 的项单独归到「待定日期」小节。一次会抽出 8 条没写截止时间的 待办全堆在会议当天,不分开那一格就没法看了。 数据层 - MemoryItem / MemoryRemindSlot / MemoryReport 手写镜像服务端 pb。 **每个字段都经宽松解析器**(memInt/memBool/memStr),不直接 as int: 服务端删字段或老记录缺列时,non-nullable 会让整个 fromJson 抛 TypeError, 表现是整页空白而不是少一个字段(appconfig_model 已经为此踩过坑)。 单条解析失败只跳过那一条。 - 分类保留原始字符串而不是 enum 解析。服务端加分类只改常量不发包, 客户端 switch 不到就抛等于服务端一加分类就打崩所有存量 App。 CalendarEventCategory 加了 other 作为未知兜底,筛选与卡片分流都改成值比较 而不是穷举 switch。 - MemoryService 只缓存最近 90 天。GetStorage 是把整个 box 读进内存的 JSON, 一年三千多条全量缓存会让每次启动越来越慢。 - 拉取失败保留本地缓存并标 staleFromCache,页面显示行内「当前显示的是本地缓存」, 不清空、不弹红条。 - 勾选完成是乐观更新 + 失败回滚。不回滚会让用户以为已经勾上,下次进页面又变回来。 - memory_today / memory_upcoming 加进 AuthInterceptor 的红条抑制名单: 它们在启动与前台恢复时自动调,用户什么都没点就吃一条英文内部状态词很差。 删除 mock mockCalendarEvents() 与它引用的 44 个 demo* i18n key 一并删除(41 个文件共 484 行)。 真实数据上线后混着演示数据会让人以为系统出错。 本地提醒(MemoryReminderScheduler) - 通知 id 占 920000 起的固定区间,**逐条 cancel,绝不 cancelAll()** —— 仓库里已有 两个各自 new 的 FlutterLocalNotificationsPlugin 实例,cancelAll 会顺手干掉正在 录音的前台通知,表现是录音悄悄失去前台身份被系统回收。 - 单独的通知通道:录音提示是常驻低优先级通道,共用会让提醒被降级成静默。 - **只查权限不申请**。申请必须走 PermissionUtil(它收敛了过审要求的 48 小时冷却), 且只允许用户在权限管理页主动发起,这里主动申请等于绕过合规规则。 无权限时降级为「打开 App 才提醒」,不阻塞。 - 精确排期失败(Android 14 起 SCHEDULE_EXACT_ALARM 默认不授予)自动退化成 inexact 再试一次——不精确的提醒也比没有强,日志会记下来。 - 拿不到系统时区时按本机偏移找等价区兜底,不落回 UTC(那会让国内用户全部偏 8 小时)。 每日播报(MemoryDailySheet) - **不 await 在启动路径上**。冷启动已串四次网络往返,仓库刚做过相反方向的优化 (6a64c3d0 把会议模板拉取改成 unawaited)。这里是进主页后异步拉、拿到再弹。 - 排在隐私政策与强更弹窗之后,且必须在登录态确认之后。 - 通话翻译进行中一律不播报:两者共用同一个 AVAudioSession,在对方刚调好的会话上 再设一次会把通话音频路由弄乱(iOS 那条 phone_call 分支被改坏过三次)。 - 关窗必须真停:speakStream 是队列式播放,只 stop 不清队列会「关了还在念下一句」。 - 播报文案本地拼,不调 LLM。 生命周期与账号 - 切前台的刷新挂在 AppLifecycleManager(仓库已有 emai/translation/permissions 三个各自实现的 observer,本类就是收敛点),全部 unawaited。 - 登出清空记忆数据与已排提醒。不清的话换账号会看到上一个人的日程花销灵感, 提醒也会继续按上一个账号的安排响。 助手闹钟迁移 SET_clock 改为双写:本地 reminders 保留一个版本(上传失败时本机仍可用), 同时写服务端 memory_item(category=alarm)。**幂等键用指令 id** —— 本类的按 id 去重只在本进程内存里,换机/重装/重启后全失效,服务端靠 (uid, client_key) 唯一索引兜住。认不出的重复规则按单次处理,宁可只响一次也不按猜的规则天天响。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
1 month ago |
|
|
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 |
|
|
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 |