Bindery e documentos sem código de colagem
O ficheiro não era o problema
O primeiro erro é pensar que o documento é o ficheiro. Ele chega como ficheiro, sim. Tem um nome, normalmente com uma extensão que parece tranquilizadora. A folha de cálculo de compras diz .xlsx, o relatório diz .docx, a exportação do arquivo diz .pdf, e toda a gente finge que o mundo ficou simples porque os últimos quatro caracteres parecem familiares. Que bonito. Depois a extensão mente, o livro de trabalho tem folhas ocultas, a apresentação contém objetos incorporados, o PDF é quase todo texto mas não bem, e o antigo ficheiro Word ainda cheira vagamente a 2003.
A maioria das equipas não constrói um pipeline de documentos. Constrói um pequeno museu de exceções de formatos. Uma biblioteca para Word, outra para Excel, outra para PDFs, um script de shell heroico para a pasta de arquivos, um pacote Python que foi atualizado pela última vez quando toda a gente ainda achava os códigos QR entusiasmantes, e algumas expressões regulares que deviam ser levadas para fora e reformadas em silêncio. Seis meses depois, a camada de cola é maior do que o produto. Isto não é um modo de falha raro. É a forma normal do trabalho com documentos quando cada formato tem o seu próprio reino.
Bindery existe porque a camada de documentos não devia tornar-se no projeto principal. Ao nível da implementação, é uma crate Rust chamada dweve-bindery. A página pública descreve uma crate com 17 formatos, DocQL, ligações Python e um motor comum. O que importa é que APIs de alto nível como Document, Presentation e Workbook assentam em módulos específicos de formatos para OLE2, OOXML, ODF, iWork, RTF, PDF, Markdown, EPUB, LaTeX, imagens, fórmulas e DocQL. Essa lista não está ali para impressionar ninguém. Está ali porque os corpora reais são rudes.
A afirmação útil é simples: abrir o documento através de um único motor, normalizar o que pode ser normalizado e manter a dor específica de cada formato abaixo de uma superfície partilhada. Isso não torna todos os formatos idênticos. Torna as diferenças suficientemente explícitas para que um pipeline consiga sobreviver-lhes.
A deteção não é um enfeite
A deteção de formatos parece uma pequena utilidade até falhar. Depois torna-se o incidente inteiro. As extensões são metadados fornecidos pela pessoa, ferramenta, gateway de correio, tarefa de exportação, script de migração ou estagiário cansado que tocou no ficheiro por último. Às vezes estão certas. Às vezes são uma sugestão educada. Um motor de documentos a sério deve inspecionar os magic bytes, a estrutura do contentor, as partes do pacote, os fluxos e as pistas internas antes de decidir qual leitor é dono do ficheiro.
Bindery trata isso como a porta de entrada. O README e a página descrevem ambos a deteção automática de formatos. A documentação da biblioteca mostra Document::open e Presentation::open como o caminho normal, não uma cerimónia de escolher o analisador. Isso importa porque os utilizadores não querem um curso de arqueologia de documentos antes de conseguirem extrair uma tabela. Querem que o motor escolha o caminho e depois lhes dê uma API estável.
Há aqui uma pequena lição seca. Quanto menos glamour tem um componente, mais estragos pode fazer quando as pessoas o ignoram. A deteção não é glamorosa. Tão pouco o são a conversão de codificação, o tratamento de ZIP, a navegação de diretórios OLE, a resolução de relações, a descompressão Snappy ou o tratamento de namespaces XML. Tudo bem. O trabalho aborrecido é exatamente onde os pipelines de produção ou se tornam fiáveis ou começam a colecionar amuletos da sorte.
Um modelo não significa uma única mentira
Uma API unificada pode tornar-se perigosa quando finge que as diferenças desapareceram. A Bindery não deve afirmar que um PDF, uma folha de cálculo, um arquivo iWork e um pacote OOXML são o mesmo animal com chapéus diferentes. Não são. A arquitetura útil não consiste em achatar a verdade até a tornar uma papa. Consiste em expor operações comuns onde são comuns e manter os limites de capacidade visíveis onde não o são.
A estrutura da origem mostra essa divisão. Existe uma API unificada para documentos Word, uma API unificada para apresentações, características de folhas de cálculo, avaliação de fórmulas por detrás de funcionalidades, conectores DocQL e módulos de nível inferior para os próprios formatos. A matriz pública de formatos afirma que OOXML e ODF são superfícies de primeira classe para leitura, escrita e consulta. PDF e RTF são mais orientados à leitura e mais cuidadosos na escrita. EPUB, LaTeX e Markdown são formatos de saída. O Office legado e o iWork têm a sua própria maquinaria interna. Essa é a postura correta. Um motor, sim. Uma fantasia, não.
Esta distinção é importante em auditorias e produtos de dados. Se um fluxo de trabalho de conformidade extrai cláusulas de contratos, tem de saber se um valor veio de um parágrafo, de uma célula de tabela, de uma nota de diapositivo, de uma fórmula ou de uma sequência de texto de um PDF. Se um trabalho de ingestão alimenta a recuperação, tem de saber se imagens, comentários, metadados e relações foram preservados, ignorados ou marcados como não suportados. A resposta não pode ficar enterrada numa nota de rodapé específica do analisador, porque essa nota de rodapé não aparecerá quando alguém perguntar por que motivo o resultado mudou.
Os documentos são dados estruturados que se esqueceram de o admitir
A pior coisa que um pipeline de documentos pode fazer é reduzir tudo a texto demasiado cedo. O texto é útil. O texto não é o documento inteiro. Uma folha de cálculo tem fórmulas, referências, folhas, linhas, células, formatos de número, comentários e estrutura de livro de trabalho. Uma apresentação tem diapositivos, formas, imagens, notas, ordenação e, por vezes, um modelo corporativo que sobreviveu a três fusões e a um rebranding por pura maldade. Um documento Word tem parágrafos, execuções, tabelas, cabeçalhos, rodapés, estilos, relações e objetos incorporados. Um PDF tem fluxos e decisões de disposição que podem ou não corresponder à ordem de leitura. Transformar tudo isso numa única cadeia plana é rápido, reconfortante e, muitas vezes, errado.
As APIs de alto nível da Bindery são úteis porque mantêm a forma do documento viva tempo suficiente para fazer melhores perguntas. A API de documentos expõe parágrafos, execuções, tabelas, linhas e células. O módulo de folhas de cálculo expõe características de livro de trabalho e de folha de trabalho. O motor de fórmulas cobre uma grande superfície de funções compatíveis com Excel. O DocQL acrescenta uma linguagem de consulta semelhante a SQL sobre o modelo de documento, com lexer, parser, validador, planeador, executor, conectores, valores e funções na árvore de origem. Isso é mais do que um invólucro de conveniência. É uma forma de deixar de reescrever a mesma lógica de extração para todos os formatos.
Imagine fazer uma pergunta ao corpus: que células referenciam esta premissa, que tabelas contêm uma categoria de risco, que diapositivos mencionam uma política, que documentos têm uma propriedade personalizada e que fórmulas dependem de uma determinada entrada. No reino por formato, isso torna-se em quatro scripts e uma folha de cálculo de desculpas. Num modelo partilhado, torna-se uma superfície de consulta. Ainda é trabalho, obviamente. O software raramente lhe oferece férias. Mas é o trabalho certo.
Porque é que Rust é um lugar sensato para esta confusão
Os formatos de documento são uma combinação maravilhosa de estruturas binárias, pacotes comprimidos, XML, codificações legadas, cargas úteis de imagem, sistemas de datas, semântica de fórmulas e preocupações de segurança. Por outras palavras, o tipo de trabalho em que a posse vaga da memória é uma escolha de estilo de vida com faturas associadas. Rust é uma base sensata porque a Bindery tem de fazer análise cuidadosa, gerir buffers, lidar com erros de forma ruidosa e expor APIs que não obrigam o resto da pilha a adivinhar o que correu mal.
As funcionalidades da crate contam a mesma história. As funcionalidades predefinidas incluem OLE, OOXML, encriptação OOXML e o motor de avaliação. O suporte completo ativa iWork, ODF, RTF, fórmulas, conversão de imagens, tipos de letra e muito mais. DocQL é uma funcionalidade com o seu próprio binário. As dependências opcionais alinham-se com os formatos e superfícies que suportam: tratamento de ZIP, análise rápida de XML, conversão de codificações, Snappy, protobuf, descodificação de imagens, estatísticas e números complexos para trabalho com fórmulas, e assim por diante. Isto não é um bloco gigante que finge que todas as dependências pertencem a todo o lado. Os sinalizadores de funcionalidades mantêm a forma do motor de documentos visível.
Isso é importante para a incorporação. Um sistema de conhecimento pode querer a superfície completa de escritório e de consulta. Um pequeno serviço pode querer apenas OOXML e extração de texto. Um fluxo de trabalho em Python pode querer ligações sobre o mesmo motor. Um caminho de inspeção por linha de comandos pode ser útil para consultas pontuais e testes. A página fala sobre Rust, PyO3 e uma superfície CLI; o código-fonte mostra um binário DocQL e um pacote PyO3. A escolha de design importante é que estes pontos de entrada assentam num único motor. Caso contrário, cada integração torna-se a sua própria verdade ligeiramente diferente, e depois os relatórios de erros começam a usar chapéus diferentes.
A história da manutenção é a história do produto
A Bindery é fácil de descrever como um analisador, mas a história da manutenção é a verdadeira história do produto. Cada nova biblioteca de formatos adicionada a um pipeline tem o seu próprio ritmo de lançamento, vocabulário de erros, tipos de erro, peculiaridades, risco de dependências, fixtures de teste e modos de falha. Em pequena escala, isso parece gerível. À escala de corpus, torna-se um arquivo operacional que morde.
Um motor partilhado não remove a complexidade dos formatos. Isso seria suspeito. Move a complexidade para um lugar onde testes, etiquetas de capacidade, funcionalidades e APIs podem ser geridos em conjunto. O README tem testes de ponta a ponta para documentos, apresentações, folhas de cálculo, iWork e outros formatos. A árvore de código-fonte tem módulos que tornam óbvias as fronteiras dos formatos. Essa estrutura é o que permite a uma equipa melhorar a camada do analisador sem pedir a todas as equipas de produto que reaprendam a diferença entre uma parte de relação e um fluxo de ficheiro composto.
É por isto que a Bindery se encaixa no resto da stack Dweve. A Reed trata da análise com recibos. A BitWeave trata da recuperação determinística. A Fabric e a Spindle tratam do conhecimento governado e da utilização operacional. A Bindery fica antes dessas camadas. Converte documentos de escritório em material estruturado sobre o qual o resto da stack consegue raciocinar. Se a camada de entrada for cola e esperança, o sistema a jusante herda cola e esperança. Muito eficiente, se o vosso objetivo estratégico for sofrimento futuro.
O que perguntar antes de a adotar
A primeira pergunta não é se a Bindery suporta a vossa extensão favorita. Essa é uma pergunta de lista de verificação, e as listas de verificação são boas, mas não chegam. A melhor pergunta é de que promessas documentais precisam. Precisam de extração só de leitura, suporte de escrita, preservação de ida e volta, avaliação de fórmulas, consulta entre formatos, metadados, imagens incorporadas, OOXML encriptado, Office legado, iWork, ODF, ou exportação para EPUB, LaTeX e Markdown? São trabalhos diferentes. Fingir que são um só é como os roteiros viram sopa.
A segunda pergunta é como a falha é exposta. Se um analisador não consegue preservar uma estrutura, diz isso? Se um escritor é de melhor esforço, isso é visível? Se uma fórmula não pode ser avaliada, pode quem chama decidir entre bloquear, avisar ou continuar? Um motor de documentos não é fiável porque nunca diz não. É fiável porque o seu não é tipado, específico e próximo do problema.
A terceira pergunta é como testam o vosso próprio corpus. Os exemplos públicos são úteis, mas o vosso arquivo é provavelmente mais estranho do que a pasta de exemplos. Tem exportações partidas, modelos antigos, formatos de número estranhos, folhas ocultas, tabelas copiadas e coladas, PDFs malformados e ficheiros chamados final_final_really_final. A Bindery dá um motor partilhado e superfícies testáveis. Continuam a precisar de testes de corpus. Infelizmente, os documentos não se tornam adultos sozinhos.
A lição
A lição da Bindery é que o processamento de documentos não é extração de texto com passos extra. É deteção de formato, análise estrutural, limites de capacidade, superfícies de consulta, caminhos de escrita e disciplina de manutenção. O utilizador vê um ficheiro. O sistema vê um contentor, fluxos, relações, registos, estilos, fórmulas, metadados, codificações e promessas de saída. Um bom motor mantém essa complexidade abaixo da superfície do produto sem fingir que ela não existe.
O trabalho da Bindery é tornar a camada de documentos aborrecida no bom sentido. Um motor Rust. APIs de alto nível para documentos, apresentações e folhas de cálculo. Módulos de formato para as partes complicadas. DocQL para perguntas partilhadas. Integração com Python e com a stack onde for útil. Etiquetas de capacidade em vez de mitologia de formatos.
O ficheiro nunca foi o problema. A cola era. A Bindery é a tentativa de deixar de pagar renda por essa camada de cola.