feat(v3): 人物模块重构 - 大模型结构化特征值替代 OpenCV 帧定位。prompt 增加 person_appearances(uid+7特征+action)并重写合并 prompt(稳定特征优先比对);gemini 透传特征字段;oracle_db events/people 加 person_appearances_json/features_json/display_uid + _merge_features;video_processor 去 cv2 改 ffprobe 校验、_store_result 聚合 uid 特征落 people、删缩略图/事件截图;person_service 聚合特征后基于特征文本 LLM 合并;api_gateway 删 3 个图接口;NAS 镜像+DDL 加新字段;fam-ui 特征卡替代头像、事件时间线人物特征块

This commit is contained in:
ericwyuan
2026-08-21 18:06:21 +08:00
parent 2ba3478291
commit ff01d14c79
12 changed files with 463 additions and 257 deletions

View File

@@ -6,8 +6,10 @@ Prompt 模板 - 集中管理,避免 gemini/nvidia 适配器各维护一份导
2. timestamp 统一"视频内相对时间 HH:MM:SS",消除绝对/相对歧义
3. 人物命名: 已知成员用真名,未知用"人物A/B/C"本视频内临时编号,
并强制 people_mentioned = events 内出现人物去重后的集合(下游合并依赖)
4. 输出硬约束: 首字符必须是 {,禁止思考过程/markdown/解释
5. 边界情况: 无人/空视频/看不清 -> 空 events + summary 说明,不凑数
4. 人物特征: 每个人物在每个 event 里输出 person_appearances含 uid + 结构化特征
文本(性别/年龄段/身形/发型/衣着/面部/辨识点);下游靠特征值跨视频绑定同一身份
5. 输出硬约束: 首字符必须是 {,禁止思考过程/markdown/解释
6. 边界情况: 无人/空视频/看不清 -> 空 events + summary 说明,不凑数
"""
from typing import Optional
@@ -44,6 +46,21 @@ def build_video_prompt(known_members: str, event_start_time: str,
"timestamp": "HH:MM:SS",
"description": "该时刻画面的详细描述:人物身份、动作细节、位置移动、交互对象、姿态/手势/朝向、手中物品、周围环境",
"people": ["人物标识"],
"person_appearances": [
{{
"uid": "人物A",
"features": {{
"gender": "",
"age_band": "中年",
"build": "瘦高",
"hair": "短发黑色",
"clothing": "红色卫衣+深色长裤",
"face": "蓄须",
"distinguishing": "左手戴手表"
}},
"action": "走向沙发坐下"
}}
],
"is_attention_event": false
}}
],
@@ -74,12 +91,27 @@ def build_video_prompt(known_members: str, event_start_time: str,
4. people: 该时刻出现的人物标识。已知成员用真名未知人物用「人物A」「人物B」
本视频内连续编号(同一人保持同一编号)。只填标识本身,不要带括号注释
(如只写"人物A",不要写"人物A别名/标识人物B")。
5. people_mentioned: 必须等于 events 中所有 people 字段出现过的标识去重后的集合。
5. person_appearances: 该时刻出现的每个人物的结构化特征 + 动作。必填字段说明:
- uid: 与 people 数组里的标识完全一致(同一人同一 uid
- features: 客观可见特征,必须包含以下 7 个子字段,看不清的写 "unknown",绝不留空:
* gender: 性别(男/女/unknown
* age_band: 年龄段(幼儿/儿童/少年/青年/中年/老年/unknown
* build: 身材(如 瘦高/中等/偏胖/壮实/矮小/unknown
* hair: 发型与颜色(如 短发黑色/长发棕色/秃顶/unknown
* clothing: 当下衣着(如 红色卫衣+深色长裤/白色T恤+牛仔裤/unknown
* face: 面部特征(如 蓄须/戴眼镜/圆脸/unknown
* distinguishing: 辨识点(如 左手戴手表/右脸有痣/跛行/无)
- action: 该人物在本时刻的动作(与 description 里该人物动作一致,单独抽出便于检索)。
特征硬约束:
* 客观描述可见特征,不猜测、不推断、不编造(看不清的字段写 unknown不要靠常识猜性别/年龄)。
* 同一 uid 在视频多个 event 出现时features 字段保持一致(衣着变了再如实更新 clothing
但 gender/age_band/build/face 必须稳定)。
6. people_mentioned: 必须等于 events 中所有 people 字段出现过的标识去重后的集合。
一致性强制events 里出现的标识必须都在 people_mentioned 里,反之亦然。
6. is_attention_event: 跌倒、危险动作、异常哭闹、陌生人闯入、身体不适等需关注事件
7. is_attention_event: 跌倒、危险动作、异常哭闹、陌生人闯入、身体不适等需关注事件
填 true否则 false。关注事件的 event 仍按上述密度规则抽取,但 description 须明确
说明"异常"点(如"张三在 00:01:15 跌坐在地,身体向右侧倾,双手撑地")。
7. global_summary: 客观描述,不猜测、不想象、不编造。须包含:谁在画面中、主要活动、
8. global_summary: 客观描述,不猜测、不想象、不编造。须包含:谁在画面中、主要活动、
是否有关注事件、时段大致结构。
【已知家庭成员】
@@ -124,9 +156,10 @@ def build_person_merge_prompt(unnamed_lines: str) -> str:
"""构建人物合并 promptperson_service._llm_merge 用)。
Args:
unnamed_lines: 待合并人物的场景描述,每行 "- label出现场景 ..."
unnamed_lines: 待合并人物的特征文本,每行 "- uid特征=...; 特征=..."
features_json 渲染而来的文本,供 LLM 判断是否同一人)
"""
return f"""你是家庭监控人物汇总助手。下面是若干人物标识及其出现场景描述。
return f"""你是家庭监控人物汇总助手。下面是若干人物标识及其结构化特征描述。
请判断哪些标识指向同一个人,并为每个人输出一个稳定的规范名。
【输出格式】
@@ -140,5 +173,12 @@ def build_person_merge_prompt(unnamed_lines: str) -> str:
3. 无法判断是否同一人的,保守不合并(各保留独立规范名)。
4. 规范名必须在输出中唯一:多个原标识可映射到同一规范名,但同一规范名只指向一个人。
【判断依据】
- 优先比对 gender / age_band / build / face 这四个稳定特征(不会在同一天内变化)。
- hair / clothing 会变化,仅作辅助;仅靠 clothing 相同不足以合并,仅靠 hair 不同不足以拆分。
- distinguishing 辨识点(如手表/痣/跛行)是强证据,一致时倾向合并。
- 任一稳定特征明确冲突(如一个写""一个写""),绝不合并。
- 任一关键特征缺失("unknown")时,其他特征一致性需更强才合并;拿不准保守不合并。
【待处理人物】
{unnamed_lines}"""