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 字段完善
This commit is contained in:
@@ -66,6 +66,38 @@ motion_segment:
|
||||
min_duration_sec: 1 # 短于该时长的事件不分割
|
||||
unfinished_grace_sec: 10 # start_time+duration 距当前 ≤ 该秒视为"已结束"容差
|
||||
|
||||
# 闭集人物识别(2026-08-22 新增,家里固定 4 人:爷爷/爸爸/媳妇/汤圆):
|
||||
# 原来靠大模型自己编的"人物A/B/C"临时 uid + 文字特征描述跨视频合并,验证下来
|
||||
# 不可靠(用户原话"现在的识别全是错的")。人脸向量方案也验证过,家庭监控这种
|
||||
# 大广角/远距离画面下同人内部相似度经常比不同人还低,此路不通。
|
||||
# 现在改成:汤圆(幼儿/儿童特征)/媳妇(唯一成年女性) 直接用 Gemini 已产出的
|
||||
# 性别/年龄字段判断,免费且验证下来接近 100% 准;爷爷/爸爸(两个成年男性,纯
|
||||
# 外观规则/人脸向量都区分不开) 改用视觉大模型"看参考图比对"——NVIDIA 实测
|
||||
# 6/6 全对且配额与主分析链路完全独立,设为优先,Gemini flash-lite(7/8) 兜底。
|
||||
# 参考图目录结构:{ref_dir}/爷爷/*.jpg、{ref_dir}/爸爸/*.jpg(已用确认过身份的
|
||||
# 历史截图种好,见 PROGRESS.md 记录)。
|
||||
person_identifier:
|
||||
enabled: true
|
||||
ref_dir: "/opt/fam-edge/data/person_refs"
|
||||
max_ref_per_person: 6
|
||||
# 连续两次分类调用之间的最小间隔(不分 provider 统一限速):正常处理新片段时
|
||||
# 调用本来就稀疏,这个主要是给历史数据批量回填用的,避免短时间内密集调用打爆配额
|
||||
min_call_interval_sec: 2
|
||||
nvidia:
|
||||
api_key: "${NVIDIA_API_KEY}"
|
||||
model_name: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning"
|
||||
fallback_models: [] # 目前只验证过这一个能用的 NVIDIA 视觉模型,先留好扩展位
|
||||
timeout: 60
|
||||
max_retries: 3 # 每个模型对瞬时故障(429/5xx/超时)最多重试几次(含首次)
|
||||
retry_backoff_sec: 3 # 重试前基础等待秒数,指数退避(3s -> 6s -> 12s)
|
||||
gemini:
|
||||
api_key: "${GEMINI_API_KEY}"
|
||||
extra_api_keys: ["${GEMINI_API_KEY_2}", "${GEMINI_API_KEY_3}", "${GEMINI_API_KEY_4}"]
|
||||
model_name: "gemini-flash-lite-latest"
|
||||
timeout: 60
|
||||
max_retries: 2
|
||||
retry_backoff_sec: 3
|
||||
|
||||
# 智能问答降级链(与视频分析独立):Gemini -> NVIDIA -> 本地 Ollama
|
||||
models:
|
||||
- provider: "gemini"
|
||||
@@ -90,6 +122,9 @@ models:
|
||||
- "智能摄像头-3"
|
||||
- "智能摄像头-4"
|
||||
timeout: 600
|
||||
# 问答专用超时(跟上面视频分析的 timeout 分开):用户在等交互式回答,一个
|
||||
# key/模型卡住不该等 10 分钟,超时要短,快速降级到下一个 key/模型/provider
|
||||
chat_timeout: 20
|
||||
# 模型级独立超时(最终值,不参与编排层 ×2 放大)
|
||||
# gemini-flash-lite 实测 ~22-34s,按用户要求放宽至 8 分钟(480s),避免大视频/排队时过早切断
|
||||
model_timeouts:
|
||||
@@ -119,6 +154,7 @@ models:
|
||||
base_url: "https://integrate.api.nvidia.com/v1"
|
||||
api_key: "${NVIDIA_API_KEY}"
|
||||
timeout: 600
|
||||
chat_timeout: 20 # 问答专用超时,跟视频分析的 timeout 分开
|
||||
max_base64_mb: 20 # 超过此大小直接跳过 NVIDIA,不做注定失败的编码+上传
|
||||
switch_interval_sec: 5 # 模型切换间隔:一个失败后等待再试下一个(未来加模型时用)
|
||||
model_timeouts: # 模型级独立超时(最终值,不参与 ×2)
|
||||
|
||||
Reference in New Issue
Block a user