IRONSOFTWAREHOME
동영상

Veryfi에서 IronOCR로 마이그레이션하기

칸나오팟 우돈판트
Kannapat Udonpant
Updated: 2026년 8월 1일

이 가이드는 .NET 개발자가 Veryfi의 클라우드 문서 처리 API를 로컬 OCR 라이브러리인 IronOCR로 대체하는 과정을 안내합니다. 이 문서는 패키지 교체, 네임스페이스 정리, 그리고 Veryfi를 중심으로 가장 흔히 구축되는 패턴에 초점을 맞춘 네 가지 완전한 코드 마이그레이션 예제(클라이언트 초기화, 영역 기반 필드 추출, 구조화된 데이터를 활용한 비용 분류, 웹훅 교체)를 다룹니다. 비교 기사를 미리 읽을 필요는 없습니다.

Veryfi에서 마이그레이션해야 하는 이유

재무 문서는 Veryfi의 파이프라인을 통해 단방향으로 전송됩니다. 즉, 귀사의 인프라에서 Veryfi의 인프라로 전송됩니다. 이러한 아키텍처적 사실이 대부분의 마이그레이션을 주도합니다. 다음은 팀들이 전환을 결정하게 만드는 구체적인 문제점들입니다.

모든 문서 호출 시 민감한 금융 데이터가 제3자 서버로 전송됩니다. 영수증에는 카드 번호의 마지막 4자리와 가맹점 정보가 포함됩니다. 송장에는 은행 계좌 번호, 라우팅 번호 및 공급업체 세금 식별 번호가 기재되어 있습니다. 은행 거래 내역서에는 전체 거래 내역이 포함되어 있습니다. Veryfi와 함께, 모든 ProcessDocumentAsync 호출은 이 바이트를 api.veryfi.com에 업로드하고, Veryfi의 인프라에서 처리하여 JSON을 반환합니다. HTTP 요청이 전송되는 순간, 해당 데이터에 대한 귀하의 통제권은 종료됩니다.

네 가지 자격 증명이 필요하며 모든 환경에서 동기화되어야 합니다. VeryfiClientclientId, clientSecret, username, 그리고 apiKey이 필요합니다. 이 네 가지 별개의 비밀을 설정에 저장하고, 일정에 따라 회전시키며, CI/CD 파이프라인에 주입하고, 노출 여부를 감사합니다. 단 하나의 인증 정보 유출만으로도 애플리케이션 전체에서 처리되는 모든 문서의 인증이 무효화됩니다. IronOCR에는 하나의 라이선스 키 문자열이 필요합니다.

문서당 요금은 상한선 없이 누적됩니다. 영수증은 건당 약 $0.05–$0.15, 청구서는 $0.10–$0.25, 은행 거래 내역서는 $0.15–$0.30입니다. 월 50,000건의 문서를 기준으로 할 때, 이는 월 $5,000–$15,000의 계량 요금이며, 2년차나 3년차에도 요금이 인하되지 않습니다. 2,999달러의IronOCR Professional License는 영구적으로 무제한 문서를 지원하며, 월 5,000달러의 베리피 사용 비용 대비 투자 회수 기간은 3주 미만입니다.

API는 비동기 전용입니다. 기본 작업이 원격에 있기 때문에 그렇습니다. ProcessDocumentAsync는 처리 시간이 길기 때문에 비동기가 아닙니다; 문서가 서버로 전송되고, 다른 요청들 뒤에 대기열에 들어가며, 추론을 완료하고, 네트워크를 통해 응답을 반환해야 하기 때문에 비동기(async) 방식입니다. 지연 시간은 비결정적입니다. HTTP 429 속도 제한에는 재시도 로직이 필요합니다. HTTP 402 결제 실패는 일괄 처리를 완전히 중단시킵니다. 베리피 인프라에서 발생하는 HTTP 500 오류는 워크플로우까지 마비시킵니다.

