Nieuws

Bon Dossier: drie versies, één intelligent systeem voor bonherkenning op het apparaat

Hoe een bonnenscanner uitgroeide van een testbaar Swift-pakket tot een privacygericht platform voor iPhone, iPad en macOS, met OCR, Core ML, CloudKit-synchronisatie, exports, trainingshulpmiddelen en productiecontroles.

Bon Dossier: drie versies, één intelligent systeem voor bonherkenning op het apparaat

"Bon Dossier" werd niet moeilijk omdat de app een ingewikkelde gebruikersinterface had. Het werd moeilijk omdat de echte wereld vijandig is tegen het schoonmaken van gegevens. Een simpele OCR demo kan tekst herkennen. Een productie-app moet beslissen welke tekst waar is.

Het project evolueerde dus door middel van drie praktische versies. Dit zijn niet alleen marketing releases. Het zijn engineering eras: eerst de basis, dan de herkenning motor, dan de productie-graad platform. Elke versie opgelost een andere klasse van het probleem, en elk blootgesteld de volgende laag van complexiteit.

Versie 1

De Stichting

Een Swift pakket, domeinmodel, parser, exportlaag en SwiftUI shell die ontvangsten testabel maakten voordat de camera en synchronisatielagen bestonden.

Versie 2

De inlichtingenmachine

Vision OCR, Core ML classificaties, YOLO-stijl layout zones, item-line assembly, validatiepoorten en lokaal leren vervangen naïef analyseren.

Versie 3

Het productieplatform

Core Data, CloudKit, back-ups, share-extensions, exporten, archiefmetadata, macOS, audits en training apps veranderden de herkenner in een product.

De aanvangsbeperking: privé, lokaal en controleerbaar

De belangrijkste architecturale beslissing kwam voor de scanner: ReceiptVault moest nuttig zijn zonder persoonlijke financiële documenten op te laden naar een server. Dat sluit het gemakkelijke pad van het verzenden van afbeeldingen naar een online OCR of taalmodeldienst uit. De productieapp zou afhankelijk zijn van Apple Vision, VisionKit, Core ML, Swift parsers en deterministische validering, allemaal lokaal. iCloud zou het privé-archief van de gebruiker kunnen synchroniseren, maar er zou geen "Bon Dossier" backend zijn.

Dat privacybeperking vormde elk later proces. Trainingsgegevens werden behandeld als lokaal projectmateriaal. Review correcties werden opgeslagen als lokale voorbeelden. Kandidaatmodellen werden alleen gepromoot na rapporten en regressiecontroles. Zelfs de Apple Foundation Models-laag werd ontworpen als een optionele lokale reviewpas met strenge JSON schema validatie en een terugval naar het gebundelde ontvangstmodel.

Versie 1: Het bouwen van de botten voor de camera

In plaats van te beginnen met een camera-scherm en te hopen dat de rest zou volgen, begon het project met een toetsbaar Swift pakket genaamd ReceiptVaultCore. Het oorspronkelijke doel was eenvoudig: het ontvangstgegevensmodel uitvoerbaar en toetsbaar te maken zonder afhankelijk te zijn van de simulator, camerabevoegdheden of live OCR.

Het kernmodel groeide rond ParsedReceipt: handelaar, adres, aankoopdatum, valuta, totaal, subtotaal, belasting, betalingsmethode, ontvangstnummer, OCR-tekst, notities, lijnartikelen, scanmiddelen en beoordelingsstatus. Vanaf daar voegde het project TSV-export, Excel-export, dubbele groepering, categorie-afbakening, deadline-aanwijzingen en kwaliteitsvalidatie toe. De app-UI kon nu werken met ontvangsten als echte records, niet als losse OCR-stringen.

De SwiftUI shell volgde hetzelfde principe. iPhone gebruikte een tabbladstructuur voor Archive, Scan, Insights en Settings. iPad gebruikte een sidebar en split navigatiemodel. Views werden gebouwd met systeemcontainers zoals TabView, NavigationStack, NavigationSplitView, List and Section in plaats van een aangepaste UI-framework. Dat hield de app nationeel, toegankelijk en meetbaar.

