Migrer de Veryfi à IronOCR
Ce guide explique aux développeurs .NET comment remplacer l'API de traitement de documents dans le cloud de Veryfipar IronOCR, une bibliothèque IronOCR locale. Elle couvre le remplacement de paquets, le nettoyage des espaces de noms et quatre exemples complets de migration de code axés sur les modèles les plus couramment utilisés avec Veryfi: initialisation du client, extraction de champs basée sur les régions, catégorisation des dépenses à l'aide de données structurées et remplacement des webhooks. Aucune lecture préalable de l'article comparatif n'est requise.
Pourquoi migrer depuis Veryfi
Les documents financiers transitent par le pipeline de Veryfidans un seul sens : de votre infrastructure vers la leur. C'est cette réalité architecturale qui motive la plupart des migrations. Voici les difficultés spécifiques qui poussent les équipes à franchir le pas.
Chaque appel de document transmet des données financières sensibles à un serveur tiers. Les reçus contiennent les quatre derniers chiffres de la carte et les relations avec les fournisseurs. Les factures comportent des numéros de compte bancaire, des numéros d'acheminement et des numéros d'identification fiscale des fournisseurs. Les relevés bancaires contiennent l'historique complet des transactions. Avec Veryfi, chaque appel ProcessDocumentAsync télécharge ces octets vers api.veryfi.com, les traite sur l'infrastructure de Veryfi, et renvoie du JSON. Votre contrôle sur ces données prend fin dès l'envoi de la requête HTTP.
Quatre identifiants sont requis et doivent être synchronisés dans chaque environnement. VeryfiClient nécessite clientId, clientSecret, username, et apiKey — quatre secrets distincts à stocker dans la configuration, à faire pivoter selon le calendrier, à injecter dans les pipelines CI/CD et à auditer pour éviter l'exposition. Une seule fuite d'identifiants compromet l'authentification de tous les documents traités dans l'ensemble de l'application. IronOCR nécessite une clé de licence.
La tarification à l'unité s'applique sans plafond. Les reçus coûtent environ 0,05 à 0,15 $ chacun, les factures 0,10 à 0,25 $, les relevés bancaires 0,15 à 0,30 $. À raison de 50 000 documents par mois, cela représente 5 000 à 15 000 $ par mois en facturation au compteur, sans réduction la deuxième ou la troisième année. The IronOCR Professional License, at a price of 2 999 $, covers an unlimited number of documents on a perpetual basis; the break-even point compared to Veryfi's monthly spending of 5 000 $ is reached in less than three weeks.
L'API est uniquement asynchrone car le travail sous-jacent est distant. ProcessDocumentAsync n'est pas asynchrone car le traitement est long sur le plan computationnel; Elle est asynchrone car le document doit être envoyé à un serveur, être mis en file d'attente derrière d'autres requêtes, effectuer l'inférence et renvoyer une réponse via le réseau. La latence est non déterministe. La limitation de débit HTTP 429 nécessite une logique de réessai. Les échecs de paiement HTTP 402 interrompent complètement le traitement par lots. Les erreurs HTTP 500 sur l'infrastructure de Veryfientraînent l'interruption de votre flux de travail.
La portée du document Veryfis'arrête à la limite du document de dépenses. Les modèles entraînés renvoient de manière fiable des champs structurés pour les reçus, les factures, les chèques, les relevés bancaires, les formulaires W-2 et les cartes de visite. En dehors de cette liste (documents commerciaux généraux, contrats, dossiers médicaux, documents d'expédition, formulaires internes personnalisés), les résultats sont de moins bonne qualité ou nécessitent une formation payante sur des modèles personnalisés. Les organisations qui adoptent Veryfipour l'automatisation des notes de frais constatent généralement, dans un délai de 6 à 12 mois, que d'autres équipes ont besoin d'un OCR pour des documents que Veryfin'a pas été conçu pour traiter.
Le schéma JSON propriétaire de Veryfiassocie toute la logique d'extraction à un seul fournisseur. Chaque ligne de code qui lit response.Vendor?.Name, response.BankAccount?.RoutingNumber, ou response.LineItems est du code qui ne fonctionne qu'avec Veryfi. Changer de fournisseur — ou passer à un OCR local — implique de réécrire toute la logique d'extraction à partir de zéro.
Le problème fondamental
// 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 Veryficloud
// 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: comparaison des fonctionnalités
Le tableau ci-dessous présente les fonctionnalités des deux produits afin de faciliter l'évaluation technique.
| Fonction | Veryfi | IronOCR |
|---|---|---|
| Lieu de traitement | Serveurs cloud Veryfi | Votre infrastructure |
| Modèle de déploiement | API cloud uniquement | Sur site, Docker, Azure, AWS, Linux |
| Assistance hors ligne | Non | Oui |
| Internet requis | Oui (chaque document) | Non |
| Les données quittent l'infrastructure | Oui (à chaque appel) | Jamais |
| Conforme à la norme HIPAA sans BAA | Non | Oui |
| Prise en charge des environnements isolés | Pas possible | Entièrement pris en charge |
| Modèle de tarification | Par document (0,05 $ à 0,30 $) | Licence perpétuelle ($999–2 999 $) |
| Compétences requises | 4 (clientId, clientSecret, nom d'utilisateur, clé API) | 1 clé de licence |
| API synchrone | Non (asynchrone uniquement) | Oui |
| limitation de débit | Oui (HTTP 429) | None |
| Portée du document | Reçus, factures, chèques, relevés bancaires, formulaires W-2, cartes de visite | Tout type de document |
| Types de documents personnalisés | Formation sur les modèles payants requise | Toute mise en page via l'extraction par expressions régulières/modèles |
| Entrée PDF | Oui (téléchargement d'octets) | Oui (natif, local) |
| Sortie PDF consultable | Non | Oui (result.SaveAsSearchablePdf()) |
| OCR basé sur la région | Non | Oui (CropRectangle) |
| Lecture de codes-barres | Non | Oui (même passage OCR) |
| Accès structuré aux résultats | Champs JSON pré-analysés | Pages, paragraphes, lignes, mots avec coordonnées |
| Score de confiance | Par champ (propriétaire) | Par mot et globalement (result.Confidence) |
| Plus de 125 langues prises en charge | Limité | Oui (packs linguistiques NuGet) |
| Traitement parallèle thread-safe | Les limites de concurrence HTTP s'appliquent | Complet (un IronTesseract par thread) |
| Tests unitaires sans simulacres | Nécessite la simulation HTTP | Tests locaux directs |
Guide de démarrage rapide : migration de Veryfivers IronOCR
Étape 1 : Remplacer le package NuGet
Supprimer le SDK Veryfi:
dotnet remove package Veryfi
Installez IronOCR depuis NuGet :
Étape 2 : Mise à jour des espaces de noms
Remplacer les espaces de noms Veryfipar l'espace de noms IronOCR :
// Before (Veryfi)
using Veryfi;
using Veryfi.Models;
// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
Étape 3 : initialisation de la licence
Ajoutez cette ligne une seule fois au démarrage de l'application, avant tout appel OCR :
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Exemples de migration de code
Remplacement du client de traitement de documents
Les services Veryfisont construits autour de l'injection de constructeur de VeryfiClient. Le constructeur à quatre identifiants est un point d'entrée naturel pour l'injection de dépendances, mais il crée quatre secrets qui doivent être gérés et renouvelés. Le remplacement par IronOCR regroupe les informations d'identification sous une seule clé de licence et déplace l'instanciation du moteur de traitement dans la classe de service elle-même.
Approche 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 Veryfion 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;
}
}
Approche 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;
}
}
Le changement de constructeur élimine quatre entrées de configuration de chaque environnement : appsettings.json, secrets Docker, références Azure Key Vault et variables de pipeline CI/CD. L'instance IronTesseract est réutilisable pour plusieurs appels sur le même thread. Consultez le guide d'installation d'IronTesseract pour les modèles d'enregistrement de singletons dans les conteneurs d'injection de dépendances .NET Core.
Extraction des champs d'un reçu à l'aide de l'OCR basé sur la région
Veryfi extrait les champs des reçus en exécutant ses modèles d'apprentissage automatique entraînés sur l'image complète du document et en renvoyant une réponse JSON pré-structurée. L'équivalent d'IronOCR est l'OCR basé sur les régions en utilisant CropRectangle, qui cible des zones spécifiques de l'image du reçu — zone d'en-tête pour le fournisseur, zone de pied de page pour les totaux — plutôt que de passer toute la page et de rechercher les motifs dans le résultat. Cette méthode est plus rapide pour les mises en page connues et plus précise lorsque la zone d'intérêt est bien définie.
Approche 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
);
}
}
Approche 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 prend (x, y, width, height) en pixels. Le traitement des zones d'en-tête et de pied de page uniquement est plus rapide qu'une lecture de la page entière et évite les correspondances erronées provenant des montants des lignes de commande dans le corps du reçu. Le guide OCR basé sur les régions couvre les stratégies de mesure des coordonnées pour les documents de taille variable, et l'exemple de recadrage de région illustre le modèle complet.
Catégorisation des dépenses à l'aide de données de paragraphes structurées
Veryfi retourne response.LineItems sous forme de tableau d'objets préstructurés avec Description, Quantity, UnitPrice, et Total déjà analysés. IronOCR fournit l'équivalent via result.Pages[0].Paragraphs et result.Lines, qui exposent chaque bloc de texte avec ses coordonnées X/Y. La logique de catégorisation des dépenses — qui détermine si une ligne correspond à un repas, un déplacement, des fournitures ou des frais de logiciel — s'applique de la même manière quel que soit le texte. La différence réside dans le fait qu'avec IronOCR, la logique de catégorisation vous appartient : vous pouvez la personnaliser et l'étendre sans avoir à passer par un cycle de réentraînement du ML payant.
Approche 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;
}
}
Approche 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 collection Paragraphs fournit la coordonnée Y de chaque bloc de texte, ce qui facilite l'isolement de la zone verticale où apparaissent les lignes d'articles sur une disposition standard de reçu. Le guide d'accès aux données structurées explique la hiérarchie complète de Pages, Paragraphs, Lines, Words, et Characters avec leurs propriétés de coordonnées. Pour les reçus dont la qualité de numérisation est médiocre (papier froissé, impression thermique à faible contraste), le guide de correction de la qualité d'image présente des filtres de prétraitement qui améliorent la précision avant l'exécution de la logique de catégorisation.
Suppression des webhooks et remplacement synchrone par traitement par lots
En cas de volumes de documents importants, Veryfirecommande les notifications par webhook plutôt que le polling. Le modèle nécessite un point de terminaison HTTPS accessible au public, un secret de webhook pour la vérification de la signature, une file d'attente pour conserver les résultats jusqu'à ce que le webhook se déclenche, et une logique de réessai pour les livraisons manquées. Il s'agit d'une infrastructure importante pour ce qui est, en fin de compte, une solution de contournement face au fait que l'OCR dans le cloud est lent par rapport au traitement local. IronOCR fonctionne en mode synchrone. Il n'y a pas de décalage asynchrone à combler avec un webhook.
Approche de Veryfi:
using Veryfi;
using Microsoft.AspNetCore.Mvc;
// Veryfiwebhook 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);
}
}
}
Approche IronOCR :
using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
// Non 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; }
}
La suppression de la couche webhook élimine le point de terminaison HTTPS, l'exigence de rotation des secrets webhook, la file d'attente des résultats, la logique de validation HMAC et la configuration des tentatives de reconnexion. Toute la structure en aval n'existe que parce que les résultats de Veryfiarrivent de manière asynchrone depuis un serveur distant. Avec IronOCR, Parallel.ForEach remplace tout cela. L'exemple de multithreading démontre en détail le modèle IronTesseract par thread, et le guide OCR async couvre l'intégration Task.Run pour la réactivité de l'interface utilisateur. Le guide d'optimisation de la vitesse couvre la configuration des instances pour un débit maximal sur les charges de travail par lots.
Référence de mappage de l'API Veryfivers IronOCR
| Veryfi | Équivalent d'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(chemin); ocr.Read(input) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" }) | input.LoadPdf(chemin); ocr.Read(input) |
response.Vendor?.Name | Premier paragraphe ordonné par p.Y à partir 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 filtré par plage de coordonnées 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 (globalement) ou word.Confidence (par mot) |
response.Payment?.Last4 | Regex.Match(result.Text, @"\*{4}\s*(\d{4})") |
VeryfiApiException (401/402/429/500) | Exceptions .NET Standard — pas de codes d'erreur HTTP pour le traitement local |
| Encodage Base64 avant le téléchargement | Pas nécessaire — ocr.Read(filePath) accepte directement les chemins de fichier |
response.Category | Correspondance de mots-clés personnalisée avec result.Text |
| Désérialisation de la charge utile d'un webhook | Pas nécessaire — ocr.Read() renvoie le résultat de manière synchrone |
ProcessDocumentAsync avec reprise/retard | Non requis — aucune limite de débit pour le traitement local |
Problèmes de migration courants et solutions
Problème n° 1 : champs pré-analysés manquants
Veryfi : response.Vendor?.Name, response.Total, et response.LineItems arrivent comme des champs structurés d'un modèle ML pré-entraîné. Aucune logique d'extraction n'est requise côté client.
Solution : Écrivez des expressions régulières (Regex) pour chaque champ utilisé par votre application. La migration prend généralement entre 8 et 24 heures, selon le nombre de mises en page de documents distinctes que vous traitez. Pour les modèles courants de reçus et de factures, le tutoriel sur l'OCR des factures et le tutoriel sur la numérisation des reçus fournissent des implémentations complètes des modèles d'extraction.
// Map each Veryfifield 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;
}
Problème n° 2 : signatures de méthodes asynchrones dans l'ensemble du code
Veryfi : ProcessDocumentAsync est asynchrone au niveau du SDK Veryfi. Les équipes propagent généralement await à travers chaque méthode d'appel dans la pile d'appels, ce qui signifie que les classes de service, les contrôleurs et les tâches d'arrière-plan portent tous des signatures async Task<t>.
Solution : L'Read() d'IronOCR est synchrone. Les signatures de méthodes async existantes peuvent être préservées en les enveloppant avec Task.Run pendant la période de transition. Cela évite des modifications massives des signatures dans l'ensemble du code tout en éliminant la dépendance au cloud.
// 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);
});
}
Problème n° 3 : configuration des identifiants dispersée entre les environnements
Veryfi : Quatre identifiants (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey) apparaissent dans appsettings.json, des blocs de variables d'environnement dans les fichiers Docker Compose, des secrets GitHub Actions, des références Azure Key Vault et des configurations de pipeline CI/CD.
Solution : Rechercher et supprimer les quatre entrées d'identifiants de chaque environnement. Ajoutez une seule variable d'environnement IRONOCR_LICENSE_KEY. Chargez-le au démarrage.
# Find all Veryficredential 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");
Problème n° 4 : Problèmes de qualité de numérisation non visibles auparavant
Veryfi : Le traitement dans le cloud inclut l'amélioration des images côté serveur avant l'exécution de l'inférence ML. Les scans de reçus de mauvaise qualité (papier froissé, impression thermique décolorée, photos prises avec un téléphone et de travers) ont été corrigés en arrière-plan avant l'extraction des champs.
Solution : Appliquer explicitement le pipeline de prétraitement d'IronOCR. Deskew(), DeNoise(), et Contrast() couvrent la majorité des problèmes de qualité de numérisation de reçus réels.
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);
Le guide de correction de la qualité d'image et le tutoriel sur les filtres d'image indiquent quels filtres appliquer pour différents types de dégradation de la numérisation.
Problématique n° 5 : Débit de traitement par lots à haut volume
Veryfi : les limites de débit régulent la vitesse de soumission des documents. Les réponses HTTP 429 nécessitent une logique de délai d'attente exponentiel. Le débit est limité par la limite de débit par forfait de Veryfi, et non par votre matériel.
Solution : IronOCR n'est limité que par le nombre de cœurs du processeur. Utilisez Parallel.ForEach avec une instance IronTesseract par thread. Sur un serveur à 8 cœurs, le débit évolue de manière à peu près linéaire avec le nombre de cœurs.
// 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);
});
Problème n° 6 : schéma JSON propriétaire verrouillé sur Veryfi
Veryfi : Tout le code d'extraction lit à partir du schéma de réponse de Veryfi: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. Ce code fonctionne uniquement avec le SDK de Veryfi. Tout changement de nom de champ dans une mise à jour de l'API Veryfirend le code de l'application inutilisable.
Solution : L'extraction IronOCR utilise System.Text.RegularExpressions.Regex standard de .NET sur du texte brut. Les modèles sont portables, testables sans simulation de SDK et sous votre contrôle. Les tests unitaires s'exécutent sans aucune connexion réseau.
// 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);
}
Liste de contrôle de migration Veryfi
Pré-migration
Auditez le code source pour recenser toutes les utilisations de Veryfiavant de modifier le code :
# Find all Veryfiusing statements
grep -rn "using Veryfi" --include="*.cs" .
# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .
# Find all Veryfiresponse 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" .
Enregistrez le nombre total de sites d'appel ProcessDocumentAsync, la liste des champs de réponse accédés par site d'appel et la liste des environnements contenant des identifiants Veryfi.
Migration de code
- Supprimez le package NuGet
Veryfide tous les projets de la solution. - Installez le package NuGet
IronOcrdans tous les projets qui référencaient précédemmentVeryfi. - Ajoutez
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";au démarrage de l'application (avant tout appel OCR). - Remplacez toutes les instructions
using Veryfi;etusing Veryfi.Models;parusing IronOcr;. - Remplacez l'injection de constructeur
VeryfiClientpar une initialisation de champIronTesseract. - Supprimez toutes les entrées d'identifiants Veryfides
appsettings.json,appsettings.*.json, et fichiers de configuration des secrets. - Convertissez les appels
ProcessDocumentAsync(bytes)enocr.Read(filePath)ouocr.Read(ocrInput). - Remplacez les accès
response.Vendor?.Namepar une extraction de texte ordonnée par paragraphe deresult.Pages[0].Paragraphs. - Remplacez les accès aux champs structurés
response.Total,response.Tax,response.InvoiceNumber, et autres par des motifs Regex surresult.Text. - Remplacez l'itération
response.LineItemspar une itération filtrée par coordonnées Yresult.Pages[0].Paragraphs. - Supprimez les classes de contrôleurs de webhooks et supprimez les enregistrements de points de terminaison de webhooks.
- Supprimez les variables d'environnement de secret de webhook de tous les environnements.
- Ajoutez
OcrInputavec prétraitement (Deskew(),DeNoise(),Contrast()) pour les entrées d'images numérisées. - Remplacez les boucles séquentielles monothread par
Parallel.ForEachutilisant une instanceIronTesseractpar thread. - Ajoutez
IRONOCR_LICENSE_KEYà toutes les configurations de variables d'environnement et aux magasins de secrets CI/CD.
Après la migration
- Vérifiez qu'aucun appel au réseau Veryfin'apparaît dans les journaux de trafic HTTP après le déploiement de la migration.
- Vérifiez que les noms de fournisseurs extraits correspondent aux valeurs attendues sur un échantillon de 20 à 50 reçus.
- Vérifiez que les totaux extraits correspondent aux valeurs attendues avec une tolérance de 0,01 $ pour le même ensemble d'échantillons.
- Vérifiez que l'extraction du numéro de facture réussit pour chaque format de facture dans le corpus de documents.
- Testez le débit du traitement par lots par rapport au débit de référence Veryfiafin de confirmer la suppression de la limitation de débit.
- Exécutez la suite de tests complète sans aucune connexion réseau pour confirmer l'absence totale de dépendance au cloud.
- Confirmez que les scores
result.Confidencedépassent 80 % pour les documents numérisés propres; Un score inférieur à 80 % indique qu'une étape de prétraitement doit être ajoutée. - Vérifiez que les quatre identifiants Veryfiont bien été supprimés de tous les environnements (développement, préproduction, production).
- Vérifiez que les points de terminaison des webhooks renvoient un code 404 ou ont été supprimés de la table de routage.
- Testez le comportement sur des scans de reçus de mauvaise qualité (froissés, décolorés, de travers) avec le pipeline de prétraitement activé.
Principaux avantages de la migration vers IronOCR
Les documents financiers traités localement sont des documents qui ne peuvent pas être divulgués à un tiers. Après la migration, les numéros de compte bancaire extraits des factures, les numéros d'acheminement analysés à partir des chèques et les historiques de transactions lus à partir des relevés bancaires sont tous traités sur votre matériel. Aucun incident de sécurité impliquant un tiers, aucun accès aux données par un sous-traitant, ni aucune violation de l'infrastructure Veryfine peut exposer des documents qui n'ont jamais quitté vos serveurs.
Les coûts par document tombent à zéro le jour où la migration est déployée. Avec 50 000 documents par mois, la ligne budgétaire Veryfide 5 000 à 15 000 dollars par mois disparaît. The Professional License for IronOCR, priced at 2 999 $, is amortized in the first week of the first month. À partir de volumes plus importants, les économies s'accumulent chaque année sans qu'il soit nécessaire de négocier des remises sur volume ou de renouveler le contrat.
Le débit de traitement évolue en fonction du matériel, et non des limites de débit imposées par les fournisseurs. Les réponses HTTP 429, les plafonds de débit au niveau du forfait et les frais de dépassement saisonniers sont des artefacts architecturaux des API cloud. Avec IronOCR, l'ajout de cœurs de processeur augmente le débit de manière proportionnelle. Un lot de 10 000 reçus est traité selon votre calendrier, et non selon le calendrier de limitation de débit de Veryfi.
Tout type de document est traité via la même API. L'organisation n'a plus besoin d'un deuxième outil OCR lorsque les RH demandent le traitement de formulaires d'intégration, que le service juridique a besoin d'extraire le texte de contrats ou que le service opérationnel a besoin des données des documents d'expédition. ocr.Read() les gère tous. Le tutoriel sur la lecture de texte à partir d'images et les guides de documents spécialisés couvrent l'ensemble des formats de documents pris en charge par IronOCR.
La logique d'extraction devient un élément à part entière du code source**.** Les modèles Regex sont sous contrôle de version, peuvent être examinés dans les pull requests, testés dans des tests unitaires sans simuler de SDK, et ajustés en fonction des retours d'expérience en production. Lorsque le modèle pré-entraîné de Veryfirenvoie un nom de fournisseur incorrect, il n'y a rien à ajuster. Lorsque le modèle d'extraction d'IronOCR renvoie un nom de fournisseur incorrect, la correction consiste en une modification d'une ligne d'expression régulière accompagnée d'un test unitaire. La page de licence d'IronOCR présente les différentes options, y compris l'abonnement SaaS pour les équipes qui préfèrent la facturation annuelle à l'achat à vie.
L'empreinte de déploiement se réduit à un seul package NuGet qui s'exécute partout. IronOCR s'installe sous la forme d'un seul package, sans dépendances externes, sans gestion des binaires natifs et sans configuration du dossier tessdata. La même référence de package fonctionne sous Windows, Linux, macOS, Docker, Azure App Service et AWS Lambda sans code spécifique à la plateforme. Consultez le guide de déploiement Docker et le guide de déploiement Linux pour les environnements conteneurisés où les exigences de sortie réseau de Veryficonstituent un obstacle au déploiement.
