Bindery och dokument utan limkod

Bindery gör om dokumentformat till en enda Rust-motor med identifiering, normaliserade API:er, DocQL och färre små formatriken att underhålla.

Bindery och dokument utan limkod

Filen var inte problemet

Det första misstaget är att tro att dokumentet är filen. Det kommer som en fil, ja. Den har ett namn, oftast med ett filändelsesom ser betryggande ut. Inköpslistan säger .xlsx, rapporten säger .docx, arkivutdraget säger .pdf, och alla låtsas att världen har blivit enkel eftersom de fyra sista tecknen ser bekanta ut. Härligt. Sedan ljuger filändelsen, arbetsboken har dolda blad, bildspelet innehåller inbäddade objekt, PDF:en är mestadels text men inte riktigt, och den gamla Word-filen luktar fortfarande svagt av 2003.

De flesta team bygger inte en dokumentpipeline. De bygger ett litet museum av formundantag. Ett bibliotek för Word, ett annat för Excel, något annat för PDF:er, ett heroiskt skalskript för arkivmappen, ett Python-paket som senast uppdaterades när alla fortfarande tyckte att QR-koder var spännande, och några reguljära uttryck som borde tas ut och få en stillsam pension. Sex månader senare är limlagret större än produkten. Detta är inte ett ovanligt feltillstånd. Det är den normala formen av dokumentarbete när varje format får sitt eget kungarike.

Bindery finns för att dokumentlagret inte ska bli huvudprojektet. På implementeringsnivå är det en Rust-crate som heter dweve-bindery. Den publika sidan beskriver en crate med 17 format, DocQL, Python-bindningar och en gemensam motor. Det viktiga är att högnivå-API:er som Document, Presentation och Workbook ligger ovanpå formatspecifika moduler för OLE2, OOXML, ODF, iWork, RTF, PDF, Markdown, EPUB, LaTeX, bilder, formler och DocQL. Den listan finns inte där för att imponera på någon. Den finns där för att verkliga korpusar är ohyfsade.

Det användbara påståendet är enkelt: öppna dokumentet genom en motor, normalisera det som kan normaliseras, och håll formatspecifik smärta under en delad yta. Det gör inte varje format identiskt. Det gör skillnaderna tillräckligt tydliga för att en pipeline ska kunna överleva dem.

Bindery börjar med att misstro filändelsen. Detektering, tolkning, normalisering, frågor och skrivning är separata uppgifter, vilket är precis därför limmet inte behöver läcka överallt.

Detektering är inte en dekoration

Formatdetektering låter som ett litet verktyg tills det misslyckas. Då blir det hela incidenten. Filändelser är metadata som tillhandahålls av personen, verktyget, mailgatewayen, exportjobbet, migreringsskriptet eller den trötta praktikanten som senast rörde filen. Ibland stämmer de. Ibland är de en artig rekommendation. En seriös dokumentmotor bör inspektera magiska byte, behållarstruktur, paketdelar, strömmar och interna ledtrådar innan den bestämmer vilken läsare som äger filen.

Bindery behandlar det som ytterdörren. README och sidan beskriver båda automatisk formatdetektering. Biblioteksdokumentationen visar Document::open och Presentation::open som den normala vägen, inte en välj-din-tolk-ceremoni. Det spelar roll eftersom användare inte vill ha en utbildning i dokumentarkeologi innan de kan extrahera en tabell. De vill att motorn ska välja vägen och sedan ge dem ett stabilt API.

Det finns en torr liten lärdom här. Ju mindre glamour en komponent har, desto mer skada kan den göra när människor viftar bort den. Detektering är inte glamoröst. Det är inte heller teckenkodningskonvertering, ZIP-hantering, OLE-kataloggenomgång, relationsupplösning, Snappy-dekomprimering eller XML-namnomruteshantering. Okej. Det tråkiga arbetet är precis där produktionspipelines antingen blir tillförlitliga eller börjar samla på lyckobringare.

En modell betyder inte en lögn

Ett enhetligt API kan bli farligt när det låtsas som att skillnaderna har försvunnit. Bindery ska inte påstå att en PDF, ett kalkylblad, ett iWork-arkiv och ett OOXML-paket är samma djur i olika kostymer. Det är de inte. Den användbara arkitekturen handlar inte om att platta till sanningen till gröt. Den handlar om att exponera gemensamma operationer där de är gemensamma och hålla kapacitetsgränserna synliga där de inte är det.

