재무제표 추출은(는) 무엇을 하나요?
보고서 PDF를 검증된 사실로 변환합니다: financial_fact(document, period, label, scope, value, unit, audit status).
콜롬보 증권거래소 제출 서류(2,707개 보고서, 72만 개 수치, 99.4% 완전 적재) 2년 치를 기반으로 구축 및 검증되었습니다.
이 방법이 빠른 이유는 다음과 같습니다. 자동 파서가 대부분의 보고서를 처리하고, 산술 검증이 신뢰할 수 있는 수치를 결정하며,
트라이지 단계에서 각 남은 명세서의 실패 원인을 정확히 알려주고, 해당 명세서만 페이지 이미지에서 배치(batch) 단위로
서브에이전트가 읽습니다. 모든 변경 사항은 단계별 적재와 감사를 거쳐 게시 데이터베이스에만 반영됩니다.
모든 것의 기반이 되는 하나의 규칙
수치는 해당 열(column)이 산술 검증을 통과한 경우에만 적재됩니다 (자산 = 부채 + 자본; 세전이익 - 법인세 = 순이익; 지배 + 비지배 = 순이익; 현금흐름표 각 섹션 합계 = 순변동액; 기초 + 변동 = 기말). 검증을 통과시키기 위해 수치가 조정되지 않습니다. 검증은 인쇄상의 반올림(마지막 인쇄 숫자의 몇 단위: 두 항은 2, 세 항은 3, 그 이상은 5)만 허용하므로, 합계가 구성 항목에서 1-2단위 차이나는 것은 통과되고 그 이상은 판독 또는 인쇄 오류입니다. 이것이 파서, OCR 엔진, 비전 트랜스크립션, 사람이 모두 동일한 데이터베이스에 기여할 수 있는 이유입니다. 검증이, 소스가 아니라, 결정합니다. 검증에 실패하면 판독이 잘못되었거나(재판독) 인쇄가 잘못된 것입니다(이유 기록, 제외).
실제로 중요한 결과:
- 레이블은 인쇄된 그대로 유지되며 정확한 별칭(
label_alias)을 통해서만 표준 라인 항목에 매핑되며, 퍼지 매칭(fuzzy matching)은 절대 사용되지 않습니다. 잘못 인쇄된 레이블은 조용히 잘못된 데이터를 만드는 대신 명세서를 적재 불가능하게 만듭니다. - 레이블 없이 인쇄된 합계는 위치로 정의되므로 대괄호 레이블(
[자산 총계])을 받을 수 있습니다. - "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에 이름을 지정합니다 (예: "재무 프로젝트: ~/stocks/cse_financials"); 없으면 물어보십시오. 구조:db/<name>.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 행을 채웁니다
(보고서당 하나: 회사, 범주 ANNUAL/INTERIM, 제목, 기간 종료일, 소스 URL), 그런 다음
병렬 및 재개 가능하게 다운로드합니다. 거래소별 부분(API, URL, 특이 사항)은 동반 스킬에 속합니다 -
콜롬보의 경우 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 사용, 함정 참조). 파서 변경 후에는 모든 보고서를 다시 파싱하고
보고서별로 비교하십시오 - 부분 재파싱은 데이터베이스를 재현 불가능하게 만듭니다.
3. 적재 및 상태 확인
load_facts.py(stage_publish.py, 6단계를 통해)는 각 보고서에 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...)와 찾을 위치를 제공합니다. 개수를 읽으십시오: 하나의 이유로 큰 클러스터가 있는 경우(예: UNCHECKED 100개)
종종 검사기 누락 또는 로더 규칙을 의미하므로 코드 수정이 수백 페이지를 트랜스크립션하는 것보다 낫습니다. 또한 FAILED 보고서가
명세서인지 확인하십시오: 공지, 주주 목록, 정오표는 흔하며 기록된 이유만 있으면 됩니다.
5. 이미지에서 배치 단위로 트랜스크립션
각 작업자는 하나의 배치 파일과 assets/worker_brief.md(경로 채우기)를 받습니다. 명세서 페이지를 찾아
읽고(텍스트 레이어 먼저, 레이아웃 및 의심스러운 부분은 이미지), reviewed/vision/<doc>.txt를 작성하고,
모든 열이 PASS할 때까지 해당 문서에 대해 vision_tables.py를 실행한 다음 bNN.result.json을 작성합니다. 작업자는 이미지를 읽을 수 있는
모델이 필요합니다. 형식 및 규칙: references/vision-format.md. 작업자를 병렬로 실행, 사용량 제한,
재개 및 결과 검토: references/orchestration.md. 서브에이전트 없이도 동일한 브리프로 배치를 하나씩 처리하십시오.
배치가 실행되는 동안 각 결과 요약이 도착할 때마다 읽으십시오:
- 반복되는 "UNCHECKED because the checker does not recognise X" ->
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")가 있는 스캔은 이미지가 필요합니다. - 회사별 배치: 하나의 레이아웃, 여러 분기. 배치당 약 10개 보고서 또는 약 12개 비용 단위, 한 번에 약 6개 작업자.
- 작업자는 검사가 UNCHECKED로 남아 있어도 전체 테이블을 작성하고
MISSING라인을 추가합니다: 나중에 검사기가 확장되면 테이블은 재판독 없이 적재됩니다. - 시스템적인 문제는 코드(검사기, 로더)에서 한 번, 중앙에서 수정하고;
vision_tables.py(몇 초)를 다시 실행하는 것으로 페이지 재판독을 대체합니다. - 오케스트레이터는 분쟁 해결 외에는 페이지 이미지를 보지 않습니다; 요약을 읽고, 검사 및 감사를 실행합니다.
- 작업자 요약은 3-6줄로 유지; 세부 사항은 파일 주석에 속합니다.
완료 정의
보고서별: EXTRACTED, 또는 누락된 각 명세서에 대해 인쇄된 증거를 명명하는(예: "인쇄 합계 3,115,995,977 vs 부채 + 자본 3,115,995,968") 이유가 있는 PARTIAL/FAILED, 또는 "보고서 N으로 커버됨". stage_publish.py를 통해서만 게시되며, 백업, 감사 통과(또는 모든 플래그 설명됨), 테스트 통과, 결과 테이블 및 날짜가 있는 노트가 프로젝트 문서에 포함됩니다.