#!/usr/bin/env python3
'''Build an interactive HTML review page for PlantGeneBench-100 questions.'''
from __future__ import annotations
import argparse
import json
from collections import Counter
from datetime import datetime
from html import escape
from pathlib import Path
from typing import Any
def load_jsonl(path: Path) -> list[dict[str, Any]]:
rows = []
with path.open('r', encoding='utf-8') as handle:
for lineno, line in enumerate(handle, start=1):
line = line.strip()
if not line:
continue
try:
rows.append(json.loads(line))
except json.JSONDecodeError as exc:
raise SystemExit(f'{path}:{lineno}: invalid JSON: {exc}') from exc
return rows
def pretty(value: Any) -> str:
if value in (None, '', [], {}):
return ''
return json.dumps(value, ensure_ascii=False, indent=2, sort_keys=True)
def inline_list(value: Any) -> str:
if not value:
return ''
if isinstance(value, list):
return ', '.join(str(v) for v in value)
return str(value)
def item_html(task: dict[str, Any], gold_row: dict[str, Any], index: int) -> str:
gold = gold_row.get('gold') or {}
task_id = task.get('task_id', '')
layer = task.get('layer') or task.get('category') or 'unknown'
difficulty = task.get('difficulty', '')
stages = gold.get('target_stages') or gold.get('expected_stages') or []
plan = gold.get('execution_plan') or gold.get('expected_execution_plan') or []
entities = gold.get('entities') or {}
params = gold.get('parameters') or gold.get('required_params') or {}
artifacts = gold.get('artifacts') or {}
must_not = gold.get('must_not_do') or []
must_include = gold.get('must_include') or []
can_execute = gold.get('can_execute')
support_status = gold.get('support_status')
boundary_action = gold.get('boundary_action')
scoring_profile = gold_row.get('scoring_profile') or task.get('scoring_profile') or []
full_task = pretty(task)
full_gold = pretty(gold)
must_not_html = ''.join(f'
'''
def build_html(tasks: list[dict[str, Any]], gold_rows: list[dict[str, Any]], task_path: Path, gold_path: Path) -> str:
gold_by_id = {row['task_id']: row for row in gold_rows}
layers = Counter(task.get('layer') or task.get('category') or 'unknown' for task in tasks)
difficulties = Counter(task.get('difficulty', 'unknown') for task in tasks)
cards = []
for index, task in enumerate(tasks, start=1):
task_id = task.get('task_id')
gold_row = gold_by_id.get(task_id) or {'task_id': task_id, 'gold': {}, 'layer': task.get('layer')}
cards.append(item_html(task, gold_row, index))
data_json = json.dumps([task.get('task_id') for task in tasks], ensure_ascii=False)
generated = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
layer_options = ''.join(f'' for k, v in sorted(layers.items()))
diff_options = ''.join(f'' for k, v in sorted(difficulties.items()))
layer_summary = escape(', '.join(f'{k}={v}' for k, v in sorted(layers.items())))
diff_summary = escape(', '.join(f'{k}={v}' for k, v in sorted(difficulties.items())))
cards_html = ''.join(cards)
return f'''
PlantGeneBench-100 题库修订审阅