Veryfi의 문서 처리 범위는 비용 문서 경계에서 종료됩니다. 훈련된 모델은 영수증, 청구서, 수표, 은행 명세서, W-2 양식 및 명함에 대해 구조화된 필드를 안정적으로 반환합니다. 이 목록에 포함되지 않은 일반 비즈니스 문서, 계약서, 의료 기록, 운송 서류, 맞춤형 내부 양서 등의 경우, 번역 품질이 저하되거나 유료 맞춤형 모델 훈련이 필요합니다. 경비 자동화를 위해 Veryfi를 도입한 조직들은 대개 6~12개월 이내에, Veryfi가 처리하도록 설계되지 않은 문서에 대해 다른 팀들이 OCR 기능을 필요로 한다는 사실을 알게 됩니다.

Veryfi의 독점적 JSON 스키마는 모든 추출 논리를 단일 공급 업체에 연결합니다. response.Vendor?.Name, response.BankAccount?.RoutingNumber, 또는 response.LineItems를 읽는 모든 코드 줄은 Veryfi에서만 작동할 수 있는 코드입니다. 공급업체를 변경하거나 로컬 OCR로 전환하는 것은 모든 추출 로직을 처음부터 다시 작성해야 함을 의미합니다.

근본적인 문제

// 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 베리피 cloud
C#
// 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;
C#

##IronOCR대 Veryfi: 기능 비교

아래 표는 기술적 평가를 지원하기 위해 두 제품의 기능을 비교한 것입니다.

기능베리피IronOCR
처리 위치베리피 클라우드 서버귀사의 인프라
배포 모델클라우드 API 전용온프레미스, Docker, Azure, AWS, Linux
오프라인 지원아니요
인터넷 연결 필요예 (모든 문서)아니요
데이터가 인프라를 떠납니다예 (모든 통화)절대
BAA 없이도 HIPAA 준수아니요
에어갭(Air-gapped) 환경 지원불가능완전히 지원
가격 모델문서당 (0.05달러~0.30달러)영구 라이선스 ($999–$2,399)
필수 자격 요건4 (클라이언트 ID, 클라이언트 시크릿, 사용자 이름, API 키)라이선스 키 1개
동기식 API아니요 (비동기 전용)
속도 제한예 (HTTP 429)None
문서 범위영수증, 청구서, 수표, 은행 거래 내역서, W-2 양식, 명함모든 문서 유형
사용자 정의 문서 유형유료 모델 훈련 필요정규 표현식/패턴 추출을 통한 모든 레이아웃
PDF 입력예 (바이트 업로드)예 (토착민, 현지인)
검색 가능한 PDF 출력아니요예 (result.SaveAsSearchablePdf())
영역 기반 OCR아니요예 (CropRectangle)
바코드 판독아니요예 (동일한 OCR 처리)
구조화된 결과 액세스사전 파싱된 JSON 필드페이지, 단락, 줄, 단어와 좌표
자신감 점수필드별 (독점)단어별 및 전체 (result.Confidence)
125개 이상의 언어 지원제한적예 (NuGet 언어 팩)
스레드 안전 병렬 처리HTTP 동시 접속 제한이 적용됩니다전체 (스레드당 한 IronTesseract)
모크 없이 단위 테스트 수행하기HTTP 모킹 기능 필요현지 직접 검사

빠른 시작: Veryfi에서 IronOCR로의 마이그레이션

1단계: NuGet 패키지 교체

Veryfi SDK 제거:

dotnet remove package Veryfi
SHELL

NuGet 에서IronOCR설치하세요.

dotnet add package IronOcr

단계 2: 네임스페이스 업데이트

Veryfi 네임스페이스를IronOCR네임스페이스로 대체하십시오:

// Before (Veryfi)
using Veryfi;
using Veryfi.Models;

// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
C#

단계 3: 라이선스 초기화

응용 프로그램 시작 시, OCR 호출 전에 다음 줄을 한 번 추가하십시오:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

코드 마이그레이션 예제

문서 처리 클라이언트 교체

