05 - OCR e PDF pesquisável¶
EnfaseCloud.ScanEnfaseCloud.LibraryEnfaseCloud.WebApi
Implemented
Objetivo¶
Definir quando e como o OCR é executado, com base na presença de um Campo do tipo OCR no Tipo Documental selecionado. O gatilho é declarativo — quem configura o tipo documental define se OCR é necessário.
Princípio de ativação¶
O OCR é acionado quando o Tipo Documental possui ao menos um Campo cujo
Tipo(tabelaTipo) contenha o token"ocr"noNomeouDescricao— ou quando o próprioNomedo campo contém"ocr".
Este mecanismo já está implementado na EnfaseCloud.WebApi (FileIndexService.IsOcrFieldAsync / ContainsOcrToken). O EnfaseCloud.Scan deve adotar a mesma heurística para decidir se executa OCR antes de gerar o PDF final.
Não há IdTipo fixo reservado para OCR — a detecção é baseada no nome do tipo/campo, tornando a configuração flexível sem exigir mudança de código.
Onde o OCR é executado¶
| Onde | Quando | Finalidade |
|---|---|---|
EnfaseCloud.Scan |
Antes do hash final, na estação | PDF pesquisável (camada de texto embutida no PDF/A) |
EnfaseCloud.WebApi |
Após upload, no cloud | Extração de texto para indexação e busca; preenchimento automático do campo OCR |
Ambos respondem ao mesmo gatilho: existência de Campo tipo OCR no Tipo Documental.
Modos¶
OCR no Scan (PDF pesquisável)¶
Executado na estação (EnfaseCloud.Scan) antes do hash final do artefato, quando o Tipo Documental selecionado possui Campo tipo OCR.
- Embutir camada de texto invisível no PDF sem invalidar PDF/A-2b.
- O hash do artefato é calculado após o OCR — o PDF pesquisável é o artefato final da estação.
A assinatura ICP-Brasil/PAdES não é responsabilidade da estação — ocorre na WebApi após upload.
OCR no cloud (indexação e preenchimento de campo)¶
Executado pela WebApi após receber e persistir o artefato.
- Extrai texto para busca full-text e indexação automática.
- Preenche automaticamente o valor do Campo tipo OCR com o texto extraído — evitando que o operador precise digitar o conteúdo.
- Não altera o PDF persistido (o artefato original é preservado intacto).
Detecção de Campo tipo OCR¶
Heurística (mesma lógica em Scan e WebApi)¶
Um campo é considerado "tipo OCR" quando qualquer uma das condições for verdadeira:
campo.Nome.ToLower().Contains("ocr")— o nome do campo contém a string"ocr".tipo.Nome.ToLower().Contains("ocr")— o nome do tipo de campo (tabelaTipo) contém"ocr".tipo.Descricao.ToLower().Contains("ocr")— a descrição do tipo contém"ocr".
Parâmetro de OCR por cliente¶
Campo OcrEnabled no Cliente¶
Controla se o EnfaseCloud.Scan deve executar OCR ao digitalizar documentos deste cliente.
ALTER TABLE Cliente ADD OcrEnabled BIT NOT NULL DEFAULT 0;
-- 0 = OCR desligado para este cliente (padrão conservador)
-- 1 = OCR ativado; gatilho fino permanece no tipo documental
Sincronização: o campo ocrEnabled é incluído no payload de GET /sync/catalogs
(ClienteDto.OcrEnabled) e armazenado em LocalCliente.OcrEnabled no SQLite do Scan.
Matriz de decisão no Scan¶
Antes de capturar, o Scan resolve:
cliente.OcrEnabled = true
└── tipo documental tem Campo tipo OCR?
├── SIM → OcrRequired = true (OCR executa antes do hash)
└── NÃO → OcrRequired = false (OCR desnecessário para este tipo)
cliente.OcrEnabled = false → OcrRequired = false (desligado pelo cliente)
Essa hierarquia preserva o comportamento atual (gatilho por campo OCR no tipo documental) e adiciona um interruptor global por cliente — útil para:
- Clientes em homologação (tessdata ainda não calibrado para os documentos deles).
- Clientes cujos documentos não beneficiam de OCR (imagens de baixa qualidade, manuscritos).
- Rollout gradual: ativar OCR cliente a cliente sem mudança de código.
Job assíncrono de OCR na WebApi (documentos sem OCR)¶
Motivação¶
Documentos chegam sem camada de texto por três razões:
OcrEnabled = falseno cliente quando o doc foi digitalizado.- Tessdata ausente na estação (
OcrStatus = Unavailable). - Upload legado (docs anteriores à implementação de OCR no Scan).
O job WebApi cobre esses casos de forma assíncrona, sem bloquear o operador.
Gatilho¶
O job deve processar documentos com:
WHERE OcrStatus IN ('Pending', 'Unavailable', 'Failed')
AND IdTipoDocumental IN (
-- tipos documentais com ao menos um Campo tipo OCR
SELECT DISTINCT tc.IdTipoDocumental
FROM TipoDocumentalCampo tc
JOIN Tipo t ON tc.IdTipo = t.Id
WHERE t.Nome LIKE '%ocr%' OR t.Descricao LIKE '%ocr%'
OR tc.Nome LIKE '%ocr%'
)
API de execução assíncrona¶
POST /ocr/jobs
Body: {
"scope": "pending", // pending | all | specific
"idCliente": 42, // opcional: restringir a um cliente
"idsTipoDocumental": [5, 7], // opcional: restringir a tipos específicos
"maxDocumentos": 500 // paginação para evitar timeouts
}
Response: {
"jobId": "ocr-job-20260601-143000",
"status": "queued",
"documentosPendentes": 347,
"estimativaSeg": 1200
}
GET /ocr/jobs/{jobId}
Response: {
"jobId": "...",
"status": "running", // queued | running | completed | failed
"processados": 200,
"sucesso": 195,
"falhas": 5,
"iniciadoEmUtc": "...",
"percentualConcluido": 57.8
}
Comportamento do job¶
- Lê bytes do documento do Azure Storage Account.
- Executa
TesseractOcrService.ExtractTextFromBytesAsyncpor página. - Se confiança ≥ limiar configurado (
OcrOptions.MinConfidence, padrão 0.70): - Atualiza
OcrStatus = Completed. - Preenche automaticamente o valor do Campo tipo OCR na indexação do documento (
Indexacao). - Se confiança < limiar:
OcrStatus = CompletedLowConfidence+ marca campo para revisão. - Se falha:
OcrStatus = Failed+ registra erro na auditoria; documento permanece acessível. - Registra evento de auditoria:
OcrJobProcessedcom jobId, motor, confiança e data.
Execução paralela controlada¶
O job deve usar Parallel.ForEachAsync com MaxDegreeOfParallelism configurável
(OcrOptions.MaxParallelDocuments, padrão 4) para não saturar o Storage nem o Tesseract.
await Parallel.ForEachAsync(
documentosPendentes,
new ParallelOptions { MaxDegreeOfParallelism = _options.MaxParallelDocuments },
async (doc, ct) => await ProcessarOcrDocumentoAsync(doc, ct));
Agendamento¶
| Modo | Quando usar |
|---|---|
On-demand via API (POST /ocr/jobs) |
Após ativar OcrEnabled num cliente existente |
| Scheduled (cron diário) | Processar docs novos com OCR pendente acumulados |
| Trigger pós-upload | Quando OcrStatus = Pending + tipo tem campo OCR (melhor latência) |
O trigger pós-upload é o mais eficiente para novos documentos: o ScanController
enfileira o job imediatamente após persistir o artefato, sem aguardar o scheduler.
Implementação existente (referência)¶
- WebApi:
FileIndexService.IsOcrFieldAsync+ContainsOcrToken— já implementado. - Scan:
ScanUserControl.IsBooleanField(detecção análoga para campos booleanos) — a mesma abordagem deve ser criada para campos OCR, verificando ocampo.Nomee consultando oIdTipona tabela de tipos sincronizada localmente.
Requisitos¶
EnfaseCloud.Scan¶
- Quando o Tipo Documental selecionado possuir ao menos um Campo tipo OCR, o Scan deve executar OCR antes de gerar o hash do artefato.
- O Scan deve usar a heurística
ContainsOcrTokensobrecampo.Nomee sobre oTipovinculado ao campo (viaIdTipo), consultando a tabela localtiposincronizada via catálogos. - O OCR executado no Scan deve embutir camada pesquisável no PDF sem invalidar PDF/A-2b.
- O Scan deve registrar no manifesto: se OCR foi executado, motor, confiança média e páginas processadas.
- Quando OCR falhar, o Scan não deve abortar a digitalização — registra
OcrFailedno manifesto e segue para o hash e upload.
EnfaseCloud.WebApi¶
- Quando receber um artefato cujo Tipo Documental possuir Campo tipo OCR, a WebApi deve executar OCR no cloud (se ainda não executado ou para melhorar confiança).
- O texto extraído deve preencher automaticamente o valor do Campo tipo OCR na indexação do documento.
- O texto extraído deve ser indexado para busca full-text, separado do artefato binário.
- A WebApi deve atualizar o status de OCR no manifesto e no banco do tenant.
Ambos¶
- O resultado de OCR deve registrar: idioma, motor, versão, confiança média, páginas processadas e falhas.
- Quando OCR completar com confiança abaixo do limiar configurado, o status deve ser
CompletedLowConfidencee o campo deve ser marcado para revisão. - Quando PDF pesquisável estiver habilitado pelo Scan, o PDF final deve continuar validando como PDF/A-2b.
Sincronização da tabela Tipo para o Scan¶
O Scan precisa da tabela de tipos (Tipo) sincronizada localmente para detectar campos OCR sem depender de conexão. Esta tabela deve ser incluída no payload de sincronização de catálogos (SyncScope.CatalogsOnly ou CatalogsAndFiles), junto com departamentos, tipos documentais e campos.
Estados¶
| Estado | Significado |
|---|---|
NotRequired |
Tipo Documental não possui Campo tipo OCR. |
Pending |
Campo OCR detectado; OCR ainda não executado. |
Completed |
OCR concluído com confiança acima do limiar. |
CompletedLowConfidence |
OCR concluído mas confiança abaixo do limiar. |
Failed |
OCR tentado mas falhou; artefato preservado. |
ReviewRequired |
Resultado disponível mas requer revisão humana. |
Aceite¶
- Quando o Tipo Documental tem Campo tipo OCR, o PDF gerado pelo Scan contém camada pesquisável.
- Quando o Tipo Documental tem Campo tipo OCR, a WebApi preenche automaticamente o valor do campo com o texto extraído.
- Quando o Tipo Documental não tem Campo tipo OCR, o Scan não executa OCR — sem overhead desnecessário.
- Falha de OCR gera pendência sem corromper o upload nem o PDF.
- O hash do artefato é calculado após o OCR na estação — PDF pesquisável é o artefato definitivo.