Källkodsstrukturen visar den uppdelningen. Det finns ett enhetligt Word-dokument-API, ett enhetligt presentations-API, kalkylbladsattribut, formelutvärdering bakom funktioner, DocQL-kopplingar och moduler på lägre nivå för själva formaten. Den publika formatmatrisen säger att OOXML och ODF är förstklassiga ytor för läsning, skrivning och frågor. PDF och RTF är lätta att läsa och mer försiktiga vid skrivning. EPUB, LaTeX och Markdown är utdataformat. Äldre Office och iWork har sin egen interna mekanik. Det är rätt hållning. En motor, ja. En fantasi, nej.

Den här distinktionen spelar roll i granskningar och dataprodukter. Om ett efterlevnadsflöde extraherar klausuler från kontrakt måste det veta om ett värde kom från ett stycke, en tabellcell, en anteckning på en bild, en formel eller en textkörning i en PDF. Om ett inmatningsjobb matar hämtning måste det veta om bilder, kommentarer, metadata och relationer bevarades, ignorerades eller markerades som ej stödda. Svaret kan inte begravas i en formatspecifik fotnot, för den fotnoten dyker inte upp när någon frågar varför resultatet ändrades.

En delad motor behöver fortfarande en kapacitetsmatris. Det ärliga löftet är inte att alla format beter sig likadant. Det är att varje löfte är namngivet och testbart.

Dokument är strukturerad data som glömde att erkänna det

Det värsta en dokumentpipeline kan göra är att reducera allt till text för tidigt. Text är användbar. Text är inte hela dokumentet. Ett kalkylblad har formler, referenser, blad, rader, celler, talformat, kommentarer och arbetsboksstruktur. En presentation har bilder, former, bilder, anteckningar, ordning och ibland en företagsmall som har överlevt tre fusioner och en omprofilering genom ren illvilja. Ett Word-dokument har stycken, textkörningar, tabeller, sidhuvuden, sidfötter, stilar, relationer och inbäddade objekt. En PDF har strömmar och layoutbeslut som kanske eller kanske inte motsvarar läsordningen. Att göra om allt detta till en enda platt sträng är snabbt, tröstande och ofta fel.

Bindery:s API:er på hög nivå är användbara eftersom de håller dokumentets form vid liv tillräckligt länge för att ställa bättre frågor. Dokument-API:et exponerar stycken, textkörningar, tabeller, rader och celler. Kalkylbladsmodulen exponerar arbetsboks- och bladattribut. Formelmotorn täcker en stor Excel-kompatibel funktionsyta. DocQL lägger till ett SQL-liknande frågespråk över dokumentmodellen, med lexer, parser, validator, planner, executor, kopplingar, värden och funktioner i källkodsträdet. Det är mer än en bekvämlighetsförpackning. Det är ett sätt att sluta skriva om samma extraktionslogik för varje format.

Tänk dig att ställa en fråga till korpusen: vilka celler refererar till detta antagande, vilka tabeller innehåller en riskkategori, vilka bilder nämner en policy, vilka dokument har en anpassad egenskap och vilka formler beror på en given indata. I per-format-riket blir det fyra skript och ett kalkylblad med ursäkter. I en delad modell blir det en frågeyta. Fortfarande arbete, förstås. Programvara ger dig sällan en semester. Men det är rätt arbete.

DocQL är skillnaden mellan att skrapa text och att ställa dokumentformade frågor. Referenser, formler, tabeller, former och metadata förblir en del av jobbet.

Varför Rust är en vettig plats för det här virrvarret

Dokumentformat är en underbar kombination av binära strukturer, komprimerade paket, XML, äldre teckenkodningar, bilddata, datumsystem, formelsemantik och säkerhetsproblem. Med andra ord den typen av arbete där vagt minnesägande är en livsstil med fakturor bifogade. Rust är en vettig bas eftersom Bindery måste göra noggrann parsning, hantera buffertar, rapportera fel högljutt och exponera API:er som inte får resten av stacken att gissa vad som gick fel.

Crate-funktionerna berättar samma historia. Standardfunktionerna inkluderar OLE, OOXML, OOXML-kryptering och eval-motorn. Fullt stöd aktiverar iWork, ODF, RTF, formler, bildkonvertering, teckensnitt och mer. DocQL är en funktion med egen binär. Valfria beroenden matchar de format och ytor de stöder: ZIP-hantering, snabb XML-parsning, teckenkodningskonvertering, Snappy, protobuf, bildavkodning, statistik och komplexa tal för formelarbete, och så vidare. Det här är inte en enda gigantisk klump som låtsas att varje beroende hör hemma överallt. Funktionsflaggor håller dokumentmotorns form synlig.

