Витяг у JSON не означає, що вилучення є правильним: установіть контракти поля для кількості, одиниці та джерела

Те, що результат вилучення можна перетворити на JSON, не означає, що вилучення є правильним. Ця стаття використовує контракти Decimal і поля для перевірки суми, одиниці вимірювання, номера сторінки, оригінального тексту та координат, а також додає детерміновані тести для нормального введення та ненормального введення, щоб помилки можна було зупинити, перш ніж вони потрапили в низхідний поток.

Те, що результат вилучення можна проаналізувати за допомогою JSON, не означає, що його можна зберігати безпосередньо в базі даних. Ця стаття написана для розробників, яким потрібно надсилати дані рахунків і цінових пропозицій у подальші системи. Ми використовуємо синтетичний фрагмент цитати, щоб продемонструвати більш жорсткі межі: крім значення, кожне поле також має одиницю вимірювання, вихідну сторінку, вихідний текст і координати. Парсер або модель відповідає лише за пропонування кандидатів, а детермінований верифікатор визначає, чи можна їх включити в базу даних.

Прочитавши це, ви зможете зрозуміти ідею набору контрактів полів і знатимете, як явно зберегти відсутні та невизначені поля замість заповнення їх нулями за замовчуванням.

Чи можна безпосередньо зберігати результати вилучення в базі даних? Висновок одним реченням

Чи можна його ввести в базу даних, залежить від того, чи проходить перевірка контракту поля та доказів, а не від того, чи можна проаналізувати JSON; поля, які не вдалося перевірити, повинні бути залишені в стані очікування та не можуть бути заповнені нулем за замовчуванням.

ваша ситуаціяРекомендовані практикипричина
Синтаксичний аналізатор повернув дійсний JSONПродовжуйте перевірку контракту на місцях і не зберігайте його безпосередньо в базі даних.JSON означає лише те, що його можна прочитати програмою
Сума не має валюти чи одиниціНе приймайте валюту, зберігайте відсутній статусУникайте таємного отримання юанів
Сума відображається в регіональних форматах, наприклад 1.200,50Визначте контракти окремо для кожного дозволеного форматуРегіональні правила не можна розглядати випадково та одноманітно
Потрібно повернутися до документа, щоб перевіритиЗбережіть номери сторінок, вихідний текст і координати та перевірте діапазони номерів сторінокСприяти позиціонуванню рецензентів
Залучення кількох валют або курсів обмінуПочаткова сума валюти, тип валюти та джерело обмінного курсу зберігаються, і неявна конвертація не виконується.Суми неможливо конвертувати без обмінних курсів

Передайте значення разом із доказом

Передайте рахунок-фактуру або цінову пропозицію синтаксичному аналізатору, і JSON, який ви отримаєте, лише скаже вам, що програма може його прочитати. 1200 Ціна за одиницю чи загальна сума? Де валюта? Відповідно до яких регіональних правил слід розуміти 1.200,50? Чи справді існує повернутий номер сторінки? Синтаксис JSON не може відповісти на ці питання.

Полеобмеженнянавіщо потрібно
сумаДесятковий рядок, приклад обмежений невід’ємними значеннями та двома десятковими знакамиУникайте ненавмисного введення двійкових наближень із плаваючою комою
валютаЦя сцена обмежена в доларах СШАНе варто таємно вважати юань, коли валюти немає
source.pageПочинаючи з 1, кількість сторінок не може перевищувати лімітЦе полегшує користувачам повернення до початкового місця розташування документа
source.quoteЦе має бути фрагмент на сторінці, наданий абонентомПідтвердження може бути надано тим, хто має підставу
source.bboxГраничне значення, розташоване в межах діапазону сторінокЗапобігати видачі порожніх кадрів і недійсних координат як доказ

Координатна одиниця тут — це точка PDF, а початок координат розташований у верхньому лівому куті поточної погодженої сторінки. Спочатку слід уніфікувати системи вгорнього потоку, вирощування культур і координат; координати різних парсерів не слід безпосередньо змішувати. Цей приклад лише демонструє конвенцію і не доводить, що коробка містить текст.

