IRONSOFTWAREHOME
ビデオ

VeryfiからIronOCRへの移行|IronOCR

Kannaopat Udonpant
Kannapat Udonpant
Updated: 2026年8月1日

このガイドでは、.NET開発者がVeryfiのクラウド文書処理APIを、ローカルOCRライブラリであるIronOCRに置き換える手順を解説します。 本資料では、パッケージの入れ替え、名前空間のクリーンアップ、および ベリーフィ を中心に構築される最も一般的なパターンに焦点を当てた 4 つの完全なコード移行例(クライアントの初期化、領域ベースのフィールド抽出、構造化データを用いた経費の分類、Webhook の置換)を扱っています。 比較記事を事前に読む必要はありません。

Veryfiからの移行理由

財務文書は、Veryfiのパイプラインを一方通行で流れます。つまり、お客様のインフラからVeryfiのインフラへと送られるのです。 そのアーキテクチャ上の事実が、ほとんどの移行の原動力となっています。 以下は、チームが移行を決断する具体的な課題です。

**ドキュメントの呼び出しが行われるたびに、機密性の高い財務データがサードパーティのサーバーに送信されます。**領収書には、カードの末尾4桁および取引先情報が含まれています。 請求書には、銀行口座番号、銀行コード、およびベンダーの納税者番号が記載されています。 銀行取引明細書には、取引履歴がすべて記載されています。 Veryfiでは、すべてのapi.veryfi.comにアップロードされ、Veryfiのインフラで処理され、JSONが返されます。 そのデータに対する制御権は、HTTPリクエストが送信された瞬間に失われます。

4つの資格情報が必要であり、すべての環境で同期が必要です。 apiKeyを必要とします。これらは、設定に保存し、スケジュールで更新し、CI/CDパイプラインに挿入し、漏洩を監査するための4つの別々の秘密です。 たった1件の認証情報の漏洩により、アプリケーション全体で処理されるすべてのドキュメントの認証が破綻します。 IronOCRには、1つのライセンスキー文字列が必要です。

**文書ごとの料金は上限なく累積します。**領収書は1通あたり約0.05~0.15ドル、請求書は0.10~0.25ドル、銀行取引明細書は0.15~0.30ドルです。月間50,000通の場合、従量課金制では月額5,000~15,000ドルとなり、2年目や3年目になっても料金は減額されません。 IronOCR Professionalライセンス(2,999ドル)は、無制限のドキュメントを永久に利用可能です。Veryfiの月額5,000ドルの利用料に対する元は3週間未満で回収できます。

APIは非同期専用です。なぜなら、基礎となる作業がリモートで行われるためです。しかし、ProcessDocumentAsyncは処理が長時間かかるため非同期ではありません。 これは非同期処理である。なぜなら、ドキュメントはサーバーへ送信され、他のリクエストの後ろにキューに入れられ、推論を完了し、ネットワーク経由でレスポンスを返す必要があるからだ。 レイテンシは非決定論的です。 HTTP 429(レート制限)にはリトライロジックが必要です。 HTTP 402 支払いエラーが発生すると、バッチ処理が完全に停止します。 VeryfiのインフラでHTTP 500エラーが発生すると、ワークフローも同時に停止してしまいます。

**Veryfiのドキュメント対象範囲は、経費精算書類の境界で終了します。**学習済みのモデルは、領収書、請求書、小切手、銀行取引明細書、W-2フォーム、名刺について、構造化されたフィールドを確実に返します。 このリスト以外のもの(一般的なビジネス文書、契約書、医療記録、出荷書類、カスタム社内フォームなど)については、翻訳品質が低下するか、有料のカスタムモデルトレーニングが必要となります。 経費管理の自動化にVeryfiを導入した組織は、通常6~12ヶ月以内に、Veryfiが対応していない種類の文書に対して他のチームがOCRを必要としていることに気づきます。