Veryfi 서비스는 VeryfiClient의 생성자 주입을 중심으로 구축됩니다. 4개의 자격 증명 생성자는 의존성 주입을 위한 자연스러운 접점이지만, 관리 및 순환이 필요한 4개의 비밀 정보를 생성하게 됩니다. 이를 IronOCR로 대체하면 자격 증명을 단일 라이선스 키로 통합하고, 처리 엔진의 인스턴스화를 서비스 클래스 자체로 이동시킵니다.

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 베리피 on this call
        var response = await _client.ProcessDocumentAsync(bytes);
        return response.Vendor?.Name;
    }

    public async Task<decimal?> GetTotalAsync(string documentPath)
    {
        var bytes = File.ReadAllBytes(documentPath);
        var response = await _client.ProcessDocumentAsync(bytes);
        return response.Total;
    }
}
C#

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;
    }
}
C#

생성자 변경은 모든 환경에서 네 가지 구성 항목을 제거합니다: appsettings.json, Docker 비밀, Azure Key Vault 참조, 그리고 CI/CD 파이프라인 변수. IronTesseract 인스턴스는 동일한 스레드에서 여러 번 호출 가능하도록 재사용 가능합니다. .NET Core 의존성 주입 컨테이너에서의 싱글톤 등록 패턴에 대해서는 IronTesseract 설정 가이드를 참조하십시오.

지역 기반 OCR을 활용한 영수증 필드 추출

Veryfi는 훈련된 ML 모델을 문서 이미지 전체에 적용하여 영수증 필드를 추출하고, 미리 구조화된 JSON 응답을 반환합니다. IronOCR의 동등한 것은 CropRectangle를 사용한 지역 기반 OCR로, 영수증 이미지의 특정 구역—공급 업체를 위한 헤더 구역, 총계를 위한 푸터 구역—을 목표로 하여 전체 페이지를 탐색하고 출력에서 패턴을 검색하지 않습니다. 이는 레이아웃이 알려진 경우 더 빠르며, 관심 영역이 명확하게 정의된 경우 더 정확합니다.

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
        );
    }
}
C#

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
        );
    }
}
C#

CropRectangle는 픽셀로 (x, y, width, height)를 가져옵니다. 헤더와 푸터 영역만 처리하는 것이 전체 페이지를 읽는 것보다 빠르며, 영수증 본문의 항목별 금액으로 인한 오인식을 방지할 수 있습니다. 영역 기반 OCR 가이드에서는 크기가 다양한 문서에 대한 좌표 측정 전략을 다루며, 영역 자르기 예제에서는 전체 패턴을 보여줍니다.

구조화된 단락 데이터를 활용한 비용 분류

Veryfi는 이미 구문 분석된 객체의 response.LineItems를 사전 구조화된 배열로 반환합니다: Description, Quantity, UnitPrice, 그리고 Total. IronOCR는 result.Pages[0].Paragraphsresult.Lines를 통해 각 텍스트 블록을 그 X/Y 좌표로 노출하여 동등한 기능을 제공합니다. 경비 분류 논리(즉, 특정 항목이 식사비, 출장비, 소모품비, 소프트웨어 비용 중 어느 것에 해당하는지 판단하는 과정)는 어느 쪽이든 동일한 텍스트를 기반으로 작동합니다. 차이점은 IronOCR을 사용하면 유료 ML 재훈련 과정 없이도 분류 로직을 직접 소유하고, 조정하며, 확장할 수 있다는 점입니다.

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;
    }
}
C#

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;
    }
}
C#

Paragraphs 컬렉션은 각 텍스트 블록의 Y 좌표를 제공하여 표준 영수증 레이아웃에서 라인 항목이 나타나는 수직 영역을 쉽게 구분할 수 있게 합니다. 구조화된 데이터 접근 가이드Pages, Paragraphs, Lines, Words, Characters의 전체 계층과 그 좌표 속성을 설명합니다. 종이 구김이나 대비가 낮은 열전사 인쇄 등으로 인해 스캔 품질이 낮은 영수증의 경우, 이미지 품질 보정 가이드에서는 분류 로직이 실행되기 전에 정확도를 높여주는 전처리 필터에 대해 다룹니다.

웹훅 제거 및 동기식 배치 대체

