feat(question_gen): AnchorContext + 12 题型-层级映射常量

- AnchorContext frozen dataclass: 锚节点生成上下文(node_id, card_text, frame_paths, subtitle, distractor_texts)
- TaskTypeSpec frozen dataclass: 题型生成规格(level, needs_frames, frame_count, context_fields)
- TASK_TYPE_LEVEL_MAP: 12 种 Video-MME 题型 → 树层级 + 生成规格映射
- 11 项单元测试覆盖:映射完整性、值类型、层级合法性、frozen 不变性

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 05:10:58 -04:00
parent eb15ab315e
commit 9eb9b86954
2 changed files with 202 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
"""赛题合成核心逻辑 — 节点采样、prompt 构造、去重。
纯函数为主,异步编排仅 generate_one。
通过 DI 接收 VLMProvider / EmbeddingProvider,不 import adapters/。
"""
from __future__ import annotations
from dataclasses import dataclass
@dataclass(frozen=True)
class AnchorContext:
"""锚节点上下文——生成单道题所需的全部素材。
属性:
node_id: 锚节点 ID。
card_text: 锚节点 card 序列化文本。
frame_paths: 帧图片路径列表。
subtitle: 对应字幕(可空)。
distractor_texts: 同视频其他节点摘要(供 VLM 生成干扰项)。
"""
node_id: str
card_text: str
frame_paths: list[str]
subtitle: str
distractor_texts: list[str]
@dataclass(frozen=True)
class TaskTypeSpec:
"""题型的生成规格。
属性:
level: 锚定层级("L3" / "L2" / "L1" / "L1-L2")。
needs_frames: 是否必须提供帧图。
frame_count: 帧数范围描述(如 "1", "2-3", "0-1")。
context_fields: 需要提取的 card 字段元组。
"""
level: str
needs_frames: bool
frame_count: str
context_fields: tuple[str, ...]
# ---------------------------------------------------------------------------
# 12 种 Video-MME 题型 → 树层级 + 生成规格映射
# ---------------------------------------------------------------------------
TASK_TYPE_LEVEL_MAP: dict[str, TaskTypeSpec] = {
# --- L3 单帧题型 ---
"Object Recognition": TaskTypeSpec("L3", True, "1", ("frame_summary",)),
"Attribute Perception": TaskTypeSpec("L3", True, "1", ("frame_summary",)),
"OCR Problems": TaskTypeSpec("L3", True, "1", ("frame_summary",)),
"Spatial Reasoning": TaskTypeSpec("L3", True, "1", ("frame_summary", "spatial_layout")),
"Spatial Perception": TaskTypeSpec("L3", True, "1", ("frame_summary",)),
# --- L2 多帧 / 事件级题型 ---
"Action Recognition": TaskTypeSpec("L2", True, "2-3", ("event_description",)),
"Action Reasoning": TaskTypeSpec("L2", True, "2-3", ("event_description",)),
"Counting Problem": TaskTypeSpec("L2", True, "2-3", ("event_description",)),
"Temporal Perception": TaskTypeSpec("L2", False, "0-1", ("event_description", "time_range")),
# --- L1 / 跨层级题型 ---
"Temporal Reasoning": TaskTypeSpec("L1", True, "per-L2", ("scene_summary",)),
"Information Synopsis": TaskTypeSpec("L1", True, "per-L2", ("scene_summary",)),
"Object Reasoning": TaskTypeSpec("L1-L2", True, "per-L2", ("event_description",)),
}