ericwyuan
|
ef56ae5662
|
feat(fam-edge): 新增 DiskGuard 磁盘空间守护,剩余空间不足自动清理旧素材
背景:Oracle 磁盘曾经被写满(gdrive_videos 持续下载新素材、旧文件迟迟没
清理),触发 rclone 的一个安全机制——同步遇到 IO 错误就整体拒绝执行删除,
形成"越满越删不掉,越删不掉越满"的死循环,最终连新视频都下载不了。这次
排查+手动清理已经解决了当次故障,但需要一道独立于 rclone 同步之外的兜底,
防止再次悄悄写满没人发现。
- oracle_db.py 新增 get_oldest_purgeable_material():只挑最旧的、已完成
分割阶段(status='done')的整段素材(非 motion_ 前缀),绝不碰运动片段
(事件时间轴/人物头像依赖它)和还在处理中的素材
- disk_guard.py 新增 DiskGuard 后台线程:5 分钟检查一次,剩余空间 <10GB
触发清理,删到 15GB 水位为止(留缓冲避免刚清完又立刻触发),复用已有的
delete_video() 完成实际删除
- app.py 启动这个后台服务;/api/oracle/activity 新增 disk 字段(实时剩余
空间 + 最近一次清理动作),供服务状态页展示
- 新增 9 个单元测试,全部通过(139/139)
已部署 Oracle 验证:DiskGuard 正常启动,配置生效。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
2026-08-28 12:08:04 +08:00 |
|
ericwyuan
|
28397e9e6a
|
feat(timeline): 事件时间轴支持删除视频会话
三端联动实现(fam-ui -> fam-core -> fam-edge),沿用项目里"NAS 转发写请求
到 Oracle"的既有模式(照抄 identity_correct 那套骨架):
- fam-edge:oracle_db.py 新增 delete_video()(删 events+videos 行 + 磁盘上
的运动片段文件;不清理 ss_motion_events 源事件,因为素材一旦处理完就不会
被生产者重新捡起,删片段不会触发重新分割);api_gateway.py 新增
POST /api/oracle/video/delete
- fam-core:新增 db_layer.delete_sync_video()(第一个"NAS 直接写自己镜像表"
的函数——增量同步只做 upsert 感知不到删除,不能像纠错那样靠 trigger_now()
拉增量顺带清理)+ oracle_sync.push_video_delete() + ui_api.py 新增
DELETE /api/ui/videos/<id>(先回推 Oracle,成功后才清本地镜像,避免数据
不一致)
- fam-ui:Timeline.vue 详情卡片加删除按钮(原生 confirm() 二次确认,项目里
之前没有确认弹窗组件先例);api.js 新增 deleteVideo()
新增 6 个 delete_video 单元测试;已在 Oracle/NAS 用自造测试数据完整跑通端
到端链路(转发成功、两端记录清理、磁盘文件删除、幂等 404),未触碰任何真
实监控数据。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
2026-08-24 04:25:43 +08:00 |
|
ericwyuan
|
5f7b27bf04
|
fix(fam-edge): 人物识别结果没同步进事件描述文字
用户反馈:事件卡片上方的人物徽章正确显示"媳妇/爸爸",但描述文字里还是
"人物B双手叉腰站在客厅中央;人物A在远处厨房"这种原始 uid——两处对不上。
根因:rewrite_event_person_names() 只改了 person_list_json /
person_appearances_json[].uid 这些结构化字段,从没碰过 description(事件
描述)和 videos.summary_json(会话摘要)——这两个是大模型写的自然语言,
"人物A"这类 uid 是直接以文字形式嵌在句子里的,结构化字段改名不会带着改。
现在 rewrite_event_person_names() 额外对 description/summary_json 做文本
替换。替换顺序按 rename_map 的 key 长度降序——uid 可能带 "#2"/"#3" 这类
同名冲突后缀,"人物A" 是 "人物A#2" 的前缀,短的先替换会把长的错误地部分
命中,长的先替换才对。
同时跑了两次一次性回填修历史数据:
1. 对所有已有 person_identity_map 映射的 1265 个视频重新跑一遍
rewrite_event_person_names,把之前只改了徽章、没改描述文字的历史数据
补上(events 里"纯人物X不带真名"的还剩 258 条,涉及 94 个视频——都是
性别/年龄特征本来就是 unknown 的画面,闭集识别本来就该留空不瞎猜,
不是回填没覆盖到,是真的没法从图像信息判断是谁)
2. 找到 9 个从未跑过闭集识别的漏网视频(应该是 person_identifier 功能上线
前处理的),重新识别后 1 个(video 2194)成功解析出汤圆+爸爸,其余 8 个
同样是性别未知,正确保持未解析
新增 2 个测试覆盖 description/summary_json 文本替换,以及带后缀 label 的
替换顺序正确性。
|
2026-08-23 10:50:52 +08:00 |
|
ericwyuan
|
2c5bf950c5
|
feat: 事件时间轴缩略帧 + 人物管理头像 + 人物合并硬规则校验
## 新架构:Oracle 集中计算 + NAS 代理展示
### Oracle 端 (fam-edge)
- 新增 frame_service: ffmpeg 视频抽帧 + VLM 人物定位裁剪头像(磁盘缓存)
- 新增 /api/oracle/frame: 按 video_id+ts 抽帧返回 jpeg(带 token)
- 新增 /api/oracle/avatar: 按 label 生成人物头像(VLM 定位人物 + 兜底整帧居中)
- 新增 person_identifier: 人物身份识别模块
- Gemini 适配器支持 flash/flash-lite 双模型切换,429 自动降级
- frame_service VLM 全模型 429 时进入 10 分钟熔断,避免每次请求白打配额
- 兜底头像不落缓存,配额恢复后自动重试 VLM 精确定位
### 人物合并硬规则校验(框架级修复)
- person_service: LLM 合并结果落库前加硬冲突检测
- 性别冲突 → 绝不合并
- 年龄档跨未成年/成年 → 绝不合并(防止把爷爷/宝宝并进同一人)
- oracle_db: upsert_person 入口剥离括号后缀(人物A(别名:人物B) → 人物A),消灭垃圾人物行
- 修复 set_canonical 丢弃 source 参数的 bug(旧代码硬编码 'manual' 导致错误合并被永久固化)
- get_events_for_label: 只提取该身份组的特征文本,头像定位更精准
### NAS 端 (fam-core)
- 新增 img_proxy: /api/proxy/frame 和 /api/proxy/avatar 代理 Oracle 图片
- app.py 注册 img_bp 蓝图
- oracle_sync / db_layer / member_manager 同步人物表
### UI 端 (fam-ui)
- 事件时间轴: 每条事件卡片加时间点缩略帧
- 人物管理: 每人卡片加头像(150x150 圆角)
- parse_persons: 剥离括号备注,与 Oracle 归一化一致
- 新增 EventItem 组件、Timeline 页改造
- Chat / ServiceStatus 页相应调整
### 数据库
- scripts/ddl.sql: 同步表结构更新
- Oracle people 表: features_json / display_uid / source 字段完善
|
2026-08-23 00:13:56 +08:00 |
|
ericwyuan
|
a1523b46c8
|
[重构] 运动事件驱动架构 - 整段素材按 ss_motion_events 分割运动片段再分析(不再整段送云端): oracle_db 加 motion_event_id/camera_id 列 + get_motion_events_in_range/has_unfinished_motion_in_range/get_video_by_motion_event_id; video_processor 素材→分割/片段→分析双分支(ffmpeg -c:v copy -c:a aac 保留音频); video_queue 片段入队; config 加 motion_segment 块
|
2026-08-22 12:19:17 +08:00 |
|
ericwyuan
|
f798c31cab
|
fix(fam-edge): 人物 uid 跨视频复用导致特征串人 - 拆分同 uid 下的性别冲突
根因: 大模型给的 人物A/B/C 这类临时 uid 只在单次视频分析内部稳定,不同视频各
自独立编号——同一个字符串在不同视频里完全可能指向不同的真人(实测生产数据里
"人物A" 在 29 个视频里混了男女两个人,"人物B" 混了男/女/儿童三个人)。但
people 表 label 全局 UNIQUE,upsert_person / person_service 的特征聚合都直接
按这个字符串当全局稳定身份用,导致不同真人的特征被硬合并进同一行,"我"这张卡
显示出来的描述其实是我和媳妇两个人的特征混在一起。
两处落地点都加了同一条硬规则(性别是相对稳定信号,冲突大概率是撞了另一个人):
1. oracle_db.upsert_person(): 单视频入库时,新特征性别与已有行冲突就不覆盖合
并,改分配 uid#2/uid#3 这样的派生 label 单独建行。
2. person_service._aggregate_features(): 每次全量重新聚合时按性别在线聚类,
同一 uid 下冲突的性别拆成独立分组,不再无脑覆盖成一坨。
拆出来的派生 label 走已有的"未命名 -> LLM 合并 -> 硬规则否决"流程,由现有机制
判断该并入哪个已命名身份。
新增 test_oracle_db.py(5 例)+ test_person_service.py(5 例)覆盖同性别合并 /
性别冲突拆分 / 后缀分配 / unknown 不触发拆分等场景。
生产数据已用新逻辑重新 reconcile 并手动核对 3 个因数据量太大 LLM 没能正确认领
的派生 label(人物A#2/人物B#2#2 -> 媳妇,爷爷#2 -> 爷爷),现在 4 个人物分组
(我/媳妇/爷爷/汤圆)特征都是内部一致的,不再互相串。
|
2026-08-22 08:45:24 +08:00 |
|