Communitygithub.com

LPSlv/doc-extract

PDF 및 Office 문서에서 빠르고 정확한 텍스트 추출을 수행하는 AI 에이전트 스킬입니다. 텍스트 추출은 로컬 엔진으로 처리하고, 차트, 스캔 페이지, 구조화 실패한 표 등 놓친 부분에만 비전(시각) 호출을 사용합니다.

doc-extract란 무엇인가요?

이 스킬은 AI 에이전트(Claude Code, Cursor, Codex 등)가 PDF, DOCX, XLSX, PPTX 및 이미지 파일에서 문서 내용을 추출할 때, 텍스트는 빠른 로컬 엔진으로 처리하고, 비전 모델이 필요한 경우(그림, 스캔 페이지, 구조화 실패한 표)에만 선별적으로 비전 호출을 사용하여 비용을 최적화합니다. `uv`를 기반으로 실행되며, 첫 실행 시 의존성이 자동으로 해결됩니다. 변환 단계에서 모든 결정적 작업(텍스트 추출, 이미지 저장, 아티팩트 캐싱)을 수행하고, `pending` 목록에 비전 검토가 필요한 항목만 남깁니다. 사용자는 `describe.py`를 통해 각 항목을 설명하고, 최종적으로 `doc.md`와 개별 단위 파일을 통해 문서를 참조합니다. 이 스킬은 벤치마크와의 호환성을 위해 직접 파일 수정을 금지하며, 모든 추가 설명은 `describe.py`를 통해서만 이루어집니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add LPSlv/doc-extract

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

doc-extract은(는) 무엇을 하나요?

텍스트 추출은 대부분의 문서를 자체적으로 처리합니다. 이 스킬은 이를 위해 빠른 로컬 엔진을 사용한 후, 비전 호출은 확실히 놓친 것—그림, 스캔 페이지, 구조화에 실패한 표—에만 사용합니다.

.pdf, .docx, .xlsx, .pptx 및 이미지 파일을 읽습니다. 형식은 확장자가 아닌 내용에 의해 결정됩니다.

사용하지 말아야 할 경우

  • 병합, 분할, 양식 작성, 암호화 → anthropics/skills@pdf.
  • 문서에서 하나의 숫자만 필요하고 페이지를 이미 알고 있는 경우 → 그냥 읽으세요.

uv가 필요합니다. 그 외에는 없습니다. 의존성은 첫 실행 시 해결됩니다.

1. 변환

uv run <skill-dir>/convert.py FILE [MORE ...]
uv run <skill-dir>/convert.py FILE --inline    # 이미지 위치에 설명 삽입

문서당 하나의 JSON 객체가 stdout에 출력됩니다. 모든 결정적 작업이 완료되었습니다: 텍스트 추출, 이미지 저장, 아티팩트 캐싱. 종료 코드는 문서 중 하나라도 실패하면 0이 아닙니다.

{"status":"ok","artifact":"/home/…/<sha>-<tag>","cached":false,
 "doc_md":"…/doc.md","pages_dir":"…/pages","manifest":"…/manifest.json",
 "pending":[{"id":"p007-render","page":7,"kind":"page_render",
             "reason":"dense_grid","path":"…/images/p007-render.png"}],
 "dropped":6,"over_scale_guard":false,"scale_guard":15}

먼저 status를 확인하세요. encrypted, unreadable, unsupported는 종료 상태입니다—보고하고 넘어가세요. 배치 작업은 계속됩니다. 동일한 파일을 다시 실행하면 즉시 cached: true를 반환하며 비용이 들지 않습니다.

over_scale_guard가 true인 경우, 사용자에게 필요한 호출 수를 알리고 계속 진행하기 전에 동의를 받으세요. 84페이지 스캔은 84번의 호출이 필요하며, 40개의 이미지로 구성된 슬라이드 데크도 마찬가지입니다.

2. 각 pending 항목 확인

pending이 비어 있으면 → 완료된 것입니다. 3단계로 가세요.