문서 양이 많은 경우, Veryfi는 폴링 방식보다 웹훅 기반 알림 방식을 권장합니다. 이 패턴을 구현하려면 공개적으로 접근 가능한 HTTPS 엔드포인트, 서명 검증을 위한 웹훅 시크릿, 웹훅이 발동될 때까지 결과를 보관할 큐, 그리고 전달 실패 시 재시도 로직이 필요합니다. 이는 클라우드 OCR이 로컬 처리 대비 속도가 느리다는 점을 궁극적으로 우회하기 위한 중요한 인프라입니다. IronOCR은 동기식으로 처리됩니다. 웹훅을 사용하면 비동기 처리의 간극을 메울 필요가 없습니다.

Veryfi의 접근 방식:

using Veryfi;
using Microsoft.AspNetCore.Mvc;

// 베리피 webhook receiver — required for high-volume reliable processing
[ApiController]
[Route("webhooks")]
public class VeryfiWebhookController : ControllerBase
{
    private readonly IDocumentResultQueue _queue;

    public VeryfiWebhookController(IDocumentResultQueue queue)
    {
        _queue = queue;
    }

    [HttpPost("veryfi")]
    public IActionResult ReceiveWebhook([FromBody] VeryfiWebhookPayload payload,
                                        [FromHeader(Name = "X-Veryfi-Token")] string token)
    {
        // Validate webhook signature — prevents spoofed payloads
        if (!IsValidSignature(token, payload))
            return Unauthorized();

        // Enqueue result for async downstream consumption
        _queue.Enqueue(new DocumentResult
        {
            DocumentId = payload.Id,
            Vendor     = payload.Data?.Vendor?.Name,
            Total      = payload.Data?.Total
        });

        return Ok();
    }

    private bool IsValidSignature(string token, VeryfiWebhookPayload payload) =>
        // HMAC validation against webhook secret — infrastructure requirement
        token == ComputeHmac(payload, Environment.GetEnvironmentVariable("VERYFI_WEBHOOK_SECRET"));
}

// Document batch submission — fire and forget, results arrive via webhook
public class VeryfiDocumentBatchSubmitter
{
    private readonly VeryfiClient _client;

    public async Task SubmitBatchAsync(string[] documentPaths)
    {
        foreach (var path in documentPaths)
        {
            var bytes = File.ReadAllBytes(path);
            // Submit — result arrives asynchronously via webhook, not here
            await _client.ProcessDocumentAsync(bytes);
        }
    }
}
C#

IronOCR 접근 방식:

using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;

// 아니요 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; }
}
C#

웹훅 계층을 제거하면 HTTPS 엔드포인트, 웹훅 시크릿 순환 요구 사항, 결과 큐, HMAC 유효성 검사 로직 및 재시도 구성이 제거됩니다. Veryfi의 결과가 원격 서버에서 비동기적으로 전송되기 때문에, 전체 하류 파이프라인이 존재합니다. IronOCR와 함께, Parallel.ForEach가 모든 것을 대체합니다. 멀티 스레딩 예제는 스레드당 IronTesseract 패턴을 자세히 설명하며, 비동기 OCR 가이드는 UI 응답성을 위한 Task.Run 통합을 다룹니다. 이 속도 최적화 가이드는 배치 워크로드에서 최대 처리량을 달성하기 위한 인스턴스 구성을 다룹니다.

베리피 API와IronOCR매핑 참조

