docs(architecture): 完成技术验证 S1–S4,确定 FR-M2-05/06 目标值

- spikes/:Word 转 PDF(Gotenberg)、格式识别、原句坐标、DeepSeek 抽取四项验证代码与两版提示词;样本派生产物和 .env 不进 git
- tech-validation.md:完整结论。四项都可行:WPS 字体字符集要修正并改用行高调整过的字体;格式识别不需要 Docling;表格内切句待改进;抽取需第三道依据校验与规则兜底
- architecture.md:§3.5 加预处理与字体包,§3.6 证据校验改为三道,§10 回填结论
- 03 功能需求与 decisions.md(TV1):召回 ≥ 99%、采纳准确率 ≥ 95%、页码 100%、高亮正文 ≥ 98% / 表格 ≥ 95%

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-03 12:46:49 +08:00
parent e1a9017cd1
commit 604e889ca4
27 changed files with 1581 additions and 9 deletions

View File

@@ -0,0 +1,37 @@
"""S2 对比:Docling 是否保留斜体 / 下划线。分别喂 DOCX 原文件和规范化 PDF。
用法:python -I docling_check.py <docling 地址> <docx> <pdf> <银标准 JSON>"""
import json, re, sys, time, pathlib, collections
import httpx
base, docx, pdf, silver = sys.argv[1], pathlib.Path(sys.argv[2]), pathlib.Path(sys.argv[3]), json.loads(pathlib.Path(sys.argv[4]).read_text())
OUT = pathlib.Path(__file__).parent / "out"
WS = re.compile(r"[\s ]")
silver_chars = sum(map(len, silver))
def run(path, name, extra):
t = time.monotonic()
data = {"to_formats": ["json"], "do_ocr": "false", **extra}
r = httpx.post(f"{base}/v1/convert/file", files={"files": (name, path.read_bytes())}, data=data, timeout=1800)
dt = round(time.monotonic() - t, 1)
r.raise_for_status()
doc = r.json()["document"]["json_content"]
(OUT / f"docling-{name}.json").write_text(json.dumps(doc, ensure_ascii=False))
fmt = collections.Counter(); iu = []
has_prov_bbox = 0
for item in doc.get("texts", []):
f = item.get("formatting") or {}
txt = WS.sub("", item.get("text", ""))
for k in ("bold", "italic", "underline"):
if f.get(k):
fmt[k] += len(txt)
if f.get("italic") and f.get("underline"):
iu.append(txt)
has_prov_bbox += bool(item.get("prov"))
got = Counter_overlap = sum((collections.Counter("".join(iu)) & collections.Counter("".join(silver))).values())
return {"sec": dt, "texts": len(doc.get("texts", [])), "tables": len(doc.get("tables", [])), "fmt_chars": dict(fmt),
"iu_chars": sum(map(len, iu)), "silver_iu_chars": silver_chars, "iu_char_overlap": round(got / silver_chars, 3),
"texts_with_page_bbox": has_prov_bbox}
res = {"docx": run(docx, "S06.docx", {}), "pdf": run(pdf, "S06.pdf", {"pdf_backend": "dlparse_v4"})}
print(json.dumps(res, ensure_ascii=False, indent=1))
(OUT / "docling-result.json").write_text(json.dumps(res, ensure_ascii=False, indent=1))