L'estrazione in JSON non significa che l'estrazione sia corretta: stabilire contratti sul campo per importo, unità e fonte

Solo perché il risultato dell'estrazione può essere convertito in JSON non significa che l'estrazione sia corretta. Questo articolo utilizza contratti decimali e di campo per verificare l'importo, l'unità, il numero di pagina, il testo originale e le coordinate e allega test deterministici per input normale e input anomalo, in modo che gli errori possano essere fermati prima che entrino nel downstream.

Solo perché il risultato dell'estrazione può essere analizzato da JSON non significa che possa essere archiviato direttamente nel database. Questo articolo è scritto per gli sviluppatori che devono inviare dati di fatture e preventivi ai sistemi downstream. Utilizziamo un frammento di citazione sintetica per dimostrare confini più rigidi: oltre al valore, ogni campo ha anche l'unità, la pagina di origine, il testo di origine e le coordinate. Il parser o modello è responsabile solo di proporre i candidati e il verificatore deterministico determina se possono essere inclusi nel database.

Dopo aver letto questo, sarai in grado di cogliere l'idea di un insieme di contratti sul campo e saprai come conservare esplicitamente i campi mancanti e incerti invece di riempirli con zero per impostazione predefinita.

I risultati dell'estrazione possono essere archiviati direttamente nel database? Conclusione di una frase

La possibilità di inserirlo nel database dipende dal fatto che il contratto sul campo e la verifica delle prove superino, piuttosto che dalla possibilità di analizzare JSON; i campi che non possono essere verificati devono essere lasciati in uno stato in sospeso e non possono essere riempiti con zero per impostazione predefinita.

la tua situazionePratiche consigliatemotivo
Il parser ha restituito un JSON validoContinuare a verificare il contratto sul campo e non memorizzarlo direttamente nel database.JSON significa solo che può essere letto dal programma
L'importo non ha valuta o unitàNon assumere valuta, mantieni lo stato mancanteEvita di assumere segretamente RMB
L'importo viene visualizzato in formati regionali come 1.200,50Definire i contratti separatamente per ciascun formato consentitoLe norme regionali non possono essere gestite in modo casuale e uniforme
È necessario tornare al documento per verificareSalva i numeri di pagina, il testo di origine e le coordinate e controlla gli intervalli dei numeri di paginaFacilitare la base di posizionamento dei revisori
Coinvolge più valute o tassi di cambioL'importo in valuta originale, il tipo di valuta e l'origine del tasso di cambio vengono mantenuti e non viene eseguita alcuna conversione implicita.Gli importi non possono essere convertiti senza tassi di cambio

Passa il valore insieme alle prove

Consegna una fattura o un preventivo a un parser e il JSON che ricevi ti dice solo che il programma può leggerlo. 1200 È il prezzo unitario o l'importo totale? Dov'è la valuta? 1.200,50 va inteso secondo quali norme regionali? Il numero di pagina restituito esiste realmente? Queste non sono domande a cui la sintassi JSON può rispondere.

Campovincoloperché necessario
quantitàStringa decimale, esempio limitato a non negativi e due cifre decimaliEvitare l'introduzione involontaria di approssimazioni binarie in virgola mobile
valutaQuesta scena è limitata a USDNon assumere segretamente RMB quando non esiste valuta
source.pageInizia da 1 e non può superare il numero di pagineSemplifica il ritorno degli utenti alla posizione originale del documento
source.quoteDeve essere un frammento in-page fornito dal chiamanteFornire prove visibili ai revisori
source.bboxValore finito, all'interno dell'intervallo di pagineImpedisci alle caselle vuote e alle coordinate non valide di impersonare prove

L'unità di coordinate qui è il punto PDF e l'origine è l'angolo in alto a sinistra della pagina concordata corrente. L'upstream dovrebbe prima unificare i sistemi di rotazione, ritaglio e coordinate e non può mescolare direttamente le coordinate di diversi parser. Questo esempio dimostra solo la convenzione e non prova che il testo sia effettivamente incluso nella casella.

Completa test di verifica e rifiuto

Può essere eseguito utilizzando solo la libreria standard Python. Decimal deve essere costruito da una stringa, non convertirlo prima in float e poi passarlo. Per l'elaborazione decimale precisa degli importi, fare riferimento a Documentazione decimale Python.

Il codice riportato di seguito è l'effettivo risultato del test, non il rapporto sull'accuratezza del riconoscimento. Gli input di esempio sono scritti a mano da noi e non è stato effettuato alcun OCR o valutazione del modello su fatture reali.

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}")

La regolarità è rigorosa perché la scena è rigorosa

Questa espressione regolare accetta solo il formato di importo inglese nell'esempio. Rifiuta le seguenti situazioni:

  • Decimale europeo
  • numero negativo
  • Rimborsi indicati tra parentesi
  • Altre valute
  • Numeri a quattro cifre senza millesimi

