Cinco segundos de silêncio
Uma leitora do Chile se cadastrou, enviou um PDF de 74 páginas de um romance infantil — "¿Quién le tiene miedo a Demetrio Latov?" de Angeles Durini — e clicou em Gerar audiolivro. Quinze segundos depois, chegou um e-mail: "Seu audiolivro está pronto."
Mas não estava. O arquivo tinha 5,6 segundos. E não continha nada.
Esse é o tipo de bug que só aparece em produção, porque os PDFs de teste que usávamos tinham texto incorporado. O dela, não. O livro tinha sido escaneado, página por página, em 2012 com Adobe Acrobat Pro — e cada página foi armazenada como imagem. Para o nosso pipeline, o PDF era 74 páginas em branco.
Por que PDFs escaneados quebram pipelines de audiolivro
Um PDF pode carregar texto de duas formas completamente diferentes:
- PDFs de texto — as palavras são armazenadas como caracteres reais, com fonte e posição. Qualquer biblioteca (pypdf, pdfminer, pypdfium2) consegue extraí-las em milissegundos.
- PDFs de imagem (escaneados) — as páginas são fotos JPEG ou TIFF embutidas dentro do envelope PDF. Para uma biblioteca de extração de texto, essas páginas contêm zero caracteres.
Qualquer coisa que saiu de um scanner de mesa, da câmera do celular ou de um projeto antigo de digitalização (pense em Google Books, archive.org, reedições de domínio público, livros infantis usados) tende a ser do segundo tipo. Para os olhos humanos são idênticos. Para o software são radicalmente diferentes.
Quando analisamos o upload que falhou, nosso parser de PDF tinha retornado exatamente 17 caracteres de lixo — bytes de controle, não letras — para o livro inteiro de 74 páginas. Em seguida, nosso pipeline obedientemente alimentou esses 17 bytes ao text-to-speech e produziu 5 segundos de uma resmungada. Depois mandou um e-mail à leitora dizendo que o audiolivro estava pronto.
O que construímos
A correção é conceitualmente simples: detectar quando um PDF não tem texto utilizável e, então, aplicar OCR em cada página. A implementação tem algumas partes que vale a pena descrever.
1. Um detector de texto esparso
Antes de partir para OCR em todos os uploads, conferimos o resultado da extração nativa. Se o PDF inteiro retornou menos de 200 caracteres, ou se a média é inferior a 30 caracteres por página ao longo de 4 ou mais páginas, tratamos como escaneamento e caímos no caminho do OCR. PDFs de texto normais — mais de 90% dos casos — nunca disparam o caminho lento.
2. pypdfium2 + tesseract (Apache 2.0 do começo ao fim)
Renderizamos cada página com pypdfium2 (um wrapper Python para a engine PDFium do Google, Apache 2.0) em escala 2,5× — cerca de 180 DPI, o suficiente para um reconhecimento de caracteres confiável. Cada imagem passa pelo tesseract com um modelo multilíngue carregado: eng+spa+por+fra+deu+pol+ita+tur. O Tesseract identifica o idioma real a partir do formato dos glifos.
Saímos do PyMuPDF de propósito — a biblioteca PDF mais popular em Python — porque a licença AGPL é incômoda para um serviço hospedado. A migração para pypdfium2 levou uma tarde e eliminou o problema legal por completo. Vale saber se você está construindo algo relacionado a PDF para um produto comercial.
3. Detecção automática de idioma
O livro da leitora era em espanhol, mas o idioma da interface dela era inglês — então, antes da correção, mesmo que o OCR tivesse funcionado, o pipeline teria sintetizado o texto em espanhol com uma voz em inglês (robótica, mal pronunciada). Agora a própria detecção de idioma usa o texto do OCR. Depois de 3 páginas de amostra, langdetect classifica o conteúdo e escolhe a voz certa — neste caso, espanhol da América Latina.
4. Caminho de falha honesto
Se o OCR ainda assim recupera menos de 100 caracteres (PDFs só decorativos, arquivos corrompidos), agora levantamos um erro claro em vez de gerar silêncio: "Este PDF não tem texto extraível. Por favor, envie um EPUB, TXT ou um PDF baseado em texto." A tarefa do audiolivro é marcada como falha, nenhum e-mail é enviado e nenhum crédito é cobrado.
Tem um PDF escaneado? Experimente agora.
O MimicReader é grátis para a primeira hora de áudio a cada mês. Sem cartão. Solte qualquer PDF — de texto ou escaneado — e a gente cuida do resto.
Começar grátisO resultado
Rodamos de novo o PDF da leitora no pipeline reconstruído. Cinco minutos de OCR extraíram 144.710 caracteres de espanhol limpo das 74 páginas escaneadas. O pipeline então dividiu o texto em 1.127 segmentos e produziu um audiolivro de 2 horas e 43 minutos com leitura sincronizada — destaque palavra por palavra atrelado ao áudio. Mandamos o e-mail para ela em espanhol, por nossa conta, e pedimos desculpas pela primeira tentativa.
A regeração inteira levou cerca de 90 minutos de relógio: aproximadamente 5 minutos de OCR, 80 minutos de text-to-speech e alguns minutos para normalização de áudio (EBU R128) e finalização em M4A. É mais lento que um PDF de texto — mas funciona. Antes, simplesmente não funcionava.
O que isso significa se você tem uma estante cheia de escaneamentos
Se você vem acumulando livros escaneados — reedições antigas, romances fora de catálogo, digitalizações de domínio público do archive.org, seus próprios escaneamentos do livro de receitas da vó — eles não estão mais presos no papel. Faça o upload. A gente roda o OCR.
Atualmente, fazemos OCR em 12 idiomas: inglês, espanhol, português, francês, alemão, polonês, italiano, turco, árabe, japonês, coreano e hindi. O audiolivro em si pode ser gerado em qualquer um dos 23 idiomas de voz. Se o seu livro escaneado estiver em um idioma para o qual ainda não fazemos OCR, é só nos avisar — adicionar um pacote de idioma do tesseract leva alguns minutos.
Uma nota sobre licenciamento comercial
Toda a pilha de OCR que usamos — tesseract, pypdfium2, pytesseract — é Apache 2.0. Isso importa se você está construindo algo parecido: o PyMuPDF é a escolha fácil para renderização de PDF em Python, mas a licença AGPL exige que você abra o código de todo o seu SaaS se usá-lo em produção. pypdfium2 + tesseract entrega as mesmas capacidades sem ressaca jurídica.
O bug que nos fez melhores
A maioria dos bugs em produção é pega em testes. Esse não foi, porque a premissa — "PDFs contêm texto" — valia para todos os arquivos de desenvolvimento que tínhamos usado. Foi preciso uma leitora real, do Chile, na primeira hora dela na plataforma, para revelar o problema.
Então obrigado, leitores reais. Vocês encontram os bugs que a gente não consegue.