Повне тестування на верифікацію та відмову

Він може працювати лише зі стандартною бібліотекою Python. Decimal слід побудувати з рядків; не конвертуйте його спочатку в float, а потім пропускайте всередину. Для точної десяткової обробки значень зверніться до Десяткова документація Python.

Нижче наведений код — це фактичний результат тесту, а не звіт про точність розпізнавання. Зразковий вхід був написаний нами від руки, і жодної OCR чи оцінки моделі на реальному чеку не проводилися.

from copy import deepcopy
from decimal import Decimal
import math
import re

pages = [{"width": 595, "height": 842,
          "text": "Total: USD 1,200.50\nDelivery within 10 days"}]

def validate(candidate, pages):
    if set(candidate) != {"amount", "currency", "source"}:
        raise ValueError("unexpected or missing field")
    raw = candidate["amount"]
    if not isinstance(raw, str) or not re.fullmatch(r"(?:0|[1-9][0-9]*)\.[0-9]{2}", raw):
        raise ValueError("amount must be a two-decimal string")
    if candidate["currency"] != "USD":
        raise ValueError("unsupported currency for this contract")
    src = candidate["source"]
    if not isinstance(src, dict) or set(src) != {"page", "quote", "bbox"}:
        raise ValueError("source contract mismatch")
    number = src["page"]
    if type(number) is not int or not 1 <= number <= len(pages):
        raise ValueError("page outside document")
    page = pages[number - 1]
    quote = src["quote"]
    if not isinstance(quote, str) or not quote or quote not in page["text"]:
        raise ValueError("source quote not found")
    match = re.fullmatch(r"Total: USD ([0-9]{1,3}(?:,[0-9]{3})*\.[0-9]{2})", quote)
    if not match or Decimal(match[1].replace(",", "")) != Decimal(raw):
        raise ValueError("amount does not agree with source")
    box = src["bbox"]
    if (not isinstance(box, list) or len(box) != 4
            or any(type(v) not in (int, float) or not math.isfinite(v) for v in box)):
        raise ValueError("invalid box values")
    x0, y0, x1, y1 = box
    if not (0 <= x0 < x1 <= page["width"] and 0 <= y0 < y1 <= page["height"]):
        raise ValueError("box outside page or empty")
    return {"amount": str(Decimal(raw)), "currency": "USD", "source": deepcopy(src)}

good = {"amount": "1200.50", "currency": "USD", "source": {
    "page": 1, "quote": "Total: USD 1,200.50", "bbox": [40, 70, 260, 90]}}
assert validate(good, pages)["amount"] == "1200.50"
print("PASS valid source-linked amount: USD 1200.50")
bad_cases = []
wrong = deepcopy(good); wrong["amount"] = "12000.50"; bad_cases.append(wrong)
wrong = deepcopy(good); wrong["source"]["page"] = 2; bad_cases.append(wrong)
wrong = deepcopy(good); wrong["source"]["bbox"][2] = float("nan"); bad_cases.append(wrong)
wrong = deepcopy(good); wrong["source"]["bbox"][0] = 300; bad_cases.append(wrong)
for index, wrong in enumerate(bad_cases, 1):
    try:
        validate(wrong, pages)
        raise AssertionError("bad candidate accepted")
    except ValueError as error:
        print(f"PASS rejection {index}: {error}")

Сувора регулярність — це тому, що сценарій суворий

Ця звичайна форма приймає лише англійський формат суми, показаний у прикладі. Він відхиляє такі ситуації:

  • Евклідова десяткова цифра
  • Від'ємне число
  • Повернення коштів, зазначене в дужках
  • Інші валюти
  • У тисячному місці немає чотиризначних чисел

У реальних системах незалежні контракти слід обирати відповідно до типу документа та регіону, а всі коми, крапки та пробіли не слід видаляти за бажанням.

Перед подальшим розширенням обсягу введення підготуйте позитивні та відхиляючі зразки для кожного дозволеного формату. Якщо купюра багатовалютна, поля мають окремо вказувати початкову суму валюти, валюту та джерело курсу; Без валютних курсів ви не можете таємно конвертувати суми.

