Извлечение в JSON не означает, что извлечение правильное: установите полевые контракты на сумму, единицу измерения и источник

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

— Валидатор определяет, можно ли его поместить в базу данных. Если он отсутствует или неопределенен, его следует сохранить явно и по умолчанию его нельзя заполнить нулем.

  • Совпадение цитат лишь демонстрирует, что исходный текст существует и что суммы согласованы, но не доказывает, что система координат точна или что истинная общая сумма акта является точной.

– Важные данные, которые не соответствуют единообразному позиционированию, устранению неоднозначности на одной странице и выборке вручную, должны быть помечены как ожидающие проверки, а не подтвержденные.

Тот факт, что результат извлечения может быть проанализирован с помощью JSON, не означает, что его можно напрямую сохранить в базе данных. Эта статья написана для разработчиков, которым необходимо отправлять данные о счетах и предложениях в последующие системы. Мы используем фрагмент синтетической цитаты, чтобы продемонстрировать более строгие границы: помимо значения, каждое поле имеет еще единицу измерения, исходную страницу, исходный текст и координаты. Анализатор или модель отвечает только за предложение кандидатов, а детерминированный верификатор определяет, могут ли они быть включены в базу данных.

Прочитав это, вы сможете уловить идею набора контрактов полей и узнать, как явно сохранять отсутствующие и неопределенные поля вместо заполнения их нулями по умолчанию.

Могут ли результаты извлечения храниться непосредственно в базе данных? Вывод в одно предложение

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

твоя ситуацияРекомендуемые практикипричина
Парсер вернул действительный JSON.Продолжайте выполнять проверку контракта на местах и не сохраняйте его напрямую в базе данных.JSON означает только то, что программа может его прочитать.
Сумма не имеет валюты или единицы измерения.Не принимайте валюту, сохраняйте статус отсутствующегоИзбегайте тайного предположения ПКМ
Сумма отображается в региональных форматах, таких как 1.200,50.Определите контракты отдельно для каждого разрешенного формата.Региональные правила не могут применяться случайно и единообразно.
Нужно вернуться к документу и проверитьСохраняйте номера страниц, исходный текст и координаты, а также проверяйте диапазоны номеров страниц.Облегчить позиционирование рецензентов
Использование нескольких валют или обменных курсовИсходная сумма валюты, тип валюты и источник обменного курса сохраняются, неявное преобразование не выполняется.Суммы не могут быть конвертированы без обменных курсов

Передайте значение вместе с доказательствами

Передайте счет или коммерческое предложение анализатору, и полученный вами JSON сообщит вам лишь о том, что программа может его прочитать. 1200 Это цена за единицу или общая сумма? Где валюта? По каким региональным правилам следует понимать 1.200,50? Действительно ли возвращенный номер страницы существует? Это не те вопросы, на которые может ответить синтаксис JSON.

Полеограничениезачем нужен
количествоДесятичная строка — пример неотрицательного и двухзначного десятичного знакаИзбегайте непреднамеренного введения двоичных аппроксимаций с плавающей запятой.
currencyЭтот сценарий ограничен долларами СШАНе рассчитывайте тайно на юань, если валюты нет.
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