Pular para conteúdo

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)