Det spelar roll för inbäddning. Ett kunskapssystem kan vilja ha hela kontors- och frågeytan. En liten tjänst kan vilja ha bara OOXML och textextrahering. Ett Python-arbetsflöde kan vilja ha bindningar över samma motor. En kommandoradsinspektionsväg kan vara användbar för engångsfrågor och tester. Sidan pratar om Rust, PyO3 och en CLI-yta; källkoden visar en DocQL-binär och ett PyO3-paket. Det viktiga designvalet är att dessa ingångspunkter sitter på en motor. Annars blir varje integration sin egen lite annorlunda sanning, och sedan börjar buggrapporterna bära olika hattar.

Ingångspunkterna kan skilja sig åt utan att sanningen förgrenas. Rust-API:er, Python-bindningar, DocQL och den bredare Dweve-stacken bör konsumera samma motor.

Underhållsberättelsen är produktberättelsen

Det är lätt att beskriva Bindery som en parser, men underhållsberättelsen är den verkliga produktberättelsen. Varje nytt formatbibliotek som läggs till i en pipeline har sin egen release-takt, felvokabulär, feltyper, egenheter, beroenderisk, testfixturer och felsätt. I liten skala ser det hanterbart ut. I korpus-skala blir det ett operativt arkivskåp som bits.

En delad motor tar inte bort formatkomplexitet. Det skulle vara misstänkt. Den flyttar komplexiteten till en plats där tester, kapacitetsetiketter, funktioner och API:er kan hanteras tillsammans. README har end-to-end-tester för dokument, presentationer, kalkylblad, iWork och andra format. Källkodsträdet har moduler som gör formatgränserna tydliga. Den strukturen är vad som låter ett team förbättra parserlagret utan att be varje produktteam att lära om skillnaden mellan en relationsdel och en sammansatt filström.

Det är därför Bindery passar ihop med resten av Dweve-stacken. Reed bryr sig om tolkning med kvitton. BitWeave bryr sig om deterministisk hämtning. Fabric och Spindle bryr sig om styrd kunskap och operativ användning. Bindery ligger före dessa lager. Det omvandlar kontorsdokument till strukturerat material som resten av stacken kan resonera kring. Om inmatningslagret är lim och förhoppningar, ärver det nedströms systemet lim och förhoppningar. Mycket effektivt, om ditt strategiska mål är framtida lidande.

Vad du bör fråga innan du inför det

Den första frågan är inte om Bindery stöder ditt favoritfilformat. Det är en checklistefråga, och checklistor är bra, men det räcker inte. Den bättre frågan är vilka dokumentlöften du behöver. Behöver du skrivskyddad extrahering, skrivstöd, bevarande vid rundtur, formelberäkning, frågor över format, metadata, inbäddade bilder, krypterad OOXML, äldre Office, iWork, ODF, eller utdata till EPUB, LaTeX och Markdown? Det är olika uppgifter. Att låtsas att de är en enda uppgift är hur färdplaner blir till soppa.

Den andra frågan är hur fel hanteras. Om en tolkare inte kan bevara en struktur, säger den ifrån? Om en skrivare är bästa möjliga, är det synligt? Om en formel inte kan beräknas, kan anroparen besluta om den ska blockera, varna eller fortsätta? En dokumentmotor är inte tillförlitlig för att den aldrig säger nej. Den är tillförlitlig för att dess nej är typat, specifikt och nära problemet.

Den tredje frågan är hur du testar ditt eget korpus. Offentliga exempel är användbara, men ditt arkiv är förmodligen konstigare än exempelmappen. Det har trasiga exporter, gamla mallar, konstiga nummerformat, dolda blad, kopierade och inklistrade tabeller, felaktiga PDF-filer och filer som heter final_final_really_final. Bindery ger en delad motor och testbara ytor. Du behöver fortfarande korpustester. Tyvärr kommer dokumenten inte att bli vuxna av sig själva.

Lärdomen

Lärdomen från Bindery är att dokumenthantering inte är textextrahering med extra steg. Det är formatidentifiering, strukturell tolkning, kapacitetsgränser, frågeytor, skrivvägar och underhållsdisciplin. Användaren ser en fil. Systemet ser en behållare, strömmar, relationer, poster, stilar, formler, metadata, kodningar och utdatalöften. En bra motor håller den komplexiteten under produktytan utan att låtsas att den inte finns.

Bindery uppgift är att göra dokumentlagret tråkigt i god bemärkelse. En Rust-motor. Hög nivå API:er för dokument, presentationer och kalkylblad. Formatmoduler för de röriga delarna. DocQL för gemensamma frågor. Python- och stackintegration där det är användbart. Kapacitetsetiketter i stället för formatmytologi.

Filen var aldrig problemet. Limmet var det. Bindery är försöket att sluta betala hyra för det limlagret.