베리피IronOCR에 상응하는
new VeryfiClient(clientId, clientSecret, username, apiKey)new IronTesseract() + IronOcr.License.LicenseKey = "key"
_client.ProcessDocumentAsync(bytes)ocr.Read(filePath) 또는 ocr.Read(ocrInput)
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" })input.LoadPdf(경로); ocr.Read(input)
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" })input.LoadPdf(경로); ocr.Read(input)
response.Vendor?.Name첫 번째 단락은 p.Y에서 result.Pages[0].Paragraphs로 정렬됩니다
response.TotalRegex.Match(result.Text, @"Total:?\s*\$?([\d,]+\.\d{2})")
response.TaxRegex.Match(result.Text, @"Tax:?\s*\$?([\d,]+\.\d{2})")
response.DateRegex.Match(result.Text, @"\d{1,2}/\d{1,2}/\d{4}")
response.LineItemsresult.Pages[0].Paragraphs는 Y 좌표 범위에 따라 필터링됩니다
response.InvoiceNumberRegex.Match(result.Text, @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)")
response.BankAccount?.AccountNumberRegex.Match(result.Text, @"Account\s*#?\s*:?\s*(\d{4,})")
response.BankAccount?.RoutingNumberRegex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})")
response.ConfidenceScoreresult.Confidence (전체) 또는 word.Confidence (단어별)
response.Payment?.Last4Regex.Match(result.Text, @"\*{4}\s*(\d{4})")
VeryfiApiException (401/402/429/500).NET Standard 예외 — 로컬 처리 시 HTTP 오류 코드 없음
업로드 전 Base64 인코딩필요하지 않음 — ocr.Read(filePath)은 파일 경로를 직접 허용합니다
response.Categoryresult.Text에 대한 사용자 정의 키워드 매칭
웹훅 페이로드 역직렬화필요하지 않음 — ocr.Read()이 결과를 동기적으로 반환합니다
ProcessDocumentAsync은 재시도/백오프 기능이 포함되어 있습니다필수 사항 아님 — 로컬 처리 시 속도 제한 없음

일반적인 마이그레이션 문제와 해결책

문제 1: 사전 파싱된 필드 누락

Veryfi: response.Vendor?.Name, response.Total, 및 response.LineItems는 사전 훈련된 ML 모델에서 구조화된 필드로 도착합니다. 클라이언트 측에서 별도의 추출 로직은 필요하지 않습니다.

해결책: 애플리케이션에서 사용하는 각 필드에 대한 정규식(Regex) 패턴을 작성하십시오. 이 마이그레이션 작업은 처리하는 고유한 문서 레이아웃의 수에 따라 일반적으로 8~24시간이 소요됩니다. 일반적인 영수증 및 청구서 양식의 경우, 청구서 OCR 튜토리얼과 영수증 스캔 튜토리얼에서 완전한 추출 패턴 구현 예시를 확인할 수 있습니다.

// Map each 베리피 field to a Regex extraction
private static readonly Dictionary<string, string> FieldPatterns = new()
{
    ["InvoiceNumber"] = @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
    ["PurchaseOrder"]  = @"(?:PO|P\.O\.|Purchase Order)\s*#?\s*:?\s*(\w+)",
    ["DueDate"]        = @"Due\s*(?:Date)?:?\s*(\d{1,2}/\d{1,2}/\d{4})",
    ["PaymentTerms"]   = @"(?:Terms|Net)\s*:?\s*(\w+\s*\d+)"
};

public string ExtractField(string text, string fieldName)
{
    if (!FieldPatterns.TryGetValue(fieldName, out var pattern))
        return null;
    var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
    return match.Success ? match.Groups[1].Value.Trim() : null;
}
C#

문제 2: 코드베이스 전반에 걸친 비동기 메서드 시그니처

Veryfi: ProcessDocumentAsync는 베리피 SDK 수준에서 비동기입니다. 팀은 일반적으로 await를 호출 스택의 모든 호출 메서드를 통해 전파하여, 서비스 클래스, 컨트롤러, 백그라운드 작업 모두가 async Task<t> 서명을 가지게 합니다.

해결책: IronOCR의 Read()는 동기식입니다. 기존 async 메서드 서명은 전환 기간 동안 Task.Run로 래핑됨으로써 보존될 수 있습니다. 이를 통해 클라우드 의존성을 제거하면서도 코드베이스 전반에 걸친 대규모 서명 변경을 피할 수 있습니다.

// 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);
    });
}
C#

문제 3: 여러 환경에 분산된 자격 증명 구성

Veryfi: 네 가지 자격 증명 (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey)은 appsettings.json, Docker Compose 파일의 환경 변수 블록, GitHub Actions 비밀, Azure Key Vault 참조 및 CI/CD 파이프라인 구성에 나타납니다.