I sistemi reali dovrebbero scegliere contratti indipendenti in base al tipo di documento e alla regione e non limitarsi a eliminare tutte le virgole, i punti e gli spazi.

Prima di espandere ulteriormente l'intervallo di input, preparare esempi positivi e di rifiuto per ciascun formato consentito. Se si tratta di una fattura multivaluta, l'importo in valuta originale, la valuta e la fonte del tasso di cambio devono essere mantenuti nei campi; senza il tasso di cambio, l’importo non può essere convertito segretamente.

📊 Confronto fondamentale

Controlla il livelloDomande a cui è possibile rispondereDomande ancora senza risposta
Analisi JSONSe il contenuto può essere letto dal programmaL'importo è il prezzo unitario o l'importo totale e qual è la valuta?
contratto sul campoIl formato dell'importo, la valuta, l'intervallo dei numeri di pagina e le coordinate sono legali?Indica se la cornice delle coordinate avvolge accuratamente il testo
Controllo della fonteSe esiste una citazione nel testo della pagina corrente e se l'importo è uguale al formato limitatoLa linea è il vero totale finale dell'azienda?

"Comprovato" non significa "provato"

Il programma verifica che esista una citazione nel testo della pagina corrente e che l'importo sia uguale a questo formato limitato. Non verifica che la cornice delle coordinate racchiuda accuratamente il testo originale, né determina se la riga rappresenta il totale reale dell'attività. I livelli di testo a monte potrebbero provenire da un OCR difettoso e sulla stessa pagina potrebbero essere visualizzati più totali.

Pertanto, i contratti sul campo sono solo la prima porta. Sono inoltre necessari successivi controlli di coerenza del posizionamento, disambiguazione dei candidati sulla stessa pagina, verifica del rapporto totale fiscale parziale e campionamento manuale. Prima che dati aziendali importanti passino attraverso queste porte, dovrebbero essere salvati con lo stato "da verificare" anziché "confermato".

Come implementarlo nel flusso di lavoro dei documenti

Conserva un riepilogo del file originale, registra la versione elaborata per ogni estrazione e salva il motivo del rifiuto. Anche il processo di traduzione dovrebbe essere controllato utilizzando gli stessi campi: il testo può essere cambiato in altre lingue, ma la corrispondenza tra importi e unità importanti non può andare persa. Puoi conoscere i servizi documentali correlati tramite Portale del prodotto OmniDoc; il contratto e il codice in questo articolo sono indipendenti dall'API del prodotto e non si basano su interfacce non divulgate.

🎯Quale metodo è adatto a te?

Se desideri elaborare fatture multivaluta

Mantieni rispettivamente l'importo della valuta originale e il tipo di valuta e registra la fonte del tasso di cambio. Nessuna conversione verrà effettuata se non è presente alcun tasso di cambio.

Se desideri espandere l'intervallo dei formati di input

Scrivi prima esempi positivi ed esempi di rifiuto per ciascun formato, quindi allenta le regole. Non allentare direttamente le regole regolari.

Se i dati verranno utilizzati per decisioni finanziarie o commerciali

Contrassegna il campo come in attesa di verifica, quindi confermalo dopo la coerenza del posizionamento, la disambiguazione della stessa pagina e il campionamento manuale.

Se vuoi tradurre documenti

La lingua del testo può essere cambiata, ma il rapporto corrispondente tra l'importo e l'unità deve essere mantenuto utilizzando lo stesso audit sul campo.

❓ Domande frequenti (FAQ)

1. Se JSON può essere analizzato, può essere archiviato direttamente nel database?

NO. L'analisi mostra solo che il contenuto può essere letto dal programma e richiede anche il contratto sul campo e la verifica delle prove.

2. Il programma ha verificato il preventivo, significa che l'importo deve essere corretto?

NO. Verifica solo che la citazione esista nel testo della pagina corrente e che l'importo sia uguale al formato limitato e non verifica la cornice delle coordinate o il significato totale dell'attività.

3. Perché l'importo mancante non può essere considerato 0?

Importo mancante, verifica non riuscita e addirittura zero sono tre stati diversi e mescolarli insieme renderà difficile la distinzione per gli utilizzatori a valle.

4. Come dovrebbero essere gestite le fatture multivaluta?

L'importo della valuta originale e il tipo di valuta vengono mantenuti rispettivamente. Non convertire gli importi in assenza di tasso di cambio e mantenere la fonte del tasso di cambio.

📝 Riepilogo

I risultati dell'estrazione sono utilizzabili per contratto, prova e accettazione, non per il formato JSON stesso. Ogni campo dovrebbe essere riconducibile a una determinata pagina del documento e i dati che non vengono verificati rimangono in attesa di verifica.

Provalo subito: carica il documento per iniziare la traduzione, mantenendo il layout originale

Aggiornato il 2026-11-14