从 CCTV 主页抓取《新闻联播》,下载 → 转 MP3/WAV → 静音切分 → ASR 识别 → LLM 校对 → 切分为单条新闻 → 入库 MySQL。 主要内容: - 全链路:getVideo5 抓取下载、audioRead 转写、deepseek 校对与切分、newsProcess 入库 - 可移植化:配置分层,.env 只放密钥、config.yml 放模型/接入点/路由/参数 - 可换供应商:endpoints(kind/base_url/api_key_env/extra_body)+ routes 按环节选路 - 数据保真:数值事实守卫,校对改动数字/年份/届次则整片回退 ASR 原文; 识别不完整不发布该日精编,避免半天内容被当成完整一天 - 定时任务:systemd 每天 21:00,失败 21:30 / 22:00 重试; 只缺切分时只重跑切分(省掉全部 ASR),用 state/.asr_complete_* 标记判定阶段 - 隧道自愈:13306 不通时自动执行 autossh.sh(所有入口共用,systemd 托管时只等待) - 中间产物每日清理;97 项离线自检(配置/清理/事实守卫/解析/隧道)
70 lines
3.0 KiB
Python
70 lines
3.0 KiB
Python
"""数值事实守卫回归测试(不依赖 pytest)
|
|
|
|
python tests/test_fidelity_guard.py
|
|
|
|
背景:LLM 校对(qwen)曾把 ASR 原文的事实改错——实测样例:
|
|
`自2027年1月1日起施行` -> `自2024年1月1日起施行`
|
|
`第十一届东方经济论坛` -> `第九届东方经济论坛`
|
|
`十五五` -> `十四五`
|
|
因此校对结果在落库前必须通过数值事实守卫:数值被改动则回退 ASR 原文。
|
|
|
|
注意守卫的取向是「宁可保留原文,也不接受 LLM 改数」:
|
|
- 书写形式差异(7 ↔ 七、2026 ↔ 二零二六)必须放行,否则会误伤大量正常校对;
|
|
- 任何真实数值变化必须拦下。
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from audioRead import _number_drift, _number_signature # noqa: E402
|
|
|
|
# (原文, 校对后, 说明, 是否应拦下)
|
|
CASES = [
|
|
# 应当放行:仅书写形式/切分差异
|
|
('7月23号', '七月二十三号', '阿拉伯数字 ↔ 中文数字', False),
|
|
('2026年', '二零二六年', '阿拉伯 ↔ 逐年读法', False),
|
|
('2027年1月1日', '2027年1月1日', '完全相同', False),
|
|
('第十五届', '第十五届', '序数未变', False),
|
|
('增长55%', '增长百分之五十五', '百分比写法差异', False),
|
|
('他3日在莫斯科', '他三日在莫斯科', '日期写法差异', False),
|
|
|
|
# 应当拦下:真实数值改动
|
|
('自2027年1月1日起施行', '自2024年1月1日起施行', '年份篡改(实测样例)', True),
|
|
('第十一届东方经济论坛', '第九届东方经济论坛', '届次篡改(实测样例)', True),
|
|
('十五五规划', '十四五规划', '规划期篡改(实测样例)', True),
|
|
('增长5.3%', '增长5.31%', '小数点篡改', True),
|
|
('55个', '60个', '数量篡改', True),
|
|
('2025年', '2023年', '年份篡改', True),
|
|
('300亿元', '30亿元', '量级篡改', True),
|
|
]
|
|
|
|
|
|
def main():
|
|
failed = 0
|
|
for raw, corrected, desc, expect_flag in CASES:
|
|
only_raw, only_new = _number_drift(raw, corrected)
|
|
flagged = bool(only_raw or only_new)
|
|
if flagged == expect_flag:
|
|
tag = '拦下' if flagged else '放行'
|
|
print(f" ✓ {desc:20} -> {tag} {only_raw}{only_new}")
|
|
else:
|
|
failed += 1
|
|
expect = '拦下' if expect_flag else '放行'
|
|
print(f" ✗ {desc:20} -> 期望{expect},实际{'拦下' if flagged else '放行'} {only_raw}{only_new}")
|
|
|
|
# 签名函数自检:十五五/十四五 必须解析为不同的数值序列
|
|
c1, s1 = _number_signature('十五五规划')
|
|
c2, s2 = _number_signature('十四五规划')
|
|
if c1 != c2:
|
|
print(f" ✓ 缩写解析 十五五={c1} 十四五={c2}(不同)")
|
|
else:
|
|
failed += 1
|
|
print(f" ✗ 缩写解析失败:十五五与十四五都被解析为 {c1}")
|
|
|
|
print(f"\n结果: {'全部通过' if failed == 0 else f'{failed} 项失败'}")
|
|
return 1 if failed else 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main()) |