Spaces:
Sleeping
Sleeping
Download skill/scripts/audit_science.py from cpuai/ahp-development-workstation: direct link, hf CLI and curl.
- Browser
- Download file 3.78 kB
-
https://huggingface.co/spaces/cpuai/ahp-development-workstation/resolve/main/skill/scripts/audit_science.py
- Command line
-
hf download hf://spaces/cpuai/ahp-development-workstation/skill/scripts/audit_science.py
-
curl -L -o audit_science.py https://huggingface.co/spaces/cpuai/ahp-development-workstation/resolve/main/skill/scripts/audit_science.py
3.78 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """Structural evidence and diagram QA gate. Humans must still verify real physics.""" | |
| import argparse,json,re,sys,xml.etree.ElementTree as ET | |
| from pathlib import Path | |
| ROOT=Path(__file__).resolve().parents[1] | |
| def run(strict=True): | |
| d=json.loads((ROOT/'story.json').read_text(encoding='utf-8')) | |
| errors=[];warnings=[] | |
| cl=d.get('claims',[]) | |
| if not cl:errors.append('缺少科学主张及对应证据 claims') | |
| ids=set() | |
| for c in cl: | |
| key=c.get('id') | |
| if not key or key in ids:errors.append('科学主张 ID 不唯一或为空') | |
| ids.add(key) | |
| if not c.get('statement'):errors.append(f'{key}: 主张内容不能为空') | |
| if not c.get('sources') or any(not re.match(r'^https?://',x) for x in c.get('sources',[])): | |
| errors.append(f'{key}: 至少一条可核实的 HTTP(S) 来源') | |
| if not c.get('diagram_truth'):errors.append(f'{key}: 必须列明示意图不容颠倒的科学关系') | |
| if c.get('source_checked') is not True: | |
| warnings.append(f'{key}: 来源尚未由制作者人工/浏览器核对;不得标记已审稿') | |
| covered=set() | |
| scenes=d.get('scenes',[]) | |
| if len(scenes)<3:errors.append('科普视频至少 3 幕:现象、原理、总结') | |
| for i,sc in enumerate(scenes): | |
| sceneid=sc.get('id',f'#{i}') | |
| links=sc.get('claim_ids',[]) | |
| if not links:errors.append(f'{sceneid}: 缺少 claim_ids') | |
| for link in links: | |
| if link not in ids:errors.append(f'{sceneid}: 未知科学主张 {link}') | |
| covered.add(link) | |
| art=sc.get('diagram_svg') or sc.get('image') | |
| if not art: | |
| errors.append(f'{sceneid}: 缺少 diagram_svg/image,不能仅凭标题渲染') | |
| elif sc.get('diagram_svg'): | |
| loc=(ROOT/sc['diagram_svg']).resolve() | |
| if not loc.exists():errors.append(f'{sceneid}: SVG 不存在:{sc["diagram_svg"]}') | |
| else: | |
| txt=loc.read_text(encoding='utf-8') | |
| if 'data-placeholder="true"' in txt: | |
| errors.append(f'{sceneid}: SVG 还是占位画面,禁止发布') | |
| try: ET.fromstring(txt) | |
| except ET.ParseError: errors.append(f'{sceneid}: SVG 语法损坏') | |
| if not sc.get('visual_truth'): | |
| errors.append(f'{sceneid}: 缺少物理关系/方向/颜色/空间约束 visual_truth') | |
| if len(sc.get('heading',''))>22:warnings.append(f'{sceneid}: 标题过长,检查竖屏适配') | |
| if len(sc.get('subtitle',''))>36:warnings.append(f'{sceneid}: 说明文字过长,易与字幕重叠') | |
| for key in ids-covered: warnings.append(f'{key}: 尚未在分镜中展示该科学主张') | |
| v=d.get('voices',{}) | |
| for role,cfg in v.items(): | |
| if not isinstance(cfg,dict) or not cfg.get('speaker'):errors.append(f'{role}: 声音配置不完整') | |
| report={'science_gate_pass':not errors and (not strict or not warnings), 'hard_errors':errors,'human_review_pending':warnings, | |
| 'scientific_truth_manually_verified':False, | |
| 'claims':len(cl),'scenes':len(scenes), | |
| 'note':'本脚本仅检查证据链和示意图规格,不能自动证明光路或公式正确。'} | |
| (ROOT/'output').mkdir(exist_ok=True) | |
| (ROOT/'output/science-audit.json').write_text(json.dumps(report,ensure_ascii=False,indent=2),encoding='utf-8') | |
| print(json.dumps(report,ensure_ascii=False,indent=2)) | |
| return 0 if report['science_gate_pass'] else 2 | |
| if __name__=='__main__': | |
| p=argparse.ArgumentParser();p.add_argument('--allow-unreviewed',action='store_true',help='Only structural drafting; never count as science approval');a=p.parse_args() | |
| sys.exit(run(strict=not a.allow_unreviewed)) | |