Veryfiの独自のJSONスキーマは、すべての抽出ロジックを1つのベンダーに結びつけます。 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
処理場所Veryfiクラウドサーバーインフラストラクチャ
展開モデルクラウドAPIのみオンプレミス、Docker、Azure、AWS、Linux
オフラインサポートなしはい
インターネット接続が必要ですはい(すべての文書)なし
データはインフラストラクチャを離れるはい(すべての通話で)一度もない
BAAなしのHIPAA準拠なしはい
エアギャップ環境のサポート不可完全サポート
価格設定モデル文書1件あたり(0.05ドル~0.30ドル)永続ライセンス ($999–$2,399)
必要な資格4 (clientId、clientSecret、username、apiKey)ライセンスキー1つ
同期APIいいえ(非同期のみ)はい
律速段階はい (HTTP 429)None
文書の範囲領収書、請求書、小切手、銀行取引明細書、W-2フォーム、名刺あらゆる文書タイプ
カスタムドキュメントタイプ有償モデルトレーニングが必要正規表現やパターン抽出によるレイアウト
PDF入力はい(バイト単位のアップロード)はい(ネイティブ、地元)
検索可能なPDF出力なしはい (result.SaveAsSearchablePdf())
地域ベースのOCRなしはい (CropRectangle)
バーコード読み取りなしはい(同じOCR処理)
構造化された結果へのアクセス事前解析済みのJSONフィールド座標付きのページ、段落、行、単語
信頼度スコアフィールド単位(独自仕様)単語ごとおよび全体として (result.Confidence)
125以上の言語に対応制限的はい(NuGet言語パック)
スレッドセーフな並列処理HTTPの同時接続数制限が適用されますフル (スレッドごとに1つの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呼び出しの前に、以下の行を1回追加してください:

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#

このコンストラクタの変更により、すべての環境から4つの設定記入が取り除かれます: appsettings.json、Dockerの秘密情報、Azure Key Vaultの参照、およびCI/CDパイプラインの変数。 同じスレッド上の複数の呼び出しに対し、IronTesseractインスタンスを再利用できます。 .NET Coreの依存性注入コンテナにおけるシングルトン登録パターンについては、IronTesseractのセットアップガイドを参照してください。

領域ベースのOCRによる領収書フィールドの抽出

Veryfiは、学習済みの機械学習モデルをドキュメント画像全体に適用し、事前に構造化された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#

(x, y, width, height)を受け取ります。 ヘッダーとフッター領域のみを処理する方が、ページ全体を読み込むよりも高速であり、領収書本文の明細金額による誤検出を防ぐことができます。 領域ベースのOCRガイドでは、可変サイズのドキュメントに対する座標測定戦略について解説しており、領域切り抜き例ではその全容を示しています。

構造化された段落データを用いた経費の分類

VeryfiはTotalを含む、事前に構造化されたオブジェクトの配列として返します。 IronOCRは、各テキストブロックをそのX/Y座標と共に公開するresult.Linesを通じて同等の機能を提供します。 経費の分類ロジック(個々の経費項目が食事代、旅費、備品費、またはソフトウェア費用のいずれに該当するかを判断する処理)は、どちらの場合でも同じテキストに基づいて動作します。 IronOCRとの違いは、分類ロジックを自社で所有し、調整し、拡張できる点にあり、有料の機械学習再トレーニングサイクルを必要としません。

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#

Y座標を提供し、標準の領収書レイアウトでラインアイテムが現れる垂直ゾーンを簡単に分離できます。 構造化データアクセスガイドは、その座標プロパティと共にCharactersの完全な階層を説明します。 紙がよれよれになっている、熱転写印刷でコントラストが低いなど、スキャン品質の悪いレシートについては、画像品質補正ガイドで、分類ロジックが実行される前に精度を向上させる前処理フィルターについて解説しています。

Webhookの排除と同期バッチ処理への置換

ドキュメントの量が多い場合、VeryfiではポーリングよりもWebhookベースの通知を推奨します。 このパターンには、一般に公開された HTTPS エンドポイント、署名検証用の Webhook シークレット、Webhook が発火するまで結果を保持するキュー、および配信に失敗した場合の再試行ロジックが必要です。 これは、クラウドOCRがローカル処理に比べて処理速度が遅いという事実に対する、いわば回避策となる重要なインフラストラクチャです。 IronOCRは同期処理を行います。 Webhookを使用する場合、非同期処理のギャップを埋める必要はありません。

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#

Webhookレイヤーを削除することで、HTTPSエンドポイント、Webhookシークレットのローテーション要件、結果キュー、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(ocrInput)
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" })input.LoadPdf(path); ocr.Read(input)
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" })input.LoadPdf(path); ocr.Read(input)
response.Vendor?.Name最初の段落は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に対するカスタムキーワードマッチング
Webhookペイロードのデシリアライズ必要ありません — ocr.Read()は結果を同期して返します
ProcessDocumentAsyncは再試行/バックオフと共に必須ではありません — ローカル処理におけるレート制限はありません

一般的な移行の問題と解決策

課題 1: 事前解析済みフィールドの欠落

Veryfi: 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はVeryfi SDKレベルで非同期です。 チームは通常、async Task<t>シグネチャを持ちます。

ソリューション: IronOCRのRead()は同期です。 既存の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: 4つの資格情報(appsettings.json、Docker Composeファイルの環境変数ブロック、GitHub Actionsの秘密情報、Azure Key Vaultの参照、CI/CDパイプライン構成に現れます。

**解決策:**すべての環境から、4つの認証情報エントリをすべて検索して削除してください。 単一の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の前処理パイプラインを明示的に適用する。 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: レート制限により、ドキュメントの送信速度が調整されます。 HTTP 429レスポンスには、指数関数的バックオフロジックが必要です。 スループットは、お客様のハードウェアではなく、Veryfiの各プランごとのレート制限によって制限されます。

**解決策:**IronOCRのパフォーマンスはCPUコア数にのみ制限されます。 スレッドごとに1つの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: ベリーフィ にロックされた独自の JSON スキーマ

Veryfi: すべての抽出コードはVeryfiのレスポンススキーマから読み取ります: response.BankAccount?.RoutingNumber。 このコードは、VeryfiのSDKでのみ動作します。 ベリーフィ APIの更新に伴うフィールド名の変更は、アプリケーションのコードに不具合を引き起こします。

ソリューション: IronOCR抽出はプレーンテキストに対して標準 for .NET System.Text.RegularExpressions.Regexを使用します。 これらのパターンは移植性が高く、SDKをモックすることなくテスト可能であり、完全に制御可能です。 ユニットテストは、ネットワーク接続なしで実行されます。

// 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呼び出しサイトの数、各呼び出しサイトでアクセスされたレスポンスフィールドのリスト、およびVeryfi資格情報を含む環境のリストを記録します。

コードの移行

  1. ソリューション内のすべてのプロジェクトからVeryfiNuGetパッケージを削除します。
  2. 以前にIronOcrNuGetパッケージをインストールします。
  3. アプリケーションの起動時(OCRコールの前)にIronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";を追加します。
  4. すべてのusing IronOcr;に置き換えます。
  5. IronTesseractのフィールド初期化に置き換えます。
  6. すべてのappsettings.*.json、および秘密設定ファイルから4つのVeryfi資格情報エントリを削除します。
  7. ocr.Read(ocrInput)に変換します。
  8. result.Pages[0].Paragraphsからの段落順テキスト抽出に置き換えます。
  9. result.Textに対するRegexパターンに置き換えます。
  10. result.Pages[0].Paragraphsイテレーションに置き換えます。
  11. Webhook コントローラークラスを削除し、Webhook エンドポイントの登録を解除します。
  12. すべての環境から Webhook シークレット環境変数を削除してください。
  13. スキャンされた画像入力に対する前処理(OcrInputを追加します。
  14. シングルスレッドの逐次ループを、スレッドごとに1つのParallel.ForEachに置き換えます。
  15. すべての環境変数設定とCI/CD秘密ストアにIRONOCR_LICENSE_KEYを追加します。

移行後

  • 移行後のデプロイ後、HTTPトラフィックログにVeryfiネットワークへの呼び出しが一切含まれていないことを確認してください。
  • 20~50件のレシートからなるサンプルセットにおいて、抽出されたベンダー名が期待される値と一致していることを確認してください。
  • 同じサンプルセットにおいて、抽出された合計値が、許容誤差±0.01ドル以内で期待値と一致することを確認してください。
  • 文書コーパス内の各請求書フォーマットについて、請求書番号の抽出が正常に行われることを確認してください。
  • レート制限の解除を確認するため、バッチ処理のスループットをVeryfiのベースラインスループットと比較テストする。
  • ネットワーク接続なしでテストSuite全体を実行し、クラウドへの依存が一切ないことを確認します。
  • クリーンなドキュメントスキャンに対してresult.Confidenceスコアが80%を超えているか確認します。 80%未満の場合は、前処理ステップを追加する必要があります。
  • すべての環境(開発、ステージング、本番)から、4つのVeryfi認証情報がすべて削除されていることを確認してください。
  • Webhookエンドポイントが404を返すか、ルーティングテーブルから削除されていることを確認してください。
  • 前処理パイプラインを有効にした状態で、品質の低いレシートスキャン(しわくちゃ、色あせ、歪み)に対する動作をテストします。

IronOCRへの移行の主なメリット

**ローカルで処理される財務文書は、第三者による不正アクセスを防ぐことができます。**移行後は、請求書から抽出された銀行口座番号、小切手から解析されたルーティング番号、および銀行取引明細書から読み込まれた取引履歴が、すべてお客様のハードウェア上で処理されます。 サードパーティによるセキュリティインシデント、下請け業者によるデータアクセス、またはVeryfiのインフラストラクチャへの侵害があっても、お客様のサーバーから一度も外部に持ち出されていないドキュメントが漏洩することはありません。

**移行がデプロイされた日をもって、文書ごとのコストはゼロになります。**月間50,000件の文書処理において、月額5,000~15,000ドルのVeryfiの経費項目は消滅します。 2,999ドルのIronOCR Professional Licenseは、導入後最初の月の第1週で回収できます。 大量利用の場合、ボリュームディスカウントの交渉や契約更新を行うことなく、毎年節約効果が積み上がっていきます。

**処理スループットは、ベンダーのレート制限ではなく、ハードウェアに応じて拡張します。**HTTP 429レスポンス、プランレベルのスループット上限、季節的な超過料金は、クラウドAPIのアーキテクチャに起因するものです。IronOCRでは、CPUコアを追加することで、スループットが比例して向上します。 10,000件の領収書バッチは、Veryfiのレート制限スケジュールではなく、お客様のタイムラインに従って処理されます。

**あらゆる種類の文書を同一のAPIで処理できます。**人事部門が入社手続き用フォームの処理を依頼したり、法務部門が契約書のテキスト抽出を必要としたり、運用部門が配送書類のデータを必要としたりする場合でも、組織は別のOCRツールを用意する必要がなくなります。 ocr.Read()はすべてを処理します。 画像からテキストを読み取るチュートリアル専門的なドキュメントガイドでは、IronOCRが対応するあらゆるドキュメント形式について網羅的に解説しています。

**抽出ロジックは、コードベースの重要な構成要素となります。**正規表現パターンはソース管理下にあり、プルリクエストでレビュー可能で、SDKをモックすることなくユニットテストで検証でき、本番環境からのフィードバックに基づいて調整可能です。 Veryfiの事前学習済みモデルが誤ったベンダー名を返した場合、調整すべき点はありません。 IronOCRの抽出パターンが誤ったベンダー名を返した場合、修正はユニットテスト付きの1行の正規表現変更で済みます。IronOCRのライセンスページでは、永続ライセンス購入よりも年次課金を希望するチーム向けのSaaSサブスクリプションを含む、各種プランのオプションについて説明しています。

**導入に必要なリソースは、どこでも実行可能な単一の NuGet パッケージに縮小されます。**IronOCR は、外部依存関係、ネイティブバイナリの管理、tessdata フォルダーの設定を一切必要とせず、1 つのパッケージとしてインストールされます。 同じパッケージ参照は、プラットフォーム固有のコードを記述することなく、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にメールしてください。
あなたの詳細は常に守秘されます。
世界中の数百万人のエンジニアから信頼されています。
ライセンスはより安く
あなたの無料30日間の試用キーをすぐに入手。
クレジットカードやアカウントの作成は不要です。