eduevidence 6.2.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +395 -0
- package/README.md +22 -13
- package/README.zh-CN.md +15 -8
- package/SKILL.md +10 -9
- package/benchmarks/evidence-library.json +277 -1
- package/docs/architecture.md +6 -3
- package/docs/j-ev-experimental.md +250 -0
- package/docs/reproducibility.md +138 -0
- package/domains/_neutral/copy/few_shots.json +21 -0
- package/domains/_neutral/copy/framing_lexicon.json +19 -0
- package/domains/_neutral/copy/module_labels.json +5 -0
- package/domains/_neutral/copy/module_labels_footer.json +102 -0
- package/domains/_neutral/copy/module_labels_modules.json +204 -0
- package/domains/_neutral/copy/module_labels_nav.json +126 -0
- package/domains/_neutral/copy/module_labels_summary.json +98 -0
- package/domains/_neutral/copy/module_labels_tables.json +164 -0
- package/domains/_neutral/copy/module_labels_v2.json +90 -0
- package/domains/_neutral/copy/risk_constructs.json +20 -0
- package/domains/_neutral/copy/section_titles.json +66 -0
- package/domains/_neutral/copy/terminology.json +11 -0
- package/domains/check_copy_packs.py +103 -0
- package/domains/education/copy/few_shots.json +22 -0
- package/domains/education/copy/framing_enums.json +167 -0
- package/domains/education/copy/framing_lexicon.json +166 -0
- package/domains/education/copy/module_labels.json +169 -0
- package/domains/education/copy/risk_constructs.json +48 -0
- package/domains/education/copy/section_titles.json +186 -0
- package/domains/education/copy/terminology.json +70 -0
- package/domains/education/manifest.json +1 -1
- package/domains/education/outcome_taxonomy.json +2 -2
- package/domains/manifest.json +1 -1
- package/domains/policy/copy/few_shots.json +22 -0
- package/domains/policy/copy/framing_enums.json +94 -0
- package/domains/policy/copy/framing_lexicon.json +174 -0
- package/domains/policy/copy/module_labels.json +168 -0
- package/domains/policy/copy/risk_constructs.json +33 -0
- package/domains/policy/copy/section_titles.json +186 -0
- package/domains/policy/copy/terminology.json +64 -0
- package/engine/capabilities.py +57 -5
- package/engine/decision_policy.py +88 -17
- package/engine/library_builtin.py +7 -4
- package/engine/tribunal.py +17 -23
- package/engine/versions.py +1 -1
- package/examples/ai-coding-assistant-evidence/EduEvidence_Report.html +4 -4
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_academic.html +4 -4
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_claude.html +4 -4
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab-dark.html +4 -4
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab.html +4 -4
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_presentation.html +4 -4
- package/examples/spaced-retrieval-practice/EduEvidence_Report.html +2728 -0
- package/examples/spaced-retrieval-practice/report.html +2522 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_academic.html +4 -4
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_claude.html +4 -4
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab-dark.html +4 -4
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab.html +4 -4
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_presentation.html +4 -4
- package/examples/workplace-ai-assistant/EduEvidence_Report.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_academic.html +36 -36
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_claude.html +36 -36
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab-dark.html +36 -36
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab.html +36 -36
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_presentation.html +36 -36
- package/integrations/jev/__init__.py +115 -0
- package/integrations/jev/approval.py +212 -0
- package/integrations/jev/cli.py +84 -0
- package/integrations/jev/config.py +112 -0
- package/integrations/jev/gateway.py +128 -0
- package/integrations/jev/modes.py +38 -0
- package/integrations/jev/tools_classify.py +88 -0
- package/integrations/jev/tools_extract.py +111 -0
- package/integrations/jev/tools_rerank.py +71 -0
- package/integrations/jev/tools_screen.py +87 -0
- package/integrations/jev/tools_verify.py +95 -0
- package/integrations/jev_mcp.py +22 -0
- package/integrations/semantic_decide.py +286 -0
- package/integrations/semdecide_cli.py +55 -0
- package/package.json +9 -1
- package/pyproject.toml +1 -1
- package/references/report-copy-style.md +43 -3
- package/schemas/v2/decision-snapshot.schema.json +20 -9
- package/schemas/v2/intake.schema.json +191 -0
- package/scripts/build_evidence_library.py +15 -5
- package/scripts/dashboard_server.py +13 -2
- package/scripts/intake/__init__.py +31 -0
- package/scripts/intake/__main__.py +18 -0
- package/scripts/intake/background.py +78 -0
- package/scripts/intake/browser.py +79 -0
- package/scripts/intake/cli.py +57 -0
- package/scripts/intake/constants.py +57 -0
- package/scripts/intake/depth.py +53 -0
- package/scripts/intake/enhancements.py +106 -0
- package/scripts/intake/hooks.py +90 -0
- package/scripts/intake/prefs.py +76 -0
- package/scripts/intake/prompts.py +85 -0
- package/scripts/intake/session.py +152 -0
- package/scripts/lint_file_layers.py +126 -0
- package/scripts/orchestrator.py +68 -17
- package/scripts/pre_verdict_gate.py +21 -7
- package/scripts/skill_lint.py +11 -1
- package/scripts/skill_payload.py +3 -3
- package/scripts/test_adversarial_empirical.py +70 -6
- package/skill/agents/evidence-judge.md +49 -7
- package/skill/workflows/experimental-jev.md +170 -0
- package/skill/workflows/intake.md +120 -0
- package/visualization/eduevidence-report/scripts/build_infographics.py +32 -14
- package/visualization/eduevidence-report/scripts/build_report.py +75 -662
- package/visualization/eduevidence-report/scripts/report_copy_pack.py +296 -0
- package/visualization/eduevidence-report/scripts/report_copy_policy_guard.py +47 -0
- package/visualization/eduevidence-report/scripts/zh_labels.py +61 -0
- package/scripts/build_esl_artifacts.py +0 -1921
- package/scripts/build_killer_demo.py +0 -295
- package/scripts/enrich_projects_human_and_lieflat.py +0 -315
- package/scripts/generate_new_projects.py +0 -686
- package/scripts/sync_killer_demo_report.py +0 -270
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
"""scripts/sync_killer_demo_report.py — Synchronizes the 50-study SSOT EvidenceGraph into result.json and renders EduEvidence_Report.html."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import json
|
|
5
|
-
import subprocess
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
ROOT = Path(__file__).resolve().parent.parent
|
|
10
|
-
if str(ROOT) not in sys.path:
|
|
11
|
-
sys.path.insert(0, str(ROOT))
|
|
12
|
-
|
|
13
|
-
from engine.evidence_graph import EvidenceGraph
|
|
14
|
-
|
|
15
|
-
def sync_report():
|
|
16
|
-
target_dir = ROOT / "examples" / "ai-coding-assistant-50"
|
|
17
|
-
target_dir.mkdir(parents=True, exist_ok=True)
|
|
18
|
-
graph_file = target_dir / "evidence_graph.json"
|
|
19
|
-
result_en_file = target_dir / "result.json"
|
|
20
|
-
result_zh_file = target_dir / "result.zh.json"
|
|
21
|
-
|
|
22
|
-
if not graph_file.exists():
|
|
23
|
-
# Fallback to build_killer_demo
|
|
24
|
-
from scripts.build_killer_demo import export_all
|
|
25
|
-
export_all()
|
|
26
|
-
|
|
27
|
-
graph = EvidenceGraph.from_json(graph_file.read_text(encoding="utf-8"))
|
|
28
|
-
|
|
29
|
-
orig_en = ROOT / "examples" / "ai-coding-assistant" / "result.json"
|
|
30
|
-
orig_zh = ROOT / "examples" / "ai-coding-assistant" / "result.zh.json"
|
|
31
|
-
en_data = json.loads(result_en_file.read_text(encoding="utf-8")) if result_en_file.exists() else (json.loads(orig_en.read_text(encoding="utf-8")) if orig_en.exists() else {})
|
|
32
|
-
zh_data = json.loads(result_zh_file.read_text(encoding="utf-8")) if result_zh_file.exists() else (json.loads(orig_zh.read_text(encoding="utf-8")) if orig_zh.exists() else {})
|
|
33
|
-
|
|
34
|
-
# 1. Update Sources
|
|
35
|
-
sources_en = []
|
|
36
|
-
sources_zh = []
|
|
37
|
-
for p in graph.papers.values():
|
|
38
|
-
s_item = {
|
|
39
|
-
"source_id": p.paper_id,
|
|
40
|
-
"title": p.title,
|
|
41
|
-
"authors": p.authors,
|
|
42
|
-
"year": p.year,
|
|
43
|
-
"venue": p.venue,
|
|
44
|
-
"doi": p.doi,
|
|
45
|
-
"canonical_url": p.url or f"https://doi.org/{p.doi}",
|
|
46
|
-
"authority_level": f"tier{p.authority_tier}_peer_reviewed",
|
|
47
|
-
"source_location": p.url or f"https://doi.org/{p.doi}",
|
|
48
|
-
}
|
|
49
|
-
sources_en.append(s_item)
|
|
50
|
-
sources_zh.append(s_item)
|
|
51
|
-
|
|
52
|
-
en_data["sources"] = sources_en
|
|
53
|
-
zh_data["sources"] = sources_zh
|
|
54
|
-
|
|
55
|
-
# 2. Update Evidence array
|
|
56
|
-
ev_list_en = []
|
|
57
|
-
ev_list_zh = []
|
|
58
|
-
|
|
59
|
-
for ev in graph.evidence.values():
|
|
60
|
-
paper = graph.papers.get(ev.paper_id)
|
|
61
|
-
val = ev.effect_size.get("value", 0.0)
|
|
62
|
-
|
|
63
|
-
# Canonical outcome mapping matching existing outcome taxonomy tokens
|
|
64
|
-
if ev.outcome_dimension == "PROCEDURAL_EFFICIENCY":
|
|
65
|
-
otype = "completion_time"
|
|
66
|
-
otype_zh = "completion_time"
|
|
67
|
-
elif ev.outcome_dimension == "INDEPENDENT_TRANSFER":
|
|
68
|
-
otype = "independent_problem_solving"
|
|
69
|
-
otype_zh = "independent_problem_solving"
|
|
70
|
-
elif ev.outcome_dimension == "CONCEPTUAL_MASTERY":
|
|
71
|
-
otype = "code_quality"
|
|
72
|
-
otype_zh = "code_quality"
|
|
73
|
-
else:
|
|
74
|
-
otype = "ai_dependency"
|
|
75
|
-
otype_zh = "ai_dependency"
|
|
76
|
-
|
|
77
|
-
ev_en_item = {
|
|
78
|
-
"evidence_id": ev.evidence_id,
|
|
79
|
-
"source_id": ev.paper_id,
|
|
80
|
-
"title": paper.title if paper else ev.paper_id,
|
|
81
|
-
"study_label": f"{paper.authors[0] if paper and paper.authors else ev.paper_id} ({paper.year if paper else 2024})",
|
|
82
|
-
"year": paper.year if paper else 2024,
|
|
83
|
-
"outcome_type": otype,
|
|
84
|
-
"outcome_dimension": ev.outcome_dimension,
|
|
85
|
-
"outcome_metric": ev.outcome_metric,
|
|
86
|
-
"effect_direction": "positive" if val > 0.10 else ("negative" if val < -0.05 else "null"),
|
|
87
|
-
"relation_to_claim": "support" if ev.direction == "SUPPORTS" else ("contradict" if ev.direction == "CONTRADICTS" else "neutral"),
|
|
88
|
-
"effect_size": ev.effect_size,
|
|
89
|
-
"sample_size": ev.sample_size,
|
|
90
|
-
"study_design": ev.study_design,
|
|
91
|
-
"quality_score": int(ev.confidence_score * 10),
|
|
92
|
-
"wwc_rating": ev.wwc_rating,
|
|
93
|
-
"url": paper.url if paper else f"https://doi.org/{ev.paper_id}",
|
|
94
|
-
"key_quote": ev.key_quote,
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
ev_zh_item = dict(ev_en_item)
|
|
98
|
-
ev_zh_item["outcome_type"] = otype
|
|
99
|
-
ev_zh_item["outcome_metric"] = ev.outcome_metric
|
|
100
|
-
|
|
101
|
-
ev_list_en.append(ev_en_item)
|
|
102
|
-
ev_list_zh.append(ev_zh_item)
|
|
103
|
-
|
|
104
|
-
en_data["evidence"] = ev_list_en
|
|
105
|
-
zh_data["evidence"] = ev_list_zh
|
|
106
|
-
|
|
107
|
-
# Compute outcomes array dynamically from evidence to pass integrity gate
|
|
108
|
-
outcome_buckets: dict[str, dict] = {}
|
|
109
|
-
for ev in ev_list_en:
|
|
110
|
-
ot = ev["outcome_type"]
|
|
111
|
-
if ot not in outcome_buckets:
|
|
112
|
-
outcome_buckets[ot] = {
|
|
113
|
-
"outcome_type": ot,
|
|
114
|
-
"positive_count": 0,
|
|
115
|
-
"negative_count": 0,
|
|
116
|
-
"null_count": 0,
|
|
117
|
-
"evidence_ids": [],
|
|
118
|
-
}
|
|
119
|
-
edir = ev["effect_direction"]
|
|
120
|
-
if edir == "positive":
|
|
121
|
-
outcome_buckets[ot]["positive_count"] += 1
|
|
122
|
-
elif edir == "negative":
|
|
123
|
-
outcome_buckets[ot]["negative_count"] += 1
|
|
124
|
-
else:
|
|
125
|
-
outcome_buckets[ot]["null_count"] += 1
|
|
126
|
-
outcome_buckets[ot]["evidence_ids"].append(ev["evidence_id"])
|
|
127
|
-
|
|
128
|
-
en_data["outcomes"] = list(outcome_buckets.values())
|
|
129
|
-
zh_data["outcomes"] = list(outcome_buckets.values())
|
|
130
|
-
|
|
131
|
-
# 3. Update Claims
|
|
132
|
-
claims_en = []
|
|
133
|
-
claims_zh = []
|
|
134
|
-
for c in graph.claims.values():
|
|
135
|
-
c_item_en = {
|
|
136
|
-
"claim_id": c.claim_id,
|
|
137
|
-
"statement": c.statement,
|
|
138
|
-
"status": "supported" if c.status == "SUPPORTED" else ("contradicted" if c.status == "CONTRADICTED" else "uncertain"),
|
|
139
|
-
"evidence_ids": c.evidence_ids,
|
|
140
|
-
"bias_warning": c.bias_warning,
|
|
141
|
-
"pooled_effect_g": c.pooled_effect_g,
|
|
142
|
-
}
|
|
143
|
-
c_item_zh = dict(c_item_en)
|
|
144
|
-
claims_en.append(c_item_en)
|
|
145
|
-
claims_zh.append(c_item_zh)
|
|
146
|
-
|
|
147
|
-
en_data["claims"] = claims_en
|
|
148
|
-
zh_data["claims"] = claims_zh
|
|
149
|
-
|
|
150
|
-
# 4. Update Decision with plain-language structured takeaways
|
|
151
|
-
en_data["decision"] = {
|
|
152
|
-
"verdict": "PILOT",
|
|
153
|
-
"recommended_action": "PILOT",
|
|
154
|
-
"confidence_score": 0.89,
|
|
155
|
-
"confidence": "High",
|
|
156
|
-
"strongest_support": "In-task programming completion time is shortened by 35%-50% with significant velocity gain (pooled g = +0.61, p < 0.001) in guided environments.",
|
|
157
|
-
"key_uncertainty": "Delayed unassisted solo exams and transfer performance decline significantly (pooled g = -0.28, p = 0.012) once scaffolding is removed.",
|
|
158
|
-
"main_risk": "Scaffolding Dependency Trap: Over-reliance on code completion degrades novice debugging, boundary testing, and fundamental computational thinking.",
|
|
159
|
-
"next_action": "Execute restricted classroom pilot: ① Enforce Socratic guidance instead of direct code generation; ② Implement 4-phase scaffolding fading; ③ Anchor summative grading in unassisted closed-book exams.",
|
|
160
|
-
"what_can_be_claimed": [
|
|
161
|
-
"In-task programming completion time is shortened by 35%-50% with significant velocity gain (pooled g = +0.61, p < 0.001) in guided environments."
|
|
162
|
-
],
|
|
163
|
-
"uncertain_claims": [
|
|
164
|
-
"Delayed unassisted solo exams and transfer performance decline significantly (pooled g = -0.28, p = 0.012) once scaffolding is removed."
|
|
165
|
-
],
|
|
166
|
-
"rationale": graph.decision.rationale,
|
|
167
|
-
"applicability_boundary": graph.decision.applicability_boundary,
|
|
168
|
-
"stop_conditions": graph.decision.stop_conditions,
|
|
169
|
-
}
|
|
170
|
-
zh_data["decision"] = {
|
|
171
|
-
"verdict": "PILOT",
|
|
172
|
-
"recommended_action": "PILOT",
|
|
173
|
-
"confidence_score": 0.89,
|
|
174
|
-
"confidence": "High",
|
|
175
|
-
"strongest_support": "即时编程任务编写耗时缩短 35%~50%,代码完成速度显著提升(综合效应量 g = +0.61, p < 0.001),在当堂受控实验中展现明显效率增益。",
|
|
176
|
-
"key_uncertainty": "撤除 AI 后的独立闭卷期末考试与概念迁移表现显著下滑(综合效应量 g = -0.28, p = 0.012),学生存在‘看似学会、实则不会’的认知盲区。",
|
|
177
|
-
"main_risk": "认知脚手架依赖陷阱(Scaffolding Dependency Trap):过度依赖实时代码补全导致学生自主调试排错、边界测试与底层计算思维出现退化。",
|
|
178
|
-
"next_action": "建议开展限制性教学试点:① 采用苏格拉底式概念引导,严禁直接给答案;② 实行 4 阶段脚手架渐进剥离;③ 坚持以无 AI 闭卷机试与独立随访作为最终考核标准。",
|
|
179
|
-
"what_can_be_claimed": [
|
|
180
|
-
"即时编程任务编写耗时缩短 35%~50%,代码完成速度显著提升(综合效应量 g = +0.61, p < 0.001),在当堂受控实验中展现明显效率增益。"
|
|
181
|
-
],
|
|
182
|
-
"uncertain_claims": [
|
|
183
|
-
"撤除 AI 后的独立闭卷期末考试与概念迁移表现显著下滑(综合效应量 g = -0.28, p = 0.012),学生存在‘看似学会、实则不会’的认知盲区。"
|
|
184
|
-
],
|
|
185
|
-
"rationale": graph.decision.rationale,
|
|
186
|
-
"applicability_boundary": graph.decision.applicability_boundary,
|
|
187
|
-
"stop_conditions": graph.decision.stop_conditions,
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
# Add Forest plot data
|
|
191
|
-
en_data["forest_plot_data"] = graph.get_forest_plot_data()[:12]
|
|
192
|
-
zh_data["forest_plot_data"] = graph.get_forest_plot_data()[:12]
|
|
193
|
-
|
|
194
|
-
# W6: outcome_mapping 从 evidence 确定性重算(消灭 stale 计数,与证据方向一致)
|
|
195
|
-
from collections import OrderedDict
|
|
196
|
-
|
|
197
|
-
def _dir_of(ev):
|
|
198
|
-
d = (ev.get("relation_to_claim") or ev.get("direction")
|
|
199
|
-
or ev.get("effect_direction") or "").lower()
|
|
200
|
-
if d in ("support", "supports", "positive", "pos"):
|
|
201
|
-
return "support"
|
|
202
|
-
if d in ("contradict", "contradicts", "negative", "neg"):
|
|
203
|
-
return "contradict"
|
|
204
|
-
return "neutral"
|
|
205
|
-
|
|
206
|
-
def rebuild_outcome_mapping(evidence_list, declared):
|
|
207
|
-
agg = OrderedDict()
|
|
208
|
-
for ev in evidence_list:
|
|
209
|
-
ot = ev.get("outcome_type") or ev.get("outcome") or "other"
|
|
210
|
-
bucket = agg.setdefault(ot, {"support": 0, "contradict": 0,
|
|
211
|
-
"neutral": 0, "evidence_ids": []})
|
|
212
|
-
bucket[_dir_of(ev)] += 1
|
|
213
|
-
eid = ev.get("evidence_id")
|
|
214
|
-
if eid and eid not in bucket["evidence_ids"]:
|
|
215
|
-
bucket["evidence_ids"].append(eid)
|
|
216
|
-
entries = []
|
|
217
|
-
for ot, b in agg.items():
|
|
218
|
-
status = ("supported" if b["support"] and not b["contradict"] else
|
|
219
|
-
"contradicted" if b["contradict"] and not b["support"] else
|
|
220
|
-
"mixed" if b["support"] and b["contradict"] else "no_evidence")
|
|
221
|
-
entries.append({
|
|
222
|
-
"outcome_type": ot,
|
|
223
|
-
"declared_in_frame": ot in declared,
|
|
224
|
-
"status": status,
|
|
225
|
-
"support_count": b["support"],
|
|
226
|
-
"contradict_count": b["contradict"],
|
|
227
|
-
"neutral_count": b["neutral"],
|
|
228
|
-
"evidence_ids": b["evidence_ids"],
|
|
229
|
-
})
|
|
230
|
-
return {"generated_by": "sync_killer_demo_report.rebuild_outcome_mapping",
|
|
231
|
-
"entries": entries}
|
|
232
|
-
|
|
233
|
-
frame_outcomes = set()
|
|
234
|
-
for k in ("primary", "secondary"):
|
|
235
|
-
for o in (((en_data.get("research_frame") or {}).get("outcomes") or {}).get(k) or []):
|
|
236
|
-
frame_outcomes.add(o)
|
|
237
|
-
om_en = rebuild_outcome_mapping(ev_list_en, frame_outcomes)
|
|
238
|
-
om_zh = rebuild_outcome_mapping(ev_list_zh, frame_outcomes)
|
|
239
|
-
en_data["outcome_mapping"] = om_en
|
|
240
|
-
zh_data["outcome_mapping"] = om_zh
|
|
241
|
-
|
|
242
|
-
# Write updated result files
|
|
243
|
-
result_en_file.write_text(json.dumps(en_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
244
|
-
result_zh_file.write_text(json.dumps(zh_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
245
|
-
print(f"[+] Synced {len(ev_list_en)} evidence nodes & {len(claims_en)} claims to result.json; "
|
|
246
|
-
f"outcome_mapping rebuilt ({len(om_en['entries'])} entries)")
|
|
247
|
-
|
|
248
|
-
# Render publication figures
|
|
249
|
-
cmd_fig = [
|
|
250
|
-
sys.executable,
|
|
251
|
-
str(ROOT / "visualization" / "eduevidence-report" / "scripts" / "build_figures.py"),
|
|
252
|
-
"--result", str(result_en_file),
|
|
253
|
-
"--out-dir", str(target_dir / "figures"),
|
|
254
|
-
]
|
|
255
|
-
subprocess.run(cmd_fig, check=True)
|
|
256
|
-
|
|
257
|
-
# Render single-file bilingual HTML report
|
|
258
|
-
cmd_rep = [
|
|
259
|
-
sys.executable,
|
|
260
|
-
str(ROOT / "visualization" / "eduevidence-report" / "scripts" / "build_report.py"),
|
|
261
|
-
"--result", str(result_en_file),
|
|
262
|
-
"--result-zh", str(result_zh_file),
|
|
263
|
-
"--out", str(target_dir / "EduEvidence_Report.html"),
|
|
264
|
-
]
|
|
265
|
-
subprocess.run(cmd_rep, check=True)
|
|
266
|
-
print(f"[+] Rendered single-file HTML report: {target_dir / 'EduEvidence_Report.html'}")
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if __name__ == "__main__":
|
|
270
|
-
sync_report()
|