feat(question_gen): add generate-v2 CLI subcommand and experiment script
- Add generate-v2 subparser with --config, --store-dir, --db-path, --seed, and --dry-run arguments to tools/generate_questions.py - Implement _run_generate_v2 async handler: config loading, video discovery, DI client construction, TreeIndex loading, pipeline invocation, and result persistence - Add scripts/generate_questions_v2.sh following build_trees.sh conventions (source .env, conda run python path, MODE=mock support) - Update app/question_gen/__init__.py to export full v2 public API: run_pipeline_v2, PipelineConfig, PipelineResult, QuestionFamilySpec, ALL_FAMILIES, CandidateQuestion, generate_one_v2, GateReport, run_gates - Add QuestionGenStore.load_progress() for pipeline resumption - Add integration tests for CLI help and dry-run behavior - Update test_question_gen_api to match expanded __all__ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
"""出题模块 — benchmark 加载、分层采样与赛题合成。"""
|
||||
"""出题模块 — benchmark 加载、分层采样、赛题合成与 v2 出题管线。"""
|
||||
|
||||
from app.question_gen.families import ALL_FAMILIES, QuestionFamilySpec
|
||||
from app.question_gen.gates import GateReport, run_gates
|
||||
from app.question_gen.generator_v2 import CandidateQuestion, generate_one_v2
|
||||
from app.question_gen.loader import load_benchmark, stratified_sample
|
||||
from app.question_gen.pipeline_v2 import PipelineConfig, PipelineResult, run_pipeline_v2
|
||||
from app.question_gen.synthesizer import (
|
||||
TASK_TYPE_LEVEL_MAP,
|
||||
AnchorContext,
|
||||
@@ -9,10 +13,21 @@ from app.question_gen.synthesizer import (
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# v1 接口
|
||||
"load_benchmark",
|
||||
"stratified_sample",
|
||||
"TASK_TYPE_LEVEL_MAP",
|
||||
"AnchorContext",
|
||||
"generate_one",
|
||||
"sample_anchor",
|
||||
# v2 接口
|
||||
"run_pipeline_v2",
|
||||
"PipelineConfig",
|
||||
"PipelineResult",
|
||||
"QuestionFamilySpec",
|
||||
"ALL_FAMILIES",
|
||||
"CandidateQuestion",
|
||||
"generate_one_v2",
|
||||
"GateReport",
|
||||
"run_gates",
|
||||
]
|
||||
|
||||
@@ -380,6 +380,46 @@ class QuestionGenStore:
|
||||
heavy_sampled=row[3] or 0,
|
||||
)
|
||||
|
||||
def load_progress(self) -> dict[str, str]:
|
||||
"""加载已完成 slot 的进度映射(用于断点续跑)。
|
||||
|
||||
从最近一次 running 状态的批次中,读取所有 final_status 非 pending 的 item,
|
||||
聚合为 slot_id → "accepted"|"rejected" 映射。
|
||||
|
||||
若存在同一 slot_id 的多条记录(多次重出),取最终状态:
|
||||
- 任一条 accepted → accepted
|
||||
- 全部 rejected → rejected
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict[str, str]
|
||||
{slot_id: "accepted"|"rejected"} 映射。无进度时返回空 dict。
|
||||
"""
|
||||
# 取最近一次未结束的 run_id
|
||||
row = self._conn.execute(
|
||||
"SELECT run_id FROM question_gen_runs WHERE status='running' "
|
||||
"ORDER BY started_at DESC LIMIT 1",
|
||||
).fetchone()
|
||||
|
||||
if row is None:
|
||||
return {}
|
||||
|
||||
run_id = row[0]
|
||||
rows = self._conn.execute(
|
||||
"SELECT slot_id, final_status FROM question_gen_items "
|
||||
"WHERE run_id=? AND final_status != 'pending'",
|
||||
(run_id,),
|
||||
).fetchall()
|
||||
|
||||
progress: dict[str, str] = {}
|
||||
for slot_id, status in rows:
|
||||
if status == "accepted":
|
||||
progress[slot_id] = "accepted"
|
||||
elif slot_id not in progress:
|
||||
progress[slot_id] = "rejected"
|
||||
|
||||
return progress
|
||||
|
||||
def close(self) -> None:
|
||||
"""关闭数据库连接。"""
|
||||
self._conn.close()
|
||||
|
||||
Reference in New Issue
Block a user