해결책: 모든 환경에서 네 가지 자격 증명 항목을 모두 검색하여 제거하십시오. 단일 IRONOCR_LICENSE_KEY 환경 변수를 추가합니다. 시작 시 로드하십시오.

# Find all 베리피 credential references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
    --include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
SHELL
// Load from environment at startup
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
C#

문제 4: 이전에 확인되지 않았던 스캔 품질 문제

Veryfi: 클라우드 처리에는 ML 추론이 실행되기 전 서버 측 이미지 보정 작업이 포함됩니다. 주름 잡힌 종이, 색이 바랜 열전사 인쇄물, 비뚤어진 휴대폰 사진 등 품질이 낮은 영수증 스캔본은 필드 추출 전에 자동으로 보정되었습니다.

해결책: IronOCR의 전처리 파이프라인을 명시적으로 적용하십시오. Deskew(), DeNoise(), 및 Contrast()은 실세계의 영수증 스캔 품질 문제의 대부분을 커버합니다.

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);
C#

이미지 품질 보정 가이드이미지 필터 튜토리얼에서는 특정 스캔 품질 저하 패턴에 어떤 필터를 적용해야 하는지 다룹니다.

이슈 5: 대량 배치 처리 처리량

Veryfi: 속도 제한(Rate limits)은 문서 제출 속도를 조절합니다. HTTP 429 응답에는 지수적 백오프 로직이 필요합니다. 처리량은 사용자의 하드웨어가 아닌 Veryfi의 플랜별 속도 제한에 따라 결정됩니다.

해결책: IronOCR은 CPU 코어 수에만 제한을 받습니다. 하나의 IronTesseract 인스턴스를 스레드당 사용하여 Parallel.ForEach을 사용하세요. 8코어 서버에서 처리량은 코어 수에 따라 대략 선형적으로 증가합니다.

// 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);
    });
C#

이슈 6: Veryfi에 고정된 독점 JSON 스키마

Veryfi: 모든 추출 코드는 Veryfi의 응답 스키마에서 읽습니다: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. 이 코드는 Veryfi의 SDK에서만 작동합니다. 베리피 API 업데이트 시 필드 이름이 변경되면 애플리케이션 코드가 작동하지 않게 됩니다.

**해결책:**IronOCR추출은 평문에 대해 표준 .NET System.Text.RegularExpressions.Regex를 사용합니다. 이 패턴들은 이식성이 뛰어나며, SDK를 모의(mocking)하지 않고도 테스트할 수 있고, 사용자가 직접 제어할 수 있습니다. 단위 테스트는 네트워크 연결 없이 실행됩니다.

// 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);
}
C#

베리피 마이그레이션 체크리스트

사전 마이그레이션

코드를 수정하기 전에 코드베이스를 검토하여 베리피 사용 내역을 모두 파악하십시오:

# Find all 베리피 using statements
grep -rn "using Veryfi" --include="*.cs" .

# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .

# Find all 베리피 response field accesses
grep -rn "response\.Vendor\|response\.Total\|response\.LineItems\|response\.BankAccount" --include="*.cs" .

# Find all credential configuration references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
    --include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .

# Find all webhook-related code
grep -rn "VeryfiWebhook\|X-Veryfi-Token\|webhook" --include="*.cs" .
SHELL

ProcessDocumentAsync 호출 사이트 수, 호출 사이트당 접근된 응답 필드 목록 및 베리피 자격 증명이 포함된 환경 목록을 기록합니다.