📊 Порівняння ядра

Рівні верифікаціїПитання, на які можна відповістиДосі залишилися питання без відповіді
Аналіз JSONЧи може програма прочитати контент?Сума — це ціна одиниці чи загальна сума? Де валюта?
Польовий контрактПеревірте, чи є формат суми, валюта, діапазон номерів сторінки та координати легальнимиПеревірте, чи координатне поле точно охоплює текст
Перевірка джерелЧи існує цитата в тексті поточної сторінки і чи відповідає сума обмеженому форматуЧи представляє банк фактичну фінальну суму бізнесу

«Мати джерело» не означає «доведено»

Програма перевіряє, що цитата існує в тексті поточної сторінки і що її кількість дорівнює цьому обмеженому формату. Вона не перевіряє, чи координатне поле точно містить оригінальний текст, і не визначає, чи є рядок фактичною загальною сумою для бізнесу. Верхній текстовий шар може виникати через неправильний OCR, і на одній сторінці може з'являтися кілька підсумків.

Отже, польовий контракт — це лише перші ворота. Відповідно, потрібні перевірки узгодженості позиціонування, визначення односторінкового визначення кандидатів, перевірки співвідношення субзагального податкового балансу та ручні спотові перевірки. Важливі бізнес-дані слід зберігати у статусі «Очікування перевірки» до проходження цих шлюзів, а не «Підтверджено».

Як реалізувати це у робочому процесі документа

Збережіть оригінальне резюме файлу, обробіть версію для кожного витягнутого запису та збережіть причину відхилення. Процес перекладу також має використовувати той самий польовий аудит: основний текст можна замінити іншими мовами, але відповідність між важливою сумою та одиницею не повинна бути втрачена. Ви можете дізнатися про пов'язані документи через Запис про продукт OmniDoc; Контракти та код у цій статті є незалежними від API продукту і не залежать від жодних неопублікованих інтерфейсів.

🎯 Який метод тобі підходить?

Якщо потрібно працювати з багатовалютними купюрами

Зберігайте початкову суму валюти та тип валюти, а також фіксуйте джерело курсу. Конвертація не здійснюється, якщо немає курсу обміну.

Якщо хочете розширити діапазон форматів введення

Спочатку напишіть приклади позитивного та заперечення для кожного формату, а потім послабте правила без прямого послаблення регебури.

Чи будуть дані використовуватися для фінансових чи бізнес-рішень

Позначте поля як очікувані перевірки та підтверджуйте після узгодженості місцезнаходження, уточнення на одній сторінці та ручних точкових перевірок.

Якщо хочеш перекладати документи

Основний текст можна змінити мовою, але відповідність між сумою та одиницею має бути перевірена і збережена в тому ж полі.

❓ Поширені запитання (FAQ)

1. Якщо JSON може розбирати, чи означає це, що його можна зберігати безпосередньо?

Ні. Парсинг лише означає, що зміст може бути прочитаний програмою; він також вимагає польових контрактів і перевірки доказів.

2. Якщо програма перевіряє пропозицію, чи означає це, що сума має бути правильною?

Ні. Вона лише перевіряє, чи існує цитата в тексті поточної сторінки і що сума відповідає обмеженому формату, не перевіряючи значення загальної суми в координатному полі або бізнесі.

3. Чому відсутня сума не може вважатися нульовою?

Відсутня кількість, невдала верифікація і справжній нуль — це три різні стани, і їх змішування робить неможливим розрізнити далі.

4. Як слід поводитися з багатовалютними купюрами?

Зберігайте відповідно початкову суму та валюту. Не конвертуйте суму, коли немає курсу, і зберігайте джерело курсу.

📝 Резюме

Щоб результати вилучення були корисними, вони покладаються на контракти, докази та прийняття, а не на сам формат JSON. Кожне поле має бути відстежуване до конкретної сторінки документа, а дані, які не перевіряються, залишаються на перевірці до перевірки.

Досвід зараз: завантажте документ, щоб почати переклад, зберігаючи оригінальне форматування

Оновлено 2026-11-14