Het eerste belangrijke procesbesluit: de app behandelen als een product van kleine verifieerbare lagen. Domain tests kwamen vóór camera integratie. Parser gedrag werd afgesloten met fixtures. het Xcode-project werd gegenereerd en beschermd door scripts. bouw- en testcommando's werden vastgelegd zodat het project kon worden gereproduceerd in plaats van handmatig verzorgd binnen Xcode.

Tooling in versie 1

  • Swift 6 en SwiftPM voor de gedeelde kernmodule.
  • Het genereren van Xcode-projecten via Ruby-scripts, met inbegrip van bronsynchronisatiebeveiligingen.
  • XCTest voor analyser-, exporteur-, archief- en bronregressiecontroles.
  • Simulator bouw scripts voor iPhone en iPad verificatie.
  • Fixture ontvangst afbeeldingen en tekst reconstructie om parser veranderingen meetbaar te maken.
  • Een levend implementatiestatusdocument dat voltooide, lopende en geblokkeerde werkzaamheden bijhoudt.

Een van de vroegste infrastructuur hindernissen was toolchain drift: de geïnstalleerde commando lijn Swift was niet altijd afgestemd op de Xcode SDK. De workaround was expliciet en herhaalbaar: gebruik xcrun Swift test en de door Xcode geselecteerde toolchain voor pakketbevelen. Dat klinkt wereldwijd, maar het voorkomt dat valse mislukkingen zich verbergen als app regressies.

Versie 2: Van OCR tekst tot ontvangst

De tweede versie begon toen het duidelijk werd dat OCR alleen niet het product was. Apple Vision kan vele regels lezen van een ontvangstbewijs, maar het weet niet welk nummer het uiteindelijke totaal is, welke rij een btw-basis is, welk bedrag een korting is, welke datum een eindtijdstempel is, of waar het itemblok begint. "Bon Dossier" had een ontvangstbewijsbegrijpende motor nodig.

Het scanpad gebruikte VisionKit voor het vastleggen van documenten op iPhone en iPad, het behouden van originele scans als activa terwijl OCR en het verwerken geknipte of gedraaide versies konden gebruiken. OCR-uitgang werd input, niet waarheid. Erkend lijnen, lijnvakken, vertrouwenswaarden en later document-structuurinformatie werden overgedragen aan een hybride pijplijn: lokale Core MLmodellen stelden rollen en regio's voor, Swiftparsers verzamelden kandidaten en deterministische validatoren besloten welke kandidaat aanvaardbaar was.

Dit veranderde het project van een app met parseringsregels naar een offline machine-learning-systeem. De codebase groeide scripts voor bootstrapping labels, trainingslijnclassificatoren, trainingsdetector en locator modellen, het voorbereiden van YOLO datasets, het evalueren van onzichtbare layouts, het genereren van niet-ontvang negatieven, het auditen van label structuur, het afleiden van gespecialiseerde datasets en het uitvoeren van post-training checks. De productieapp bleef lokaal en deterministisch, maar de ontwikkelingsworkflow werd een loop van meting, isolatie, etikettering, training, vergelijking en promotie.

De erkenningspijpleiding

LayerDoelRepresentatieve hulpmiddelen
GevangenKrijg ontvangstbeelden terwijl je de originalen bewaart voor latere beoordeling, delen en back-up.VisionKit, AVFoundation, SwiftUI scan review, oogst en rotatiestromen.
Uittrekking van tekstenHerken OCR lijnen, geometrie, vertrouwen en documentstructuren.Apple Vision OCR, vaste lijst voor het herkennen van ontvangsten in de ontvangsttaal, iOS 26-documentstructuur indien beschikbaar.
LayoutZoek het ontvangstpapier, de handelaar, de post, het totaal, de BTW en de betalingsgebieden.YOLO/Ultralytics training, Core ML locator exports, structuurcontroles, evaluatie van de kwaliteit van de zones.
SemantiekKlassificeer lijnen en bedragen als handelaar, item, totaal, btw, betaling, metadata of ignoreer.Creëer ML/Core ML classificaties, JSON fallback model, veldrangers, zone specialisten.
VergaderingOntwerpen van items, totalen, belastingafdelingen en betalingsfeiten van luidruchtige kandidaten.Swift parseren, item row assembler, zone-first parser, line item arbiter.
ValideringAccepteer alleen output's die voldoen aan de wiskunde en vermijd terminal, barcode en belastingvallen.Kwaliteitsvalidator, valuta-detectie, btw-inclusieve wiskunde, uiteindelijke totale poorten, regressietoestellen.