그렇지 않은 경우, 각 항목에 대해: path의 파일을 읽고, 본 내용을 작성하세요:

uv run <skill-dir>/describe.py <artifact> <id> "your description"
# 또는 긴 내용은 파이프로: … describe.py <artifact> <id> -

설명을 작성하는 방법은 reason에 따라 다릅니다— reference/describing-visuals.md 참조:

reason작성할 내용
standalone_raster, curves, diagonals그림 설명: 유형, 보여주는 내용, 축과 단위, 주목할 값, 모든 읽을 수 있는 텍스트.
no_text_layer페이지를 그대로 전사하세요. OCR 경로이며, 텍스트가 전혀 없습니다.
dense_grid, stroke_grid추출기가 구조화하지 못한 표입니다. 마크다운 표로 재현하세요.
raster_grid많은 이미지로 타일링된 페이지—복합 그림, 또는 스트립으로 저장된 하나의 사진입니다. 패널이 함께 보여주는 내용을 설명하고, 각 패널별로 주목할 점을 설명하세요.

describe.py는 안전하게 다시 실행할 수 있습니다—중복되지 않고 대체하므로, 중간에 실패한 비전 패스는 다시 시작할 수 있습니다.

kind: "native_chart" 항목은 pending에 절대 나타나지 않습니다. 이는 차트 정의에서 계열을 읽은 스프레드시트 차트로, 숫자가 픽셀 추정치가 아닌 정확합니다.

3. 답변

  • 전체 문서: doc.md.
  • 특정 질문: 단위 파일에서 grep하여 필요한 파일만 읽으세요.
  • 단위로 인용하거나, 여러 문서에 걸쳐 파일명을 접두사로 사용하세요 ([report.pdf:p12]).
형식단위인용 방법단위 파일
PDF페이지[p12]pages/p012.md
PowerPoint슬라이드[s07]pages/u007.md
Excel시트[Sheet2]pages/u002.md
Word레벨-1 제목[Budget assumptions]pages/u003.md
이미지전체 파일[img]pages/u001.md

Office 단위 파일은 이름이 아닌 번호로 지정됩니다. manifest.json에는 각 파일을 레이블에 매핑하는 units 목록이 순서대로 포함되어 있습니다.

하나의 규칙

절대 doc.md를 수동으로 편집하지 마세요. 추가하는 모든 내용은 describe.py를 통해 전달되며, 이는 구분 기호로 감쌉니다. 이것이 벤치마크가 추가 내용을 제거하고 스킬이 텍스트 추출을 저하시키지 않음을 증명할 수 있게 하는 방법입니다. 직접 편집하면 이 보장이 조용히 깨집니다.

설명이 배치되는 위치와 --inline이 보장하지 않는 것

기본적으로 모든 설명은 doc.md 끝에 하나의 블록으로 추가되며, [s02], [p12] 또는 [Sheet2]로 레이블이 지정됩니다. --inline은 대신 각 블록을 이미지 위치에 배치합니다. 변환 시점에 전달해야 하며, describe.py에 전달하지 마세요: 배치는 아티팩트(및 캐시 키)에 기록되므로, 재개된 비전 패스가 두 가지를 혼합할 수 없습니다.

형식--inline이 앵커할 수 있는 대상
PowerPoint해당 라인이 그림의 것임이 증명될 경우 그림 자체의 라인; 그렇지 않으면 슬라이드 끝
Word그림이 있는 섹션의 끝 — anydoc는 그림을 대체 텍스트로 렌더링하며, Word는 작성자가 입력하지 않는 한 대체 텍스트를 쓰지 않으므로 일반적으로 앵커할 라인이 없음
Excel시트의 끝 — 이미지와 차트는 패키지에서 가져오며, anydoc는 둘 다 렌더링하지 않음
PDF, 이미지없음. --inline은 PDF에 대해 아무것도 변경하지 않음

블록은 엔진의 라인 옆에 삽입되며, 대체되지 않습니다. 이것이 바이트 동일성이 유지되는 이유입니다—eval/gate.py는 두 배치를 모두 실행하고 직접 편집이 있으면 실패합니다.

