Extrahování do JSON neznamená, že je extrakce správná: vytvořte pole smlouvy pro množství, jednotku a zdroj
To, že lze výsledek extrakce převést na JSON, neznamená, že je extrakce správná. Tento článek používá desetinné a polní kontrakty ke kontrole množství, jednotky, čísla stránky, původního textu a souřadnic a připojuje deterministické testy pro normální vstup a abnormální vstup, aby bylo možné chyby zastavit dříve, než se dostanou do downstreamu.
To, že výsledek extrakce může být analyzován pomocí JSON, neznamená, že může být přímo uložen v databázi. Tento článek je napsán pro vývojáře, kteří potřebují posílat data faktur a cenových nabídek do navazujících systémů. K demonstraci přísnějších hranic používáme syntetický fragment citace: kromě hodnoty má každé pole také jednotku, zdrojovou stránku, zdrojový text a souřadnice. Analyzátor nebo model je zodpovědný pouze za navrhování kandidátů a deterministický ověřovatel určuje, zda mohou být zahrnuti do databáze.
Po přečtení tohoto budete schopni pochopit myšlenku sady smluv o polích a budete vědět, jak explicitně zachovat chybějící a nejistá pole místo toho, abyste je ve výchozím nastavení vyplnili nulou.
Mohou být výsledky extrakce přímo uloženy v databázi? Závěr jednou větou
Zda jej lze vložit do databáze, závisí spíše na tom, zda projde terénní smlouva a ověření důkazů, než zda lze JSON analyzovat; pole, která se nepodaří ověřit, by měla být ponechána v nevyřízeném stavu a ve výchozím nastavení je nelze vyplnit nulou.
| vaší situaci | Doporučené postupy | důvod |
|---|---|---|
| Analyzátor vrátil platný JSON | Pokračujte v ověřování smlouvy v terénu a neukládejte ji přímo do databáze. | JSON znamená pouze to, že jej může program číst |
| Částka nemá žádnou měnu ani jednotku | Nepřebírejte měnu, ponechte chybějící stav | Vyhněte se tajnému převzetí RMB |
Částka se objevuje v regionálních formátech, jako je 1.200,50 | Definujte smlouvy samostatně pro každý povolený formát | S regionálními pravidly nelze zacházet nenuceně a jednotně |
| Je třeba se vrátit do dokumentu a zkontrolovat | Uložte čísla stránek, zdrojový text a souřadnice a zkontrolujte rozsahy čísel stránek | Usnadněte recenzentům základ pro umístění |
| Zapojení více měn nebo směnných kurzů | Původní částka měny, typ měny a zdroj směnného kurzu jsou zachovány a neprovádí se žádná implicitní konverze. | Částky nelze převést bez směnných kurzů |
Předejte hodnotu spolu s důkazy
Odešlete fakturu nebo cenovou nabídku analyzátoru a JSON, který dostanete zpět, vám pouze řekne, že jej program dokáže přečíst. 1200 Je to jednotková cena nebo celková částka? Kde je měna? 1.200,50 je třeba chápat podle jakých regionálních pravidel? Opravdu existuje vrácené číslo stránky? Toto nejsou otázky, na které může syntaxe JSON odpovědět.
| Pole | omezení | proč potřeba |
|---|---|---|
| množství | Desetinný řetězec, příklad omezený na nezáporné a dvě desetinná místa | Vyhněte se neúmyslnému zavedení binárních aproximací s pohyblivou řádovou čárkou |
| měna | Tato scéna je omezena na USD | Nepřebírejte tajně RMB, když neexistuje žádná měna |
| source.page | Začíná na 1 a nesmí překročit počet stránek | Usnadněte uživatelům návrat do původního umístění dokumentu |
| zdroj.citát | Musí to být fragment na stránce poskytnutý volajícím | Poskytněte recenzentům viditelné důkazy |
| source.bbox | Konečná hodnota v rozsahu stránek | Zabraňte prázdným krabicím a neplatným souřadnicím před vydáváním se za důkazy |
Souřadnicovou jednotkou je zde bod PDF a počátek je levý horní roh aktuální dohodnuté stránky. Upstream by měl nejprve sjednotit systémy rotace, ořezávání a souřadnic a nemůže přímo míchat souřadnice různých analyzátorů. Tento příklad pouze demonstruje konvenci a nedokazuje, že text je skutečně obsažen v rámečku.
Dokončete ověření a testování odmítnutí
Lze jej spustit pouze pomocí standardní knihovny Pythonu. Decimal musí být sestaven z řetězce, nepřevádějte jej nejprve na float a poté jej nepředávejte. Přesné desítkové zpracování částek naleznete v Desítková dokumentace Pythonu.
Níže uvedený kód je skutečným výstupem testu, nikoli zprávou o přesnosti rozpoznávání. Vzorové vstupy jsou ručně psané námi a na skutečných účtech nebylo provedeno žádné OCR nebo modelové vyhodnocení.
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}")
Pravidelnost je přísná, protože scéna je přísná
Tento regulární výraz přijímá pouze anglický formát částky v příkladu. Odmítá následující situace:
- evropské desetinné číslo
- záporné číslo
- Vrácení peněz je uvedeno v závorkách
- Ostatní měny
- Čtyřmístná čísla bez tisícin
Skutečné systémy by si měly vybírat nezávislé smlouvy na základě typu dokumentu a regionu, a ne pouze mazat všechny čárky, tečky a mezery.
Před dalším rozšiřováním vstupního rozsahu si připravte příklady pozitivních a zamítnutých položek pro každý povolený formát. Pokud se jedná o bankovku ve více měnách, měla by být v polích zachována původní částka v měně, měna a zdroj směnného kurzu; bez směnného kurzu nelze částku tajně převést.
📊 Srovnání jádra
| Zkontrolujte hladinu | Otázky, na které lze odpovědět | Stále nezodpovězené otázky |
|---|---|---|
| Analýza JSON | Zda může program číst obsah | Je částka jednotkovou cenou nebo celkovou částkou a jaká je měna? |
| terénní smlouva | Jsou formát částky, měna, rozsah čísel stránek a souřadnice legální? | Zda souřadnicový rámeček přesně zalamuje text |
| Kontrola zdroje | Zda v textu aktuální stránky existuje citace a zda se částka rovná omezenému formátu | Je čára skutečným konečným součtem pro firmu? |
"Osvědčený" neznamená "osvědčený"
Program ověří, že v textu aktuální stránky existuje citace a že se částka rovná tomuto omezenému formátu. Neověřuje, že souřadnicový rámec přesně zalamuje původní text, ani neurčuje, zda je řádek skutečným součtem podniku. Upstream textové vrstvy mohou pocházet z chybného OCR a na stejné stránce se může objevit více součtů.
Proto jsou smlouvy v terénu pouze prvními dveřmi. Dále jsou vyžadovány následné kontroly konzistence umístění, jednoznačné rozlišení kandidátů na stejné stránce, ověření vztahu mezisoučtu a celkové daně a ruční vzorkování. Než důležitá obchodní data projdou těmito dveřmi, měla by být uložena ve stavu „k ověření"namísto „potvrzeno".
Jak to implementovat do workflow dokumentů
Uchovávejte shrnutí původního souboru, zaznamenejte zpracovanou verzi pro každou extrakci a uložte důvod zamítnutí. Proces překladu by měl být také kontrolován pomocí stejných polí: text lze změnit do jiných jazyků, ale nelze ztratit shodu mezi důležitými částkami a jednotkami. O souvisejících dokumentových službách se můžete dozvědět prostřednictvím Produktový portál OmniDoc; smlouva a kód v tomto článku jsou nezávislé na rozhraní API produktu a nespoléhají na žádná nezveřejněná rozhraní.
🎯 Která metoda je pro vás vhodná?
Pokud chcete zpracovávat účty ve více měnách
Zachovejte původní částku a typ měny a zaznamenejte zdroj směnného kurzu. Pokud neexistuje směnný kurz, nebude proveden žádný převod.
Pokud chcete rozšířit rozsah vstupních formátů
Nejprve napište pozitivní příklady a příklady odmítnutí pro každý formát a poté pravidla uvolněte. Neuvolňujte přímo pravidelná pravidla.
Pokud budou data použita pro finanční nebo obchodní rozhodnutí
Označte pole jako čekající na ověření a poté jej potvrďte po konzistenci umístění, jednoznačné jednoznačnosti a ručním vzorkování.
Pokud chcete udělat překlad dokumentů
Jazyk textu lze změnit, ale odpovídající vztah mezi částkou a jednotkou musí být zachován pomocí stejného auditu v terénu.
❓ Často kladené otázky (FAQ)
1. Pokud lze JSON analyzovat, lze jej přímo uložit do databáze?
žádný. Analýza pouze ukazuje, že program může číst obsah, a také vyžaduje terénní smlouvu a ověření důkazů.
2. Program ověřil cenovou nabídku, znamená to, že částka musí být správná?
žádný. Pouze ověřuje, že v textu aktuální stránky existuje citace a že se částka rovná omezenému formátu, a neověřuje souřadnicový rámec ani celkový význam podniku.
3. Proč nelze chybějící částku považovat za 0?
Chybějící množství, neúspěšné ověření a skutečně nula jsou tři různé stavy a jejich smícháním bude pro následné uživatele obtížné rozlišit.
4. Jak by se mělo zacházet s víceměnovými účty?
Původní částka v měně a typ měny jsou zachovány. Nepřevádějte částky, když neexistuje žádný směnný kurz, a ponechte zdroj směnného kurzu.
📝 Shrnutí
Výsledky extrakce jsou použitelné na základě smlouvy, důkazů a akceptace, nikoli pro samotný formát JSON. Každé pole by mělo být dohledatelné zpět na určitou stránku v dokumentu a data, která se nepodaří ověřit, zůstanou čekající na ověření.
Vyzkoušejte to hned: Nahrajte dokument a začněte překládat při zachování původního rozvržení