De belangrijkste technische verandering: validatie werd de baas

Een model kan suggereren. Een analysator kan afleiden. Maar de uiteindelijke ontvangst moet evenwichtig zijn. "Bon Dossier" behandelt uiteindelijk de wiskundige validatie als de poortbewaker: itemlijnen moeten worden afgesloten tegen het uiteindelijke totaal, btw moet niet dubbelgeteld worden, subtotaal en belastingbasen moeten niet winnen over de uiteindelijke totaal, en betalings- of kaartmetadata mogen niet worden aankoopbedragen.

Deze regel onthulde subtiele fouten. Voor Europese BTW-inclusieve ontvangsten is de correcte controle meestal totale == som ((item), niet totale == items + belasting. Deze laatste tellen BTW dubbel en kan precies het verkeerde totaal zegenen. Het oplossen van die één regel veranderde het systeem van "looks plausibel" naar "mathematisch eerlijk" voor een grote klasse van ontvangsten.

Andere correcties waren even concreet: kortingsopsommingen stopten met het overheersen van de uiteindelijke totalen, kolomopschriften zoals "prijs" en "totaal" stopten met het verwarren van de itemprijs met ontvangsttotalen, belastingbasisseries stopten met het winnen over betalingstotalen, en gesplitte labels zoals "totaal" gevolgd door het bedrag op de volgende lijn kregen speciale behandeling. Het waren correcties aan het model van de realiteit van de app.

Opleidingsgegevens zonder onszelf te misleiden

Het project gebruikte verschillende soorten labels omdat niet alle trainingsbewijzen hetzelfde vertrouwen verdienen. Handgeaccepteerde labels werden goud. Voorbeelden afgeleid van visie en app-backup werden behandeld als bootstrap- of zilveren gegevens. Handmatige correcties werden opgeslagen als traceerbare voorbeelden. De productielijn vermijdte expliciet het overschrijven van de aanvaarde YOLO-etiketten, en de kandidaatmodellen moesten worden geëvalueerd op basis van vaste validatie- en testsplitsingen.

Dit was belangrijk omdat ontvangststsystemen heel gemakkelijk per ongeluk overlaten. Een gedocumenteerde fout maakte zone-specialist training zinloos: de specialist input bevatte de antwoord-achtige label functie, waardoor het model een kunstmatige echo. Het resultaat was eerlijker en tijdelijk pijnlijker, maar het maakte de resterende problemen zichtbaar in plaats van ze achter cheats te verbergen.

Representatieve getallen voor kwaliteitsmodellen die tijdens de inspanning zijn opgenomen

  • Een huidige benchmark op het apparaat omvatte 728 ontvangsten en 35.361 OCR lijnen.
  • De herziene analyse verwachtingen bereikten 545 overeenkomsten uit 546 herziene ontvangsten, met een herziene datum mismatch nog steeds zichtbaar.
  • De nauwkeurigheid van de lijnclassificatie was 96,3 procent.
  • De gemiddelde analysetijd werd geregistreerd rond 47,5 ms, met p95 rond 81,4 ms op de lokale niet-netwerkpijpleiding.
  • De release ambitie bleef hoger dan dat: bijna 99 procent automatisering vereist meer geverifieerde echte ontvangsten en item-line labels.

Versie 3: Het maken van een herkenning tot een product

De derde versie ging over alles wat een slimme motor bruikbaar maakt: persistentie, synchronisatie, zoek, bestandsinvoer, back-ups, exporten, instellingen, privacy manifestes, App Store notities, toegankelijkheid, prestaties, lokalisatie, macOS en operationele tooling. Dit is waar veel prototypes instorten, omdat productengineering meestal het werk is dat gebruikers niet zien totdat het faalt.

Persistence begon met een lokaal JSON archief omdat het eenvoudig, inspecteerbaar en snel te evolueren was. Dat was correct voor de vroege fase, maar het was niet genoeg voor een privé iPhone/iPad archief. De productierichting verhuisde naar een depot abstractie met Core Data als primaire winkel en NSPersistentCloudKitContainer voor privé iCloud synchronisatie. Het ontwerp hield expliciet de originele scanmiddelen, checksums, thumbnails en ontvangstmetadata gecoördineerd in plaats van te doen alsof een ontvangst slechts een rij in een tabel is.

Het archief werd ook meer dan een lijst. Het adopteerde een Mail-achtige organisatie: alle ontvangsten, mappen, slimme mappen, vlaggen, scope search, selectie, bewegen acties, export en mail handover. Import werd uitgebreid via bestanden, mail, afbeeldingen, PDF's en tekst payloads. App Intents en diepe links konden gebruikers leiden naar Archief, Scan, Inzichten en instellingen. Spotlight- en share-extension-werk zorgden ervoor dat ontvangsten zich voelen als systeemburgers in plaats van opgesloten app-gegevens.

Core Data en CloudKit: De harde onderdelen waren operationeel

De Core Data beslissing was pragmatisch. SwiftData is aangenaam voor prototypes, maar ReceiptVault had expliciete migratiebeheer, binaire asset handling, CloudKit debugging hooks, conflict handling en jaren van toekomstige schema evolutie nodig. Core Data gaf die hefboom.

De operationele risico's waren reëel. CloudKit schema initialisatie moest programmatische entiteiten zoals ontvangstgegevens, scannen van activagegevens, mappen, markers en slimme mappen omvatten. Dit zijn geen glamoureuze problemen, maar ze bepalen of sync werkt voor echte gebruikers.

Backups, export en kosten van originele scans

"Bon Dossier" De app voegde TSV export, echte XLSX export, gefilterde archief export, geselecteerde ontvangsten export, handmatige back-up en herstel, en share sheets. Het hield ook originele scan pagina's in plaats van het weggooien van bewijs na het analyseren. Dat is de juiste product beslissing, maar het creëert prestaties en opslagwerk.

Een productie-audit identificeerde de trade-off duidelijk: het opslaan van scanbeelden zowel op de schijf als als als Core Data externe binaire records verdubbelt de lokale opslag, terwijl volledig ingebedde JSON back-ups het geheugen kunnen vergroten omdat alle scanbyte tegelijkertijd worden gematerialiseerd. Het oplossingspad was even duidelijk: het verplaatsen van dure opslagplaatsen en back-upwerk van de belangrijkste draad, stroom of stuk grote back-ups, cache-thumbnails, en overwegen of Core Data of het bestandsysteem de enige bron is voor scanbyte.

De macOS versie was niet een kijker

Het macOS-plan was opzettelijk ambitieus: niet een lees-alleen metgezel, maar een native desktop ReceiptVault die hetzelfde privé iCloud-archief en dezelfde kernlogica deelt. Het Mac-target hergebruikt de gedeelde kern, OCR/ML-pipeline, archief-, export-, back-up- en synchronisatie-logic terwijl het presentatie, commando's, bestandsimport en camera-opname aanpast voor macOS-conventies.

Dat voegde een andere laag van tooling toe: macOS rechten, App Sandbox, door de gebruiker geselecteerde bestanden toegang, camera privacy stringen, menu commando's, Continuity Camera planning, native import panelen en App Store multi-platform release overwegingen. Het bewees ook de waarde van het houden van ReceiptVaultCore gescheiden van de app shells. Platform UI kan verschillen; ontvangstintelligentie moet niet.

De ingenieursprocessen achter het werk

Het project overleefde omdat het niet werd uitgevoerd als een gigantische uitbarsting van functioneel werk. Het gebruikte gelaagde levering, bron audits, lokale scripts, fixtures, modelverslagen en gedocumenteerde poorten.

Ontwerpen en verificaties

SwiftPM-testen, simulator-builds, bronbeschermingstests, projectgeneratorcontroles, lokalisatieverbindingen, CI-scripts en handmatige screenshot-verificatie hielden het product tegen drift.

Gegevens en ML-operaties

In de pijpleiding werden gouden, zilveren en bootstrap-etiketten gescheiden, zijwagens bewaard gebleven, YOLO structuren gecontroleerd, lokale modellen getraind en artefacten slechts na vergelijking gepromoot.

Verharding van het product

Performance audits, privacy-inventaris, app-store notities, toegankelijkheidscontroles, synchronisatie-diagnostics en release-blocker-reviews maakten verborgen storingsmodus zichtbaar.

Representatieve instrumenten en technieken

  • Swift en SwiftUI: app shells voor iPhone, iPad en macOS, met inheemse lijsten, gesplitte weergaven, instellingen en delenstromen.
  • SwiftPM: een gedeelde kernmodule en ML-tools die uitvoerbaar zijn om de zakelijke logica buiten de doelstelling van de app te laten testen.
  • XCTest: Parser, archief, back-up, export, localisatie, bronbescherming, app-intentie en ML-contracttests.
  • Apple Vision en VisionKit: scanopname, OCR, lijngeometrie en extractie van documentstructuren.
  • Core ML en Create ML: ontvangstdetektor, locator, classificator, veldranger en lokale lijnrolmodellen.
  • YOLO en Ultralytics: het experimenteren met de regio's van de uitleg, de zonelabels en de uitvoer van modellen voor de regio's van de ontvangstpapier- en inhoud.
  • Python, Swift en Ruby scripts: Voorbereiding van datasets, projectopwekking, modelopleiding, audits, rapporten en synchronisatie van middelen.
  • Core Data en CloudKit: private synchroniseerde archiefopslag, migratie van JSON en scan-actiefspiegeling.
  • CryptoKit: SHA-256 checksums voor scan-asset integriteit en een toekomstig pad voor versleutelde back-ups.
  • Integratie van app-ecosystemen: Deel uitbreiding, documentimport, App Intents, diepe links, Spotlight-records, Mail-stijl export en handmatige back-ups.

De hindernissen en hun oplossingen

HurdleWaarom het belangrijk wasOplossingsrichtlijn
OCR produceerde tekst, niet waarheid.De ontvangsten in totaal, de btw-grondslagen, de betalingslijnen en de barcode-nummers leken op een ruwe string te lijken.Combineer OCR-geometrie, Core ML-rollen, zonecontext en deterministische validatie.
De itemlijnen waren structureel rommelig.Beschrijvingen, hoeveelheden en prijzen verschenen vaak in afzonderlijke kolommen of afzonderlijke visuele blokken.Bouw een item-reeks assembler, gebruik item zones en voeg lijn-item arbiters toe met somcontroles.
Modellen kunnen in stilte overmatig passen.Leaked labels en hardcoded merchant shortcuts maakten scores beter uitzien dan echt gedrag.Verwijder antwoordlekken, verdeel de betrouwbaarheid van het etiket en vervang cheats door correctie geheugen en generieke filters.
CloudKit synchronisatie vereist exacte operationele opstelling.Een ontbrekend productieschema of een verkeerd APN-recht kan synchronisatie laten falen ondanks de juiste appcode.Voeg expliciete schema-initialisatie toe, release audits en TestFlight-controles op meerdere apparaten.
Oorspronkelijke scans creëerden geheugen en opslagdruk.Grote ontvangsten, back-ups en dubbel opgeslagen afbeeldingen kunnen UI bevriezen of spike geheugen.Cache thumbnails, verplaats opslagruimte werk van de hoofddraad, stroom back-ups en rationaliseren scan opslag.
De naleving van de vrijlating was gemakkelijk te onderschatten.Privacy manifesten, rechten, gegevensbescherming en App Store notities kunnen uploaden of herzien blokkeren.Voer productie-readiness-audits uit vóór de laatste sprint, niet nadat de binaire is gebouwd.

Wat maakte het tot een Herculeus ingenieurswerk

Het moeilijke deel was niet één algoritme. Het was het aantal grenzen dat allemaal tegelijkertijd moest vasthouden. Een scan moest een OCR-resultaat worden. Het OCR-resultaat moest een ontvangstbewijs worden. Het ontvangstbewijs moest zoekbaar, uitvoerbaar, synchroniseerbaar, herstellbaar en verklarend worden. Het herkenningssysteem moest verbeteren zonder privégegevens te lekken of afhankelijk van een server. De gebruikersinterface moest normaal en kalm blijven terwijl de pijpleiding hieronder werkte die dichter bij de forensische documentatie was dan het analyseren van formulieren.

Elke versie liet de vorige versie kleiner lijken. Versie 1 bewees dat de app kon bestaan als een schoon Swift product. Versie 2 bewees dat ontvangst begrip vereist een echte lokale ML en validatie pipeline. Versie 3 bewees dat een herkenner is geen product totdat de persistentie, synchronisatie, import, export, privacy, prestaties en release operaties betrouwbaar zijn.

De codebase bevat nu de vorm van die reis: een gedeelde kernmodule, een app shell, scannerdiensten, archiefvoorzieningen, Core Data-repositories, CloudKit-configuratie, ML-contracten, modelcaches, trainingsscripts, productielijnlopers, app-store-documentatie, prestatie-audits en tientallen gerichte tests. Het resultaat is geen dunne wrapper rond OCR. Het is een on-device inlichtingenplatform die het verschil tussen tekst en bewijs moest leren.

Lessen voor vergelijkbare projecten

  1. Begin met een testbare kern. De camera en OCR zijn luidruchtig.
  2. Behandel OCR als bewijs, niet als output. Geometrie, vertrouwen, layout en ontvangst wiskunde maken deel uit van de waarheid.
  3. Afzonderlijk modelvoorstel en productontvankelijkheid. De deterministische validatie moet beslissen of een analyse goed genoeg is.
  4. Laat de trainingsresultaten niet het theater worden. Bewaking tegen lekken, hardcoded shortcuts en validatie-set besmetting.
  5. Plan voor activa vroegtijdig. Oorspronkelijke afbeeldingen veranderen de opslag-, back-up-, synchronisatie- en prestatiearchitectuur.
  6. Controleer de productieconfiguratie als code. Rechten, privacy manifesten en CloudKit schema's maken deel uit van de app.
  7. Houd het platformspecifieke gebruikersinterface dun. Een gedeelde kern maakte iPhone, iPad en macOS mogelijk zonder de ontvangst hersenen te dupliceren.

Bon Dossier's ontwikkelingsverhaal is een herinnering aan dat serieuze lokale intelligentie niet een enkele functie is. Het is een keten van vertrouwen: vangen, OCR, lay-out, classificatie, analyseren, valideren, volharden, synchroniseren, exporteren en vrijgeven discipline. Breken een link en de gebruiker ziet het hele systeem als verkeerd. Versterk elke link en een rommelige papieren ontvangst wordt betrouwbare private gegevens.

Terug naar nieuws

Meer

Gerelateerde artikelen

2 mei 2026

Een tien uur durende debugsessie in AccountView

Softwareonderhoud is soms overzichtelijk. En soms betekent het tien uur zoeken in Visual FoxPro, oude ActiveX-elementen, tijdelijke DBF-bestanden, versleutelde gecompileerde code, verborgen viewers, crashende PDF-componenten en een hardnekkig transportmanagementsysteem.

Lees meer

Wilt u met ons samenwerken?

Neem contact op, dan bespreken we uw project.