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 的 替换顺序正确性。
This commit is contained in:
@@ -267,6 +267,58 @@ def test_rewrite_event_person_names_updates_events_and_video(tmp_path):
|
||||
assert set(json.loads(vrow["people_json"])) == {"爷爷", "媳妇"}
|
||||
|
||||
|
||||
def test_rewrite_event_person_names_rewrites_description_text(tmp_path):
|
||||
"""核心诉求: description 是大模型写的自然语言句子,"人物A/人物B"这类 uid
|
||||
会直接以文字形式嵌在句子里,只改 person_list_json/person_appearances_json
|
||||
这些结构化字段的话,事件卡片上方徽章显示对了,描述文字里还是旧 uid,两处
|
||||
对不上——description 也要做文本替换。"""
|
||||
db = _db(tmp_path)
|
||||
vid = db.ensure_video("motion_2_2000.mp4", "/tmp/motion_2_2000.mp4",
|
||||
event_start_time="2026-08-22 13:00:00")
|
||||
events = [
|
||||
{"timestamp": "13:29:24",
|
||||
"description": "人物B双手叉腰站在客厅中央;人物A在远处厨房;儿童已离开画面。",
|
||||
"people": ["人物A", "人物B"],
|
||||
"person_appearances": [
|
||||
{"uid": "人物A", "features": {"gender": "男"}, "action": "站立"},
|
||||
{"uid": "人物B", "features": {"gender": "女"}, "action": "叉腰"}]},
|
||||
]
|
||||
db.mark_video_processed(vid, "人物A和人物B都在客厅活动。", events,
|
||||
["人物A", "人物B"], "gemini")
|
||||
db.rewrite_event_person_names(vid, {"人物A": "爸爸", "人物B": "媳妇"})
|
||||
|
||||
ev_row = db._conn.execute(
|
||||
"SELECT description FROM events WHERE video_id=?", (vid,)).fetchone()
|
||||
assert ev_row["description"] == "媳妇双手叉腰站在客厅中央;爸爸在远处厨房;儿童已离开画面。"
|
||||
|
||||
v_row = db._conn.execute(
|
||||
"SELECT summary_json FROM videos WHERE id=?", (vid,)).fetchone()
|
||||
assert v_row["summary_json"] == "爸爸和媳妇都在客厅活动。"
|
||||
|
||||
|
||||
def test_rewrite_event_person_names_longer_labels_replaced_before_shorter(tmp_path):
|
||||
"""核心诉求: uid 可能带 "#2"/"#3" 这类同名冲突后缀,"人物A" 是 "人物A#2" 的
|
||||
前缀——如果先替换短的 "人物A","人物A#2" 会被错误地部分命中变成"爷爷#2",
|
||||
而不是走它自己在 rename_map 里对应的正确目标。必须长的先替换。"""
|
||||
db = _db(tmp_path)
|
||||
vid = db.ensure_video("motion_3_3000.mp4", "/tmp/motion_3_3000.mp4",
|
||||
event_start_time="2026-08-22 13:00:00")
|
||||
events = [
|
||||
{"timestamp": "13:00:01",
|
||||
"description": "人物A和人物A#2一起在客厅。",
|
||||
"people": ["人物A", "人物A#2"],
|
||||
"person_appearances": [
|
||||
{"uid": "人物A", "features": {"gender": "男"}, "action": "站立"},
|
||||
{"uid": "人物A#2", "features": {"gender": "女"}, "action": "站立"}]},
|
||||
]
|
||||
db.mark_video_processed(vid, "摘要", events, ["人物A", "人物A#2"], "gemini")
|
||||
db.rewrite_event_person_names(vid, {"人物A": "爷爷", "人物A#2": "媳妇"})
|
||||
|
||||
ev_row = db._conn.execute(
|
||||
"SELECT description FROM events WHERE video_id=?", (vid,)).fetchone()
|
||||
assert ev_row["description"] == "爷爷和媳妇一起在客厅。"
|
||||
|
||||
|
||||
def test_rewrite_event_person_names_noop_on_empty_map(tmp_path):
|
||||
db = _db(tmp_path)
|
||||
vid = _seed_video_with_events(db)
|
||||
|
||||
Reference in New Issue
Block a user