- Tirar o texto de um PDF com
/augment/text-parser - Descrever o registro que queremos como um JSON schema
- Extraí-lo, com o schema imposto em vez de solicitado
- Lidar com o arquivo que não tem texto algum
- Comparar o que os dois caminhos produzem a partir da mesma página
Configuração
Você precisa do Python 3.9 ou superior, do pacoterequests e de uma chave da API Venice. Veja Gerando uma Chave de API caso ainda não tenha uma.
extract.py:
AUTH e JSON_HEADERS são separados. O parser aceita um upload multipart, e definir Content-Type você mesmo numa requisição multipart impede que o requests adicione o boundary, o que falha de um jeito chato de diagnosticar.
1. Extraia o texto
/augment/text-parser aceita um arquivo PDF, DOCX, XLSX ou texto puro de até 25 MB e retorna o texto com uma contagem de tokens. Os documentos são processados em memória e o conteúdo não é retido.
tokens é a parte útil dessa resposta. Ela te diz o que o documento vai custar na próxima requisição antes de você fazê-la, o que importa porque um PDF longo facilmente ultrapassa o que você pretendia gastar.
2. Descreva o registro que você quer
Pedir JSON a um modelo te dá um JSON com um formato aproximadamente parecido com o que você pediu. Passar um schema te dá um JSON que casa, porque o schema restringe a geração em vez de aconselhá-la.additionalProperties: False em todos os níveis. Sem isso, um modelo que ache algo interessante pode adicionar uma chave que você nunca planejou, e o código que lê o resultado não vai esperá-la.
3. Extraia
Uma chamada, comresponse_format carregando o schema e strict ligado:
200:
affiliation é obrigatório, então o modelo retornou uma string vazia em vez de omitir. É o schema fazendo exatamente o que você mandou.
Uma string vazia e um valor ausente são fatos diferentes, e
required os funde. Se você precisa distinguir “o documento não diz” de “o documento não diz nada aqui”, tipe o campo como {"type": ["string", "null"]} e peça null no system prompt. O modo strict aceita a união, e você recebe null em vez de "".Desligue o raciocínio
disable_thinking é a linha dessa requisição sobre a qual vale a pena discutir, então aí vai o argumento. O modelo de texto padrão raciocina antes de responder, e o raciocínio é sacado do mesmo orçamento de completion que o JSON. Execute a mesma extração quatro vezes e veja o que o modelo gasta:
Aumentar o orçamento não resolve o primeiro problema, apenas eleva o teto que o modelo pode encostar. A execução que gastou 4003 tokens voltou com
finish_reason de length e uma string vazia.
Desligar o raciocínio deixou essa extração cinco vezes mais barata e, mais útil ainda, fez com que fosse igual toda vez. O schema já está fazendo o trabalho que o raciocínio faria, que é decidir a forma que a resposta assume.
4. Quando não há texto para pegar
Um PDF produzido por um scanner contém imagens de páginas, não texto. Nada no nome do arquivo diz isso, e nada no tamanho do arquivo entrega também. Você não precisa detectar, porque o parser detecta:400, e é um sinal de roteamento em vez de uma falha. O caminho de texto está indisponível para este arquivo, então tome o outro: renderize a página e deixe um modelo olhá-la.
5. No que os dois caminhos discordam
Rode os dois contra a mesma primeira página e os registros voltam quase idênticos. O “quase” é a parte interessante:
O caminho do texto preservou o Ł. O caminho da visão retornou um L ASCII, porque ele está lendo formas de letra em vez de códigos de caractere, e um diacrítico é um pequeno detalhe visual que sobrevive mal. Se você está casando nomes extraídos contra um banco de dados, essa diferença decide se a linha é encontrada.
O oitavo autor importa mais. A página não indica afiliação para Illia Polosukhin, e o caminho do texto reporta isso fielmente como uma string vazia toda vez. O caminho da visão, em algumas execuções, preencheu o campo com um vizinho plausível da mesma página. Ler pixels deixa mais espaço para inferência do que ler caracteres, e um campo obrigatório é um convite para preencher. Quando você não consegue conferir a saída à mão, isso é motivo para preferir texto parseado sempre que o documento oferecer.
O custo é mais próximo do que parece. Com raciocínio desligado nos dois lados, os dois caminhos rodaram com prompts de tamanho parecido nesta página:
A imagem tinha 923.732 caracteres de base64, e nada disso é o que você paga. Imagens são tokenizadas por tamanho, não pelo comprimento da codificação, então um PNG grande não custa o que parece que deveria.
Prefira texto parseado quando o documento tem texto. Ele preserva os caracteres exatos, não custa nada a mais para ir além da primeira página, e não se importa com como a página foi diagramada. Recorra à visão quando o parser disser que não há nada para ler, ou quando o significado está no layout, como em um gráfico, um carimbo ou uma assinatura.
Extraindo outra coisa
Nada acima é específico a papers. Troque o schema e o system prompt, e o pipeline extrai notas fiscais:description estão fazendo trabalho de verdade. Uma data só fica sem ambiguidade depois que você diz qual formato quer, e 03/04/2026 significa dois dias diferentes dependendo de quem escreveu.
Próximos passos
- Valide o resultado contra o schema com
pydanticoujsonschema, para que um registro malformado falhe na borda em vez de três funções depois. - Armazene o texto extraído com Embeddings para buscar entre documentos em vez de reextraí-los.
- Anexe documentos diretamente a uma chat completion com File Inputs quando você quiser respostas em vez de registros.
- Entregue o extrator a um agente como ferramenta, usando Construindo um Agente que Usa Ferramentas com Function Calling.
Processamento de Documentos
Referência do endpoint text-parser.
Respostas Estruturadas
Como o json_schema restringe uma completion.
Visão
Enviando imagens a um modelo de chat.
File Inputs
Anexe um documento sem parseá-lo você mesmo.