Delphiと.NET向けのAIドキュメント抽出

· コンポーネント
Delphiと.NET向けのAIドキュメント抽出

多くの業務ソフトウェアには、今もPDFを読んで数字をフォームに手入力する担当者がいます。仕入先からの請求書、レジのレシート、受付での身分証明書のスキャンなどです。大規模言語モデルは今日そうした文書をよく読み取れますが、モデルに「請求書のデータ」を尋ねると、返ってくるのは文章か、モデルが好きな形で書いたJSONで、どの値に確信が持てなかったのかを知る手段はありません。

sgcWebSockets 2026.10は、Delphi、C++Builder、.NET向けにTsgcAIDocumentExtractorを追加します。PDFや画像を渡すと、すでにTsgcAIChatで使っているモデルに問い合わせ、スキーマに照らして検証済みのJSONを、各フィールドの信頼度付きで返します。このコンポーネントは現行のダウンロード版には含まれておらず、2026.10のリリースで登場します。

TsgcAIDocumentExtractorがAnthropic Claudeを使って実際の請求書PDFを読み取り、フィールドごとの信頼度付きで検証済みのJSONを返します。YouTubeでも公開中。

PDF入力、JSON出力

フォームにTsgcAIChatとTsgcAIDocumentExtractorを配置し、抽出コンポーネントをチャットに関連付けて、プリセットを選び、ExtractFileを呼び出します。OpenAI、Anthropic、GeminiはPDFファイルをそのまま読み取ります。DeepSeek、Grok、Mistral、Ollamaは画像しか受け付けないため、これらのプロバイダーにはページをPNGまたはJPEGとして送信します。

uses
  sgcAI, sgcAI_Chat, sgcAI_DocumentExtractor;

procedure TForm1.btnExtractClick(Sender: TObject);
begin
  oChat := TsgcAIChat.Create(Self);
  oChat.Provider := aicpAnthropic;
  oChat.ChatOptions.ApiKey := 'your-api-key';

  oExtractor := TsgcAIDocumentExtractor.Create(Self);
  oExtractor.AIChat := oChat;
  oExtractor.Preset := dpInvoice;

  Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');
end;

これが動画で示されているフローであり、実際の請求書PDFを使ってAnthropic Claudeに対しライブで検証済みです。ExtractFilesは1つの文書の複数ページを1回のリクエストで送信し、ExtractAttachmentsはすでにメモリ上にbase64として保持している文書を受け取ります。

抽出コンポーネントはTsgcAIChatを通じて処理を行い、これは独自のプロンプトでも同じ機能を使えるようになりました。ChatWithDocumentはメッセージと一緒にPDFや画像を送信し、ChatWithAttachmentsは複数を一度に送信し、ChatJSONWithAttachmentsはそれらについてJSON形式の回答を要求します。新しいTLSOptionsプロパティは、各プロバイダーで使用するOpenSSLのバージョン、IOHandler、証明書を設定します。

Memo1.Lines.Text := oChat.ChatWithDocument('Summarize this contract', 'contract.pdf');

oFiles := TsgcAIChatAttachments.Create;
try
  oFiles.AddFile('page1.png');
  oFiles.AddFile('page2.png');
  Memo1.Lines.Text := oChat.ChatJSONWithAttachments(
    'List every line item as JSON', oFiles);
finally
  oFiles.Free;
end;

プリセットと独自スキーマ

一般的な文書は3つのプリセットでカバーされます。dpInvoice、dpReceipt、dpIDCardです。それぞれがJSONスキーマと抽出指示を備えているため、他に設定することはありません。それ以外の文書では、PresetをdpCustomに設定して、スキーマを自分で記述します。

oExtractor.Preset := dpCustom;
oExtractor.SchemaName := 'purchase_order';
oExtractor.Schema.Text :=
  '{"type": "object", "additionalProperties": false,' +
  ' "required": ["order_number", "supplier", "total"],' +
  ' "properties": {' +
  '   "order_number": {"type": "string"},' +
  '   "supplier": {"type": ["string", "null"]},' +
  '   "total": {"type": "number"}}}';
oExtractor.Instructions.Text := 'Write every amount without a currency symbol.';

OpenAIではスキーマが厳格モードで送信されるため、厳格な規則に従う必要があります。すべてのオブジェクトで"additionalProperties": falseを宣言し、すべてのプロパティをrequiredに列挙し、省略可能な値には["string", "null"]のようなnull許容型を使います。組み込みのプリセットはすでにこれらの規則に従っています。いずれかのプリセットを出発点にしてフィールドを追加するには、TsgcAIDocumentExtractor.GetPresetSchema(dpInvoice)でコピーします。

検証と再試行

回答が未検証のままコードに届くことはありません。抽出コンポーネントはスキーマに照らしてローカルで検証します。型、必須プロパティ、ネストされたオブジェクトや配列、列挙型です。一致しない場合、コンポーネントは何が間違っていたかをモデルに伝え、もう一度依頼します。ValidationRetriesが再試行回数を設定し、既定値は1です。

再試行の後もデータが無効なままであれば、抽出コンポーネントは例外を発生させます。RaiseOnInvalidをFalseに設定すると、それでもデータを取得でき、LastResult.ValidationErrorsから問題を読み取れます。各行はpath: message形式です。

