C#'da Asenkron ve Çoklu İşlem Kullanımı
Mindee'den IronOCR'a geçmek, belge işleme işlemini harici bulut sunucularından kaldırıp kendi altyapınıza taşır — sayfa başına faturalandırmayı, üçüncü taraf veri iletimini ve işletim sırasında ağ kullanılabilirliğini ortadan kaldırır. Aşağıdaki bölümler, paket değişimi, ad alanı güncellemeleri ve dört pratik öncesi ve sonrası kod senaryosunu kapsar: fatura bölge çıkarımı, çok sayfalı makbuz PDF işleme, finansal belge ön işleme ve aranabilir PDF arşivleme.
Neden Mindee'den Geçiş Yapılmalı
Mindee gerçek bir sorunu zarif bir şekilde çözer: bir belge gönderin, yapılandırılmış JSON alanları alın. Finansal belgeleri bir harici API'ye iletmenin kabul edilebilir olduğu ve hacmin ılımlı kaldığı ekipler için hızlı sonuçlar sunar. Göç tetikleyicisi genellikle birkaç koşuldan birinin değişmesiyle meydana gelir.
Finansal Veri Bir Uyum Sınırını Aşıyor. Mindee'nin ParseAsync<InvoiceV4> tüm belgeyi harici sunuculara yüklüyor. IBAN kodları, yönlendirme numaraları, satıcı EIN'leri ve maddeler, kamu interneti üzerinden seyahat eder ve sizin kontrolünüz dışındaki donanımlarda işlenir. SOC 2 Tip II sertifikası, Mindee'nin güvenlik uygulamalarına uyduğunu doğrular; belgelerinizi kendi güvenlik çerçevenizin içinde tutmaz. Bir uyum incelemesi, yeni bir müşteri sözleşmesi veya bir veri yerleşim yönetmeliği, üçüncü taraf bulut işlemini çizgi çekiyorsa, Mindee'nin mimarisi, çıkartma doğruluğu ne olursa olsun diskalifiye edici olur.
Sayfa Başına Maliyetler Aleyhinize Ölçeklenir. Başlangıç planı, 1.000 sayfa ayda 49 $ olarak sağlar. Pro planı, ayda 5.000 sayfa 499 $ olarak sağlar. Çok sayfalı PDF'ler her sayfayı sayar. Geliştirme çalışmaları kota dahilindedir. Aylık 4.000 fatura işleyen bir ekip ayda 499 $ öder — yılda 5.988 $ — bu rakam her yıl sıfırlanır ve herhangi bir hacim artışıyla yukarı ölçeklenir. Aylık 24.000 sayfada Kurumsal fiyatlandırma için pazarlık yapıyorsunuz. IronOCR'nin 1.499 $ (Profesyonel katman) süresiz lisansı sınırsız belge hacmi kapsar ve maliyetiniMindeePro'ya karşı dört aydan kısa sürede geri kazandırır.
Async Yineleme Yığınınızda Yayılır. Mindee'nin her işlemi asenkroniktir çünkü her işlem bir ağ isteğidir. Bu zorunlu asenkron zincir kontrolörler, hizmet katmanları ve işçi sınıfları boyunca yukarıya doğru yayılır. Ağ mevcut olmadığında veya Mindee'nin hizmeti bir kesinti yaşadığında, yıkım sonucunda yerel bir geri dönüş olmadan başarısızlık meydana gelir. IronOCR, senkron çalışır — yerel CPU işlemi — ve mimari tutarlılık için async arayüzlerin gerektiği yerde Task.Run ile sarılır.
Önceden Hazırlanmış API Kataloğu Sert Bir Sınıra Sahiptir. Mindee, InvoiceV4, ReceiptV5, PassportV1 ve diğer belge türlerinden küçük bir kataloğu kapsar. Bu listenin dışındaki herhangi bir belge türü, Enterprise planı özel model eğitimi gerektirir: örnek toplama, etiketleme, eğitim süresi ve API'nin kullanıma hazır hale gelmesinden önceki süre. İşletmenizin ihtiyaç duyduğu her yeni belge türü, ayrı bir satıcı katılımını gerektirir. IronOCR, aynı IronTesseract().Read() çağrısını kullanarak herhangi bir belge türünü işler; yeni bir belge türü eklemek, bir eğitim sözleşmesi müzakere etmek değil, çıkarım desenlerini yazmak anlamına gelir.
API Anahtarı Yönetimi İşletim Yüzeyi Ekler.Mindeekimlik bilgileri, sunucu tarafında güvenli bir şekilde saklanmalı, periyodik olarak döndürülmeli ve maruziyetten korunmalıdır. Ağ çıkış kuralları,Mindeeuç noktalarına giden HTTPS'e izin vermelidir. Yeniden deneme mantığı, kaçınılmaz ağ hatalarından kaynaklanan HttpRequestException ve MindeeException ele almalıdır. Mindee'yi kaldırmak, tüm bu işletim yüzeyini kaldırır: kimlik bilgileri, çıkış kuralları, ağ G/Ç etrafında yeniden deneme sarmalayıcıları yoktur.
İzole ve Kısıtlı Ortamlar Hariç Bırakılır. Hükümet müteahhitleri, savunma taşeronları, sıkı dış internet kontrolleri olan sağlık ağları ve güvenilir internet bağlantısı olmayan tesislerde konuşlandırılan endüstriyel sistemler, Mindee'yi tasarlandığı şekilde kullanamaz. IronOCR, çıkış erişimi olmadan Docker konteynerlerinde, çıkış kısıtlamaları olan Azure Fonksiyonlarında ve tamamen izole edilmiş ortamlarda aynı şekilde çalışır. Çalışma zamanı sırasında bulut bağımlılığı yoktur. Dağıtım katmanı detayları için IronOCR lisans sayfasını görebilirsiniz.
Temel Sorun
Mindee'nin işlediği her finansal belge sizin kontrol etmediğiniz bir ağ sınırını aşar:
// Mindee: invoice with bank details leaves your infrastructure on this line
var response = await _client.ParseAsync<InvoiceV4>(new LocalInputSource("invoice.pdf"));
// IBAN, routing number, EIN, line items — all transmitted toMindeecloud
// Mindee: invoice with bank details leaves your infrastructure on this line
var response = await _client.ParseAsync<InvoiceV4>(new LocalInputSource("invoice.pdf"));
// IBAN, routing number, EIN, line items — all transmitted toMindeecloud
Imports System.Threading.Tasks
' Mindee: invoice with bank details leaves your infrastructure on this line
Dim response = Await _client.ParseAsync(Of InvoiceV4)(New LocalInputSource("invoice.pdf"))
' IBAN, routing number, EIN, line items — all transmitted to Mindee cloud
// IronOCR: same invoice, same result, zero data transmission
var result = new IronTesseract().Read("invoice.pdf");
// All processing local — bank details never leave your machine
// IronOCR: same invoice, same result, zero data transmission
var result = new IronTesseract().Read("invoice.pdf");
// All processing local — bank details never leave your machine
' IronOCR: same invoice, same result, zero data transmission
Dim result = New IronTesseract().Read("invoice.pdf")
' All processing local — bank details never leave your machine
IronOCR vs Mindee: Özellik Karşılaştırması
Aşağıdaki tablo, geçiş kararlarını yönlendiren mimari ve yetenek farklarını yakalar.
| Özellik | Mindee | IronOCR |
|---|---|---|
| İşleme yeri | Mindee bulut sunucuları | Yerel makine / sizin altyapınız |
| Çalışma zamanı sırasında internet gerekli | Her zaman | Asla |
| Veri iletimi | Çağrı başına tam belge yüklendi | None |
| Belge başına maliyet | Evet (sayfa başına, plana dayalı) | Hayır (süresiz lisans) |
| Başlangıç fiyatı | $49/ay (1.000 sayfa) | $999 tek seferlik (Lite) |
| Çevrimdışı / izole destek | Desteklenmiyor | Tam destek |
| Yerinde dağıtım | Mevcut değil | Tek seçenek |
| Fatura ayrıştırma | Önceden hazırlanmış yapısal API (InvoiceV4) |
OCR + bölge tabanlı veya regex çıkarım |
| Makbuz ayrıştırma | Önceden hazırlanmış yapısal API (ReceiptV5) |
OCR + çıkarım desenleri |
| Keyfi belge türleri | Özel eğitim olmadan desteklenmiyor | Tam destek, herhangi bir belge |
| Özel model eğitimi | Kurumsal plan + öncül süre | Gerekli değil |
| API çağrı deseni | Asenkron zorunlu (ağ G/Ç) | Eşzamanlı (asenkron opsiyonel) |
| Hız sınırlama | Plana bağımlı | None |
| PDF girişi | Evet | Evet (yerel, dönüştürme yok) |
| Çok sayfalı PDF işleme | Evet | Evet |
| Aranabilir PDF çıktısı | Hayır | Evet (result.SaveAsSearchablePdf()) |
| Görüntü ön işleme | Hiçbiri açığa çıkarılmamış | Yeniden hizalama, Gürültü Giderme, Kontrast, İkiliye Çevirme, Keskinleştirme, Ölçekleme |
| Bölge bazlı çıkarım | Yanıt içindeki alan koordinatları | Giriş üzerinde CropRectangle |
| 125+ dil desteği | Sınırlı | Evet (paketlenmiş, tessdata yönetimi yok) |
| Barkod okuma | Hayır | Evet (OCR ile eşzamanlı) |
| Yapısal kelime koordinatları | Hayır | Evet (Sayfalar, Paragraflar, Satırlar, Kelimeler) |
| Thread güvenliği | N/A (çağrı başına ağ G/Ç) | Yerleşik |
| Çapraz platform | Bulut (platform bağımsız) | Windows, Linux, macOS, Docker, Azure, AWS |
| .NET uyumluluğu | .NET Standard 2.0+ | .NET Framework 4.6.2+, .NET 5/6/7/8/9 |
| Ticari destek | Evet | Evet |
Hızlı Başlangıç: Mindee'den IronOCR'ye Geçiş
Adım 1: NuGet Paketini Değiştirin
Mindee paketini kaldırın:
dotnet remove package Mindee
dotnet remove package Mindee
NuGet kullanarak IronOCR'u yükleyin:
dotnet add package IronOcr
Adım 2: Ad Alanlarını Güncelleyin
Mindee ad alanı bloğunu IronOCR ad alanı ile değiştirin:
// Before (Mindee)
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
using Mindee.Product.Receipt;
using Mindee.Product.FinancialDocument;
// After (IronOCR)
using IronOcr;
// Before (Mindee)
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
using Mindee.Product.Receipt;
using Mindee.Product.FinancialDocument;
// After (IronOCR)
using IronOcr;
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.Invoice
Imports Mindee.Product.Receipt
Imports Mindee.Product.FinancialDocument
Imports IronOcr
Adım 3: Lisansa İzin Verin
İlk OCR çağrısından önce uygulama başlatılırken lisans anahtarını ekleyin:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Kod Göç Örnekleri
Doküman Bölgeleri Kullanarak Fatura Alanı Çıkarımı
Mindee, sunucu tarafı modeli, fatura numaralarının, tarihlerin ve toplamların genellikle nerede göründüğünü bildiğinden, bilinen yerlerde önceden ayrıştırılmış alanlar döndürür.IronOCR eşdeğeri, belgenin belirli bölgelerini okumak için CropRectangle kullanır ve belgeyi iletmeden Mindee'nin çıkarım uzamsal farkındalığını taklit eder.
Mindee Yaklaşımı:
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeZoneExtractor
{
private readonly MindeeClient _client;
public MindeeZoneExtractor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<(string invoiceNumber, string supplierName, decimal? total)>
ExtractKeyFieldsAsync(string filePath)
{
// Document transmitted toMindee— spatial field detection happens server-side
var inputSource = new LocalInputSource(filePath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
// Fields arrive pre-parsed; no zone configuration required on your end
return (
prediction.InvoiceNumber?.Value,
prediction.SupplierName?.Value,
prediction.TotalAmount?.Value
);
}
}
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeZoneExtractor
{
private readonly MindeeClient _client;
public MindeeZoneExtractor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<(string invoiceNumber, string supplierName, decimal? total)>
ExtractKeyFieldsAsync(string filePath)
{
// Document transmitted toMindee— spatial field detection happens server-side
var inputSource = new LocalInputSource(filePath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
// Fields arrive pre-parsed; no zone configuration required on your end
return (
prediction.InvoiceNumber?.Value,
prediction.SupplierName?.Value,
prediction.TotalAmount?.Value
);
}
}
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.Invoice
Imports System.Threading.Tasks
Public Class MindeeZoneExtractor
Private ReadOnly _client As MindeeClient
Public Sub New(apiKey As String)
_client = New MindeeClient(apiKey)
End Sub
Public Async Function ExtractKeyFieldsAsync(filePath As String) As Task(Of (invoiceNumber As String, supplierName As String, total As Decimal?))
' Document transmitted to Mindee— spatial field detection happens server-side
Dim inputSource = New LocalInputSource(filePath)
Dim response = Await _client.ParseAsync(Of InvoiceV4)(inputSource)
Dim prediction = response.Document.Inference.Prediction
' Fields arrive pre-parsed; no zone configuration required on your end
Return (
prediction.InvoiceNumber?.Value,
prediction.SupplierName?.Value,
prediction.TotalAmount?.Value
)
End Function
End Class
IronOCR Yaklaşımı:
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrZoneExtractor
{
private readonly IronTesseract _ocr = new IronTesseract();
public (string invoiceNumber, string supplierName, string total)
ExtractKeyFields(string filePath)
{
// Zone 1: supplier name — top 12% of document, full width
var headerRegion = new CropRectangle(0, 0, 850, 120);
using var headerInput = new OcrInput();
headerInput.LoadImage(filePath, headerRegion);
var supplierResult = _ocr.Read(headerInput);
// Zone 2: invoice number and date — upper-right quadrant
var metaRegion = new CropRectangle(450, 80, 400, 100);
using var metaInput = new OcrInput();
metaInput.LoadImage(filePath, metaRegion);
var metaResult = _ocr.Read(metaInput);
// Zone 3: totals block — bottom-right 20%
var totalsRegion = new CropRectangle(500, 800, 350, 200);
using var totalsInput = new OcrInput();
totalsInput.LoadImage(filePath, totalsRegion);
var totalsResult = _ocr.Read(totalsInput);
var invoiceNumber = Regex.Match(
metaResult.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var total = Regex.Match(
totalsResult.Text,
@"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.?\d*)",
RegexOptions.IgnoreCase).Groups[1].Value;
// Supplier name is the first substantial text line in the header zone
var supplierName = supplierResult.Text
.Split('\n')
.FirstOrDefault(l => l.Trim().Length > 4)
?.Trim();
return (invoiceNumber, supplierName, total);
}
}
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrZoneExtractor
{
private readonly IronTesseract _ocr = new IronTesseract();
public (string invoiceNumber, string supplierName, string total)
ExtractKeyFields(string filePath)
{
// Zone 1: supplier name — top 12% of document, full width
var headerRegion = new CropRectangle(0, 0, 850, 120);
using var headerInput = new OcrInput();
headerInput.LoadImage(filePath, headerRegion);
var supplierResult = _ocr.Read(headerInput);
// Zone 2: invoice number and date — upper-right quadrant
var metaRegion = new CropRectangle(450, 80, 400, 100);
using var metaInput = new OcrInput();
metaInput.LoadImage(filePath, metaRegion);
var metaResult = _ocr.Read(metaInput);
// Zone 3: totals block — bottom-right 20%
var totalsRegion = new CropRectangle(500, 800, 350, 200);
using var totalsInput = new OcrInput();
totalsInput.LoadImage(filePath, totalsRegion);
var totalsResult = _ocr.Read(totalsInput);
var invoiceNumber = Regex.Match(
metaResult.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var total = Regex.Match(
totalsResult.Text,
@"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.?\d*)",
RegexOptions.IgnoreCase).Groups[1].Value;
// Supplier name is the first substantial text line in the header zone
var supplierName = supplierResult.Text
.Split('\n')
.FirstOrDefault(l => l.Trim().Length > 4)
?.Trim();
return (invoiceNumber, supplierName, total);
}
}
Imports IronOcr
Imports System.Text.RegularExpressions
Public Class IronOcrZoneExtractor
Private ReadOnly _ocr As New IronTesseract()
Public Function ExtractKeyFields(filePath As String) As (invoiceNumber As String, supplierName As String, total As String)
' Zone 1: supplier name — top 12% of document, full width
Dim headerRegion As New CropRectangle(0, 0, 850, 120)
Using headerInput As New OcrInput()
headerInput.LoadImage(filePath, headerRegion)
Dim supplierResult = _ocr.Read(headerInput)
' Zone 2: invoice number and date — upper-right quadrant
Dim metaRegion As New CropRectangle(450, 80, 400, 100)
Using metaInput As New OcrInput()
metaInput.LoadImage(filePath, metaRegion)
Dim metaResult = _ocr.Read(metaInput)
' Zone 3: totals block — bottom-right 20%
Dim totalsRegion As New CropRectangle(500, 800, 350, 200)
Using totalsInput As New OcrInput()
totalsInput.LoadImage(filePath, totalsRegion)
Dim totalsResult = _ocr.Read(totalsInput)
Dim invoiceNumber = Regex.Match(metaResult.Text, "Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)", RegexOptions.IgnoreCase).Groups(1).Value
Dim total = Regex.Match(totalsResult.Text, "Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.?\d*)", RegexOptions.IgnoreCase).Groups(1).Value
' Supplier name is the first substantial text line in the header zone
Dim supplierName = supplierResult.Text.Split(vbLf).FirstOrDefault(Function(l) l.Trim().Length > 4)?.Trim()
Return (invoiceNumber, supplierName, total)
End Using
End Using
End Using
End Function
End Class
Bölge tabanlı OCR, Mindee'nin mekansal alan tespitinin amacına uyar: belgeyi tüm sayfaya uygulamak yerine belirli bölgelerini okuyun. CropRectangle(x, y, width, height) piksel koordinatları alır, bu yüzden ayarlama, temsilci bir örnek faturaya karşı ölçüm gerektirir. bölge tabanlı OCR kılavuzu koordinat ölçümü ve bölge örtüşme stratejilerini kapsar. Değişken düzenlere sahip faturalar için, result.Text üzerindeki tam sayfa regex ile bölge çıkarımını birleştirmek en güvenilir sonuçları üretir.
Çok Sayfalı Harcama Rapor PDF İşleme
Mindee, PDF dosyasını kabul eder ve her sayfayı ayrı bir belge birimi olarak işler, her sayfa için yapılandırılmış bir sonuç döndürür. IronOCR, tüm sayfaları tek bir çağrıda işleyen ve her sayfanın içeriğiyle kelime koordinatlarını döndüren OcrInput.LoadPdf() aracılığıyla çok sayfalı PDF'leri yerel olarak okur.
Mindee Yaklaşımı:
using Mindee;
using Mindee.Input;
using Mindee.Product.Receipt;
public class MindeeExpenseReportProcessor
{
private readonly MindeeClient _client;
public MindeeExpenseReportProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<List<ExpenseSummary>> ProcessExpenseReportAsync(string pdfPath)
{
var summaries = new List<ExpenseSummary>();
//Mindeeprocesses per-document; each page of a PDF is a separate upload
// For a 10-page expense report: 10 API calls, 10 pages billed
var inputSource = new LocalInputSource(pdfPath);
var response = await _client.ParseAsync<ReceiptV5>(inputSource);
var prediction = response.Document.Inference.Prediction;
summaries.Add(new ExpenseSummary
{
MerchantName = prediction.SupplierName?.Value,
Date = prediction.Date?.Value?.ToString(),
TotalAmount = prediction.TotalAmount?.Value ?? 0m,
Category = prediction.Category?.Value
});
return summaries;
}
}
using Mindee;
using Mindee.Input;
using Mindee.Product.Receipt;
public class MindeeExpenseReportProcessor
{
private readonly MindeeClient _client;
public MindeeExpenseReportProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<List<ExpenseSummary>> ProcessExpenseReportAsync(string pdfPath)
{
var summaries = new List<ExpenseSummary>();
//Mindeeprocesses per-document; each page of a PDF is a separate upload
// For a 10-page expense report: 10 API calls, 10 pages billed
var inputSource = new LocalInputSource(pdfPath);
var response = await _client.ParseAsync<ReceiptV5>(inputSource);
var prediction = response.Document.Inference.Prediction;
summaries.Add(new ExpenseSummary
{
MerchantName = prediction.SupplierName?.Value,
Date = prediction.Date?.Value?.ToString(),
TotalAmount = prediction.TotalAmount?.Value ?? 0m,
Category = prediction.Category?.Value
});
return summaries;
}
}
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.Receipt
Imports System.Threading.Tasks
Public Class MindeeExpenseReportProcessor
Private ReadOnly _client As MindeeClient
Public Sub New(apiKey As String)
_client = New MindeeClient(apiKey)
End Sub
Public Async Function ProcessExpenseReportAsync(pdfPath As String) As Task(Of List(Of ExpenseSummary))
Dim summaries As New List(Of ExpenseSummary)()
' Mindee processes per-document; each page of a PDF is a separate upload
' For a 10-page expense report: 10 API calls, 10 pages billed
Dim inputSource As New LocalInputSource(pdfPath)
Dim response = Await _client.ParseAsync(Of ReceiptV5)(inputSource)
Dim prediction = response.Document.Inference.Prediction
summaries.Add(New ExpenseSummary With {
.MerchantName = prediction.SupplierName?.Value,
.Date = prediction.Date?.Value?.ToString(),
.TotalAmount = If(prediction.TotalAmount?.Value, 0D),
.Category = prediction.Category?.Value
})
Return summaries
End Function
End Class
IronOCR Yaklaşımı:
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrExpenseReportProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public List<ExpenseSummary> ProcessExpenseReport(string pdfPath)
{
// Load entire multi-page PDF in one call — no per-page upload
using var input = new OcrInput();
input.LoadPdf(pdfPath); // all pages loaded locally
var result = _ocr.Read(input);
var summaries = new List<ExpenseSummary>();
// Each page maps to one receipt in the expense report
foreach (var page in result.Pages)
{
var pageText = page.Text;
// Skip pages without receipt content
if (!pageText.Contains("Total", StringComparison.OrdinalIgnoreCase))
continue;
var merchantName = page.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
var totalMatch = Regex.Match(
pageText,
@"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
var dateMatch = Regex.Match(
pageText,
@"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b");
var categoryMatch = Regex.Match(
pageText,
@"(?:Category|Dept|Department)\s*:?\s*(.+)",
RegexOptions.IgnoreCase);
summaries.Add(new ExpenseSummary
{
PageNumber = page.PageNumber,
MerchantName = merchantName,
Date = dateMatch.Success ? dateMatch.Value : null,
TotalAmount = totalMatch.Success
? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
: 0m,
Category = categoryMatch.Success
? categoryMatch.Groups[1].Value.Trim()
: null,
Confidence = page.Words.Any()
? page.Words.Average(w => (double)w.Confidence)
: 0
});
}
return summaries;
}
}
public class ExpenseSummary
{
public int PageNumber { get; set; }
public string MerchantName { get; set; }
public string Date { get; set; }
public decimal TotalAmount { get; set; }
public string Category { get; set; }
public double Confidence { get; set; }
}
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrExpenseReportProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public List<ExpenseSummary> ProcessExpenseReport(string pdfPath)
{
// Load entire multi-page PDF in one call — no per-page upload
using var input = new OcrInput();
input.LoadPdf(pdfPath); // all pages loaded locally
var result = _ocr.Read(input);
var summaries = new List<ExpenseSummary>();
// Each page maps to one receipt in the expense report
foreach (var page in result.Pages)
{
var pageText = page.Text;
// Skip pages without receipt content
if (!pageText.Contains("Total", StringComparison.OrdinalIgnoreCase))
continue;
var merchantName = page.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
var totalMatch = Regex.Match(
pageText,
@"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
var dateMatch = Regex.Match(
pageText,
@"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b");
var categoryMatch = Regex.Match(
pageText,
@"(?:Category|Dept|Department)\s*:?\s*(.+)",
RegexOptions.IgnoreCase);
summaries.Add(new ExpenseSummary
{
PageNumber = page.PageNumber,
MerchantName = merchantName,
Date = dateMatch.Success ? dateMatch.Value : null,
TotalAmount = totalMatch.Success
? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
: 0m,
Category = categoryMatch.Success
? categoryMatch.Groups[1].Value.Trim()
: null,
Confidence = page.Words.Any()
? page.Words.Average(w => (double)w.Confidence)
: 0
});
}
return summaries;
}
}
public class ExpenseSummary
{
public int PageNumber { get; set; }
public string MerchantName { get; set; }
public string Date { get; set; }
public decimal TotalAmount { get; set; }
public string Category { get; set; }
public double Confidence { get; set; }
}
Imports IronOcr
Imports System.Text.RegularExpressions
Public Class IronOcrExpenseReportProcessor
Private ReadOnly _ocr As New IronTesseract()
Public Function ProcessExpenseReport(pdfPath As String) As List(Of ExpenseSummary)
' Load entire multi-page PDF in one call — no per-page upload
Using input As New OcrInput()
input.LoadPdf(pdfPath) ' all pages loaded locally
Dim result = _ocr.Read(input)
Dim summaries As New List(Of ExpenseSummary)()
' Each page maps to one receipt in the expense report
For Each page In result.Pages
Dim pageText = page.Text
' Skip pages without receipt content
If Not pageText.Contains("Total", StringComparison.OrdinalIgnoreCase) Then
Continue For
End If
Dim merchantName = page.Lines _
.FirstOrDefault(Function(l) l.Text.Trim().Length > 4) _
?.Text.Trim()
Dim totalMatch = Regex.Match(
pageText,
"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase)
Dim dateMatch = Regex.Match(
pageText,
"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b")
Dim categoryMatch = Regex.Match(
pageText,
"(?:Category|Dept|Department)\s*:?\s*(.+)",
RegexOptions.IgnoreCase)
summaries.Add(New ExpenseSummary With {
.PageNumber = page.PageNumber,
.MerchantName = merchantName,
.Date = If(dateMatch.Success, dateMatch.Value, Nothing),
.TotalAmount = If(totalMatch.Success, Decimal.Parse(totalMatch.Groups(1).Value.Replace(",", "")), 0D),
.Category = If(categoryMatch.Success, categoryMatch.Groups(1).Value.Trim(), Nothing),
.Confidence = If(page.Words.Any(), page.Words.Average(Function(w) CDbl(w.Confidence)), 0)
})
Next
Return summaries
End Using
End Function
End Class
Public Class ExpenseSummary
Public Property PageNumber As Integer
Public Property MerchantName As String
Public Property Date As String
Public Property TotalAmount As Decimal
Public Property Category As String
Public Property Confidence As Double
End Class
Mindee ile 10 sayfalı bir harcama raporu PDF işlemi 10 API çağrısı ve 10 faturalı sayfa üretir. IronOCR, aynı dosyayı tek bir yerel çağrıda işler, sayfa başına maliyet olmadan ve her sayfada ağ turu olmadan. result.Pages koleksiyonu, sayfa başına metin, kelime seviyesinde sınırlayıcı kutular ve düzen bilinçli çıkarım için satır pozisyonları sağlar. Parola korumalı PDF yükleme ve sayfa aralığı seçimi için PDF giriş kılavuzu ve kelime koordinatlarıyla çalışma için yapılandırılmış okuma sonuç kılavuzu'na bakınız.
Tarama Faturası Ön İşleme Hattı
Mindee'nin bulut işlemi, alan çıkarımının çalıştırılmasından önce kendi görüntü normalleştirmesini uygular. Bu normalleştirmenin kalitesi belirsizdir — üzerinde bir kontrolünüz yoktur ve ne tür bir ön işlem çalıştırıldığına dair bir görünürlüğünüz yoktur. Taransöz faturasında eğiklik, gölge veya düşük kontrast olduğunda, Mindee, gönderim öncesinde taramayı iyileştirmenize imkan tanımadan daha düşük güven puanları döndürür. IronOCR, her belgenin tanıma başlamadan önce ihtiyaç duyduğu tam düzeltmeleri uygulamanıza olanak tanıyan ön işleme hattını açıkça gösterir.
Mindee Yaklaşımı:
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeScanProcessor
{
private readonly MindeeClient _client;
public MindeeScanProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<ScanResult> ProcessScannedInvoiceAsync(string scanPath)
{
//Mindeeapplies internal normalization — no developer control over preprocessing
var inputSource = new LocalInputSource(scanPath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
return new ScanResult
{
InvoiceNumber = prediction.InvoiceNumber?.Value,
Total = prediction.TotalAmount?.Value,
// Per-field confidence: only proxy for scan quality
InvoiceNumberConfidence = prediction.InvoiceNumber?.Confidence,
TotalConfidence = prediction.TotalAmount?.Confidence
};
}
}
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeScanProcessor
{
private readonly MindeeClient _client;
public MindeeScanProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<ScanResult> ProcessScannedInvoiceAsync(string scanPath)
{
//Mindeeapplies internal normalization — no developer control over preprocessing
var inputSource = new LocalInputSource(scanPath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
return new ScanResult
{
InvoiceNumber = prediction.InvoiceNumber?.Value,
Total = prediction.TotalAmount?.Value,
// Per-field confidence: only proxy for scan quality
InvoiceNumberConfidence = prediction.InvoiceNumber?.Confidence,
TotalConfidence = prediction.TotalAmount?.Confidence
};
}
}
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.Invoice
Imports System.Threading.Tasks
Public Class MindeeScanProcessor
Private ReadOnly _client As MindeeClient
Public Sub New(apiKey As String)
_client = New MindeeClient(apiKey)
End Sub
Public Async Function ProcessScannedInvoiceAsync(scanPath As String) As Task(Of ScanResult)
' Mindee applies internal normalization — no developer control over preprocessing
Dim inputSource = New LocalInputSource(scanPath)
Dim response = Await _client.ParseAsync(Of InvoiceV4)(inputSource)
Dim prediction = response.Document.Inference.Prediction
Return New ScanResult With {
.InvoiceNumber = prediction.InvoiceNumber?.Value,
.Total = prediction.TotalAmount?.Value,
' Per-field confidence: only proxy for scan quality
.InvoiceNumberConfidence = prediction.InvoiceNumber?.Confidence,
.TotalConfidence = prediction.TotalAmount?.Confidence
}
End Function
End Class
IronOCR Yaklaşımı:
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrScanProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public ScanResult ProcessScannedInvoice(string scanPath)
{
// First pass: read without preprocessing
var quickResult = _ocr.Read(scanPath);
OcrResult result;
if (quickResult.Confidence < 75)
{
// Low confidence — apply full preprocessing pipeline
using var input = new OcrInput();
input.LoadImage(scanPath);
input.Deskew(); // correct page rotation up to ±45 degrees
input.DeNoise(); // remove scanner artifacts and speckle
input.Contrast(); // normalize contrast for faded or overexposed scans
input.Sharpen(); // sharpen blurred text edges
result = _ocr.Read(input);
}
else
{
result = quickResult;
}
var invoiceNumber = Regex.Match(
result.Text,
@"Invoice\s*(?:Number|#|No\.?)?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var total = Regex.Match(
result.Text,
@"(?:Total|Amount\s+Due)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase).Groups[1].Value;
return new ScanResult
{
InvoiceNumber = invoiceNumber,
Total = total,
DocumentConfidence = result.Confidence,
PreprocessingApplied = quickResult.Confidence < 75
};
}
}
public class ScanResult
{
public string InvoiceNumber { get; set; }
public string Total { get; set; }
public double DocumentConfidence { get; set; }
public bool PreprocessingApplied { get; set; }
}
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrScanProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public ScanResult ProcessScannedInvoice(string scanPath)
{
// First pass: read without preprocessing
var quickResult = _ocr.Read(scanPath);
OcrResult result;
if (quickResult.Confidence < 75)
{
// Low confidence — apply full preprocessing pipeline
using var input = new OcrInput();
input.LoadImage(scanPath);
input.Deskew(); // correct page rotation up to ±45 degrees
input.DeNoise(); // remove scanner artifacts and speckle
input.Contrast(); // normalize contrast for faded or overexposed scans
input.Sharpen(); // sharpen blurred text edges
result = _ocr.Read(input);
}
else
{
result = quickResult;
}
var invoiceNumber = Regex.Match(
result.Text,
@"Invoice\s*(?:Number|#|No\.?)?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var total = Regex.Match(
result.Text,
@"(?:Total|Amount\s+Due)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase).Groups[1].Value;
return new ScanResult
{
InvoiceNumber = invoiceNumber,
Total = total,
DocumentConfidence = result.Confidence,
PreprocessingApplied = quickResult.Confidence < 75
};
}
}
public class ScanResult
{
public string InvoiceNumber { get; set; }
public string Total { get; set; }
public double DocumentConfidence { get; set; }
public bool PreprocessingApplied { get; set; }
}
Imports IronOcr
Imports System.Text.RegularExpressions
Public Class IronOcrScanProcessor
Private ReadOnly _ocr As New IronTesseract()
Public Function ProcessScannedInvoice(scanPath As String) As ScanResult
' First pass: read without preprocessing
Dim quickResult = _ocr.Read(scanPath)
Dim result As OcrResult
If quickResult.Confidence < 75 Then
' Low confidence — apply full preprocessing pipeline
Using input As New OcrInput()
input.LoadImage(scanPath)
input.Deskew() ' correct page rotation up to ±45 degrees
input.DeNoise() ' remove scanner artifacts and speckle
input.Contrast() ' normalize contrast for faded or overexposed scans
input.Sharpen() ' sharpen blurred text edges
result = _ocr.Read(input)
End Using
Else
result = quickResult
End If
Dim invoiceNumber = Regex.Match(
result.Text,
"Invoice\s*(?:Number|#|No\.?)?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups(1).Value
Dim total = Regex.Match(
result.Text,
"(?:Total|Amount\s+Due)\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase).Groups(1).Value
Return New ScanResult With {
.InvoiceNumber = invoiceNumber,
.Total = total,
.DocumentConfidence = result.Confidence,
.PreprocessingApplied = quickResult.Confidence < 75
}
End Function
End Class
Public Class ScanResult
Public Property InvoiceNumber As String
Public Property Total As String
Public Property DocumentConfidence As Double
Public Property PreprocessingApplied As Boolean
End Class
Çift geçişli desen — önce hızlı okuma, düşük güvenliğe sahip olanlarda ön işleme —, temiz taramalarda tam ön işlem maliyetinden kaçınır. Hafif eğik düz yatak taramaları, faks eserleri, fotokopi faturaları gibi hesap borçlarında en yaygın tarama kalitesi senaryoları için Deskew() ve DeNoise() birlikte çoğu tanıma doğruluğunu geri kazanır. görüntü kalitesi düzeltme rehberi, her mevcut filtreyi, farklı tarama kusurları için en iyi hangi kombinasyonların çalıştığı konusunda kılavuzluk ile belgeler. görüntü yönü düzeltme rehberi, ters tarama yapılmış belgeler için otomatik döndürmeyi kapsar.
Finansal Belgeler için Aranabilir PDF Arşivleme
Mindee herhangi bir PDF çıktısı üretmez. Mimarisi yalnızca giriştir: bir belge gönderin, JSON alanlarını alın. Taransöz faturalarını aranabilir bir formatta arşivleyen ekipler, bu hattı Mindee'nin çıkarımından ayrı olarak sürdürmelidir. IronOCR, alan çıkarımında kullanılan aynı tanıma geçişinden doğrudan aranabilir PDF'ler üretir — ek bir kütüphane yoktur, ikinci bir işleme adımı yoktur.
Mindee Yaklaşımı:
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeArchiveProcessor
{
private readonly MindeeClient _client;
public MindeeArchiveProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task ArchiveInvoiceAsync(string scanPath, string archivePath)
{
// Extract fields viaMindee(document transmitted to cloud)
var inputSource = new LocalInputSource(scanPath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
//Mindeereturns no PDF output — searchable PDF requires a separate library
// (e.g., iTextSharp, PdfSharp, or a separate OCR library)
// The scan at scanPath is the only PDF available for archiving;
// it remains image-only with no embedded text layer
Console.WriteLine($"Fields extracted. Searchable PDF: not available from Mindee.");
Console.WriteLine($"Invoice: {prediction.InvoiceNumber?.Value}");
}
}
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
public class MindeeArchiveProcessor
{
private readonly MindeeClient _client;
public MindeeArchiveProcessor(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task ArchiveInvoiceAsync(string scanPath, string archivePath)
{
// Extract fields viaMindee(document transmitted to cloud)
var inputSource = new LocalInputSource(scanPath);
var response = await _client.ParseAsync<InvoiceV4>(inputSource);
var prediction = response.Document.Inference.Prediction;
//Mindeereturns no PDF output — searchable PDF requires a separate library
// (e.g., iTextSharp, PdfSharp, or a separate OCR library)
// The scan at scanPath is the only PDF available for archiving;
// it remains image-only with no embedded text layer
Console.WriteLine($"Fields extracted. Searchable PDF: not available from Mindee.");
Console.WriteLine($"Invoice: {prediction.InvoiceNumber?.Value}");
}
}
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.Invoice
Imports System.Threading.Tasks
Public Class MindeeArchiveProcessor
Private ReadOnly _client As MindeeClient
Public Sub New(apiKey As String)
_client = New MindeeClient(apiKey)
End Sub
Public Async Function ArchiveInvoiceAsync(scanPath As String, archivePath As String) As Task
' Extract fields via Mindee (document transmitted to cloud)
Dim inputSource = New LocalInputSource(scanPath)
Dim response = Await _client.ParseAsync(Of InvoiceV4)(inputSource)
Dim prediction = response.Document.Inference.Prediction
' Mindee returns no PDF output — searchable PDF requires a separate library
' (e.g., iTextSharp, PdfSharp, or a separate OCR library)
' The scan at scanPath is the only PDF available for archiving;
' it remains image-only with no embedded text layer
Console.WriteLine($"Fields extracted. Searchable PDF: not available from Mindee.")
Console.WriteLine($"Invoice: {prediction.InvoiceNumber?.Value}")
End Function
End Class
IronOCR Yaklaşımı:
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrArchiveProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public ArchiveResult ArchiveInvoice(string scanPath, string archiveOutputPath)
{
// Apply preprocessing before recognition and archiving
using var input = new OcrInput();
input.LoadPdf(scanPath); // works with both PDF scans and image files
input.Deskew();
input.DeNoise();
var result = _ocr.Read(input);
// Extract fields from the same recognition pass
var invoiceNumber = Regex.Match(
result.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var vendor = result.Pages.FirstOrDefault()?.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
var totalMatch = Regex.Match(
result.Text,
@"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
// Write searchable PDF to archive in one call — no separate library needed
result.SaveAsSearchablePdf(archiveOutputPath);
return new ArchiveResult
{
InvoiceNumber = invoiceNumber,
VendorName = vendor,
Total = totalMatch.Success ? totalMatch.Groups[1].Value : null,
ArchivePath = archiveOutputPath,
DocumentConfidence = result.Confidence,
PageCount = result.Pages.Count()
};
}
}
public class ArchiveResult
{
public string InvoiceNumber { get; set; }
public string VendorName { get; set; }
public string Total { get; set; }
public string ArchivePath { get; set; }
public double DocumentConfidence { get; set; }
public int PageCount { get; set; }
}
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrArchiveProcessor
{
private readonly IronTesseract _ocr = new IronTesseract();
public ArchiveResult ArchiveInvoice(string scanPath, string archiveOutputPath)
{
// Apply preprocessing before recognition and archiving
using var input = new OcrInput();
input.LoadPdf(scanPath); // works with both PDF scans and image files
input.Deskew();
input.DeNoise();
var result = _ocr.Read(input);
// Extract fields from the same recognition pass
var invoiceNumber = Regex.Match(
result.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
var vendor = result.Pages.FirstOrDefault()?.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
var totalMatch = Regex.Match(
result.Text,
@"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
// Write searchable PDF to archive in one call — no separate library needed
result.SaveAsSearchablePdf(archiveOutputPath);
return new ArchiveResult
{
InvoiceNumber = invoiceNumber,
VendorName = vendor,
Total = totalMatch.Success ? totalMatch.Groups[1].Value : null,
ArchivePath = archiveOutputPath,
DocumentConfidence = result.Confidence,
PageCount = result.Pages.Count()
};
}
}
public class ArchiveResult
{
public string InvoiceNumber { get; set; }
public string VendorName { get; set; }
public string Total { get; set; }
public string ArchivePath { get; set; }
public double DocumentConfidence { get; set; }
public int PageCount { get; set; }
}
Imports IronOcr
Imports System.Text.RegularExpressions
Imports System.Linq
Public Class IronOcrArchiveProcessor
Private ReadOnly _ocr As New IronTesseract()
Public Function ArchiveInvoice(scanPath As String, archiveOutputPath As String) As ArchiveResult
' Apply preprocessing before recognition and archiving
Using input As New OcrInput()
input.LoadPdf(scanPath) ' works with both PDF scans and image files
input.Deskew()
input.DeNoise()
Dim result = _ocr.Read(input)
' Extract fields from the same recognition pass
Dim invoiceNumber = Regex.Match(result.Text, "Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)", RegexOptions.IgnoreCase).Groups(1).Value
Dim vendor = result.Pages.FirstOrDefault()?.Lines.FirstOrDefault(Function(l) l.Text.Trim().Length > 4)?.Text.Trim()
Dim totalMatch = Regex.Match(result.Text, "Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.\d{2})", RegexOptions.IgnoreCase)
' Write searchable PDF to archive in one call — no separate library needed
result.SaveAsSearchablePdf(archiveOutputPath)
Return New ArchiveResult With {
.InvoiceNumber = invoiceNumber,
.VendorName = vendor,
.Total = If(totalMatch.Success, totalMatch.Groups(1).Value, Nothing),
.ArchivePath = archiveOutputPath,
.DocumentConfidence = result.Confidence,
.PageCount = result.Pages.Count()
}
End Using
End Function
End Class
Public Class ArchiveResult
Public Property InvoiceNumber As String
Public Property VendorName As String
Public Property Total As String
Public Property ArchivePath As String
Public Property DocumentConfidence As Double
Public Property PageCount As Integer
End Class
result.SaveAsSearchablePdf(), tanınan metin katmanını doğrudan çıkış PDF'ine yerleştirir ve her kelimenin seçilebilir ve aranabilir olduğu bir dosya oluşturur. Alan çıkarımı ve arşivleme aynı geçişte çalışır — bir _ocr.Read(input) çağrısı hem kalıp eşleşmesi için result.Text hem de arşiv için result.SaveAsSearchablePdf() sağlar. aranabilir PDF kılavuzu, HOCR dışa aktarımı ve PDF OCR kullanım alanı sayfası belge arşivleme hatları için üretim dağıtım kalıplarını kapsar.
FinancialDocumentV1 Özel Uç Noktasının Kaldırılması
Mindee'nin FinancialDocumentV1 API'si, belge türünü otomatik olarak algılayarak hem faturaları hem de makbuzları işler. Bunu kullanan ekipler, her belge türü yüklenirken malesef daha yüksek bulut bağımlılığı maliyetine uğrar.IronOCR kullanarak, belge yapısını ve bulut çağrısı olmadan çıkarma mantığını yönlendirmek için kelime seviyesindeki konumsal verileri kullanır.
Mindee Yaklaşımı:
using Mindee;
using Mindee.Input;
using Mindee.Product.FinancialDocument;
public class MindeeFinancialRouter
{
private readonly MindeeClient _client;
public MindeeFinancialRouter(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<FinancialSummary> ProcessFinancialDocumentAsync(string filePath)
{
// All financial documents uploaded for auto-detection and parsing
var inputSource = new LocalInputSource(filePath);
var response = await _client.ParseAsync<FinancialDocumentV1>(inputSource);
var prediction = response.Document.Inference.Prediction;
return new FinancialSummary
{
DocumentType = prediction.DocumentType?.Value, // "INVOICE" or "RECEIPT"
InvoiceNumber = prediction.InvoiceNumber?.Value,
Date = prediction.Date?.Value?.ToString(),
TotalAmount = prediction.TotalAmount?.Value,
SupplierName = prediction.SupplierName?.Value,
CustomerName = prediction.CustomerName?.Value
};
}
}
using Mindee;
using Mindee.Input;
using Mindee.Product.FinancialDocument;
public class MindeeFinancialRouter
{
private readonly MindeeClient _client;
public MindeeFinancialRouter(string apiKey)
{
_client = new MindeeClient(apiKey);
}
public async Task<FinancialSummary> ProcessFinancialDocumentAsync(string filePath)
{
// All financial documents uploaded for auto-detection and parsing
var inputSource = new LocalInputSource(filePath);
var response = await _client.ParseAsync<FinancialDocumentV1>(inputSource);
var prediction = response.Document.Inference.Prediction;
return new FinancialSummary
{
DocumentType = prediction.DocumentType?.Value, // "INVOICE" or "RECEIPT"
InvoiceNumber = prediction.InvoiceNumber?.Value,
Date = prediction.Date?.Value?.ToString(),
TotalAmount = prediction.TotalAmount?.Value,
SupplierName = prediction.SupplierName?.Value,
CustomerName = prediction.CustomerName?.Value
};
}
}
Imports Mindee
Imports Mindee.Input
Imports Mindee.Product.FinancialDocument
Imports System.Threading.Tasks
Public Class MindeeFinancialRouter
Private ReadOnly _client As MindeeClient
Public Sub New(apiKey As String)
_client = New MindeeClient(apiKey)
End Sub
Public Async Function ProcessFinancialDocumentAsync(filePath As String) As Task(Of FinancialSummary)
' All financial documents uploaded for auto-detection and parsing
Dim inputSource = New LocalInputSource(filePath)
Dim response = Await _client.ParseAsync(Of FinancialDocumentV1)(inputSource)
Dim prediction = response.Document.Inference.Prediction
Return New FinancialSummary With {
.DocumentType = prediction.DocumentType?.Value, ' "INVOICE" or "RECEIPT"
.InvoiceNumber = prediction.InvoiceNumber?.Value,
.Date = prediction.Date?.Value?.ToString(),
.TotalAmount = prediction.TotalAmount?.Value,
.SupplierName = prediction.SupplierName?.Value,
.CustomerName = prediction.CustomerName?.Value
}
End Function
End Class
IronOCR Yaklaşımı:
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrFinancialRouter
{
private readonly IronTesseract _ocr = new IronTesseract();
public FinancialSummary ProcessFinancialDocument(string filePath)
{
var result = _ocr.Read(filePath);
var text = result.Text;
// Detect document type using structural keywords from word data
var isInvoice = DetectInvoice(result);
if (isInvoice)
{
return new FinancialSummary
{
DocumentType = "INVOICE",
InvoiceNumber = Regex.Match(text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value,
Date = Regex.Match(text,
@"(?:Invoice\s+)?Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})",
RegexOptions.IgnoreCase).Groups[1].Value,
TotalAmount = ParseAmount(text,
@"Total\s*(?:Due|Amount)?\s*:?\s*\$?([\d,]+\.\d{2})"),
SupplierName = ExtractTopLine(result),
CustomerName = Regex.Match(text,
@"Bill\s+To\s*:?\s*\n?(.+)",
RegexOptions.IgnoreCase).Groups[1].Value.Trim()
};
}
else
{
// Receipt structure: merchant at top, no "Bill To" section
return new FinancialSummary
{
DocumentType = "RECEIPT",
Date = Regex.Match(text,
@"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b").Value,
TotalAmount = ParseAmount(text,
@"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})"),
SupplierName = ExtractTopLine(result)
};
}
}
private bool DetectInvoice(OcrResult result)
{
// Invoice indicators: "Invoice", "Bill To", "Due Date", line items with quantities
var text = result.Text;
var invoiceSignals = new[] { "Invoice", "Bill To", "Due Date", "Purchase Order" };
return invoiceSignals.Any(s =>
text.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0);
}
private string ExtractTopLine(OcrResult result)
{
return result.Pages
.FirstOrDefault()
?.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
}
private decimal? ParseAmount(string text, string pattern)
{
var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
if (match.Success &&
decimal.TryParse(match.Groups[1].Value.Replace(",", ""), out var val))
return val;
return null;
}
}
public class FinancialSummary
{
public string DocumentType { get; set; }
public string InvoiceNumber { get; set; }
public string Date { get; set; }
public decimal? TotalAmount { get; set; }
public string SupplierName { get; set; }
public string CustomerName { get; set; }
}
using IronOcr;
using System.Text.RegularExpressions;
public class IronOcrFinancialRouter
{
private readonly IronTesseract _ocr = new IronTesseract();
public FinancialSummary ProcessFinancialDocument(string filePath)
{
var result = _ocr.Read(filePath);
var text = result.Text;
// Detect document type using structural keywords from word data
var isInvoice = DetectInvoice(result);
if (isInvoice)
{
return new FinancialSummary
{
DocumentType = "INVOICE",
InvoiceNumber = Regex.Match(text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value,
Date = Regex.Match(text,
@"(?:Invoice\s+)?Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})",
RegexOptions.IgnoreCase).Groups[1].Value,
TotalAmount = ParseAmount(text,
@"Total\s*(?:Due|Amount)?\s*:?\s*\$?([\d,]+\.\d{2})"),
SupplierName = ExtractTopLine(result),
CustomerName = Regex.Match(text,
@"Bill\s+To\s*:?\s*\n?(.+)",
RegexOptions.IgnoreCase).Groups[1].Value.Trim()
};
}
else
{
// Receipt structure: merchant at top, no "Bill To" section
return new FinancialSummary
{
DocumentType = "RECEIPT",
Date = Regex.Match(text,
@"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b").Value,
TotalAmount = ParseAmount(text,
@"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})"),
SupplierName = ExtractTopLine(result)
};
}
}
private bool DetectInvoice(OcrResult result)
{
// Invoice indicators: "Invoice", "Bill To", "Due Date", line items with quantities
var text = result.Text;
var invoiceSignals = new[] { "Invoice", "Bill To", "Due Date", "Purchase Order" };
return invoiceSignals.Any(s =>
text.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0);
}
private string ExtractTopLine(OcrResult result)
{
return result.Pages
.FirstOrDefault()
?.Lines
.FirstOrDefault(l => l.Text.Trim().Length > 4)
?.Text.Trim();
}
private decimal? ParseAmount(string text, string pattern)
{
var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
if (match.Success &&
decimal.TryParse(match.Groups[1].Value.Replace(",", ""), out var val))
return val;
return null;
}
}
public class FinancialSummary
{
public string DocumentType { get; set; }
public string InvoiceNumber { get; set; }
public string Date { get; set; }
public decimal? TotalAmount { get; set; }
public string SupplierName { get; set; }
public string CustomerName { get; set; }
}
Imports IronOcr
Imports System.Text.RegularExpressions
Public Class IronOcrFinancialRouter
Private ReadOnly _ocr As New IronTesseract()
Public Function ProcessFinancialDocument(filePath As String) As FinancialSummary
Dim result = _ocr.Read(filePath)
Dim text = result.Text
' Detect document type using structural keywords from word data
Dim isInvoice = DetectInvoice(result)
If isInvoice Then
Return New FinancialSummary With {
.DocumentType = "INVOICE",
.InvoiceNumber = Regex.Match(text,
"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups(1).Value,
.Date = Regex.Match(text,
"(?:Invoice\s+)?Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})",
RegexOptions.IgnoreCase).Groups(1).Value,
.TotalAmount = ParseAmount(text,
"Total\s*(?:Due|Amount)?\s*:?\s*\$?([\d,]+\.\d{2})"),
.SupplierName = ExtractTopLine(result),
.CustomerName = Regex.Match(text,
"Bill\s+To\s*:?\s*\n?(.+)",
RegexOptions.IgnoreCase).Groups(1).Value.Trim()
}
Else
' Receipt structure: merchant at top, no "Bill To" section
Return New FinancialSummary With {
.DocumentType = "RECEIPT",
.Date = Regex.Match(text,
"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b").Value,
.TotalAmount = ParseAmount(text,
"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})"),
.SupplierName = ExtractTopLine(result)
}
End If
End Function
Private Function DetectInvoice(result As OcrResult) As Boolean
' Invoice indicators: "Invoice", "Bill To", "Due Date", line items with quantities
Dim text = result.Text
Dim invoiceSignals = {"Invoice", "Bill To", "Due Date", "Purchase Order"}
Return invoiceSignals.Any(Function(s) text.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0)
End Function
Private Function ExtractTopLine(result As OcrResult) As String
Return result.Pages _
.FirstOrDefault() _
?.Lines _
.FirstOrDefault(Function(l) l.Text.Trim().Length > 4) _
?.Text.Trim()
End Function
Private Function ParseAmount(text As String, pattern As String) As Decimal?
Dim match = Regex.Match(text, pattern, RegexOptions.IgnoreCase)
If match.Success AndAlso
Decimal.TryParse(match.Groups(1).Value.Replace(",", ""), val) Then
Return val
End If
Return Nothing
End Function
End Class
Public Class FinancialSummary
Public Property DocumentType As String
Public Property InvoiceNumber As String
Public Property Date As String
Public Property TotalAmount As Decimal?
Public Property SupplierName As String
Public Property CustomerName As String
End Class
Belge türü algılama mantığı, Mindee'nin sunucu tarafı DocumentType alanını result.Text karşısına basit bir anahtar kelime taramasıyla değiştirir. Finansal belgelerin büyük çoğunluğu için, 'Fatura' veya 'Gönderilen Kişi' varlığı faturaları belirsiz bir şekilde tanımlar; eksikliği makbuzları tanımlar. result.Pages içindeki kelime seviyesi pozisyon verileri, belge kümeniz sınır durumlarını içeriyorsa daha karmaşık düzen tabanlı algılama sağlar. okuma sonuçları kılavuzu, sınırlayıcı koordinatlarıyla birlikte Words, Lines ve Paragraphs dahil olmak üzere tam nesne modelini açıklar.
Mindee API'si ile IronOCR Haritalama Başvuru
| Mindee | IronOCR Karşılığı |
|---|---|
new MindeeClient(apiKey) |
new IronTesseract() — API anahtarı gerekmez |
new LocalInputSource(filePath) |
new OcrInput() + input.LoadImage(filePath) veya ocr.Read(filePath) |
_client.ParseAsync<InvoiceV4>(input) |
_ocr.Read(filePath) + result.Text üzerinde regex çıkarımı |
_client.ParseAsync<ReceiptV5>(input) |
_ocr.Read(filePath) + makbuz çıkarım kalıpları |
_client.ParseAsync<PassportV1>(input) |
_ocr.Read(filePath) + CropRectangle ile MRZ bölgesi çıkarımı |
_client.ParseAsync<FinancialDocumentV1>(input) |
_ocr.Read(filePath) + result.Text üzerinde belge türü algılama |
response.Document.Inference.Prediction |
result.Text, result.Pages, result.Lines, result.Words |
prediction.InvoiceNumber?.Value |
Regex.Match(result.Text, @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)") |
prediction.SupplierName?.Value |
İlk sayfanın üst satırı result.Pages[0].Lines.First() aracılığıyla |
prediction.TotalAmount?.Value |
Regex.Match(result.Text, @"Total\s*:?\s*\$?([\d,]+\.\d{2})") |
prediction.LineItems |
result.Lines, satır öğesi regex kalıplarına göre filtrelendi |
prediction.SupplierPaymentDetails[].Iban |
Regex.Match(result.Text, @"IBAN\s*:?\s*([\w\s]+)") |
prediction.InvoiceDate?.Value |
Regex.Match(result.Text, @"Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{4})") |
field.Confidence |
result.Confidence (belge seviyesi) veya word.Confidence (kelime başına) |
catch (MindeeException ex) |
Eşdeğer yok — tanıma esnasında ağ hataları yok |
await Task.Delay(100) (oran sınırı) |
Gerekli değil — hız sınırı yok |
input.LoadPdf(path) |
ocrInput.LoadPdf(path) — aynı işlem, tamamen yerel |
| API anahtarı yapılandırmada | Lisans anahtarı IronOcr.License.LicenseKey = "..." ile — dönüşüme ihtiyaç yok |
Yaygın Göç Sorunları ve Çözümleri
Sorun 1: CropRectangle Koordinatları Belge Düzeniyle Uyumlu Değil
Mindee: Mekansal alan koordinatları sunucu tarafında işlenir. Mindee'nin modeli geliştiriciden herhangi bir koordinat yapılandırması olmaksızın farklı fatura düzenlerine uyum sağlar.
Çözüm: Satıcı setinizden belgelerin temsili bir örneğiyle karşılaştırarak bölge koordinatlarını ölçün. Herhangi bir resim düzenleyiciyi açın, piksel boyutlarını okuyun ve CropRectangle(x, y, width, height) buna göre tanımlayın. Değişken düzenlere sahip faturalar için, önce tüm belgeyi okuyun ve bölgeleri dinamik olarak bulmak için kelime konum verilerini kullanın:
var result = _ocr.Read("invoice.jpg");
var allWords = result.Pages.First().Words;
// Find the word "Total" and read the region 50px to its right
var totalLabel = allWords.FirstOrDefault(w =>
w.Text.Equals("Total", StringComparison.OrdinalIgnoreCase));
if (totalLabel != null)
{
var valueRegion = new CropRectangle(
totalLabel.X + totalLabel.Width + 5,
totalLabel.Y - 5,
200,
totalLabel.Height + 10);
using var valueInput = new OcrInput();
valueInput.LoadImage("invoice.jpg", valueRegion);
var valueResult = _ocr.Read(valueInput);
Console.WriteLine($"Total: {valueResult.Text.Trim()}");
}
var result = _ocr.Read("invoice.jpg");
var allWords = result.Pages.First().Words;
// Find the word "Total" and read the region 50px to its right
var totalLabel = allWords.FirstOrDefault(w =>
w.Text.Equals("Total", StringComparison.OrdinalIgnoreCase));
if (totalLabel != null)
{
var valueRegion = new CropRectangle(
totalLabel.X + totalLabel.Width + 5,
totalLabel.Y - 5,
200,
totalLabel.Height + 10);
using var valueInput = new OcrInput();
valueInput.LoadImage("invoice.jpg", valueRegion);
var valueResult = _ocr.Read(valueInput);
Console.WriteLine($"Total: {valueResult.Text.Trim()}");
}
Imports System
Imports System.Linq
Dim result = _ocr.Read("invoice.jpg")
Dim allWords = result.Pages.First().Words
' Find the word "Total" and read the region 50px to its right
Dim totalLabel = allWords.FirstOrDefault(Function(w) w.Text.Equals("Total", StringComparison.OrdinalIgnoreCase))
If totalLabel IsNot Nothing Then
Dim valueRegion = New CropRectangle(totalLabel.X + totalLabel.Width + 5, totalLabel.Y - 5, 200, totalLabel.Height + 10)
Using valueInput As New OcrInput()
valueInput.LoadImage("invoice.jpg", valueRegion)
Dim valueResult = _ocr.Read(valueInput)
Console.WriteLine($"Total: {valueResult.Text.Trim()}")
End Using
End If
bölge tabanlı OCR örneği, bu dinamik bölge desenini eksiksiz bir çalışan örnekte gösterir.
Sorun 2:MindeeKaldırıldıktan Sonra Asenkron Çağrı Siteleri Kırılır
Mindee: TümMindeeAPI yüzeyi asenkrondur çünkü ağ G/Ç'sidir. await _client.ParseAsync<t>() üzerinde inşa edilen denetleyiciler ve servis yöntemleri, çağrı zinciri boyunca asenkron olur.
Çözüm: IronOCR'nin Read() yöntemi senkron çalışır. Mevcut asenkron çağrı yerleri, senkron çağrısı Task.Run içerisinde sararak hemen çalışır hale gelir:
// Existing async signature preserved for callers
public async Task<string> ExtractInvoiceNumberAsync(string filePath)
{
return await Task.Run(() =>
{
var result = new IronTesseract().Read(filePath);
return Regex.Match(result.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
});
}
// Existing async signature preserved for callers
public async Task<string> ExtractInvoiceNumberAsync(string filePath)
{
return await Task.Run(() =>
{
var result = new IronTesseract().Read(filePath);
return Regex.Match(result.Text,
@"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups[1].Value;
});
}
Imports System.Text.RegularExpressions
Imports System.Threading.Tasks
' Existing async signature preserved for callers
Public Async Function ExtractInvoiceNumberAsync(filePath As String) As Task(Of String)
Return Await Task.Run(Function()
Dim result = New IronTesseract().Read(filePath)
Return Regex.Match(result.Text,
"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
RegexOptions.IgnoreCase).Groups(1).Value
End Function)
End Function
Yüksek verimli ASP.NET senaryoları için, Task.Run sarmalayıcılara ve yerel async yoluna karar vermeden önce async OCR kılavuzu inceleyin.
Sorun 3: Düşük Kalitede Taramalarda Çıkarım Doğruluğu Düşüyor
Mindee: Mindee'nin ön işlemesi içsel ve otomatiktir. Tarama kalitesi sorunları, geliştirici müdahalesi olmadan yeniden gönderimden önce alan güven puanlarını düşürür.
Çözüm: IronOCR'nin ön işleme hattını tanımadan önce uygulayın. Deskew() ve DeNoise() kombinasyonu, hesaplar ödeme akışında görülen tipik düz yatak tarama kusurlarının çoğunda doğruluğu geri kazanır:
using var input = new OcrInput();
input.LoadImage("faded-invoice.jpg");
input.Deskew();
input.DeNoise();
input.Contrast(); // for faded or low-contrast thermal paper receipts
input.Binarize(); // convert to clean black-and-white before recognition
var result = new IronTesseract().Read(input);
using var input = new OcrInput();
input.LoadImage("faded-invoice.jpg");
input.Deskew();
input.DeNoise();
input.Contrast(); // for faded or low-contrast thermal paper receipts
input.Binarize(); // convert to clean black-and-white before recognition
var result = new IronTesseract().Read(input);
Imports IronOcr
Using input As New OcrInput()
input.LoadImage("faded-invoice.jpg")
input.Deskew()
input.DeNoise()
input.Contrast() ' for faded or low-contrast thermal paper receipts
input.Binarize() ' convert to clean black-and-white before recognition
Dim result = New IronTesseract().Read(input)
End Using
Ağır bozulmuş taramalar için input.DeepCleanBackgroundNoise() daha yoğun bir arka plan kaldırma geçişi uygular. görüntü kalitesi düzeltme rehberi, eşikleri belgeler ve filtre sihirbazı, bir verilen belge örneğinde hangi filtrelerin doğruluğu arttırdığını belirlemenize yardımcı olur.
Sorun 4: API Anahtarı ve Ağ Çıkış Yapılandırılması Kaldırıldı
Mindee: Uygulama ayarlarında depolanan API anahtarı, api.mindee.net'a çıkıcı HTTPS'ye izin veren ağ çıkış kuralları ve HttpRequestException sarmalayıcı geri döngü mantığı tümü gereken altyapıdır.
Çözüm: Üçü de birlikte kaldırılır.MindeeAPI anahtarı girişi yapılandırmadan silinir. Ağ çıkış kuralı geçersiz kılınır. try/catch (HttpRequestException) bloğu kaldırılır. Kalan tek kimlik bilgisi, başlangıçta bir kez ayarlanan IronOCR lisans anahtarıdır:
// appsettings.json: remove "Mindee:ApiKey"
// Firewall: revoke egress rule for api.mindee.net
// Startup.cs or Program.cs:
IronOcr.License.LicenseKey = Configuration["IronOcr:LicenseKey"];
//Hayırrotation schedule, no secure storage beyond standard config secret management
// appsettings.json: remove "Mindee:ApiKey"
// Firewall: revoke egress rule for api.mindee.net
// Startup.cs or Program.cs:
IronOcr.License.LicenseKey = Configuration["IronOcr:LicenseKey"];
//Hayırrotation schedule, no secure storage beyond standard config secret management
' appsettings.json: remove "Mindee:ApiKey"
' Firewall: revoke egress rule for api.mindee.net
' Startup.vb or Program.vb:
IronOcr.License.LicenseKey = Configuration("IronOcr:LicenseKey")
' Hayırrotation schedule, no secure storage beyond standard config secret management
Sorun 5: Çoklu Sayfa PDF Sayfa Sayma Faturalandırması
Mindee: Mindee'ye yüklenen 12 sayfalık bir satıcı bildirimi, aylık kotaya karşı 12 sayfa tüketir. Pro katman aşma oranlarında, eğer sınıra yakınsanız, bu tek belge, aylık allotmanın ötesinde ek olarak 1,20 $ maliyet gerektirir.
Çözüm: IronOCR, çoklu sayfalı PDF'leri sayfa başına sıfır maliyetle işler. Tüm belgeyi yükleyin ve sayfaları yineleyin:
using var input = new OcrInput();
input.LoadPdf("vendor-statement.pdf"); // 12 pages — no billing unit increment
var result = new IronTesseract().Read(input);
foreach (var page in result.Pages)
Console.WriteLine($"Page {page.PageNumber}: {page.Text.Length} characters recognized");
using var input = new OcrInput();
input.LoadPdf("vendor-statement.pdf"); // 12 pages — no billing unit increment
var result = new IronTesseract().Read(input);
foreach (var page in result.Pages)
Console.WriteLine($"Page {page.PageNumber}: {page.Text.Length} characters recognized");
Imports IronOcr
Using input As New OcrInput()
input.LoadPdf("vendor-statement.pdf") ' 12 pages — no billing unit increment
Dim result = New IronTesseract().Read(input)
For Each page In result.Pages
Console.WriteLine($"Page {page.PageNumber}: {page.Text.Length} characters recognized")
Next
End Using
Sorun 6: FinancialDocumentV1 Bağımlılığı Tek Bir Desenle Değiştirilemez
Mindee: FinancialDocumentV1, belge tipi otomatik olarak algılar ve alanları belge türüne göre dallanma olmadan çıkarır.
Çözüm: Anahtar kelime varlığını kullanarak hafif bir dedektör oluşturun. Finansal belgeler, 'Fatura', 'Gönderilen Kişi' veya 'Ödeme Tarihi' içeren faturalar ve 'Makbuz', 'Teşekkürler' içeren, fatura işaretçileri içermeyen makbuzlar olarak temiz bir şekilde bölünür. İki çıkarım yöntemi artı üç satırlık bir dedektör, iyi biçimlendirilmiş belgelerde doğruluğu kaybetmedenMindeeAPI çağrısını değiştirir:
var result = _ocr.Read(filePath);
var summary = result.Text.IndexOf("Invoice", StringComparison.OrdinalIgnoreCase) >= 0
? ExtractInvoiceFields(result)
: ExtractReceiptFields(result);
var result = _ocr.Read(filePath);
var summary = result.Text.IndexOf("Invoice", StringComparison.OrdinalIgnoreCase) >= 0
? ExtractInvoiceFields(result)
: ExtractReceiptFields(result);
Dim result = _ocr.Read(filePath)
Dim summary = If(result.Text.IndexOf("Invoice", StringComparison.OrdinalIgnoreCase) >= 0, ExtractInvoiceFields(result), ExtractReceiptFields(result))
Mindee Geçiş Kontrol Listesi
Öncesi-Geçiş
TümMindeekullanımlarını kod tabanında denetleyin:
grep -r "using Mindee" --include="*.cs" .
grep -r "MindeeClient\|ParseAsync\|InvoiceV4\|ReceiptV5\|PassportV1\|FinancialDocumentV1" --include="*.cs" .
grep -r "LocalInputSource\|MindeeException" --include="*.cs" .
grep -r "Mindee:ApiKey\|mindee_api_key\|MINDEE_API_KEY" --include="*.json" --include="*.env" --include="*.yml" .
grep -r "using Mindee" --include="*.cs" .
grep -r "MindeeClient\|ParseAsync\|InvoiceV4\|ReceiptV5\|PassportV1\|FinancialDocumentV1" --include="*.cs" .
grep -r "LocalInputSource\|MindeeException" --include="*.cs" .
grep -r "Mindee:ApiKey\|mindee_api_key\|MINDEE_API_KEY" --include="*.json" --include="*.env" --include="*.yml" .
Keşif bulguları:
- Benzersiz çağrı yerlerini
ParseAsync<t>kullanarak sayın - Hangi belge türlerinin kullanıldığını not alın (
InvoiceV4,ReceiptV5,PassportV1,FinancialDocumentV1) -Mindeeçağrılarından yayılan tüm asenkron yöntem zincirlerini belirleyin - Yapılandırma dosyalarında ve gizli yeniliklerde API anahtarı referanslarını bulundurun -Mindeeağ çağrılarının etrafında çevrilen yeniden deneme mantığını belirleyin -Mindeeuç noktalarına giden dış trafiğe izin veren ağ çıkış kurallarını belirleyin
Kod Geçişi
- Proje dosyasından
MindeeNuGet paketini kaldırın 2.IronOCR yüklemek içindotnet add package IronOcrçalıştırın - Uygulama başlangıcına
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"ekleyin - Tüm
using Mindee,using Mindee.Inputveusing Mindee.Product.*yönergelerini kaldırın MindeeClientyapılandırma enjeksiyonunuIronTesseractbaşlatma veya DI kaydı ile değiştirin- Her
ParseAsync<InvoiceV4>çağrısını_ocr.Read(filePath)artı fatura çıkarım yöntemleri ile değiştirin - Her
ParseAsync<ReceiptV5>çağrısını_ocr.Read(filePath)artı makbuz çıkarım yöntemleri ile değiştirin - Her
ParseAsync<PassportV1>çağrısınıCropRectangleile MRZ alanı üzerinde bölge tabanlı OCR ile değiştirin - Her
ParseAsync<FinancialDocumentV1>çağrısını, belge türü dedektörü + yönlendirme deseni ile değiştirin - Tüm
await Task.Delay(...)oran sınırlı uygunluk çizgilerini kaldırın - OCR yollarından tüm
catch (MindeeException)vecatch (HttpRequestException)bloklarını kaldırın - Tarama belge yolları için
Deskew,DeNoise,Contrastile birlikteOcrInputön işleme çağrılarını ekleyin - Herhangi bir belge arşivleme yollarına
result.SaveAsSearchablePdf(archivePath)ekleyin - Tüm yapılandırma dosyalarından ve gizli yeniliklerdenMindeeAPI anahtarını kaldırın
- Ağ taklidi olmadan eşzamanlı çalışan bir şekilde entegrasyon testlerini güncelleyin
Geçiş Sonrası
- Kullanılan her belge türünü kapsayan 20-30 belge örneği setine karşı çıkarım doğruluğunu doğrulayın
- Temiz taramaların temsili örneklerinde
result.Confidencedeğerlerini 80'in üzerinde onaylayın; 80'in altına düşerse ön işleme uygulayın - Eğik ve bozulmuş tarama örneklerinde ön işlem hattını (
Deskew,DeNoise) test edin - Çok sayfalı PDF'lerin doğru
result.Pages.Countve sayfa başı içerik ürettiğini doğrulayın result.SaveAsSearchablePdf()çıktısının Adobe Acrobat ve sistem PDF görüntüleyicilerinde aranabilir olduğunu onaylayın- Tedarikçi kümenizdeki belge düzen varyasyonları karşısında tüm bölge tabanlı çıkarımı (
CropRectangle) test edin Task.Delayçağrıları olmadan toplu işlem yapın ve herhangi bir iş parçacığı sorunu olmadığını doğrulayın- Uygulamanın doğru bir şekilde çalışıp çalışmadığını ve dış internet erişimi olmadan başladığını doğrulayın
- Her giriş noktasında ilk
_ocr.Read()çağrısından önce lisans anahtarı başlatmanın çalıştığını doğrulayın - Yapılandırmada, ortam değişkenlerinde veya gizli anahtarlardaMindeeAPI anahtarı referanslarının kalmadığını kontrol edin
IronOCR'a Geçişin Ana Faydaları
Finansal Belgeler Üzerinde Tam Veri Egemenliği. Geçiş sonrası, satıcı IBAN kodları, yönlendirme numaraları, müşteri EIN'leri ve madde madde liste öğeleri altyapınızı terk etmez. Uyumluluk kapsamı yalnızca kuruluşunuzu kapsar. Üçüncü taraf AI satıcılarıyla yapılan işlemci anlaşmaları denetim izi listenizden kaldırılır. GLBA, CMMC, FedRAMP veya veri konumlandırma gereksinimleri altında çalışan ekipler, harici bulut iletimini gerektiren uyumluluk incelemesine gerek kalmadan finansal belgeleri işleyebilirler.
Hacimden Bağımsız Tahmin Edilebilir Maliyet. $999'daki IronOCR Lite lisansı, belgelerin sınırsız işlenmesi ile tek bir geliştiriciyi kapsar. Aylık 500 fatura işlem hacminden 50.000'e ölçekleme, ek bir maliyet getirmez. Yıl sonu işlem artışları, yığın hata düzeltme çalışmaları ve geliştirme test döngüleri, herhangi bir fatura sayacı artırımı oluşturmaz. Aylık 5.000 sayfa işleyen bir takımın üç yıllık toplam sahiplik maliyeti, yaklaşık $17,964 (Mindee Pro) - $1,499–$2,999 (IronOCR süresiz lisans) arasına düşer. Katman detayları için tam IronOCR ürün sayfasını görüntüleyin.
Kalıcı Olarak Sahip Olunan Çıkarma Mantığı.IronOCR çıkarma desenleri, depo içerisindeki basit C# kodlarıdır. Bunlar, herhangi bir dış satıcı yayına programından veya API versiyonlama kararlarından bağımsız olarak sürüm kontrolü yapılabilir, incelenebilir, test edilebilir ve dağıtılabilir. Mindee, InvoiceV5 yayınladığında ve InvoiceV4 devre dışı bıraktığında, bu, satıcı tarafından uygulanan bir geçiş son tarihtir. Çıkarım kalıplarını sürdürdüğünüzde, iyileştirme bir git commit'dir.
Gerçek Dünyadaki Tarama Kalitesi İçin Ön İşlem Kontrolü. Borç hesapları operasyonları, her biri farklı ayarlarda farklı ekipmanlarla taranan onlarca veya yüzlerce satıcıdan faturalar alır. IronOCR'nin ön işleme hattı — Deskew(), DeNoise(), Contrast(), Sharpen(), Binarize() — her tarama kategorisindeki belirli kusurları ele alır. Termal makbuz fotoğrafı, düz yataklı taranan çok sayfalı fatura ile farklı kusurlara sahiptir; her yol için uygun filtreleri uygulayabilirsiniz. Mindee'nin ön işleme süreci görünmez ve yapılandırılamaz. Tam filtre kataloğunu görüntülemek için ön işleme özellikleri sayfasına bakın.
Tek Adımda Aranabilir PDF Arşivleme.IronOCR yoluyla işlenen her fatura, result.SaveAsSearchablePdf() ile aranabilir bir PDF olarak arşivlenebilir. Tanınan metin katmanı, çıktı dosyasına gömülüdür ve bu sayede belge yönetim sistemleri, SharePoint kütüphaneleri ve kurumsal içerik depolarında her kelime tam metin aranabilir olur.Mindeehiçbir PDF çıktısı sağlamaz; aranabilir arşivleme daha önce ayrı bir kütüphane, ayrı bir işleme geçişi ve ek bakım gerektiriyordu. Geçişten sonra, çıkarım ve arşivleme tek bir _ocr.Read(input) çağrısında birleştirilir.
Mimari Değişiklik Olmadan Her Yerde Dağıtım. IronOCR, Windows, Linux, macOS, Docker, Azure App Service, AWS Lambda ve Google Cloud Run gibi ortamlarda aynı NuGet paketi ve aynı başlatmayla dağıtılır. İzole ortamlar, fabrika zemin sistemleri ve güvenli devlet tesisleri değişiklik yapmadan çalışır. Docker dağıtım kılavuzu, Azure kılavuzu ve AWS kılavuzu, her platform için ortama özgü yapılandırmayı kapsar.
Sıkça Sorulan Sorular
Mindee OCR API'dan IronOCR'ye neden geçmeliyim?
Yaygın geçiş nedenleri arasında COM ara bağlamının karmaşıklığını ortadan kaldırmak, dosya tabanlı lisans yönetimini değiştirmek, sayfa başına fatura düzenlemekten kaçınmak, Docker/kapsayıcı dağıtımını etkinleştirmek ve standart .NET araçlarıyla entegre olan bir NuGet doğal iş akışı benimsemek yer almaktadır.
Mindee OCR API'dan IronOCR'ye geçişteki ana kod değişiklikleri nelerdir?
Mindee başlangıç dizilerini IronTesseract örneği ile değiştirin, COM yaşam döngüsü yönetimini (açık Create/Load/Close desenleri) kaldırın ve sonuç özellik adlarını güncelleyin. Sonuç, önemli ölçüde daha az boilerplate satırıdır.
Geçişi başlatmak için IronOCR'u nasıl kurarım?
Paket Yöneticisi Konsolunda 'Install-Package IronOcr' veya CLI'da 'dotnet add package IronOcr' çalıştırın. Dil paketleri ayrı paketlerdir: Örneğin, Fransızca için 'dotnet add package IronOcr.Languages.French'.
IronOCR, Mindee OCR API'nin standart iş belgeleri için OCR doğruluğunu karşılıyor mu?
IronOCR, faturalar, sözleşmeler, makbuzlar ve yazılı formlar dahil olmak üzere standart işletme içerikleri için yüksek doğruluğa ulaşır. Görüntü ön işleme filtreleri (dengelemeyi düzeltme, gürültü kaldırma, kontrast artırma) bozulmuş girdiler üzerindeki tanımayı daha da iyileştirir.
IronOCR, Mindee OCR API'nin ayrı kurduğu dil verilerini nasıl yönetiyor?
IronOCR'daki dil verileri, NuGet paketleri olarak dağıtılır. 'dotnet add package IronOcr.Languages.German' komutuyla Almanca desteği yüklenir. Herhangi bir manuel dosya yerleştirme veya dizin yolu gerekmez.
Mindee OCR API'dan IronOCR'ye geçiş, dağıtım altyapısında değişiklik gerektiriyor mu?
IronOCR, Mindee OCR API'dan daha az altyapı değişikliği gerektirir. SDK ikili yolları, lisans dosyası yerleşimleri veya lisans sunucu yapılandırmaları yoktur. NuGet paketi, tam OCR motorunu içerir ve lisans anahtarı uygulama kodunda belirlenmiş bir dizgedir.
Geçişten sonra IronOCR lisanslamasını nasıl yapılandırırım?
Uygulama başlangıç kodunda IronOcr.License.LicenseKey = "SİZİN-ANAHTARINIZ" atayın. Docker veya Kubernetes'te, anahtarı bir ortam değişkeni olarak saklayın ve başlangıçta okuyun. Trafiği kabul etmeden önce doğrulamak için License.IsValidLicense kullanın.
IronOCR, PDF'leri Mindee gibi işleyebilir mi?
Evet. IronOCR hem yerel hem de taranmış PDF'leri okur. Bir PDF yolu veya OcrPdfInput olan girdiye ocr.Read(input) çağrısı yapmak için IronTesseract örneği çağırın ve OcrResult sayfalarını yineleyin. Ayrı bir PDF işleme hattı gerekmez.
IronOCR, yüksek hacim işleme sırasında iş parçacığı nasıl ele alır?
IronTesseract, iş parçacığı başına örnek olacak şekilde güvenlidir. Paralel.ForEach veya Görev havuzunda her iş parçacığı için bir örnek oluşturun, OCR'u eşzamanlı olarak çalıştırın ve her örneği iş tamamlandığında bırakın. Küresel durum veya kilitleme gerekmez.
IronOCR metin çıktıktan sonra hangi çıktıları destekler?
IronOCR, metin, kelime koordinatları, güven skorları ve sayfa yapısını içeren yapılandırılmış sonuçlar döndürür. Dışa aktarma seçenekleri düz metin, aranabilir PDF ve aşağı akış işlemesi için yapılandırılmış sonuç nesneleri içerir.
IronOCR'ın fiyatlandırması, ölçeklendirme iş yükleri için Mindee OCR API'dan daha öngörülebilir mi?
IronOCR, sayfa başına veya hacim ücretlendirmesi olmadan düz oranlı sürekli lisanslama kullanır. 10.000 veya 10 milyon sayfa işleseniz de lisans maliyeti sabit kalır. Hacim ve ekip lisanslama seçenekleri IronOCR fiyatlandırma sayfasındadır.
Mindee OCR API'dan IronOCR'ye geçtikten sonra mevcut testlerime ne olacak?
Çıkarılmış metin içeriğini doğrulayan testler, geçişten sonra çalışmaya devam etmelidir. API çağrı şablonlarını veya COM nesne yaşam döngüsünü doğrulayan testler, IronOCR'un daha basit başlatma ve sonuç modelini yansıtacak şekilde güncellenmelidir.