코드 마이그레이션

  1. 모든 솔루션의 프로젝트에서 Veryfi NuGet 패키지를 제거합니다.
  2. 이전에 Veryfi를 참조한 모든 프로젝트에 IronOcr NuGet 패키지를 설치합니다.
  3. 모든 OCR 호출 전 애플리케이션 시작 부분에 IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";를 추가합니다.
  4. 모든 using Veryfi;using Veryfi.Models; 문을 using IronOcr;으로 교체합니다.
  5. 모든 VeryfiClient 생성자 주입을 IronTesseract 필드 초기화로 대체합니다.
  6. 모든 appsettings.json, appsettings.*.json, 및 비밀 설정 파일에서 네 가지 베리피 자격 증명 항목을 제거합니다.
  7. ProcessDocumentAsync(bytes) 호출을 ocr.Read(filePath) 또는 ocr.Read(ocrInput)로 변환합니다.
  8. response.Vendor?.Name 접근을 result.Pages[0].Paragraphs에서 단락 정렬된 텍스트 추출로 교체합니다.
  9. response.Total, response.Tax, response.InvoiceNumber, 그리고 다른 구조화된 필드 접근을 result.Text에 대해 정규 표현식 패턴으로 교체합니다.
  10. response.LineItems 반복을 Y-좌표 필터링된 result.Pages[0].Paragraphs 반복으로 교체합니다.
  11. 웹훅 컨트롤러 클래스를 삭제하고 웹훅 엔드포인트 등록을 제거하십시오.
  12. 모든 환경에서 웹훅 시크릿 환경 변수를 제거하십시오.
  13. 스캔된 이미지 입력을 위한 전처리 (Deskew(), DeNoise(), Contrast())와 함께 OcrInput를 추가합니다.
  14. 단일 스레드 순차 루프를 Parallel.ForEach로 교체하며, 스레드 당 하나의 IronTesseract를 사용합니다.
  15. 모든 환경 변수 구성 및 CI/CD 비밀 저장소에 IRONOCR_LICENSE_KEY을 추가합니다.

마이그레이션 이후

  • 마이그레이션 배포 후 HTTP 트래픽 로그에 베리피 네트워크 호출이 나타나지 않는지 확인하십시오.
  • 20~50개의 영수증 샘플 세트에서 추출된 공급업체 이름이 예상 값과 일치하는지 확인하십시오.
  • 동일한 샘플 세트에 대해 추출된 합계가 예상값과 0.01달러 이내의 오차 범위 내에 있는지 확인하십시오.
  • 문서 코퍼스 내의 각 청구서 형식에서 청구서 번호 추출이 성공적으로 이루어지는지 확인하십시오.
  • Veryfi의 기준 처리량과 비교하여 일괄 처리 처리량을 테스트하여 속도 제한이 해제되었는지 확인하십시오.
  • 네트워크 연결 없이 전체 테스트 Suite를 실행하여 클라우드 의존성이 전혀 없음을 확인하십시오.
  • result.Confidence 점수가 깨끗한 문서 스캔에서 80% 이상인지 확인하세요; 80% 미만인 경우 전처리 단계를 추가해야 함을 나타냅니다.
  • 모든 환경(개발, 스테이징, 프로덕션)에서 네 가지 베리피 자격 증명이 모두 제거되었는지 확인하십시오.
  • 웹훅 엔드포인트가 404를 반환하는지, 또는 라우팅 테이블에서 제거되었는지 확인하십시오.
  • 전처리 파이프라인이 활성화된 상태에서 품질이 낮은 영수증 스캔본(구겨지거나, 색이 바래거나, 비뚤어진)에 대한 동작을 테스트합니다.

##IronOCR로 마이그레이션할 때의 주요 이점

로컬에서 처리되는 금융 문서는 제3자에게 유출될 우려가 없는 문서입니다. 마이그레이션 후에는 송장에서 추출된 은행 계좌 번호, 수표에서 파싱된 라우팅 번호, 그리고 은행 명세서에서 읽은 거래 내역이 모두 사용자의 하드웨어에서 처리됩니다. 서버를 벗어나지 않은 문서는 제3자의 보안 사고, 하청업체의 데이터 접근, 또는 베리피 인프라 침해로 인해 노출될 수 없습니다.

마이그레이션이 배포되는 날부터 문서당 비용은 0으로 떨어집니다. 월 50,000건의 문서를 처리할 경우, 월 5,000~15,000달러에 달하던 베리피 항목이 사라집니다. 2,999달러에 판매되는IronOCR Professional License 비용은 첫 달 첫 주 내에 회수됩니다. 대량 주문 시, 볼륨 할인 협상이나 계약 갱신 없이도 매년 절약 효과가 누적됩니다.

