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:
ericwyuan
2026-08-23 00:13:56 +08:00
parent aca1a674b1
commit 2c5bf950c5
31 changed files with 2166 additions and 25 deletions

View File

@@ -0,0 +1,180 @@
# 2026-08-21 工作记录
## #51 部署验证 - rclone 同步 Google 硬盘 + 全链路跑通
### Oraclefam-edge部署完成
- rclone v1.75.0 装到 /usr/local/binaarch64zip 解压)
- 服务账号 JSON 存 /opt/fam-edge/gdrive-sa.jsonchmod 600用户提供
- rclone remote `gdrive:`drive scope + service_account_file
- 同步脚本 /opt/fam-edge/rclone_sync.sh + systemd timer每 5 分钟):
`rclone sync --drive-shared-with-me gdrive:SS/Generic_ONVIF-001 /opt/fam-edge/gdrive_videos`
- 首次全量同步 20 个视频 7.52GB~2 分钟完成)
- 共享目录是 `SS`(群晖监控站),摄像头 `Generic_ONVIF-001` 按 YYYYMMDDAM/PM 分目录
### 踩坑与修复3 个 commit
1. `watch_processor._scan_files` 改 os.walk 递归(原 listdir 只看根目录,视频在子目录)
2. `.env` 的 GEMINI/NVIDIA key 是旧无效值 → 用 env.sh 的真实 key 修复config_loader 只读 .env
3. **Gemini 上传**:必须用 `/upload/v1beta/files` 端点(/v1beta/files 是元数据端点)+ resumable 协议370MB 整视频 ~55s 上传成功
4. **NVIDIA**base64 塞 payload 超 25MB 上限 → 改 Assets APIPOST 拿 assetId+uploadUrlPUT 上传PUT 必须**全小写 content-type 且值=POST contentType(video/mp4)**,否则 S3 预签名 SignatureDoesNotMatch
5. `parse_vlm_json` schema 从旧架构entities_json/frame_details改为新架构global_summary/events/people_mentioned兼容旧结构转换
### 端到端验证通过
- 21 视频全部登记video 1/2 已 doneprovider=gemini凌晨视频无事件=分析正确)
- NAS 重启 fam-core 触发立即同步sync_videos=21cursor 推进正确
- 剩余 19 个视频串行处理中Gemini 免费配额 429 会降级 flash-lite之后可考虑 NVIDIA
### 待观察
- Gemini 免费 key 配额限制(~20 req/day后续 19 个视频可能大量 429
- rclone timer 每 5 分钟增量同步验证
- NAS 30 分钟自动同步已生效
## 生产-消费队列 + 模型超时×2新需求commit ce27e4a
- 新增 `fam-edge/src/fam_edge/video_queue.py`VideoQueue 生产-消费队列
- 生产者线程30s 轮询 rclone 落地目录,新文件登记 pending 并入队;启动时补入队 DB 未处理完的(重启恢复,实测 14 个)
- 消费者线程max_concurrent=1从队列取 video_id → VideoProcessor.process_video(timeout_multiplier=2)
- 防重复入队_queued set重试上限max_retries=2oracle_db.videos 加 retry_count 列mark_video_failed 递增)
- `video_processor.process_video` 加 timeout_multiplier遍历 adapter 时临时 adapter.timeout = 原配置 ×倍数finally 恢复gemini 600→1200s 生效日志确认)
- config.yaml video_processing 加 timeout_multiplier: 2 / max_retries: 2
- 删除旧 watch_processor.pyapp.py 改启动 VideoQueue
- oracle_dbretry_count 列(建表+ALTER 兼容旧库、get_video_by_id、PRAGMA busy_timeout=10000
- 部署验证:启动恢复入队 14 个、video_id=8 gemini 600→1200s、生产者登记 id=22 新视频、done 持续增长
## 模型调用统计界面 + lite 超时实测×4commit b87b38b + 3e94c2a
- Oracle 端oracle_db 新增 model_calls 表provider/model/video_id/started_at/duration_sec/success/error/created_atBaseModelAdapter 加 model_call_hook + _emit_model_callgemini(_generate_video 每模型每attempt)/nvidia(analyze_video) 每次请求记录get_sync_delta 下发 model_callscreated_at >= since + NAS 幂等 upsert 防漏)
- gemini 支持模型级 model_timeouts最终值不参与 ×2实测 lite 370MB 视频耗时 22.6s(生产 27~34slite 限制 = 22.6×4 ≈ 90sflash 仍 1200s600×2。日志确认flash 本轮 1200s / lite 本轮 90s
- NAS 端sync_model_calls 镜像表ddl 8.1db_layer upsert_sync_model_calls/get_sync_model_calls/get_sync_model_calls_statsoracle_sync 拉 model_callslast_count 变 4 元组)
- fam-ui 新增 "🤖 模型统计" 页:按模型聚合(成功/失败/成功率/平均耗时/最后调用)+ 最近 100 条调用明细(请求时间/模型/耗时/状态/失败原因/视频)
- 验证Oracle model_calls 正常记录flash 429_quota 失败、lite 成功 27~34sNAS 同步 4 条fam-ui 200
## 整体排查 + lite 超时 8 分钟commit 83eefc1
- **NVIDIA 400 排查结论**`nvidia/nemotron-nano-12b-v2-vl` 对整视频分析**稳定复现 400/500 服务端内部错误**"not enough values to unpack (expected 2, got 1)"),所有视频、有无 num_frames 均复现 → NVIDIA 兜底在当前模型/端点**不可用**asset 上传 OKchat.completions 必失败)。建议从 vision_order 移除或换模型
- gemini-flash-lite 超时 90s → **480s8 分钟)**config model_timeouts 已改并部署(日志确认 480s
- 处理进度done 33 / failed 1video24 待重试)/ pending 12
## NVIDIA 多模型降级链 + 实测结论commit b7b5fe6
- nvidia_adapter 改造model_chainasset 上传一次,逐个模型 video_url 引用尝试)+ switch_interval_sec 切换间隔(默认 5s+ model_timeouts 每模型独立超时 + compute_provider 带模型名nvidia:{model}
- **实测全部 NVIDIA 云端视频候选不可用**omni 500asset_id 引用失败、12b 400、llama-3.2-11b-vision 400不支持视频、cosmos-reason2/phi-3-vision/gemma-3/kosmos-2/fuyu-8b/paligemma 404base64 超 25MBpublic URL 方案被用户否决(不暴露视频)
- configmodel_name=omni + fallback 12b/llama-11b链机制保留未来可用模型出现只需改配置
- 手动验证:模型链 [1/3]→[2/3]→[3/3] 逐个尝试+5s 间隔+失败原因记录,全部失败返回 None
- ⚠️ 安全提醒Oracle 曾短暂起 http.server:8000 暴露视频目录做 POC已按用户要求关闭
## 前端修复SQL 1054 + 视频缩略图commit 4148507
- **SQL 1054 修复**fam-ui 事件查询 `SELECT ... camera_name FROM sync_events`(该列在 sync_videos→ 改 JOIN sync_videos 取 v.camera_name
- **视频缩略图**Oracle 装 opencv-python-headless(5.0)video_processor 处理成功后抽首帧(宽≤640, JPEG q65)存 /opt/fam-edge/thumbs/{video_id}.jpgapi_gateway 新增 GET /api/oracle/video/{id}/thumbtoken 校验,无 token 401已 done 46 视频 backfill 46/46
- **fam-ui**config 加 oracle_url(129.146.203.203:5000)+oracle_token(${ORACLE_SYNC_TOKEN})事件时间轴视频会话头显示缩略图img onerror 优雅降级start_ui.sh 补 source 项目 .env 注入 token
- 验证NAS→Oracle thumb HTTP 200/40KBfam-ui 进程 token env 就绪UI 8501 正常
- 人物管理无照片架构局限LLM 仅输出人物名,无图像锚点),如需人物照片需从视频定位+裁剪,待后续
## 每个事件对应时间点画面截图commit 05f727a
- oracle_db.mark_video_processed 返回 event_ids与 events 一一对应)
- video_processor._generate_event_thumbs事件 ts - 视频 event_start_time = 偏移秒 → cv2 跳帧(CAP_PROP_POS_MSEC)截图,存 /opt/fam-edge/thumbs/ev_{event_id}.jpg宽≤640, q65解析失败/负偏移取首帧)
- api_gateway 新增 GET /api/oracle/event/{event_id}/thumbtoken 校验)
- fam-ui 事件查询加 e.idrender_event_list 每条事件显示对应截图onerror 隐藏降级)
- backfill已 done 视频 102 个事件截图全部生成;验证 NAS→Oracle HTTP 200/51KB、无 token 401
## 事件截图时间对不上修复commit 5233296 + 3fcd00d
- **根因**:模型输出"绝对北京时间"靠自身推算1 小时视频内误差可达分钟级 → 截图按不准的时间定位帧必然图文不符
- **修复**:① prompt 改为要求输出"视频内相对时间 HH:MM:SS"(模型对相对位置判断准);② 后端 _parse_event_ts 解析相对时间 → 绝对时间 = start + offset 精确落库(兼容旧绝对格式);③ 截图直接用 offset 跳帧
- **连带 bug**_parse_event_start_from_filename 只认带分隔符日期2026-08-21监控文件名是纯数字 20260820-140416 → event_start_time 空 → 新增纯数字格式解析
- 启发式:相对时间 >6h 视为模型误输出绝对时间,不强行定位
- 验证:重置 video 46 重分析 → event_start=14:04:16 ✓,事件 ts 14:05:37/14:06:21/14:13:02截图 offset 36/48/81/125/526s 精确 ✓
- 旧视频(除重分析的)仍用旧时间戳截图;如需全部修正需批量重分析(成本高,用户确认后再做)
## 全部旧视频重分析 + 人物管理图片commit 92ef9fe
- **全量重分析**:清空 events(104) + 旧事件截图(108) + 重置全部 45+1 个视频 pending → 队列后台串行重跑(新相对时间逻辑,预计 1.5-2.5hGemini flash 429 → lite 兜底)
- **人物管理图片**fam-ui 每个人物身份取其一 label 出现事件的截图作头像(查 sync_events.person_list_json LIKE → 显示 Oracle event thumb
- 修正video 46 起初被排除重跑但 events 被清 → 一并重置统一重跑
## 队列健壮性三项commit 6afdda5用户需求清单
1. **失败重试间隔 30s→1h**videos 表加 last_fail_atmark_video_failed 记录video_queue._retry_allowed 对 failed 要求 retry_count<max_retries 且距上次失败 ≥ retry_interval_sec(3600) 才重新入队(配额类瞬时故障等恢复,避免重复打爆)
2. **max_retries 2→10**:默认值与 config 均改 10瞬时故障更多机会
3. **入队前文件校验**validate_video()OpenCV大小>0/可打开/可读帧/元数据 fps-frames-duration-分辨率);新文件先过 mtime 稳定窗口(stable_window_sec=60 防 rclone 半成品)再校验,失败登记 status='invalid' 不入队可追溯_retry_allowed 排除process_video 处理前二次确认(失败标 failed:invalid_file:xxx
- 验证:正常视频 ok+meta(30min/2880x1620/14.28fps)、损坏 cannot_open、空文件 file_empty部署后日志"重试上限 10"
- 重分析 42 个 pending 继续后台跑
## 代码审查 18 项处理commit 034dca9 + 4e85a98
- **已解决(新增)**#18 密钥明文直配 config.yamltoken/gemini/nvidia弃 .env 依赖,验证 token_ok/key 长度正常);#5 appearances 改 distinct 视频数覆盖校准set_person_appearances防 reconcile 累加膨胀);#9 oracle_sync _pull_lock 防 trigger_now 与后台并发双拉;#11 LLM 合并命名解析 target 已有 canonical统一显示名#12 熔断器状态转换加锁;#10 问答人名匹配改 JSON_CONTAINS 精确匹配MariaDB 语法验证 OK#4 OracleDB _write_lock 复合写串行化;#6 每消费者独立 VideoProcessor消 adapter.timeout 共享竞争);#15 done 视频文件被覆盖 mtime>processed_at 自动重置重分析
- **累计已解决**#1/#2/#3/#4/#5/#6/#9/#10/#11/#12/#15/#18;部分缓解 #7/#14/#17
- **未解决(说明)**#8 删除传播tombstone 大工程,暂缓);#13 Gemini 文件/NVIDIA asset 残留清理(暂缓);#16 gunicorn 线程数(运维配置,暂缓)
- 重分析进度done 13 / pending 33约剩 1h
## Prompt 集中化重构commit a72b286用户提供详细设计文档
- 新增 fam-edge/src/fam_edge/ai_orchestrator/prompts.pybuild_video_prompt含 3 秒密度抽取/7 维度描述/people_mentioned 一致性强制/输出硬约束/边界情况/camera_name 注入、build_chat_prompt、build_person_merge_prompt唯一性+保守不合并__init__ 导出
- gemini/nvidia adapter._build_video_prompt 改调共享函数(消除两份发散),注入 camera_name
- person_service._llm_merge 改调 build_person_merge_prompt
- fam-core chat_handler 新增 prompts.py跨模块独立维护风格一致删除内联 CHAT_SYSTEM_PROMPTchat_ask 改调 build_chat_prompt
- 部署验证prompt 生成正常3 秒密度/camera/唯一性均含fam-edge activefam-core health OK
- 注意3 秒密度可能让有人时段 events 数百条Gemini maxOutputTokens=4096 可能截断——若出现 JSON 解析失败需提高 max_tokens
## 最新代码调试 + 人物标识清洗commit 0d73c23
- 调试结果服务全正常fam-edge active、NAS core/ui 200、rclone timer active重分析 done 26/pending 20新 prompt 正常——有人视频 5-16 事件、无人时段(晚 19:31/凌晨 5 点)events=0 合理、无 JSON 解析失败
- 发现并修复:模型输出 people 含 known_members 上下文格式串"人物A别名/标识人物B"污染人物表 → prompts.py 明确"people 只填标识本身不带括号注释" + video_processor._clean_person 后端清洗events.people 与 people_mentioned 均清洗)+ 清理存量脏 label人物A别名/标识人物B→ 人物A
- people 表现状A/B/C/D 四标签LLM 合并 B/C/D → canonical 人物A
## 前端日期标签与视频文件对不上commit da76319
**用户反馈**:前端显示"2026-08-21 · 画面静止/无人员活动",和下面的视频文件对不上。
**根因链**(排查发现):
1. 前端事件时间轴/统计按 `processed_at`**分析处理时间**)做日期分组——全量重分析都在 8/21 完成,导致 8/15~8/20 录制的视频全部堆在"2026-08-21"标签下,与文件名(录制时间)错位
2. Oracle videos 表 8/21 11:29~12:59 被整表重建created 全在此区间),重分析串行进行
3. 20 个视频 event_start_time 为空video 30-45 在 13:00~13:25 处理时服务器跑的是旧文件名解析代码(无纯数字正则 YYYYMMDD-HHMMSS且被后续部署重启中断pending28/29 从未处理
4. NAS 镜像状态与 Oracle 错位35-45 NAS 显示 done、Oracle 实为 pending——Oracle 重建后 NAS 增量未对齐
**修复**
1. **日期维度统一改视频实际录制时间**fam-ui事件时间轴统计/列表/关注事件统计)与 db_layerget_sync_videos/get_sync_stats/query_sync_events_for_person_date全部改用 `COALESCE(NULLIF(event_start_time,''), processed_at)`(录制时间优先,回退处理时间)
2. **Oracle backfill**:对 12 个缺失 start 的视频按文件名解析回填30/33-42/45→ Oracle 46 个视频全部有 event_start_time
3. **NAS 强制全量重同步**:删 sync_cursor last_since + 重启 fam-core → since='' 全量拉取 → EMPTY_START 20→0、状态与 Oracle 对齐done 28/failed 4/pending 14
**验证**done 视频按录制日期分布 8/15:10、8/16:8、8/17:2、8/18:2、8/19:2、8/20:1、8/21:38/15/8/20 筛选正确fam-ui 200 无报错。
**遗留**Oracle 端 pending 14 个在队列继续串行处理video 28 处理中failed 4 个24/25/26 等Gemini 429等 1h 重试间隔自动重试。
## Google 硬盘删除联动 + DB 摘要保留(用户需求确认,无代码改动)
- **用户需求**①谷歌删了甲骨文也删文件层②Oracle/NAS 数据库生成的摘要不能删DB 层)
- **验证结论**
- 文件层rclone sync 本就是镜像语义远程删→本地删实测放临时文件→sync→Deleted:1 确认生效
- DB 层video_queue 生产者只扫描"目录存在的文件",文件消失不影响 Oracle videos/events/people 记录NAS 镜像照常同步,前端摘要保留;截图接口 404 由前端 onerror 降级
- **加固**rclone_sync.sh 加 `--max-delete 200`(防 Google API 临时故障级联误删本地,单次最多删 200 个),脚本验证 exit=0、75 文件不受影响
- 注意:当前是**单向镜像**Google 为源→本地),不建议反向传播(本地删→谷歌删会误删原始监控),如需 rclone bisync 真双向需用户确认风险
## 实时服务状态界面 + 7 天活动记录commit 0d0a7f6 + fec9a3e
- **Oracle**service_activity 表service/action/detail/ts写入时清 7 天前record_activity/get_recent_activities/get_queue_statusVideoQueue 打点(register/reanalyze/process_start/process_done/process_fail)+_current 当前处理跟踪+status()PersonService 打点(merge_done/merge_skip)api_gateway 新增 GET /api/oracle/activitytoken 鉴权,返回 queue/db.by_status/rclone/person/model_calls/最近50条活动
- **rclone_sync.sh**:同步结果写 activity 表service=rclone, transferred/deleted/exitTRANS 提取正则修过一次(输出带 B 单位)
- **fam-ui**:新增"🖥 服务状态"页导航第7项状态卡队列运行/排队/完成/待处理/失败 + 当前处理视频 + rclone/人物/NAS同步/模型 4 张服务卡)+ 最近活动时间流(服务徽章),直连 Oracle /api/oracle/activity复用 oracle_url+token
- **踩坑**video_queue.status() 用 Dict 注解未导入 → worker 启动 NameError → 补 typing.Dict
- 验证接口数据正常queue running/queued 19/当前 video 56rclone sync_done/person merge_done 打点生效401 鉴权NAS→Oracle HTTP 200fam-ui 200
## 模型调用时间差 8 小时修复commit 02fc80b
- **根因**gemini/nvidia adapter 的 model_calls.started_at 用 `datetime.now()`Oracle 服务器 UTC而 created_at 用 _now_iso()(北京时间)→ 前端模型统计/服务状态页时间差 8h
- **修复**:两个 adapter started_at 改 `datetime.now(timezone(timedelta(hours=8)))`Oracle 历史 215 条 +8hNAS 镜像 sync_model_calls 210 条 DATE_ADD +8h
- 验证:最新记录 started 16:05:02 与 created 对齐(北京时间)✓
## 人物管理无照片修复commit 27bfd6a
- **根因**NAS sync_events 残留重分析前旧事件223 条 vs Oracle 115 条id 1-108 旧事件未删除——#8 删除传播未做的副作用)。人物页头像查 `ORDER BY e.id LIMIT 1` 取到旧事件 id=1 → Oracle ev_1.jpg 不存在(重分析后事件从 109 起)→ 404 → onerror 隐藏 → 无照片
- **修复**:① NAS 清空 sync_events + 重置 cursor 全量重拉 → 精确 115 条镜像;② api_gateway event_thumb 兜底ev 缺失时查所属 video 返回 thumbs/{video_id}.jpg视频首帧③ 清理 Oracle people 脏 label人物A别名/标识人物B→人物A
- 验证NAS→Oracle ev109 HTTP 200/51KB ✓;人物页查询到的都是新事件 id → 截图存在
## 人物头像改为"出现事件画面"commit 2ba3478用户否决视频首帧方案
- **用户意见**:不能用视频首帧当头像(首帧可能无人/非本人)——该人物在众多视频中多次出现,肯定能在他出现的事件里找到画面
- **新方案**Oracle 新增 GET /api/oracle/person/avatar?label=Xtoken 鉴权events.person_list_json 按 `%"label"%` JSON 数组精确匹配,按 id DESC 遍历返回第一个 ev_{id}.jpg 存在的截图(人物出现事件中最新的有截图画面);撤销 event_thumb 的视频首帧兜底(改回 404
- **fam-ui 人物页**:头像改调 avatar 接口(先 requests 探测 200 再渲染 imglabel 用 urllib.parse.quote 编码)
- 验证人物A/B avatar 均 20039-41KB 真实事件画面)、无 token 401、NAS→Oracle 200、UI 200
## Oracle 磁盘扩容(用户控制台扩盘 + 重启生效)
- **背景**rclone 持续同步视频导致 45G 盘写满(剩 46Mgdrive_videos 31G/75 个视频)。用户说已扩容但服务器 lsblk 一直 46.6G(在线未生效)
- **处理**growpart/resize2fs 均 NOCHANGE块设备没变临时清理 /tmp 残留+apt+journal 释放 ~900M禁用 rclone timer 防写满;按用户要求重启服务器
- **重启后扩容生效**sda 46.6G→**150G**Ubuntu cloud-init 开机自动扩展分区+文件系统 → df 146G 可用 90G39%
- **恢复**enable --now rclone-sync.timer同步恢复视频 75→121 个持续下载中fam-edge active
- 经验Oracle 在线扩容偶尔不立即生效重启可触发Ubuntu 自动 growfs扩容后无需手动 growpart
- 提醒视频持续增长121 个已占 56G150G 约可再装 240 个视频,长期需考虑清理策略(如只保留分析完的摘要+删本地视频,需改 rclone 策略避免重新拉回)或再扩盘
## 人物模块重构 v3 - 大模型特征值替代 OpenCVcommit ff01d14 + 68337f8 + 677c5bd用户提供设计文档
- **核心**prompt 增加 person_appearances(uid+7特征+action)VLM 直接产出结构化特征,跨视频靠特征合并,彻底移除 cv2
- **改动**12 文件prompts.py(6原则+schema+规则8条+合并prompt重写)、gemini _normalize 透传、oracle_db(events.person_appearances_json/people.features_json/display_uid + _merge_features + upsert_person/mark_video_processed)、video_processor(validate_video 改 ffprobe 去 cv2、_store_result 聚合 uid 特征落 people、删 thumb/event_thumbs)、person_service(_aggregate_features/_collect_features_text 特征文本合并)、api_gateway 删 3 图接口、NAS db_layer+ddl 加字段、fam-ui 特征卡替代头像+事件人物特征块
- **踩坑 2 个**
1. max_tokens 4096→163843秒密度+特征使 JSON 巨大被截断解析失败
2. **json_parser.validate_schema 白名单丢弃 person_appearances**(在 _normalize 之前执行)→ 补透传
- **验证**video 46 重分析 → lite 输出 16 事件含完整特征(性别男/中年/中等/短发/蓝色POLO衫/无辨识events 带特征 6、people.features_json 落库NAS 同步 6 条+人物A特征卡数据 ✓
- 部署Oracle 卸载 opencv/numpyffprobe 已有NAS ALTER 加 3 列
- 遗留NVIDIA 模型链仍不可用gemini 429 时 lite 兜底);历史视频无特征(前端显示"特征待大模型补充",下段分析自动补)