Migrando do Veryfi para o IronOCR
Este guia orienta os desenvolvedores .NET na substituição da API de processamento de documentos em nuvem da Muito bom pelo IronOCR , uma biblioteca OCR local. Este documento aborda a troca de pacotes, a limpeza do namespace e quatro exemplos completos de migração de código focados nos padrões mais comumente utilizados no Veryfi: inicialização do cliente, extração de campos baseada em região, categorização de despesas com dados estruturados e substituição de webhooks. Não é necessário ler o artigo comparativo previamente.
Por que migrar do Veryfi?
Os documentos financeiros fluem pelo sistema da Muito bom em uma única direção: da sua infraestrutura para a deles. Esse fato arquitetônico impulsiona a maioria das migrações. Aqui estão os principais problemas que levam as equipes a fazer a mudança.
Cada solicitação de documento transmite dados financeiros confidenciais para um servidor de terceiros. Os recibos contêm os quatro últimos dígitos do cartão e informações sobre o fornecedor. As faturas contêm números de contas bancárias, números de roteamento e números de identificação fiscal do fornecedor. Os extratos bancários contêm o histórico completo das transações. Com a Veryfi, cada chamada de ProcessDocumentAsync faz upload desses bytes para api.veryfi.com, processa-os na infraestrutura da Muito bom e retorna JSON. Seu controle sobre esses dados termina no momento em que a solicitação HTTP é enviada.
Quatro credenciais são necessárias e devem ser mantidas em sincronia em todos os ambientes. VeryfiClient requer clientId, clientSecret, username e apiKey—quatro segredos separados para armazenar na configuração, rodar conforme o cronograma, injetar em pipelines CI/CD e auditar quanto à exposição. Uma única falha de credencial compromete a autenticação de todos os documentos processados em toda a aplicação. O IronOCR requer uma única chave de licença.
O preço por documento é cumulativo, sem limite máximo. Os recibos custam aproximadamente de US$ 0,05 a US$ 0,15 cada, as faturas de US$ 0,10 a US$ 0,25 e os extratos bancários de US$ 0,15 a US$ 0,30. Com 50.000 documentos por mês, isso representa um custo de US$ 5.000 a US$ 15.000 por mês em faturamento por consumo, sem redução no segundo ou terceiro ano. A licença IronOCR Professional , a US$ 2.999, cobre um número ilimitado de documentos de forma perpétua — o ponto de equilíbrio em relação aos US$ 5.000 gastos mensais com a Muito bom ocorre em menos de três semanas.
A API é exclusivamente assíncrona porque o trabalho subjacente é remoto. ProcessDocumentAsync não é assíncrono porque o processamento é computacionalmente longo; É assíncrono porque o documento precisa ser enviado para um servidor, entrar em fila atrás de outras solicitações, concluir a inferência e retornar uma resposta pela rede. A latência não é determinística. A limitação de taxa de requisições HTTP 429 requer lógica de repetição. Erros de pagamento HTTP 402 interrompem completamente o processamento em lote. Erros HTTP 500 na infraestrutura da Muito bom comprometem seu fluxo de trabalho.
O escopo de documentos do Muito bom termina no limite do documento de despesa. Os modelos treinados retornam campos estruturados de forma confiável para recibos, faturas, cheques, extratos bancários, formulários W-2 e cartões de visita. Fora dessa lista — documentos comerciais gerais, contratos, registros médicos, documentos de remessa, formulários internos personalizados — os resultados são inferiores ou exigem treinamento pago em modelos personalizados. Organizações que adotam o Muito bom para automação de despesas normalmente descobrem, dentro de 6 a 12 meses, que outras equipes precisam de OCR para documentos que o Muito bom não foi projetado para processar.
O esquema JSON proprietário da Muito bom acopla toda a lógica de extração a um único fornecedor. Cada linha de código que lê response.Vendor?.Name, response.BankAccount?.RoutingNumber ou response.LineItems é código que só funciona com a Veryfi. Mudar de fornecedor — ou optar por um sistema OCR local — significa reescrever toda a lógica de extração do zero.
O problema fundamental
// Veryfi: financial data leaves your infrastructure on every call
var client = new VeryfiClient(clientId, clientSecret, username, apiKey); // 4 secrets
var bytes = File.ReadAllBytes("invoice-with-routing-number.pdf");
var response = await client.ProcessDocumentAsync(bytes); // bank details transmitted
var routingNumber = response.BankAccount?.RoutingNumber; // arrived via Muito bom cloud
// IronOCR: routing numbers never leave your server
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // 1 key
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("invoice-with-routing-number.pdf"); // processed locally
var result = ocr.Read(input);
var routingNumber = Regex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})").Groups[1].Value;
##IronOCR vs Veryfi: Comparação de Recursos
A tabela abaixo mapeia as funcionalidades de ambos os produtos para auxiliar na avaliação técnica.
| Recurso | Muito bom | IronOCR |
|---|---|---|
| Local de processamento | Servidores em nuvem Muito bom | Sua infraestrutura |
| Modelo de implantação | Somente API em nuvem | Local, Docker, Azure, AWS, Linux |
| Suporte offline | Não | Sim |
| É necessário ter acesso à internet. | Sim (todos os documentos) | Não |
| Os dados saem da infraestrutura. | Sim (em todas as chamadas) | Nunca |
| Compatível com HIPAA sem BAA | Não | Sim |
| Suporte para ambiente isolado (air-gapped) | Não é possível. | Suporte completo |
| Modelo de preços | Por documento (US$ 0,05 a US$ 0,30) | Licença perpétua ($999–$2,399) |
| Credenciais necessárias | 4 (clientId, clientSecret, username, apiKey) | 1 chave de licença |
| API síncrona | Não (somente assíncrono) | Sim |
| Limitação de taxa | Sim (HTTP 429) | None |
| Escopo do documento | Recibos, faturas, cheques, extratos bancários, formulários W-2, cartões de visita. | Qualquer tipo de documento |
| Tipos de documentos personalizados | Treinamento remunerado para modelos é obrigatório. | Qualquer layout via extração de regex/padrão |
| Entrada de PDF | Sim (upload de bytes) | Sim (nativo, local) |
| Saída em PDF pesquisável | Não | Sim (result.SaveAsSearchablePdf()) |
| OCR baseado em região | Não | Sim (CropRectangle) |
| Leitura de código de barras | Não | Sim (mesma aprovação do OCR) |
| Acesso estruturado aos resultados | Campos JSON pré-analisados | Páginas, parágrafos, linhas, palavras com coordenadas |
| Pontuação de confiança | Por campo (proprietário) | Por palavra e no geral (result.Confidence) |
| Suporte para mais de 125 idiomas | Limitado | Sim (pacotes de idiomas NuGet ) |
| Processamento paralelo seguro para threads | Aplicam-se limites de simultaneidade HTTP. | Completo (um IronTesseract por thread) |
| Testes unitários sem mocks | Requer simulação HTTP | Testes locais diretos |
Guia rápido: Migração do Muito bom para o IronOCR
Passo 1: Substitua o pacote NuGet
Remova o SDK Veryfi:
dotnet remove package Veryfi
Instale o IronOCR a partir do NuGet :
Etapa 2: Atualizar Namespaces
Substitua os namespaces Muito bom pelo namespace IronOCR:
// Before (Veryfi)
using Veryfi;
using Veryfi.Models;
// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
Etapa 3: Inicializar a licença
Adicione esta linha uma única vez na inicialização do aplicativo, antes de qualquer chamada de OCR:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Exemplos de migração de código
Substituição de Cliente de Processamento de Documentos
Os serviços Muito bom são construídos em torno da injeção de construtores de VeryfiClient. O construtor de quatro credenciais é uma solução natural para injeção de dependência, mas cria quatro segredos que precisam ser gerenciados e rotacionados. Substituir isso pelo IronOCR consolida as credenciais em uma única chave de licença e move a instanciação do mecanismo de processamento para a própria classe de serviço.
Abordagem Veryfi:
using Veryfi;
using Microsoft.Extensions.Configuration;
public class ExpenseDocumentService
{
private readonly VeryfiClient _client;
// Four credentials injected — four secrets to manage, store, rotate
public ExpenseDocumentService(IConfiguration config)
{
_client = new VeryfiClient(
config["Veryfi:ClientId"], // secret 1
config["Veryfi:ClientSecret"], // secret 2
config["Veryfi:Username"], // secret 3
config["Veryfi:ApiKey"] // secret 4
);
}
public async Task<string> GetVendorNameAsync(string documentPath)
{
var bytes = File.ReadAllBytes(documentPath);
// Document uploaded to Muito bom on this call
var response = await _client.ProcessDocumentAsync(bytes);
return response.Vendor?.Name;
}
public async Task<decimal?> GetTotalAsync(string documentPath)
{
var bytes = File.ReadAllBytes(documentPath);
var response = await _client.ProcessDocumentAsync(bytes);
return response.Total;
}
}
Abordagem IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
public class ExpenseDocumentService
{
private readonly IronTesseract _ocr;
// One license key — set once at startup, not per-instance
public ExpenseDocumentService()
{
_ocr = new IronTesseract();
}
public string GetVendorName(string documentPath)
{
// All processing local — document bytes never leave this server
var result = _ocr.Read(documentPath);
// Vendor is typically the first non-whitespace line on a receipt
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
}
public decimal? GetTotal(string documentPath)
{
var result = _ocr.Read(documentPath);
var match = Regex.Match(result.Text,
@"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return match.Success
? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
: (decimal?)null;
}
}
A alteração do construtor elimina quatro entradas de configuração de cada ambiente: appsettings.json, segredos do Docker, referências do Azure Key Vault e variáveis de pipeline CI/CD. A instância IronTesseract é reutilizável em várias chamadas na mesma thread. Consulte o guia de configuração do IronTesseract para obter informações sobre padrões de registro singleton em contêineres de injeção de dependência do ASP.NET Core .
Extração de campos de recibo com OCR baseado em região
O Muito bom extrai os campos do recibo executando seus modelos de aprendizado de máquina treinados em toda a imagem do documento e retornando uma resposta JSON pré-estruturada. O equivalente do IronOCR é OCR baseado em região usando CropRectangle, que visa zonas específicas da imagem de recibo—zona de cabeçalho para fornecedor, zona de rodapé para totais—ao invés de executar uma passagem de página completa e procurar padrões na saída. Este método é mais rápido para layouts conhecidos e mais preciso quando a área de interesse está bem definida.
Abordagem Veryfi:
using Veryfi;
public class ReceiptFieldExtractor
{
private readonly VeryfiClient _client;
public ReceiptFieldExtractor(VeryfiClient client)
{
_client = client;
}
public async Task<(string Vendor, decimal? Total, decimal? Tax)>
ExtractReceiptFieldsAsync(string imagePath)
{
var bytes = File.ReadAllBytes(imagePath);
// Full document uploaded — Veryfi's ML returns structured fields
var response = await _client.ProcessDocumentAsync(bytes);
return (
Vendor: response.Vendor?.Name,
Total: response.Total,
Tax: response.Tax
);
}
}
Abordagem IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
public class ReceiptFieldExtractor
{
private readonly IronTesseract _ocr = new IronTesseract();
public (string Vendor, decimal? Total, decimal? Tax)
ExtractReceiptFields(string imagePath)
{
// Region 1: Header zone — vendor name typically in top 15% of receipt
var headerRegion = new CropRectangle(0, 0, 800, 150);
using var headerInput = new OcrInput();
headerInput.LoadImage(imagePath, headerRegion);
headerInput.Deskew();
var headerResult = _ocr.Read(headerInput);
// Region 2: Footer zone — totals typically in bottom 20% of receipt
var footerRegion = new CropRectangle(0, 650, 800, 200);
using var footerInput = new OcrInput();
footerInput.LoadImage(imagePath, footerRegion);
footerInput.DeNoise();
var footerResult = _ocr.Read(footerInput);
var vendor = headerResult.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
var footerText = footerResult.Text;
var totalMatch = Regex.Match(footerText,
@"(?:Total|Grand Total):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
var taxMatch = Regex.Match(footerText,
@"(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return (
Vendor: vendor,
Total: totalMatch.Success
? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
: (decimal?)null,
Tax: taxMatch.Success
? decimal.Parse(taxMatch.Groups[1].Value.Replace(",", ""))
: (decimal?)null
);
}
}
CropRectangle leva (x, y, width, height) em pixels. Processar apenas o cabeçalho e o rodapé é mais rápido do que ler a página inteira e evita correspondências falsas devido aos valores dos itens no corpo do recibo. O guia de OCR baseado em regiões aborda estratégias de medição de coordenadas para documentos de tamanho variável, e o exemplo de recorte de região mostra o padrão completo.
Categorização de despesas com dados estruturados em parágrafos
Veryfi retorna response.LineItems como um array pré-estruturado de objetos com Description, Quantity, UnitPrice, e Total já analisados.IronOCR fornece o equivalente através de result.Pages[0].Paragraphs e result.Lines, que expõem cada bloco de texto com suas coordenadas X/Y. A lógica de categorização de despesas — que decide se um item de linha é uma despesa com refeição, viagem, suprimentos ou software — opera no mesmo texto em ambos os casos. A diferença é que, com o IronOCR, a lógica de categorização é sua, você pode ajustá-la e estendê-la sem precisar pagar por um novo ciclo de treinamento de aprendizado de máquina.
Abordagem Veryfi:
using Veryfi;
public class ExpenseCategorizer
{
private readonly VeryfiClient _client;
public ExpenseCategorizer(VeryfiClient client)
{
_client = client;
}
public async Task<Dictionary<string, decimal>> CategorizeExpensesAsync(string receiptPath)
{
var bytes = File.ReadAllBytes(receiptPath);
var response = await _client.ProcessDocumentAsync(bytes);
var categories = new Dictionary<string, decimal>();
// Line items arrive pre-parsed from Veryfi's ML pipeline
foreach (var item in response.LineItems ?? Enumerable.Empty<dynamic>())
{
var category = response.Category ?? "Uncategorized";
var amount = (decimal)(item.Total ?? 0m);
if (!categories.ContainsKey(category))
categories[category] = 0m;
categories[category] += amount;
}
return categories;
}
}
Abordagem IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
public class ExpenseCategorizer
{
private readonly IronTesseract _ocr = new IronTesseract();
// Keyword-based categorization — tune these for your expense policy
private static readonly Dictionary<string, string[]> CategoryKeywords = new()
{
["Meals & Entertainment"] = new[] { "restaurant", "cafe", "coffee", "lunch", "dinner", "food", "bar" },
["Travel"] = new[] { "airline", "hotel", "uber", "lyft", "taxi", "parking", "gas", "fuel" },
["Office Supplies"] = new[] { "staples", "office depot", "paper", "ink", "toner", "supplies" },
["Software & Subscriptions"] = new[] { "adobe", "microsoft", "github", "aws", "azure", "slack" }
};
public Dictionary<string, decimal> CategorizeExpenses(string receiptPath)
{
var result = _ocr.Read(receiptPath);
// Use paragraph coordinates to isolate line items
// Line items typically appear in the middle vertical band of the receipt
var lineItemParagraphs = result.Pages[0].Paragraphs
.Where(p => p.Y > 150 && p.Y < 650) // skip header/footer regions
.OrderBy(p => p.Y)
.ToList();
var categories = new Dictionary<string, decimal>();
var pricePattern = new Regex(@"\$?([\d,]+\.\d{2})$");
var vendorText = result.Text.ToLower();
// Determine top-level category from vendor name
var topCategory = "Uncategorized";
foreach (var (cat, keywords) in CategoryKeywords)
{
if (keywords.Any(kw => vendorText.Contains(kw)))
{
topCategory = cat;
break;
}
}
// Extract individual line item amounts
foreach (var para in lineItemParagraphs)
{
var priceMatch = pricePattern.Match(para.Text.Trim());
if (!priceMatch.Success)
continue;
if (!decimal.TryParse(priceMatch.Groups[1].Value.Replace(",", ""), out var amount))
continue;
// Classify individual items where keywords appear in the description
var itemCategory = topCategory;
var descriptionText = para.Text.ToLower();
foreach (var (cat, keywords) in CategoryKeywords)
{
if (keywords.Any(kw => descriptionText.Contains(kw)))
{
itemCategory = cat;
break;
}
}
if (!categories.ContainsKey(itemCategory))
categories[itemCategory] = 0m;
categories[itemCategory] += amount;
}
return categories;
}
}
A coleção Paragraphs fornece a coordenada Y de cada bloco de texto, o que facilita isolar a zona vertical onde os itens de linha aparecem em um layout padrão de recibo. O guia de acesso a dados estruturados explica a hierarquia completa de Pages, Paragraphs, Lines, Words, e Characters com suas propriedades de coordenadas. Para recibos com baixa qualidade de digitalização — papel amassado, impressão térmica de baixo contraste — o guia de correção da qualidade da imagem abrange filtros de pré-processamento que melhoram a precisão antes da execução da lógica de categorização.
Eliminação de Webhooks e Substituição Síncrona em Lote
Em situações de alto volume de documentos, a Muito bom recomenda notificações baseadas em webhooks em vez de polling. O padrão requer um endpoint HTTPS acessível publicamente, um segredo webhook para verificação de assinatura, uma fila para armazenar os resultados até que o webhook seja acionado e uma lógica de repetição para entregas perdidas. Trata-se de uma infraestrutura significativa para o que, em última análise, é uma solução alternativa para o fato de o OCR na nuvem ser lento em comparação com o processamento local. O IronOCR processa de forma síncrona. Não existe nenhuma lacuna assíncrona a ser preenchida com um webhook.
Abordagem Veryfi:
using Veryfi;
using Microsoft.AspNetCore.Mvc;
// Muito bom webhook receiver — required for high-volume reliable processing
[ApiController]
[Route("webhooks")]
public class VeryfiWebhookController : ControllerBase
{
private readonly IDocumentResultQueue _queue;
public VeryfiWebhookController(IDocumentResultQueue queue)
{
_queue = queue;
}
[HttpPost("veryfi")]
public IActionResult ReceiveWebhook([FromBody] VeryfiWebhookPayload payload,
[FromHeader(Name = "X-Veryfi-Token")] string token)
{
// Validate webhook signature — prevents spoofed payloads
if (!IsValidSignature(token, payload))
return Unauthorized();
// Enqueue result for async downstream consumption
_queue.Enqueue(new DocumentResult
{
DocumentId = payload.Id,
Vendor = payload.Data?.Vendor?.Name,
Total = payload.Data?.Total
});
return Ok();
}
private bool IsValidSignature(string token, VeryfiWebhookPayload payload) =>
// HMAC validation against webhook secret — infrastructure requirement
token == ComputeHmac(payload, Environment.GetEnvironmentVariable("VERYFI_WEBHOOK_SECRET"));
}
// Document batch submission — fire and forget, results arrive via webhook
public class VeryfiDocumentBatchSubmitter
{
private readonly VeryfiClient _client;
public async Task SubmitBatchAsync(string[] documentPaths)
{
foreach (var path in documentPaths)
{
var bytes = File.ReadAllBytes(path);
// Submit — result arrives asynchronously via webhook, not here
await _client.ProcessDocumentAsync(bytes);
}
}
}
Abordagem IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
// Não webhook controller needed — results are synchronous and local
public class DocumentBatchProcessor
{
// IronTesseract is thread-safe when one instance is created per thread
public List<DocumentResult> ProcessBatch(string[] documentPaths)
{
var results = new ConcurrentBag<DocumentResult>();
Parallel.ForEach(documentPaths, documentPath =>
{
// One IronTesseract per thread — thread-safe pattern
var ocr = new IronTesseract();
var result = ocr.Read(documentPath);
results.Add(new DocumentResult
{
FilePath = documentPath,
Vendor = ExtractVendor(result),
Total = ExtractTotal(result.Text),
Confidence = result.Confidence,
// Result is available immediately — no queue, no webhook
ProcessedAt = DateTime.UtcNow
});
});
return results.OrderBy(r => r.FilePath).ToList();
}
private string ExtractVendor(OcrResult result)
{
// Vendor: first substantive paragraph ordered by vertical position
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => !string.IsNullOrWhiteSpace(t) && t.Length > 3);
}
private decimal? ExtractTotal(string text)
{
var match = Regex.Match(text,
@"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return match.Success
? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
: (decimal?)null;
}
}
public class DocumentResult
{
public string FilePath { get; set; }
public string Vendor { get; set; }
public decimal? Total { get; set; }
public double Confidence { get; set; }
public DateTime ProcessedAt { get; set; }
}
A remoção da camada de webhook elimina o endpoint HTTPS, a exigência de rotação do segredo do webhook, a fila de resultados, a lógica de validação HMAC e a configuração de repetição. Toda a infraestrutura subsequente só existe porque os resultados do Muito bom chegam de forma assíncrona de um servidor remoto. Com IronOCR, Parallel.ForEach substitui tudo isso. O exemplo de multithreading demonstra o padrão IronTesseract por thread em detalhes, e o guia de OCR assíncrono cobre a integração de Task.Run para a responsividade da interface do usuário. O guia de otimização de velocidade aborda a configuração da instância para obter o máximo desempenho em cargas de trabalho em lote.
Referência de mapeamento da API Muito bom para o IronOCR
| Muito bom | Equivalente de IronOCR |
|---|---|
new VeryfiClient(clientId, clientSecret, username, apiKey) | new IronTesseract() + IronOcr.License.LicenseKey = "key" |
_client.ProcessDocumentAsync(bytes) | ocr.Read(filePath) ou ocr.Read(ocrInput) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" }) | input.LoadPdf(caminho); ocr.Read(entrada) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" }) | input.LoadPdf(caminho); ocr.Read(entrada) |
response.Vendor?.Name | Primeiro parágrafo ordenado por p.Y de result.Pages[0].Paragraphs |
response.Total | Regex.Match(result.Text, @"Total:?\s*\$?([\d,]+\.\d{2})") |
response.Tax | Regex.Match(result.Text, @"Tax:?\s*\$?([\d,]+\.\d{2})") |
response.Date | Regex.Match(result.Text, @"\d{1,2}/\d{1,2}/\d{4}") |
response.LineItems | result.Pages[0].Paragraphs filtrado por intervalo de coordenadas Y |
response.InvoiceNumber | Regex.Match(result.Text, @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)") |
response.BankAccount?.AccountNumber | Regex.Match(result.Text, @"Account\s*#?\s*:?\s*(\d{4,})") |
response.BankAccount?.RoutingNumber | Regex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})") |
response.ConfidenceScore | result.Confidence (no geral) ou word.Confidence (por palavra) |
response.Payment?.Last4 | Regex.Match(result.Text, @"\*{4}\s*(\d{4})") |
VeryfiApiException (401/402/429/500) | Exceções padrão do .NET — sem códigos de erro HTTP para processamento local. |
| Codificação Base64 antes do upload | Não requerido — ocr.Read(filePath) aceita caminhos de arquivos diretamente |
response.Category | Correspondência de palavra-chave personalizada contra result.Text |
| desserialização da carga útil do webhook | Não requerido — ocr.Read() retorna o resultado de forma síncrona |
ProcessDocumentAsync com tentativa/recuperação | Não é necessário — não há limites de taxa para processamento local. |
Problemas e soluções comuns em migrações
Problema 1: Campos pré-analisados ausentes
Veryfi: response.Vendor?.Name, response.Total, e response.LineItems chegam como campos estruturados de um modelo de ML pré-treinado. Nenhuma lógica de extração é necessária no lado do cliente.
Solução: Escreva padrões Regex para cada campo utilizado pela sua aplicação. O processo de migração normalmente leva de 8 a 24 horas, dependendo da quantidade de layouts de documentos distintos que você precisa processar. Para padrões comuns de recibos e faturas, o tutorial de OCR para faturas e o tutorial de digitalização de recibos fornecem implementações completas de padrões de extração.
// Map each Muito bom field to a Regex extraction
private static readonly Dictionary<string, string> FieldPatterns = new()
{
["InvoiceNumber"] = @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
["PurchaseOrder"] = @"(?:PO|P\.O\.|Purchase Order)\s*#?\s*:?\s*(\w+)",
["DueDate"] = @"Due\s*(?:Date)?:?\s*(\d{1,2}/\d{1,2}/\d{4})",
["PaymentTerms"] = @"(?:Terms|Net)\s*:?\s*(\w+\s*\d+)"
};
public string ExtractField(string text, string fieldName)
{
if (!FieldPatterns.TryGetValue(fieldName, out var pattern))
return null;
var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
return match.Success ? match.Groups[1].Value.Trim() : null;
}
Problema 2: Assinaturas de Métodos Assíncronos em Toda a Base de Código
Veryfi: ProcessDocumentAsync é assíncrono no nível do SDK da Veryfi. As equipes tipicamente propagam await através de cada método de chamada na pilha de chamadas, significando que classes de serviços, controladores e trabalhos em segundo plano todos carregam assinaturas async Task<t>.
Solução: O Read() do IronOCR é síncrono. As assinaturas de método async existentes podem ser preservadas envolvidas com Task.Run durante o período de transição. Isso evita alterações em massa nas assinaturas em toda a base de código, eliminando ao mesmo tempo a dependência da nuvem.
// Preserve async signature during transition — no codebase-wide refactor needed
public async Task<string> GetVendorNameAsync(string documentPath)
{
return await Task.Run(() =>
{
var result = _ocr.Read(documentPath);
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
});
}
Problema 3: Configuração de credenciais dispersa em diferentes ambientes
Veryfi: Quatro credenciais (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey) aparecem em appsettings.json, blocos de variáveis de ambiente em arquivos Docker Compose, segredos de Ações GitHub, referências de Azure Key Vault e configurações de pipeline CI/CD.
Solução: Pesquise e remova todas as quatro entradas de credenciais de todos os ambientes. Adicionar uma única variável de ambiente IRONOCR_LICENSE_KEY. Carregue-o na inicialização.
# Find all Muito bom credential references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
--include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
// Load from environment at startup
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
Problema 4: Problemas de qualidade de digitalização não visíveis anteriormente
Veryfi: O processamento em nuvem inclui aprimoramento de imagem no servidor antes da execução da inferência de aprendizado de máquina. As digitalizações de recibos de baixa qualidade — papel amassado, impressão térmica desbotada, fotos distorcidas tiradas com celular — foram corrigidas silenciosamente antes da extração dos dados.
Solução: Aplique explicitamente o pipeline de pré-processamento do IronOCR. Deskew(), DeNoise(), e Contrast() cobrem a maioria dos problemas de qualidade de escaneamento de recibos do mundo real.
using var input = new OcrInput();
input.LoadImage("receipt-phone-photo.jpg");
input.Deskew(); // correct rotation from angled phone capture
input.DeNoise(); // remove compression artifacts
input.Contrast(); // improve faded thermal print
input.Sharpen(); // recover edge detail
var result = _ocr.Read(input);
O guia de correção da qualidade da imagem e o tutorial de filtros de imagem abordam quais filtros aplicar para padrões específicos de degradação da digitalização.
Problema 5: Capacidade de Processamento em Lote de Alto Volume
Veryfi: Os limites de taxa restringem a velocidade de envio de documentos. As respostas HTTP 429 exigem lógica de recuo exponencial. A taxa de transferência é limitada pelo limite de taxa por plano da Veryfi, não pelo seu hardware.
Solução: O IronOCR é limitado apenas pelos núcleos da CPU. Use Parallel.ForEach com uma instância IronTesseract por thread. Em um servidor de 8 núcleos, a taxa de transferência aumenta aproximadamente de forma linear com o número de núcleos.
// One IronTesseract per thread — do not share instances across threads
Parallel.ForEach(
documentPaths,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
path =>
{
var ocr = new IronTesseract();
var result = ocr.Read(path);
SaveResult(path, result.Text, result.Confidence);
});
Problema 6: Esquema JSON proprietário bloqueado para Veryfi
Veryfi: Todo o código de extração lê do esquema de resposta da Veryfi: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. Este código funciona apenas com o SDK da Veryfi. Qualquer alteração no nome de um campo durante uma atualização da API Muito bom quebra o código do aplicativo.
Solução: A extração do IronOCR usa System.Text.RegularExpressions.Regex padrão do .NET contra texto simples. Os padrões são portáteis, testáveis sem a necessidade de simular nenhum SDK e estão sob seu controle. Os testes unitários são executados sem qualquer conexão de rede.
// Extraction logic that is fully portable and unit-testable
[Fact]
public void ExtractsRoutingNumberFromInvoiceText()
{
const string sampleText = "Routing Number: 021000021\nAccount: 1234567890";
var match = Regex.Match(sampleText, @"Routing\s*(?:Number)?:?\s*(\d{9})",
RegexOptions.IgnoreCase);
Assert.True(match.Success);
Assert.Equal("021000021", match.Groups[1].Value);
}
Lista de verificação para migração Veryfi
Pré-migração
Antes de modificar qualquer código, faça uma auditoria do código-fonte para inventariar todo o uso do Veryfi:
# Find all Muito bom using statements
grep -rn "using Veryfi" --include="*.cs" .
# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .
# Find all Muito bom response field accesses
grep -rn "response\.Vendor\|response\.Total\|response\.LineItems\|response\.BankAccount" --include="*.cs" .
# Find all credential configuration references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
--include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
# Find all webhook-related code
grep -rn "VeryfiWebhook\|X-Veryfi-Token\|webhook" --include="*.cs" .
Grave o total de sites de chamadas ProcessDocumentAsync, a lista de campos de resposta acessados por site de chamada e a lista de ambientes contendo credenciais Veryfi.
Migração de código
- Remova o pacote NuGet
Veryfide todos os projetos na solução. - Instale o pacote NuGet
IronOcrem todos os projetos que anteriormente referenciavamVeryfi. - Adicione
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";ao início do aplicativo (antes de qualquer chamada OCR). - Substitua todas as declarações
using Veryfi;eusing Veryfi.Models;porusing IronOcr;. - Substitua a injeção de construtor
VeryfiClientpor inicialização de campoIronTesseract. - Remova todas as quatro entradas de credenciais Muito bom de cada
appsettings.json,appsettings.*.json, e arquivo de configuração de segredos. - Converta chamadas
ProcessDocumentAsync(bytes)paraocr.Read(filePath)ouocr.Read(ocrInput). - Substitua os acessos
response.Vendor?.Namepor extração de texto ordenado por parágrafo deresult.Pages[0].Paragraphs. - Substitua os acessos aos campos estruturados
response.Total,response.Tax,response.InvoiceNumbere outros, por padrões Regex contraresult.Text. - Substitua a iteração
response.LineItemspor iteraçãoresult.Pages[0].Paragraphsfiltrado por coordenada Y. - Exclua as classes do controlador de webhook e remova os registros de endpoints de webhook.
- Remova as variáveis de ambiente secretas do webhook de todos os ambientes.
- Adicione
OcrInputcom pré-processamento (Deskew(),DeNoise(),Contrast()) para entradas de imagem escaneadas. - Substitua os loops sequenciais single-threaded por
Parallel.ForEachusando umIronTesseractpor thread. - Adicione
IRONOCR_LICENSE_KEYa todas as configurações de variáveis de ambiente e armazenamentos de segredos de CI/CD.
Pós-migração
- Verifique se não há chamadas de rede Muito bom nos registros de tráfego HTTP após a implantação da migração.
- Confirme se os nomes dos fornecedores extraídos correspondem aos valores esperados em uma amostra de 20 a 50 recibos.
- Confirme se os totais extraídos correspondem aos valores esperados dentro de uma tolerância de US$ 0,01 para o mesmo conjunto de amostras.
- Verificar se a extração do número da fatura é bem-sucedida para cada formato de fatura no conjunto de documentos.
- Testar a taxa de transferência do processamento em lote em comparação com a taxa de transferência de referência do Muito bom para confirmar a remoção do limite de taxa.
- Execute o Suite completo de testes sem qualquer conexão de rede para confirmar a ausência de dependência da nuvem.
- Confirme que as pontuações
result.Confidenceexcedem 80% para escaneamentos de documentos limpos; Valores abaixo de 80% indicam que uma etapa de pré-processamento deve ser adicionada. - Verifique se todas as quatro credenciais do Muito bom foram removidas de todos os ambientes (desenvolvimento, teste e produção).
- Confirme se os endpoints do webhook retornam 404 ou se foram removidos da tabela de roteamento.
- Testar o comportamento em digitalizações de recibos de baixa qualidade (amassados, desbotados, tortos) com o pipeline de pré-processamento ativo.
Principais benefícios da migração para o IronOCR
Os documentos financeiros processados localmente são documentos que não podem ser acessados por terceiros. Após a migração, os números de contas bancárias extraídos de faturas, os números de roteamento obtidos de cheques e os históricos de transações lidos de extratos bancários são todos processados em seu hardware. Nenhum incidente de segurança de terceiros, acesso a dados de subcontratados ou violação da infraestrutura da Muito bom pode expor documentos que nunca saíram dos seus servidores.
Os custos por documento caem para zero no dia em que a migração é implementada. Com 50.000 documentos por mês, o item de custo mensal do Veryfi, que variava de US$ 5.000 a US$ 15.000, desaparece. A licença IronOCR Professional , que custa US$ 2.999 e é adquirida uma única vez, é recuperada na primeira semana do primeiro mês. Em volumes maiores, as economias se acumulam a cada ano, sem necessidade de negociação de descontos por volume ou renovação de contrato.
A capacidade de processamento escala com o hardware, não com os limites de taxa do fornecedor. Respostas HTTP 429, limites de taxa de transferência por plano e cobranças sazonais por excesso de uso são artefatos arquitetônicos de APIs em nuvem. Com o IronOCR, adicionar núcleos de CPU aumenta a capacidade de processamento proporcionalmente. Um lote de 10.000 recibos é processado de acordo com o seu cronograma, e não com base na programação de limite de taxa da Veryfi.
Qualquer tipo de documento é processado com a mesma API. A organização não precisa mais de uma segunda ferramenta de OCR quando o RH solicita o processamento de formulários de integração, o departamento jurídico precisa extrair o texto de contratos ou a área de operações precisa de dados de documentos de remessa. ocr.Read() lida com todos eles. O tutorial de leitura de texto em imagens e os guias de documentos especializados abrangem toda a gama de formatos de documentos que o IronOCR suporta.
A lógica de extração torna-se parte integrante do código-fonte. Os padrões de expressões regulares estão no controle de versão, podem ser revisados em pull requests, testados em testes unitários sem a necessidade de simular nenhum SDK e ajustados com base no feedback da produção. Quando o modelo pré-treinado da Muito bom retorna um nome de fornecedor incorreto, não há nada para ajustar. Quando o padrão de extração do IronOCR retorna um nome de fornecedor incorreto, a correção consiste em uma alteração de expressão regular de uma linha com um teste unitário. A página de licenciamento do IronOCR aborda as opções de planos, incluindo a assinatura SaaS para equipes que preferem o faturamento anual em vez da compra perpétua.
A infraestrutura de implantação é reduzida a um único pacote NuGet que pode ser executado em qualquer lugar. O IronOCR é instalado como um único pacote, sem dependências externas, sem gerenciamento de binários nativos e sem configuração da pasta tessdata. A mesma referência de pacote é resolvida no Windows, Linux, macOS, Docker, Azure App Service e AWS Lambda sem código condicional à plataforma. Consulte o guia de implantação do Docker e o guia de implantação do Linux para ambientes conteinerizados onde o requisito de saída de rede do Muito bom representa um obstáculo à implantação.
