Migración de Veryfi a IronOCR
Esta guía guía a los desarrolladores de .NET a través del proceso de sustitución de la API de procesamiento de documentos en la nube de Muy fi por IronOCR, una biblioteca IronOCR local. Abarca el intercambio de paquetes, la limpieza de espacios de nombres y cuatro ejemplos completos de migración de código centrados en los patrones más comunes en torno a Veryfi: inicialización del cliente, extracción de campos basada en regiones, categorización de gastos con datos estructurados y sustitución de webhooks. No es necesario haber leído previamente el artículo comparativo.
¿Por qué migrar desde Veryfi?
Los documentos financieros fluyen a través del proceso de Muy fi en una sola dirección: desde su infraestructura hacia la de ellos. Ese hecho arquitectónico impulsa la mayoría de las migraciones. Estos son los puntos débiles específicos que empujan a los equipos a dar el salto.
Cada llamada de documento transmite datos financieros confidenciales a un servidor de terceros. Los recibos contienen los cuatro últimos dígitos de la tarjeta y las relaciones con los proveedores. Las facturas incluyen números de cuenta bancaria, números de ruta y números de identificación fiscal de los proveedores. Los extractos bancarios contienen el historial completo de transacciones. Con Veryfi, cada llamada ProcessDocumentAsync carga esos bytes a api.veryfi.com, los procesa en la infraestructura de Veryfi, y devuelve JSON. Tu control sobre esos datos termina en el momento en que se envía la solicitud HTTP.
Se requieren cuatro credenciales y deben mantenerse sincronizadas en todos los entornos. VeryfiClient requiere clientId, clientSecret, username, y apiKey—cuatro secretos separados para almacenar en la configuración, rotar según horario, inyectar en las tuberías de CI/CD, y auditar para exposición. Una sola fuga de credenciales rompe la autenticación de todos los documentos procesados en toda la aplicación.IronOCR requiere una cadena de clave de licencia.
El precio por documento se acumula sin límite máximo. Los recibos cuestan aproximadamente entre 0,05 y 0,15 dólares cada uno, las facturas entre 0,10 y 0,25 dólares, y los extractos bancarios entre 0,15 y 0,30 dólares. A razón de 50 000 documentos al mes, eso supone entre 5000 y 15 000 dólares al mes en facturación por consumo, sin reducción en el segundo ni en el tercer año. La licencia IronOCR Professional, con un precio de 2999 $, cubre un número ilimitado de documentos de forma perpetua; el umbral de rentabilidad frente a un gasto mensual de 5000 $ en Muy fi se alcanza en menos de tres semanas.
La API es solo asincrónica porque el trabajo subyacente es remoto. ProcessDocumentAsync no es asincrónica porque el procesamiento es computacionalmente prolongado; Es asíncrono porque el documento debe enviarse a un servidor, ponerse en cola detrás de otras solicitudes, completar la inferencia y devolver una respuesta a través de la red. La latencia no es determinista. La limitación de velocidad HTTP 429 requiere una lógica de reintento. Los errores de pago HTTP 402 detienen por completo el procesamiento por lotes. Los errores HTTP 500 en la infraestructura de Muy fi paralizan tu flujo de trabajo.
El alcance de los documentos de Muy fi termina en el límite del documento de gastos. Los modelos entrenados devuelven campos estructurados de forma fiable para recibos, facturas, cheques, extractos bancarios, formularios W-2 y tarjetas de visita. Fuera de esa lista —documentos empresariales generales, contratos, historiales médicos, documentos de envío, formularios internos personalizados— los resultados se deterioran o requieren un entrenamiento de modelos personalizados de pago. Las organizaciones que adoptan Muy fi para la automatización de gastos suelen descubrir, en un plazo de 6 a 12 meses, que otros equipos necesitan OCR para documentos que Muy fi no fue diseñado para gestionar.
El esquema propietario JSON de Muy fi acopla toda la lógica de extracción a un único proveedor. Cada línea de código que lee response.Vendor?.Name, response.BankAccount?.RoutingNumber, o response.LineItems es código que solo funciona con Veryfi. Cambiar de proveedor —o pasar a un OCR local— implica reescribir toda la lógica de extracción desde cero.
El 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 Muy fi 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 frente a Veryfi: comparación de características
La tabla siguiente compara las capacidades de ambos productos para facilitar la evaluación técnica.
| Característica | Muy fi | IronOCR |
|---|---|---|
| Lugar de procesamiento | Servidores en la nube Muy fi | Su infraestructura |
| Modelo de despliegue | Solo API en la nube | Local, Docker, Azure, AWS, Linux |
| Soporte sin conexión | No | Sí |
| Se requiere conexión a Internet | Sí (todos los documentos) | No |
| Los datos salen de la infraestructura | Sí (en cada llamada) | Nunca |
| Compatible con la HIPAA sin BAA | No | Sí |
| Compatibilidad con entornos aislados | No es posible | Totalmente compatible |
| Modelo de precios | Por documento (entre 0,05 y 0,30 dólares) | Licencia perpetua ($999–$2,399) |
| Credenciales requeridas | 4 (clientId, clientSecret, username, apiKey) | 1 clave de licencia |
| API síncrona | No (solo asíncrono) | Sí |
| limitación de velocidad | Sí (HTTP 429) | None |
| Alcance del documento | Recibos, facturas, cheques, extractos bancarios, formularios W-2, tarjetas de visita | Cualquier tipo de documento |
| Tipos de documentos personalizados | Se requiere formación en modelos de pago | Cualquier diseño mediante extracción de expresiones regulares/patrones |
| Entrada de PDF | Sí (carga de bytes) | Sí (nativo, local) |
| Salida en PDF con capacidad de búsqueda | No | Sí (result.SaveAsSearchablePdf()) |
| OCR basado en regiones | No | Sí (CropRectangle) |
| Lectura de BarCodes | No | Sí (mismo proceso de OCR) |
| Acceso estructurado a los resultados | Campos JSON preanalizados | Páginas, párrafos, líneas, palabras con coordenadas |
| Puntuación de confianza | Por campo (propietario) | Por palabra y en general (result.Confidence) |
| Soporte para más de 125 idiomas | Limitado | Sí (paquetes de idiomas de NuGet) |
| Procesamiento paralelo seguro para subprocesos | Se aplican límites de concurrencia HTTP | Completo (un IronTesseract por hilo) |
| Pruebas unitarias sin simulaciones | Requiere simulación de HTTP | Pruebas locales directas |
Inicio rápido: Migración de Muy fi a IronOCR
Paso 1: Sustituir el paquete NuGet
Eliminar el SDK de Veryfi:
dotnet remove package Veryfi
Instala IronOCR desde NuGet :
Paso 2: Actualizar los espacios de nombres
Sustituya los espacios de nombres de Muy fi por el espacio de nombres de IronOCR:
// Before (Veryfi)
using Veryfi;
using Veryfi.Models;
// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
Paso 3: Inicializar licencia
Añade esta línea una vez al iniciar la aplicación, antes de cualquier llamada a OCR:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Ejemplos de migración de código
Sustitución del cliente de procesamiento de documentos
Los servicios de Muy fi están construidos alrededor de la inyección de constructor de VeryfiClient. El constructor de cuatro credenciales es un punto natural para la inyección de dependencias, pero crea cuatro secretos que deben gestionarse y rotarse. Al sustituir esto por IronOCR, se consolidan las credenciales en una única clave de licencia y se traslada la instanciación del motor de procesamiento a la propia clase de servicio.
Enfoque de 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 Muy fi 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;
}
}
Enfoque 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;
}
}
El cambio de constructor elimina cuatro entradas de configuración de cada entorno: appsettings.json, secretos de Docker, referencias de Azure Key Vault y variables de tuberías de CI/CD. La instancia de IronTesseract es reutilizable a través de múltiples llamadas en el mismo hilo. Consulte la guía de configuración de IronTesseract para conocer los patrones de registro de singletons en contenedores de inyección de dependencias de .NET Core.
Extracción de campos de recibos con OCR basado en regiones
Veryfi extrae los campos de los recibos ejecutando sus modelos de aprendizaje automático entrenados sobre la imagen completa del documento y devolviendo una respuesta JSON preestructurada. El equivalente de IronOCR es OCR basado en regiones usando CropRectangle, que apunta a zonas específicas de la imagen del recibo—zona de encabezado para el proveedor, zona de pie de página para totales—en lugar de realizar un pase de página completa buscando patrones en la salida. Esto es más rápido para diseños conocidos y más preciso cuando el área de interés está bien definida.
Enfoque de 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
);
}
}
Enfoque 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 toma (x, y, width, height) en píxeles. Procesar solo las zonas del encabezado y el pie de página es más rápido que leer la página completa y evita coincidencias falsas con los importes de las partidas individuales del cuerpo del recibo. La guía OCR basada en regiones abarca estrategias de medición de coordenadas para documentos de tamaño variable, y el ejemplo de recorte de región muestra el patrón completo.
Categorización de gastos con datos de párrafos estructurados
Veryfi devuelve response.LineItems como un array preestructurado de objetos con Description, Quantity, UnitPrice, y Total ya analizados.IronOCR proporciona el equivalente a través de result.Pages[0].Paragraphs y result.Lines, que exponen cada bloque de texto con sus coordenadas X/Y. La lógica de categorización de gastos —decidir si una partida es una comida, un viaje, un material o un gasto de software— funciona con el mismo texto en ambos casos. La diferencia es que, con IronOCR, la lógica de categorización es tuya: puedes controlarla, ajustarla y ampliarla sin necesidad de un ciclo de reentrenamiento de ML de pago.
Enfoque de 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;
}
}
Enfoque 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;
}
}
La colección de Paragraphs proporciona la coordenada Y de cada bloque de texto, lo que facilita aislar la zona vertical donde aparecen los ítems en un diseño de recibo estándar. La guía de acceso a datos estructurados explica la jerarquía completa de Pages, Paragraphs, Lines, Words, y Characters con sus propiedades de coordenadas. Para los recibos con mala calidad de escaneo —papel arrugado, impresión térmica con poco contraste—, la guía de corrección de la calidad de la imagen incluye filtros de preprocesamiento que mejoran la precisión antes de que se ejecute la lógica de categorización.
Eliminación de webhooks y sustitución de lotes sincrónicos
En caso de grandes volúmenes de documentos, Muy fi recomienda las notificaciones basadas en webhooks en lugar del sondeo. El patrón requiere un punto final HTTPS de acceso público, un secreto de webhook para la verificación de la firma, una cola para almacenar los resultados hasta que se active el webhook y una lógica de reintento para las entregas fallidas. Se trata de una infraestructura importante para lo que, en última instancia, es una solución alternativa al hecho de que el OCR en la nube es lento en comparación con el procesamiento local.IronOCR procesa de forma sincrónica. No hay ninguna brecha asíncrona que salvar con un webhook.
Enfoque de Veryfi:
using Veryfi;
using Microsoft.AspNetCore.Mvc;
// Muy fi 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);
}
}
}
Enfoque IronOCR:
using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
// No 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; }
}
Al eliminar la capa de webhooks, se suprime el punto final HTTPS, el requisito de rotación de secretos de webhooks, la cola de resultados, la lógica de validación HMAC y la configuración de reintentos. Toda la infraestructura de procesamiento posterior existe únicamente porque los resultados de Muy fi llegan de forma asíncrona desde un servidor remoto. Con IronOCR, Parallel.ForEach reemplaza todo eso. El ejemplo de multihilos demuestra el patrón IronTesseract por hilo en detalle, y la guía OCR asincrónica cubre la integración Task.Run para la capacidad de respuesta de la UI. La guía de optimización de la velocidad abarca la configuración de instancias para obtener el máximo rendimiento en cargas de trabajo por lotes.
Referencia de mapeo de la API de Muy fi a IronOCR
| Muy fi | Equivalente a IronOCR |
|---|---|
new VeryfiClient(clientId, clientSecret, username, apiKey) | new IronTesseract() + IronOcr.License.LicenseKey = "key" |
_client.ProcessDocumentAsync(bytes) | ocr.Read(filePath) o ocr.Read(ocrInput) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" }) | input.LoadPdf(ruta); ocr.Leer(entrada) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" }) | input.LoadPdf(ruta); ocr.Leer(entrada) |
response.Vendor?.Name | Primer párrafo ordenado por p.Y desde 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 rango 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 (en general) o word.Confidence (por palabra) |
response.Payment?.Last4 | Regex.Match(result.Text, @"\*{4}\s*(\d{4})") |
VeryfiApiException (401/402/429/500) | Excepciones de .NET Standard: sin códigos de error HTTP para el procesamiento local |
| Codificación Base64 antes de la carga | No es necesario — ocr.Read(filePath) acepta rutas de archivo directamente |
response.Category | Emparejamiento de palabras clave personalizadas contra result.Text |
| Deserialización de la carga útil de Webhook | No es necesario — ocr.Read() devuelve el resultado de manera sincrónica |
ProcessDocumentAsync con reintento/retroceso | No es obligatorio: sin límites de frecuencia en el procesamiento local |
Problemas comunes de migración y soluciones
Problema 1: Campos preanalizados que faltan
Veryfi: response.Vendor?.Name, response.Total, y response.LineItems llegan como campos estructurados de un modelo de ML previamente entrenado. No se requiere ninguna lógica de extracción en el lado del cliente.
Solución: Escribe patrones Regex para cada campo que utilice tu aplicación. El tiempo de migración suele ser de entre 8 y 24 horas, dependiendo del número de diseños de documento distintos que se procesen. Para los patrones comunes de recibos y facturas, el tutorial de OCR de facturas y el tutorial de escaneo de recibos proporcionan implementaciones completas de los patrones de extracción.
// Map each Muy fi 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: Firmas de métodos asíncronos en todo el código base
Veryfi: ProcessDocumentAsync es asincrónico a nivel del SDK de Veryfi. Los equipos típicamente propagan await a través de cada método de llamada hacia arriba en la pila de llamadas, lo que significa que las clases de servicio, los controladores y los trabajos en segundo plano todos llevan firmas async Task<t>.
Solución: El Read() de IronOCR es sincrónico. Las firmas de métodos existentes async se pueden preservar envolviendo con Task.Run durante el período de transición. Esto evita cambios masivos de firmas en todo el código, al tiempo que elimina la dependencia de la nube.
// 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: Configuración de credenciales dispersa por los entornos
Veryfi: Cuatro credenciales (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey) aparecen en appsettings.json, bloques de variables de entorno en archivos de Docker Compose, secretos de GitHub Actions, referencias de Azure Key Vault y configuraciones de tuberías de CI/CD.
Solución: Buscar y eliminar las cuatro entradas de credenciales de todos los entornos. Agregue una sola variable de entorno IRONOCR_LICENSE_KEY. Cárgala al iniciar el sistema.
# Find all Muy fi 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 calidad de escaneo no visibles anteriormente
Veryfi: El procesamiento en la nube incluye la mejora de imágenes del lado del servidor antes de que se ejecute la inferencia de ML. Los escaneos de recibos de baja calidad —papel arrugado, impresión térmica descolorida, fotos de móvil torcidas— se corrigieron de forma automática antes de la extracción de campos.
Solución: Aplicar explícitamente el proceso de preprocesamiento de IronOCR. Deskew(), DeNoise(), y Contrast() cubren la mayoría de los problemas de calidad de escaneo de recibos en el 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);
La guía de corrección de la calidad de la imagen y el tutorial sobre filtros de imagen abordan qué filtros aplicar para patrones específicos de degradación de la digitalización.
Tema 5: Rendimiento del procesamiento por lotes de gran volumen
Veryfi: Los límites de velocidad restringen la velocidad de envío de documentos. Las respuestas HTTP 429 requieren una lógica de retroceso exponencial. El rendimiento está limitado por el límite de velocidad por plan de Veryfi, no por tu hardware.
**Solución:**IronOCR solo está limitado por los núcleos de la CPU. Use Parallel.ForEach con una instancia IronTesseract por hilo. En un servidor de 8 núcleos, el rendimiento escala de forma aproximadamente lineal con el 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 propietario vinculado a Veryfi
Veryfi: Todo el código de extracción lee del esquema de respuesta de Veryfi: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. Este código solo funciona con el SDK de Veryfi. Cualquier cambio en el nombre de un campo en una actualización de la API de Muy fi provoca errores en el código de la aplicación.
Solución: La extracción de IronOCR utiliza System.Text.RegularExpressions.Regex estándar de .NET contra texto plano. Los patrones son portátiles, se pueden probar sin necesidad de simular ningún SDK y están bajo tu control. Las pruebas unitarias se ejecutan sin conexión a la red.
// 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 verificación de migración de Veryfi
Pre-Migración
Revisa el código para hacer un inventario de todos los usos de Muy fi antes de tocar ningún código:
# Find all Muy fi using statements
grep -rn "using Veryfi" --include="*.cs" .
# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .
# Find all Muy fi 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" .
Registre el conteo total de los sitios de llamada ProcessDocumentAsync, la lista de campos de respuesta accesados por sitio de llamada, y la lista de entornos que contienen credenciales Veryfi.
Migración de código
- Elimine el paquete NuGet
Veryfide todos los proyectos en la solución. - Instale el paquete NuGet
IronOcren todos los proyectos que anteriormente referenciabanVeryfi. - Agregue
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";al inicio de la aplicación (antes de cualquier llamada de OCR). - Reemplace todas las declaraciones
using Veryfi;yusing Veryfi.Models;conusing IronOcr;. - Reemplace la inyección de constructor
VeryfiClientcon la inicialización de campoIronTesseract. - Elimine las cuatro entradas de credenciales Muy fi de cada archivo de configuración de
appsettings.json,appsettings.*.json, y secretos. - Convierta llamadas
ProcessDocumentAsync(bytes)aocr.Read(filePath)oocr.Read(ocrInput). - Reemplace los accesos
response.Vendor?.Namecon extracción de texto ordenada por párrafo desderesult.Pages[0].Paragraphs. - Reemplace
response.Total,response.Tax,response.InvoiceNumber, y otros accesos a campos estructurados con patrones Regex contraresult.Text. - Reemplace la iteración
response.LineItemscon iteraciónresult.Pages[0].Paragraphsfiltrada por coordenada Y. - Eliminar las clases del controlador de webhooks y eliminar los registros de puntos finales de webhooks.
- Eliminar las variables de entorno secretas de webhook de todos los entornos.
- Agregue
OcrInputcon preprocesamiento (Deskew(),DeNoise(),Contrast()) para entradas de imagen escaneada. - Reemplace los bucles secuenciales de un solo hilo con
Parallel.ForEachusando unaIronTesseractpor hilo. - Agregue
IRONOCR_LICENSE_KEYa todas las configuraciones de variables de entorno y almacenes de secretos de CI/CD.
Posmigración
- Comprueba que no aparezcan llamadas a la red Muy fi en los registros de tráfico HTTP tras la implementación de la migración.
- Confirme que los nombres de los proveedores extraídos coinciden con los valores esperados en una muestra de entre 20 y 50 recibos.
- Confirme que los totales extraídos coinciden con los valores esperados con una tolerancia de 0,01 $ para el mismo conjunto de muestras.
- Verifica que la extracción del número de factura se realice correctamente para cada formato de factura del corpus de documentos.
- Comprueba el rendimiento del procesamiento por lotes con respecto al rendimiento de referencia de Muy fi para confirmar la eliminación del límite de velocidad.
- Ejecute la Suite completa de pruebas sin conexión a la red para confirmar la ausencia total de dependencia de la nube.
- Confirme que las puntuaciones
result.Confidenceexceden el 80% para escaneos de documentos limpios; Un valor inferior al 80 % indica que se debe añadir un paso de preprocesamiento. - Comprueba que se han eliminado las cuatro credenciales de Muy fi de todos los entornos (desarrollo, staging, producción).
- Confirma que los puntos finales de webhook devuelven un 404 o han sido eliminados de la tabla de enrutamiento.
- Comprueba el comportamiento con escaneos de recibos de baja calidad (arrugados, descoloridos, torcidos) con el proceso de preprocesamiento activo.
Principales ventajas de migrar a IronOCR
Los documentos financieros procesados localmente son documentos que no pueden ser interceptados por terceros. Tras la migración, los números de cuenta bancaria extraídos de las facturas, los números de ruta analizados de los cheques y los historiales de transacciones leídos de los extractos bancarios se procesan en su propio hardware. Ningún incidente de seguridad de terceros, acceso a datos por parte de subcontratistas o violación de la infraestructura de Muy fi puede exponer documentos que nunca han salido de sus servidores.
Los costes por documento se reducen a cero el día en que se implementa la migración. Con 50 000 documentos al mes, desaparece la partida mensual de Muy fi de entre 5000 y 15 000 dólares. The Professional License of IronOCR, with a price of 2999 $, is amortized in the first week of the first month. A partir de volúmenes más elevados, el ahorro se acumula cada año sin necesidad de negociar descuentos por volumen ni renovar el contrato.
El rendimiento del procesamiento se adapta al hardware, no a los límites de velocidad de los proveedores. Las respuestas HTTP 429, los límites de rendimiento a nivel de plan y los recargos por exceso de uso estacional son características propias de la arquitectura de las API en la nube. Con IronOCR, al añadir núcleos de CPU, el rendimiento aumenta proporcionalmente. Un lote de 10 000 recibos se procesa según tu calendario, no según el programa de límites de velocidad de Veryfi.
Cualquier tipo de documento se procesa con la misma API. La organización ya no necesita una segunda herramienta de OCR cuando RR. HH. solicita el procesamiento de formularios de incorporación, el departamento jurídico necesita extraer el texto de los contratos o el departamento de operaciones necesita datos de documentos de envío. ocr.Read() maneja todos ellos. El tutorial sobre lectura de texto a partir de imágenes y las guías de documentos especializados abarcan toda la gama de formatos de documentos que IronOCR maneja.
La lógica de extracción se convierte en una parte fundamental del código base. Los patrones Regex se encuentran en el control de código fuente, se pueden revisar en pull requests, se pueden probar en pruebas unitarias sin necesidad de simular ningún SDK y se pueden ajustar en función de los comentarios de producción. Cuando el modelo preentrenado de Muy fi devuelve un nombre de proveedor incorrecto, no hay nada que ajustar. Cuando el patrón de extracción de IronOCR devuelve un nombre de proveedor incorrecto, la solución consiste en un cambio de una sola línea en la expresión regular, acompañado de una prueba unitaria. La página de licencias de IronOCR describe las opciones de planes, incluida la suscripción SaaS para equipos que prefieren la facturación anual en lugar de la compra perpetua.
**El espacio de implementación se reduce a un único paquete NuGet que se ejecuta en cualquier entorno.**IronOCR se instala como un único paquete sin dependencias externas, sin gestión de binarios nativos y sin configuración de la carpeta tessdata. La misma referencia de paquete se resuelve en Windows, Linux, macOS, Docker, Azure App Service y AWS Lambda sin código condicional de plataforma. Consulte la guía de implementación de Docker y la guía de implementación de Linux para entornos en contenedores en los que los requisitos de salida de red de Muy fi supongan un obstáculo para la implementación.
