Files
Video-Tree-TRM5/app/harness/tree_nodes.py
T

90 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""诊断侧树读取适配:把嵌套 tree.json 展平成诊断消费的扁平 nodes dict。
诊断编排(core/evolution/diagnose.py)期望 tree_data 形如
{"nodes": {node_id: {card, level, time_range}}},但 TRM5 建树产物
store/videos/<vid>/tree.json 是嵌套 {"metadata","roots":[...]}。本模块递归展平,
接通 TRM4→TRM5 迁移时断掉的 ground_truth 加载环。
不走 TreeIndex 对象层:仅 L1Node 有 to_dictapp/tree/index.py:260),L2/L3 为其内部闭包,
且 to_dict 输出无 level、L3 用 timestamp 无 time_range。直接遍历 json 更省且零改建树模块。
"""
from __future__ import annotations
import json
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from pathlib import Path
def load_tree_nodes(store_dir: Path, video_id: str) -> dict[str, Any]:
"""加载单视频 tree.json 并展平成扁平 nodes dict。
参数:
store_dir: store 根目录(含 videos/<video_id>/tree.json)。
video_id: 视频标识。
返回:
{"nodes": {node_id: {"card": dict, "level": int, "time_range": list}}}。
异常:
FileNotFoundError: tree.json 不存在(沿用 factory.py fail-loud 先例)。
ValueError: roots 非 list 或为空、节点缺 id、或节点既无 time_range 又无 timestamp。
关键实现:
level 由遍历深度赋值(root=1/child=2/孙=3),不解析 node_id——node_id 累积式
..._L1_..._L2_..._L3_)用正则首匹配会把 L2/L3 误判成 1。
L3 无 time_range,用 timestamp 合成 [t, t]。
"""
tree_path = store_dir / "videos" / video_id / "tree.json"
if not tree_path.exists():
raise FileNotFoundError(f"树索引文件不存在: {tree_path}(诊断需真实树,P5 fail loud")
tree = json.loads(tree_path.read_text(encoding="utf-8"))
roots = tree.get("roots")
if not isinstance(roots, list) or not roots:
raise ValueError(f"树无有效 roots: {tree_path}")
nodes: dict[str, Any] = {}
def _walk(node: dict[str, Any], level: int) -> None:
node_id = node.get("id")
if not isinstance(node_id, str) or not node_id:
raise ValueError(f"节点缺 id: {tree_path}")
time_range = node.get("time_range")
if time_range is None:
ts = node.get("timestamp")
if ts is None:
raise ValueError(
f"节点既无 time_range 又无 timestamp(树损坏): {node_id} in {tree_path}"
)
time_range = [ts, ts]
nodes[node_id] = {
"card": node.get("card", {}),
"level": level,
"time_range": time_range,
}
for child in node.get("children", []) or []:
_walk(child, level + 1)
for root in roots:
_walk(root, 1)
return {"nodes": nodes}
def load_tree_data_for_videos(store_dir: Path, video_ids: list[str]) -> dict[str, Any]:
"""按一组 video_id 去重加载展平树,供诊断按 video 注入。
参数:
store_dir: store 根目录。
video_ids: 视频标识列表(可含重复,内部按首次出现顺序去重)。
返回:
{video_id: {"nodes": {...}}}。
异常:
同 load_tree_nodes(任一视频树缺失/无效即 fail-loud)。
"""
return {vid: load_tree_nodes(store_dir, vid) for vid in dict.fromkeys(video_ids)}