oExtractor.ValidationRetries := 1;
oExtractor.RaiseOnInvalid := False;

Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');
if not oExtractor.LastResult.Valid then
  Memo1.Lines.AddStrings(oExtractor.LastResult.ValidationErrors);

信頼度と人による確認

有効なJSONは正しいJSONと同じではありません。ぼやけた合計額やにじんだ日付でも、形式が整った数値が生成されることがあります。そのため、モデルは抽出した各フィールドについてどれだけ確信しているかも報告し、抽出コンポーネントはその値を提供します。LastResult.Confidenceはそれらのうち最も低い値、LastResult.FieldConfidence('total')は特定のパスの値を返し、OnLowConfidenceはMinConfidenceを下回る各フィールドについて1回ずつ発火します。

oExtractor.MinConfidence := 0.8;
oExtractor.OnLowConfidence := OnLowConfidenceEvent;
Memo1.Lines.Text := oExtractor.ExtractFile('invoice.pdf');

if oExtractor.LastResult.FieldConfidence('total') < 0.8 then
  ShowMessage('Check the total by hand');

procedure TForm1.OnLowConfidenceEvent(Sender: TObject; const aField: string;
  aConfidence: Double);
begin
  lstReview.Items.Add(Format('%s: %.2f', [aField, aConfidence]));
end;

これにより、確認待ちの案件は人が処理しきれるものになります。モデルが確信を持てなかった2つのフィールドだけを確認すればよく、請求書全体を見る必要はありません。

ローカルOCR、データはマシンの外に出ない

文書によっては、クラウドサービスに一切送ってはならないものもあります。OCRコンポーネントを抽出コンポーネントに関連付け、用途に合ったエンジンを選びます。TsgcAIOCRTesseractは、マシンにインストールされたTesseract OCRエンジンを実行します。TsgcAIOCRWindowsはWindows 10以降に組み込まれたテキスト認識機能を使用するため、インストールする必要はありません。OCRModeをdomAlwaysに設定すると、画像がモデルに送信されることはありません。OCRエンジンがテキストをローカルで読み取り、Ollamaのようなテキストモデルが抽出を行うため、パイプライン全体が自分のハードウェア上で動作します。

oOCR := TsgcAIOCRTesseract.Create(Self);
oOCR.Language := 'eng';

oChat.Provider := aicpOllama;
oChat.ChatOptions.Model := 'llama3.1';

oExtractor.OCR := oOCR;
oExtractor.OCRMode := domAlways;
oExtractor.Preset := dpReceipt;
Memo1.Lines.Text := oExtractor.ExtractFile('receipt.png');

Windowsエンジンはen-USのようなBCP-47言語タグを受け取ります。Languageを空にすると、ユーザープロファイルの言語が使用されます。

oWinOCR := TsgcAIOCRWindows.Create(Self);
oWinOCR.Language := 'en-US';

oExtractor.OCR := oWinOCR;
oExtractor.OCRMode := domFallback;
Memo1.Lines.Text := oExtractor.ExtractFile('invoice.png');

この2つ目の例で使われているdomFallbackはもう一つの選択肢です。抽出コンポーネントはまずビジョンリクエストを試み、そのリクエストが失敗した場合にのみ認識済みのテキストを使用し、その際にOnOCRFallbackを発火させて分かるようにします。LastResult.UsedOCRとLastResult.OCRTextは、どちらの経路でデータが生成されたかを後から教えてくれます。OCRの工程は画像を読み取るため、スキャンされたPDFはページ画像として入力されます。

.NET向けのC#

sgcWebSocketsの.NET版には、esegece.sgcWebSockets名前空間内に同じ名前の同じコンポーネントがあります。プリセット、信頼度の値、イベントも同じように動作し、2つのOCRエンジンTsgcAIOCRTesseractとTsgcAIOCRWindowsも揃っています。

using esegece.sgcWebSockets;

var chat = new TsgcAIChat();
chat.Provider = TsgcAIChatProvider.aicpAnthropic;
chat.ChatOptions.ApiKey = "your-api-key";

var extractor = new TsgcAIDocumentExtractor();
extractor.AIChat = chat;
extractor.Preset = TsgcAIDocumentPreset.dpInvoice;
extractor.MinConfidence = 0.8;
extractor.OnLowConfidence += (sender, field, confidence) =>
    Console.WriteLine($"review {field}: {confidence:0.00}");

string json = extractor.ExtractFile("invoice.pdf");
Console.WriteLine(json);
Console.WriteLine($"valid: {extractor.LastResult.Valid}, confidence: {extractor.LastResult.Confidence:0.00}");

提供時期

TsgcAIDocumentExtractor、TsgcAIOCRTesseract、TsgcAIOCRWindows、そして新しいTsgcAIChatのメソッドは、Delphi、C++Builder、.NET向けのsgcWebSockets 2026.10で登場します。現在ダウンロードできるバージョンには含まれていません。2026.10がリリースされたら、ダウンロードページに掲載されます。

すべてのプロパティとイベント、そして請求書処理のステップバイステップガイドを含む完全なリファレンスは、TsgcAIDocumentExtractorのヘルプにあります。AIコンポーネントがそれ以外にできることについては、sgcAI製品ページとsgcWebSockets AIページをご覧ください。

次に読む

ご質問、ご意見、移行のお手伝いが必要ですか。お問い合わせください。コードを書いた本人から返信いたします。