처리 처리량은 공급업체의 속도 제한이 아닌 하드웨어에 따라 확장됩니다. HTTP 429 응답, 플랜별 처리량 제한, 계절별 초과 사용 요금은 클라우드 API의 구조적 산물입니다. IronOCR을 사용하면 CPU 코어를 추가할수록 처리량이 비례하여 증가합니다. 10,000건의 영수증 처리는 Veryfi의 속도 제한 일정이 아닌 귀하의 일정에 따라 처리됩니다.

동일한 API를 통해 모든 문서 유형을 처리합니다. 인사팀에서 신입 사원 입사 서류 처리를 요청하거나, 법무팀에서 계약서 내용 추출이 필요하거나, 운영팀에서 배송 문서 데이터가 필요할 때, 조직은 더 이상 별도의 OCR 도구를 사용할 필요가 없습니다. ocr.Read()가 그 모두를 처리합니다. 이미지 내 텍스트 읽기 튜토리얼전문 문서 가이드에서는 IronOCR이 처리하는 모든 문서 형식을 다룹니다.

추출 로직은 코드베이스의 핵심 구성 요소가 됩니다. 정규식 패턴은 소스 제어에 포함되어 있으며, 풀 리퀘스트에서 검토할 수 있고, SDK를 모의 객체화하지 않고도 단위 테스트에서 검증할 수 있으며, 운영 환경의 피드백에 따라 조정할 수 있습니다. Veryfi의 사전 학습된 모델이 잘못된 공급업체 이름을 반환할 경우, 조정할 사항이 없습니다. IronOCR의 추출 패턴이 잘못된 공급업체 이름을 반환할 경우, 수정 방법은 단위 테스트를 동반한 한 줄의 정규식 변경입니다. IronOCR 라이선스 페이지에는 영구 구매보다 연간 결제를 선호하는 팀을 위한 SaaS 구독 경로를 포함한 티어 옵션이 설명되어 있습니다.

배포 규모는 어디서나 실행 가능한 단일 NuGet 패키지로 축소됩니다. IronOCR은 외부 종속성, 네이티브 바이너리 관리, tessdata 폴더 구성이 필요 없는 단일 패키지로 설치됩니다. 동일한 패키지 참조는 플랫폼별 조건부 코드 없이 Windows, Linux, macOS, Docker, Azure App Service 및 AWS Lambda에서 모두 정상적으로 작동합니다. Veryfi의 네트워크 아웃바운드 요구 사항이 배포의 걸림돌이 되는 컨테이너화된 환경에 대해서는 Docker 배포 가이드와 Linux 배포 가이드를 참조하십시오.

참고해 주세요: Tesseract와 Veryfi는 각 소유자의 등록상표입니다. 이 사이트는 Google 또는 Veryfi와 관련이 없으며, 승인또는 후원을 받지 않았습니다. 모든 제품명, 로고 및 브랜드는 해당 소유자의 자산입니다. 비교는 정보 제공 목적으로만 사용되며, 작성 시점에 공개적으로 이용 가능한 정보를 반영합니다.

관련 기사

Key in blue circle

무료 30일 체험 키를 즉시 받으세요.

Your trial license will be sent to your email address

제한 없음. 100% 무제한 이용. 신용카드 불필요.

bullet_checked신용카드나 계정 생성은 필요하지 않습니다.제한 없음. 100% 무제한 이용. 신용카드 불필요.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
부담 없는 무료 상담을 받아보세요
아래 양식을 작성하시거나 sales@ironsoftware.com으로 이메일을 보내주세요.
고객님의 정보는 항상 비밀로 유지됩니다.
전 세계 수백만 엔지니어들이 신뢰하는 제품입니다.
Iron Software의 고객 로고
지금 바로 30일 무료 체험판 키를 받으세요.
신용카드나 계정 생성은 필요하지 않습니다.