feat: export core Hermes skills

This commit is contained in:
2026-07-15 02:45:56 +00:00
parent a028b63eda
commit 54711fee2a
308 changed files with 41310 additions and 1 deletions
@@ -0,0 +1,232 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
OCR完整性检查 / OCR Integrity Check
==================================
物理依赖链第一环:OCR → 建表
检查OCR后的.md文件是否有未补全的乱码/占位符。
如果有,拒绝生成checkpoint,建表脚本将因此中止。
用法:
python3 ocr-integrity-check.py <工作目录>
检查模式:
1. 公司名乱码:连续3+英文字母出现在中文语境中(如"HAT"代替公司名)
2. 地址残缺:【…】、〔…〕、"了 B}"等占位符模式
3. 关键数字乱码:字母代替数字(如"5 1 te"代替"号1幢"
4. OCR标记残留:OCR模糊、OCR无法识别、待补全等
通过 → 生成 step1.verified checkpoint(含签名)
失败 → 列出所有需要vision补全的字段,不生成checkpoint
退出码:0=通过,1=有问题需补全
🔴 安全机制:checkpoint文件包含HMAC签名,防止手动创建
"""
import sys, os, re, json, glob, hmac, hashlib
from datetime import datetime
# checkpoint签名密钥(固定值,脚本内置)
CHECKPOINT_SECRET = b'ocr-integrity-check-v1-2026-06-29'
def generate_checkpoint_signature(workdir, md_files, timestamp):
"""生成checkpoint签名"""
# 签名内容:工作目录+文件列表+时间戳
sign_content = f"{workdir}|{','.join(sorted(md_files))}|{timestamp}"
sig = hmac.new(CHECKPOINT_SECRET, sign_content.encode('utf-8'), hashlib.sha256).hexdigest()
return sig[:16] # 取前16位
def check_ocr_file(md_path):
"""检查单个.md文件的OCR完整性"""
issues = []
with open(md_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = content.split('\n')
# 模式1:公司名乱码 - 连续3+大写字母或混合大小写英文(中文语境中)
# 例如:"HAT CP RRA)" 应该是公司名
company_garble = re.finditer(r'[A-Z]{3,}(?:\s+[A-Z]{2,}){0,2}', content)
for m in company_garble:
# 排除常见的合理英文(如OCR、PDF、API等)
if m.group() not in ['OCR', 'PDF', 'API', 'URL', 'HTTP', 'HTTPS', 'JSON', 'XML', 'LOGO', 'EMS', 'WPS',
'PAGE', 'REMARK', 'NOTE', 'TODO', 'FIXME', 'HACK', 'XXX', 'EOF']:
# 排除统一社会信用代码中的字母部分(前后有数字的字母序列)
pre = content[max(0, m.start()-2):m.start()]
post = content[m.end():min(len(content), m.end()+2)]
if (pre and pre[-1:].isdigit()) or (post and post[:1].isdigit()):
continue # 信用代码中的字母,跳过
line_num = content[:m.start()].count('\n') + 1
context_start = max(0, m.start() - 20)
context_end = min(len(content), m.end() + 20)
context = content[context_start:context_end].replace('\n', ' ')
issues.append({
'type': '公司名乱码',
'line': line_num,
'pattern': m.group(),
'context': f"...{context}...",
'fix': '用vision看原图,补全公司全称'
})
# 模式2:地址残缺占位符
placeholder_patterns = [
(r'\.{1,5}】', '中文省略号占位符'),
(r'【…】', '中文省略号占位符'),
(r'\.{1,5}〕', '方括号省略号占位符'),
(r'\s*[A-Za-z0-9]}', '地址残缺模式(如"了 B}"'),
]
for pat, desc in placeholder_patterns:
for m in re.finditer(pat, content):
line_num = content[:m.start()].count('\n') + 1
context_start = max(0, m.start() - 20)
context_end = min(len(content), m.end() + 20)
context = content[context_start:context_end].replace('\n', ' ')
issues.append({
'type': desc,
'line': line_num,
'pattern': m.group(),
'context': f"...{context}...",
'fix': '用vision看原图,补全完整地址'
})
# 模式3:OCR标记残留
ocr_markers = [
r'OCR模糊',
r'OCR无法识别',
r'OCR乱码',
r'OCR识别失败',
r'待补全',
r'〔待核PDF〕',
r'〔待核〕',
]
for marker in ocr_markers:
for m in re.finditer(marker, content):
line_num = content[:m.start()].count('\n') + 1
context_start = max(0, m.start() - 15)
context_end = min(len(content), m.end() + 15)
context = content[context_start:context_end].replace('\n', ' ')
issues.append({
'type': 'OCR标记残留',
'line': line_num,
'pattern': m.group(),
'context': f"...{context}...",
'fix': '用vision看原图补全,删除标记'
})
# 模式4:关键字段中的字母代替数字
# 例如:"5 1 te 202" 应该是 "号1幢202"
# 检测:中文+空格+单个字母+空格+数字 的模式
digit_garble = re.finditer(r'[\u4e00-\u9fff]\s+[a-zA-Z]\s+\d{2,4}', content)
for m in digit_garble:
line_num = content[:m.start()].count('\n') + 1
context_start = max(0, m.start() - 10)
context_end = min(len(content), m.end() + 10)
context = content[context_start:context_end].replace('\n', ' ')
issues.append({
'type': '数字乱码(字母代替)',
'line': line_num,
'pattern': m.group(),
'context': f"...{context}...",
'fix': '用vision看原图,确认正确数字'
})
# 模式5:严重乱码段落(连续3+英文无义词,如"peMet iy ecsapae"、"Fak"开头)
# 表明该区域OCR完全失败,不可用于模版比对
garble_patterns = re.finditer(r'(?:[a-zA-Z]{3,}\s+){2,}[a-zA-Z]{2,}', content)
for m in garble_patterns:
# 排除已知英文短语
text = m.group().strip()
if any(kw in text.lower() for kw in ['page', 'total', 'remark', 'note']):
continue
line_num = content[:m.start()].count('\n') + 1
context_start = max(0, m.start() - 15)
context_end = min(len(content), m.end() + 15)
context = content[context_start:context_end].replace('\n', ' ')
issues.append({
'type': '严重乱码段落(OCR完全失败)',
'line': line_num,
'pattern': text[:40],
'context': f"...{context[:60]}...",
'fix': '该区域OCR不可读,必须vision核实原文后才能写入比对报告'
})
return issues
def main():
if len(sys.argv) < 2:
print("用法: python3 ocr-integrity-check.py <工作目录>")
print("例: python3 ocr-integrity-check.py /tmp/人民中路")
sys.exit(1)
workdir = sys.argv[1]
if not os.path.isdir(workdir):
print(f"❌ 工作目录不存在: {workdir}")
sys.exit(1)
# 查找所有OCR产出的.md文件
md_files = glob.glob(os.path.join(workdir, '*.md'))
md_files += glob.glob(os.path.join(workdir, 'md', '*.md'))
md_files += glob.glob(os.path.join(workdir, 'ocr', '*.md'))
if not md_files:
print(f"❌ 未找到OCR产出的.md文件: {workdir}")
sys.exit(1)
print(f"检查 {len(md_files)} 个OCR文件的完整性...\n")
all_issues = []
for md_file in md_files:
fname = os.path.basename(md_file)
issues = check_ocr_file(md_file)
if issues:
all_issues.append((fname, issues))
checkpoint_path = os.path.join(workdir, 'step1.verified')
if all_issues:
print("❌ OCR完整性检查失败\n")
for fname, issues in all_issues:
print(f" {fname}: {len(issues)} 个问题")
for i, issue in enumerate(issues[:5], 1): # 只显示前5个
print(f" {i}. [{issue['type']}] 第{issue['line']}")
print(f" {issue['context']}")
print(f"{issue['fix']}")
if len(issues) > 5:
print(f" ... 还有 {len(issues) - 5} 个问题")
print(f"\n⛔ 未生成checkpoint: {checkpoint_path}")
print(" 建表脚本将拒绝执行,直到所有问题用vision补全。")
# 写入问题清单供后续处理
issues_log = os.path.join(workdir, 'step1.issues.json')
with open(issues_log, 'w', encoding='utf-8') as f:
json.dump({
'timestamp': datetime.now().isoformat(),
'issues': {fname: issues for fname, issues in all_issues}
}, f, ensure_ascii=False, indent=2)
print(f" 问题清单已保存: {issues_log}")
sys.exit(1)
else:
print("✅ OCR完整性检查通过\n")
for md_file in md_files:
print(f"{os.path.basename(md_file)}")
# 生成checkpoint(含签名)
timestamp = datetime.now().isoformat()
signature = generate_checkpoint_signature(workdir, md_files, timestamp)
with open(checkpoint_path, 'w', encoding='utf-8') as f:
f.write(f"OCR完整性检查通过\n")
f.write(f"时间: {timestamp}\n")
f.write(f"文件数: {len(md_files)}\n")
for md_file in md_files:
f.write(f" - {os.path.basename(md_file)}\n")
f.write(f"签名: {signature}\n")
print(f"\n✓ checkpoint已生成: {checkpoint_path}")
print(f" 签名: {signature}")
sys.exit(0)
if __name__ == '__main__':
main()