인라인이 보장하지 않는 것은 위치가 정확하다는 점입니다. 바이트 동일성은 배치를 확인할 수 없습니다. 삽입은 어디에 위치하든 왕복하기 때문입니다. 앵커는 anydoc의 대체 텍스트이며, 이는 일반 산문입니다: image.png라는 파일에 대한 슬라이드는 그림과 동일한 라인을 렌더링합니다. 따라서 이미지 자체의 라인은 해당 단위의 후보 라인 수가 그림 수와 같을 때만 사용되며, 그렇지 않으면 설명은 단위 경계로 대체됩니다. 위치는 증명 가능하게 해당 그림의 위치이거나 단위 경계입니다—비슷해 보이는 두 라인 사이의 추측이 아닙니다.

필터가 이렇게 설정된 이유

이것들을 "단순화"하지 마세요—각각은 대안이 테스트되었고 실제 문서에서 실패했기 때문에 존재합니다:

필터이유
단위의 >50%에 이미지가 있거나, <120px이거나, 종횡비 >8:1인 이미지 드롭14페이지 보조금 PDF에는 69개의 이미지 배치가 있었습니다: 7개의 개별 객체 중 6개는 로고, 구분선 및 사이드바 스트라이프였습니다.
이미 마크다운 표를 생성한 페이지 건너뛰기추출기가 파싱할 수 있는 표는 비전보다 더 나은 결과를 냅니다. 아무것도 생성되지 않은 경우에만 개입하세요.
두 방향 모두에 획(stroke)이 필요밑줄과 구분선은 수평만 있습니다. 모든 축 정렬 획을 세면 참고문헌 페이지와 밑줄 친 제목이 있는 계약서에서 발동되었습니다.
diagonals를 면적 하한에서 제외4개 이상의 대각선 세그먼트는 본문 텍스트에서 발생하지 않으며, 면적 하한이 페이지 모서리에 배치된 차트를 거부했습니다.
밀집 그리드 분기의 잉크 임계값추출기가 놓친 음영 표를 장식용 섹션 배너와 구분합니다.
>6개의 래스터가 있는 페이지를 하나의 렌더링으로 통합48타일 인페인팅 비교는 하나의 그림이며, 하나의 TI 패키지 사진이 12개의 스트립으로 도착합니다. 타일당 호출은 ~2배의 토큰 비용이 들고 구성을 잃습니다. 5-6개의 래스터가 있는 페이지는 때로 별개의 그림이므로 임계값은 6에 설정됩니다.
EMF, WMF 및 OLE 페이로드 드롭텍스트 엔진에 의해 충실히 보존되며, 래스터라이저 없이는 읽을 수 없습니다. 이를 pending으로 라우팅하면 완료할 수 없는 항목이 생성됩니다. dropped에 집계되며, 조용히 폐기되지 않습니다.

harvest.py는 PDF 라우팅의 단일 진실 공급원이며, filters.py는 모든 형식에 적용되는 부분에 대한 것입니다. README 및 설계 사양의 모든 숫자는 이 파일들에서 재생성됩니다. 숫자를 수동으로 편집하지 마세요. 파일을 실행할 수 없는 경우, reference/harvest-block.md는 복사하여 실행할 수 있는 자체 포함 복사본입니다.

Office 라우팅은 의도적으로 더 가벼우며, 이는 정직합니다

PDF 페이지는 그림을 숨기는 그리기 명령 프로그램이므로 harvest.py가 벡터 기하학에서 그림을 추론합니다. OOXML은 패키지에 이미지를 선언하므로 추론할 것이 없습니다. Office 문서는 가구 필터, 인용 및 캐시 계약, 이 루브릭을 받지만—render_reason, raster_grid 및 cost_guard는 없습니다. 렌더링 엔진이 없으면 슬라이드나 시트를 렌더링할 수 없기 때문입니다.

관련 스킬