財務諸表抽出 は何をしますか?
報告書PDFを検証済みの事実に変換します: financial_fact(文書, 期間, ラベル, 範囲, 値, 単位, 監査ステータス)。
コルンボ証券取引所(CSE、スリランカ)の2年間の提出書類(2,707件の報告書、72万の数値、99.4%が完全読み込み)で構築・実証済み。
このメソッドが高速な理由は、自動パーサーが大部分の報告書を処理し、算術チェックで信頼できるデータを判断し、トリアージステップで残った各明細書の失敗理由を正確に特定し、サブエージェントによって画像からの読み取りがバッチ処理されるからです。すべての変更は、ステージングされた読み込みと監査を経て初めて公開データベースに反映されます。
すべての基盤となる唯一のルール
数値が読み込まれるのは、その列が算術チェックを通過した場合のみ(資産 = 負債 + 純資産、税引前利益 - 税 = 利益、親会社株主持分 + 非支配株主持分 = 利益、キャッシュフローの各セクションの合計がネット変動額と一致、期首 + 変動 = 期末)。チェックを通過させるために調整は一切行われません。チェックでは印刷上の丸め誤差のみを許容します(最後の印刷桁で数単位の差:2項なら2、3項なら3、それ以上なら5)。そのため、合計が内訳から1~2単位ずれていれば通過し、それ以上は読み取りまたは印刷の誤りとみなされます。これこそが、パーサー、OCRエンジン、ビジョン転写、そして人間が同じデータベースにデータを供給できる理由です。データの出所ではなくチェックが信頼性を決定します。チェックが失敗した場合、読み取りが間違っている(再読み取り)か、印刷が間違っている(理由を記録して除外)かのいずれかです。
実際上重要な帰結:
- ラベルは印刷されたまま厳密に保持され、標準的なラインアイテムへのマッピングは完全一致のエイリアス(
label_alias)のみを通じて行われ、あいまい一致は使用されません。誤って印刷されたラベルがあると、黙って間違ったデータが読み込まれるのではなく、その明細書が読み込めなくなります。 - ラベルのない合計は、その位置で定義されるため、括弧付きラベル(
[Total assets])が付与されることがあります。 - 「UNCHECKED」(チェック不能)は「FAIL」ではありません。通常、チェッカーがまだ認識していないレイアウトを意味します。チェッカーを一度修正すれば、そのレイアウトを持つすべての報告書が読み込めるようになります(references/checks.md 参照)。
ファイル構成
scripts/pipeline/- パイプライン:parse_report.py(PDF -> JSONテーブル)、segment.py、columns.py、tokens.py、checks.py、ocr_words.py(OCRを疑似テキストレイヤーとして)、load_facts.py(JSON -> DB、通過した列のみ)、vision_tables.py(画像のテキスト化 -> JSONテーブル)、extract_all.py、normalize.py。 マッピング、データ構造、および他市場への適応方法: references/pipeline.md。scripts/triage.py、scripts/make_batches.py、scripts/render.py、scripts/stage_publish.py- 以下のステップのためのヘルパー。assets/schema.sql(データベース)、assets/dictionary.sql(252の標準ラインアイテム + 471の完全一致ラベルエイリアス)、assets/worker_brief.md(転写作業者向け概要)、assets/examples/(転写ファイル)。- プロジェクトディレクトリ: データベース、PDF、出力が存在する場所。ユーザーが
CLAUDE.md/AGENTS.mdで命名します(例: 「Financials project: ~/stocks/cse_financials」)。記載がない場合は確認してください。レイアウト:db/<名前>.db、reports/<SYMBOL>/<doc>.pdf、パーサー出力extracted_final/、公開ソースextracted_final_v/、転写reviewed/vision/、メモdocs/。プロジェクトに独自のpipeline/がある場合、それを現在のコードとして扱います(このスキルのコピーは古い可能性があります)。
Pythonは常に -I(分離モード)および CSE_OCR=0 で実行します(OCRが必要な場合は除く。CSE_ 接頭辞は歴史的なものです)。
報告書のPDF: select local_path from report_document where document_id=?(プロジェクトディレクトリからの相対パス)、次に python -I scripts/render.py <pdf> <pages> <out_dir> --text を実行してテキストレイヤーを抽出し、ページをレンダリングします。
ワークフロー
1. 範囲の決定とダウンロード
期間範囲を選択します。報告書タイトルから期間終了日を取得します(取引所の提出日は信頼できません)。report_document の行を埋めます(報告書ごとに1行: 企業、カテゴリ ANNUAL/INTERIM、タイトル、期間終了日、ソースURL)。その後、並行かつ再開可能にダウンロードします。取引所固有の部分(API、URL、癖)は補助スキル(CSEの場合は cse-financials)に属します。各年のブロックは、これらのステップを個別の実行として保持します。新しい市場または新しい年に進む前に、references/traps.md を読んでください。最も時間を費やすデータ上の落とし穴がリストされています。
2. 単一のパーサーバージョンですべてをパース
python -I scripts/pipeline/extract_all.py <db> <out_dir> --workers N を CSE_OCR=0 で実行します(2,700報告書で約9分)。その後、スキャン画像用に別のOCRパスを実行します(可能ならGPUを使用。traps.mdを参照)。パーサーを変更した後は、すべての報告書を再パースし、報告書ごとに比較します。部分的な再パースはデータベースを再現不可能にします。
3. 読み込みとステータスの確認
load_facts.py(ステップ6の stage_publish.py 経由)により、各報告書に EXTRACTED(ISとBSが読み込まれた)、PARTIALまたはFAILEDのステータスが付与されます。パーサーのみで約80%がEXTRACTEDになると予想されます。
4. 残った報告書のトリアージ – ページを見る前に
python -I scripts/triage.py <db> <extracted_dir> triage.json --pdf-hints
python -I scripts/make_batches.py triage.json batches/ --target=12
トリアージにより、欠落している各明細書の理由(not_found、UNCHECKED、FAIL、no_columns、no_months、unit_unproven、pass_refused...)と参照箇所が示されます。カウントを読んでください。1つの理由で大きなクラスターが発生している場合(例: 100件のUNCHECKED)、それは多くの場合、チェッカーのギャップやローダーのルールを意味します。コードを修正することは、何百ページも転写するよりも効率的です。また、FAILED報告書がそもそも財務諸表ではないかどうかも確認してください。通知、株主リスト、訂正事項などは一般的であり、理由を記録するだけで済みます。
5. 画像からの転写をバッチで実行
各ワーカーは1つのバッチファイルと assets/worker_brief.md(パスを埋める)を受け取ります。明細書ページを特定し、読み取り(最初にテキストレイヤー、レイアウトと不明な点については画像)、reviewed/vision/<doc>.txt に書き込み、各列がPASSするまで vision_tables.py を実行し、bNN.result.json を書き込みます。ワーカーには画像を読み取れるモデルが必要です。フォーマットとルール: references/vision-format.md。ワーカーの並列実行、使用制限、再開、結果のレビュー: references/orchestration.md。サブエージェントがない場合は、同じ概要でバッチを順番に処理します。
バッチの実行中、各結果のサマリーが到着したらすぐに読んでください:
- 繰り返し発生する「チェッカーがXを認識しないためUNCHECKED」 ->
checks.pyを拡張し(references/checks.md)、影響を受けるファイルをvision_tables.pyで再テストし、ルールを概要に追加して後続のバッチが認識できるようにします。既に書き込まれたテーブルは再転写なしで通過します。 - 判断を要するケース(監査ステータス、修正再表示された列、変則的な期間長、供給されたラベル) -> 概要に従っているか確認し、中央で修正します(例: COLS行に対するsedなど)。ワーカーを再実行する必要はありません。
6. ステージング、監査、公開
python -I scripts/stage_publish.py --project <dir> # ステージング + 監査のみ
python -I scripts/stage_publish.py --project <dir> --publish # 監査確認後
監査で報告書がEXTRACTEDのまま、空の報告書が発生、整合性/FKエラー、新しい単位の外れ値、または転写ファイルがない報告書でデータの損失・変更が示された場合、公開は拒否されます(コード変更が誰も再読み取りしていないデータに影響を与えたことを意味します)。ビジョン報告書以外での増加は正常です(競合解決により別の報告書の列が解放される)が、それぞれ確認します。完了したバッチから順に公開し、作業が中断から回復できるようにします。その後、プロジェクトにテストがあれば実行します。
7. すべての明細書をクローズアウト
目標は、欠落しているすべての明細書が読み込まれるか、理由が明記されることです。明細書ごとの結果テーブルを作成します(読み込まれた / 読み込まれなかった + MISSING 行と結果ファイルからの理由)。読み込まれなかった各明細書について、同じ数値が別の報告書(翌年の比較、該当する中間報告書)から既に読み込まれているかどうかを確認します。通常は既に読み込まれており、「ギャップ」が「カバー済み」に変わります。結果をプロジェクトドキュメントに記録します。
トークンと時間の節約
- まずトリアージ。理由とページのヒントなしにワーカーを「問題を探せ」と送り出さないでください。
- テキストレイヤーを優先:クリーンなテキストレイヤーがあれば、無料で桁を確認できます。画像はレイアウトの確認用です。1500pxでレンダリングし、大きなページ全体をレンダリングする代わりに
render.py --clipでトリミングします。テキストレイヤーが「9,O4349L」のようなゴミデータのスキャンは画像が必要です。 - 企業ごとにバッチ処理:1つのレイアウトで多くの四半期。バッチあたり約10報告書または約12コストユニット、一度に約6ワーカー。
- ワーカーはチェックがUNCHECKEDのままでも完全なテーブルを書き込み、さらに
MISSING行を追加します。後でチェッカーが拡張された場合、再読み取りなしでテーブルが読み込まれます。 - 体系的な問題はコード(チェッカー、ローダー)で1回、中央で修正し、
vision_tables.py(数秒)を再実行することでページの再読み取りを回避します。 - オーケストレーターは、争点を解決する場合を除き、ページ画像を表示しません。サマリーを読み、チェックと監査を実行します。
- ワーカーのサマリーは3〜6行に抑えます。詳細はファイルコメントに記述します。
完了の定義
報告書ごとに: EXTRACTED、またはPARTIAL/FAILEDで欠落している各明細書の理由が印刷証拠を明示している(例: 「印刷された合計 3,115,995,977 に対して負債+純資産 3,115,995,968」)、または「報告書Nでカバー済み」。公開は stage_publish.py を通じてのみ行われ、バックアップがあり、監査がクリーン(またはすべてのフラグが説明済み)、テストが合格し、結果テーブルと日付入りのメモがプロジェクトドキュメントに存在することを条件とします。