From 09d95675b5bd9bdcddf2824b8bea9c557a050a7f Mon Sep 17 00:00:00 2001 From: damingishere-coder Date: Sat, 5 Sep 2026 13:12:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=85=81=E8=AE=B8=E6=98=B5=E7=A7=B0?= =?UTF-8?q?=E6=95=B0=E5=AD=97=E7=9A=84=20OCR=20=E7=A9=BA=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/image/fact_verification.py | 38 ++++++++++++++++++++------- tests/test_image_fact_verification.py | 26 ++++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/app/image/fact_verification.py b/app/image/fact_verification.py index e9b8422..61105d1 100644 --- a/app/image/fact_verification.py +++ b/app/image/fact_verification.py @@ -111,6 +111,31 @@ def _numeric_fact_is_allowed(candidate: str, allowed: set[str]) -> bool: return False +def _unverified_numeric_facts( + ocr_text: str, + allowed_numbers: set[str], + evidence_lines: list[str], +) -> tuple[str, ...]: + """逐行判断数字,允许 OCR 仅在真实字母数字昵称中插入空格。""" + + allowed_line_compacts = { + compact + for line in evidence_lines + if len(compact := _compact_text(line)) >= 4 + } + unknown: set[str] = set() + for line in ocr_text.splitlines(): + line_compact = _compact_text(line) + exact_evidence_line = line_compact in allowed_line_compacts + for candidate in _numeric_facts(line): + if _numeric_fact_is_allowed(candidate, allowed_numbers): + continue + if exact_evidence_line: + continue + unknown.add(candidate) + return tuple(sorted(unknown, key=lambda item: (len(item), item))) + + def strip_unverified_prompt_numeric_units(prompt_file: Path) -> tuple[str, tuple[str, ...]]: """去掉摘要擅自附加、但原始证据没有的数字单位。 @@ -275,15 +300,10 @@ def review_image_facts( allowed_numbers = _numeric_facts(numeric_evidence) # 分镜序号属于版式,不是聊天事实。 allowed_numbers.update(str(number) for number in range(0, 11)) - unknown_numeric = tuple( - sorted( - ( - item - for item in _numeric_facts(text) - if not _numeric_fact_is_allowed(item, allowed_numbers) - ), - key=lambda item: (len(item), item), - ) + unknown_numeric = _unverified_numeric_facts( + text, + allowed_numbers, + evidence_lines, ) normalized_lines = [line.strip() for line in text.splitlines() if line.strip()] diff --git a/tests/test_image_fact_verification.py b/tests/test_image_fact_verification.py index a271d17..39138c7 100644 --- a/tests/test_image_fact_verification.py +++ b/tests/test_image_fact_verification.py @@ -84,6 +84,32 @@ def test_allows_ocr_fragments_of_known_numbers_and_ignores_name_garble(tmp_path) assert review.unknown_text == () +def test_allows_ocr_space_inside_evidenced_alphanumeric_sender_name(tmp_path): + prompt, image = _evidence(tmp_path) + messages_path = tmp_path / "messages.json" + messages = json.loads(messages_path.read_text(encoding="utf-8")) + messages.append({"sender_name": "Gaosong925", "content": "推荐 Grok App"}) + messages_path.write_text(json.dumps(messages, ensure_ascii=False), encoding="utf-8") + + review = review_image_facts(prompt, image, ocr_text="Gaosong 925") + + assert review.ok + assert review.unknown_numeric == () + + +def test_rejects_changed_number_in_alphanumeric_sender_name(tmp_path): + prompt, image = _evidence(tmp_path) + messages_path = tmp_path / "messages.json" + messages = json.loads(messages_path.read_text(encoding="utf-8")) + messages.append({"sender_name": "Gaosong925", "content": "推荐 Grok App"}) + messages_path.write_text(json.dumps(messages, ensure_ascii=False), encoding="utf-8") + + review = review_image_facts(prompt, image, ocr_text="Gaosong 926") + + assert not review.ok + assert review.unknown_numeric == ("926",) + + def test_numeric_units_do_not_join_across_ocr_lines(tmp_path): prompt, image = _evidence(tmp_path)