Docling OCR¶
Conversão de documentos (PDF, DOCX, PPTX, XLSX, HTML, imagens) para Markdown (e JSON estruturado), usando o docling-serve rodando no IBM Code Engine.
Endpoints¶
| Recurso | URL |
|---|---|
| API | https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud |
| Documentação interativa (Swagger UI) | docling-docs |
Autenticação¶
Todas as chamadas exigem o header X-Api-Key. Sem a chave a API responde 401.
X-Api-Key: <chave>
Onde está a chave?
A chave é armazenada em segurança pela equipe de desenvolvimento. Solicite acesso ao responsável pelo serviço.
Uso rápido¶
Síncrono (documentos pequenos)¶
curl -X POST \
-H "X-Api-Key: <chave>" \
-F "files=@documento.pdf" \
"https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud/v1/convert/file"
Assíncrono (documentos grandes / lotes)¶
# 1. Envia e recebe um task_id
curl -X POST \
-H "X-Api-Key: <chave>" \
-F "files=@documento.pdf" \
"https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud/v1/convert/file/async"
# 2. Consulta o status
curl -H "X-Api-Key: <chave>" \
"https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud/v1/status/poll/<task_id>"
# 3. Baixa o resultado
curl -H "X-Api-Key: <chave>" \
"https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud/v1/result/<task_id>"
Persistência do modo assíncrono
As tasks são enfileiradas no Redis (fila RQ) e processadas por um worker dedicado. Status e resultados sobrevivem a restart/escala da API e ficam disponíveis por ~4 horas (TTL padrão).
Python¶
import requests
API = "https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud"
HEADERS = {"X-Api-Key": "<chave>"}
with open("documento.pdf", "rb") as f:
r = requests.post(f"{API}/v1/convert/file", headers=HEADERS,
files={"files": f})
markdown = r.json()["document"]["md_content"]
Qualidade da extração: quando forçar OCR¶
Por padrão o docling aproveita a camada de texto embutida no PDF e só recorre ao OCR onde não há texto. Em documentos oficiais digitalizados (deliberações, ofícios, documentos com brasão e carimbo) essa camada costuma vir com o mapeamento de caracteres quebrado em títulos e cabeçalhos — o texto sai embaralhado, mesmo o documento parecendo perfeito na tela.
Nesses casos, envie force_ocr=true para rasterizar todas as páginas e ignorar a camada de texto:
curl -X POST \
-H "X-Api-Key: <chave>" \
-F "files=@documento.pdf" \
-F "do_ocr=true" -F "force_ocr=true" \
"https://docling-serve.2d3xg120feyh.br-sao.codeengine.appdomain.cloud/v1/convert/file/async"
Comparativo medido¶
Documento oficial digitalizado, 7 páginas / 2,1 MB, com brasões, assinaturas e títulos em fonte estilizada:
| Padrão | force_ocr=true |
|
|---|---|---|
| Tempo de processamento | 40,0 s | 36,3 s |
| Caracteres extraídos | 17.458 | 17.617 |
| Headings reconhecidos | 18 | 18 |
| Linhas com texto embaralhado | 3 | 0 |
Exemplo do que muda — mesma linha, nas duas execuções:
padrão: ## TIT PA D D D DPIO DPO AIS
force_ocr: ## TÍTULO: POLÍTICA CORPORATIVA DE PRIVACIDADE E PROTEÇÃO DE DADOS PESSOAIS
Recomendação
Para documentos oficiais digitalizados, use force_ocr=true por padrão. Neste teste ele não custou tempo a mais — rasterizar saiu mais barato do que conciliar uma camada de texto ruim com o layout. Para PDFs nativos (gerados por editor de texto, exportados de sistemas), o modo padrão é suficiente e evita o custo do OCR.
Mesmo com OCR forçado, sobram pequenos erros típicos de reconhecimento: Il no lugar de II, caixa alta/baixa trocada em texto em versalete. Vale revisar quando o texto for usado para extração de campos exatos.
Arquitetura (Code Engine + Redis)¶
A API é stateless e apenas enfileira jobs; a conversão roda em um worker separado que consome a fila do Redis (engine RQ do docling-serve).
flowchart LR
A["Cliente<br>(app, script, página de teste)"]
subgraph CE["IBM Code Engine — br-sao"]
B["API docling-serve<br>1 vCPU / 4 GB · escala 0 → 2<br>auth: X-Api-Key"]
C["Worker docling-worker<br>4 vCPU / 16 GB · escala fixa 1<br>docling-serve rq-worker"]
end
D[("Databases for Redis — br-sao<br>fila convert + resultados<br>TTL ~4 h")]
A -->|"1. POST /v1/convert/.../async"| B
B -->|"2. enfileira job"| D
C <-->|"3. consome job / 4. grava resultado"| D
A -->|"5. GET /v1/status/poll + /v1/result"| B
B <-->|"6. lê status/resultado"| D
O fluxo síncrono (/v1/convert/file) passa pelo mesmo caminho — a API enfileira e aguarda o worker concluir antes de responder.
| Componente | Configuração |
|---|---|
API docling-serve |
1 vCPU / 4 GB RAM, escala 0 → 2, porta 5001, imagem quay.io/docling-project/docling-serve:latest (v1.29.0) |
Worker docling-worker |
4 vCPU / 16 GB RAM, escala fixa 1, fila convert via docling-serve rq-worker |
| Fila/resultados | IBM Cloud Databases for Redis (docling-redis), 8 GB RAM / 10 GB disco, TLS, região br-sao |
Comportamento¶
- Cold start da API: alguns segundos a ~1 min (a API não carrega mais os modelos; quem carrega é o worker, que fica sempre ligado)
- Quente: ~1,1 s por página (PDF simples processa em ~4 s ponta a ponta)
- Resultados: ficam no Redis por ~4 horas após a conclusão
- Residência: processamento e fila em
br-sao(São Paulo) — dado não sai do Brasil
Troubleshooting¶
| Sintoma | Causa provável | Ação |
|---|---|---|
401 Unauthorized |
Chave ausente ou inválida | Conferir header X-Api-Key |
| Primeira chamada lenta | Cold start da API | Esperar ~1 min; chamadas seguintes são rápidas |
| Erro 5xx logo após deploy | Revisão ainda subindo | ibmcloud ce revision list --app docling-serve |
| Resultado de task retorna 404/expirado | TTL do Redis (~4 h) | Reenviar o documento |
Task fica pending para sempre |
Worker fora do ar | ibmcloud ce app logs --name docling-worker |
| Markdown com títulos embaralhados | Camada de texto quebrada no PDF | Reenviar com force_ocr=true (veja Qualidade da extração) |