Skip to main content

scanbook

Turn a scanned Korean book PDF into a clean EPUB via the MinerU→post-process→org→ox-epub pipeline in ~/repos/gh/memex-kb. Use when working on any book under scanpdf/work/<book>/ — parsing a scan with MinerU, writing/extending a book correction config, fixing OCR misreads, reconstructing heading/footnote/paragraph structure, merging page-split paragraphs, building or validating the EPUB, or starting a NEW book (e.g. 물리학강의, 물리의정석, 자연철학강의, 인공지능시대). Triggers: 'scanbook', 'mineru', '물리학강의', '스캔책', '스캔북', 'epub 만들', 'epub 빌드', 'mineru-parse', 'mineru2org', '책 전사', 'OCR 책', 'org2epub', '용어집 만들', 'diff-review', 'para-splits', '문단 잘림', '문단 봉합', '감독형 봉합'. This skill carries the tribal knowledge run.sh and docs cannot: the remote GPU dependency, the correction strategy, the paragraph-merge judgment, and the hard-won gotchas.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
junghan0611/memex-kb
آخر نشاط في المصدر
٣٠ يوليو ٢٠٢٦ في ٠٩:٤١
لغة SKILL.md المكتشفة
لغات متعددة
النجوم
٣
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
scanbook
description
Turn a scanned Korean book PDF into a clean EPUB via the MinerU→post-process→org→ox-epub pipeline in ~/repos/gh/memex-kb. Use when working on any book under scanpdf/work/<book>/ — parsing a scan with MinerU, writing/extending a book correction config, fixing OCR misreads, reconstructing heading/footnote/paragraph structure, merging page-split paragraphs, building or validating the EPUB, or starting a NEW book (e.g. 물리학강의, 물리의정석, 자연철학강의, 인공지능시대). Triggers: 'scanbook', 'mineru', '물리학강의', '스캔책', '스캔북', 'epub 만들', 'epub 빌드', 'mineru-parse', 'mineru2org', '책 전사', 'OCR 책', 'org2epub', '용어집 만들', 'diff-review', 'para-splits', '문단 잘림', '문단 봉합', '감독형 봉합'. This skill carries the tribal knowledge run.sh and docs cannot: the remote GPU dependency, the correction strategy, the paragraph-merge judgment, and the hard-won gotchas.
user_invocable
true
# scanbook — scanned book → EPUB pipeline Repo: `~/repos/gh/memex-kb`. Book data + outputs live in the **nested private repo** `scanpdf/` (Forgejo `glg-bot/scanpdf`). This skill is the operating surface; `run.sh` covers the *local* commands, this file covers the rest (remote GPU server, per-book config, correction + paragraph-merge judgment, gotchas). Mental model: **MinerU lays down ~95% (chars + layout). The last 5% is judgment** — char misreads and **page-split paragraphs**. Both are fixed by *detect-then-supervise* tools, never by blind blanket automation. ## Pipeline ``` PDF ──①MinerU VLM (REMOTE gpu2i)──▶ md + content_list.json + images/ ──②mineru2org.py (post-process)─▶ clean .org (headings/footnotes/eq/images │ + corrections + supervised paragraph-merge) ──③ox-epub──────────────────────▶ .epub (epubcheck 0/0/0) QA: ④diff-review · para-splits config: ⑤scripts/corrections/<book>.json ``` - **Stage ① is the only non-local part**, not fully expressible in `run.sh`. - vision/Opus full transcription is **retired**. Do not spin Opus agents on page images. - Two classes of last-5% work, each with a detect→supervise tool: - char misreads → `corrections/<book>.json` (`safe_regex`/`literal`/`candidate_regex`) - page-split paragraphs → `para-splits` detector + supervised merge (§Paragraph splits) ## ⚠️ Stage ① — remote MinerU server (run.sh can't own this) Inference runs on **gpu2i** (RTX 5080), a vLLM server serving `MinerU2.5-Pro` on port 30000. This is **nixos 담당's domain** — a tmux session, not a memex-kb artifact. ```bash ssh gpu2i 'tmux ls | grep mineru-vllm' # alive? do this FIRST every parse session # Missing → it is down. Ask GLG/nixos to bring it up. Do NOT start the vLLM from here. ``` - `run.sh mineru-parse` **auto-tunnels** `localhost:30000 → gpu2i:30000`; only needs the server already running. Health = `curl -sf localhost:30000/health` (vLLM returns 200 with empty body — the `-sf` exit code is truth, not the empty output). - Client install (one-time): `./run.sh mineru-setup` (uv sync; opencv-headless override). The client (`mineru-client/`) is a thin http-client; weights live on gpu2i. - A 261-page book parses in **~3 min**. Background it for big books. ```bash ./run.sh mineru-parse scanpdf/<book>001.pdf mineru-client/out # → out/<book>001/vlm/{<book>001.md, _content_list.json, images/} # MOVE useful artifacts under scanpdf/ for commit (Forgejo): # <book>001.md, _content_list.json, images/ → scanpdf/work/<book>/mineru/ # DROP heavy *_origin.pdf / *_layout.pdf / *_model.json / *_middle.json ``` ## OCR engine choice — 4 engines, **model layer vs tool layer** (measured 2026-06) The single most important frame: an engine is **two layers**. Compare *within* a layer. - **Tool** (layout + **asset 픽셀 crop** + **formula LaTeX** + structure labels): MinerU pipeline, PaddleOCR **PP-StructureV3**. These give what a pure OCR model cannot. - **Model** (page→text only): MinerU2.5-VLM, DeepSeek-OCR, PaddleOCR-VL. | | MinerU | PP-StructureV3 | DeepSeek-OCR | PaddleOCR-VL | GLM-OCR | **Upstage DP** | |---|---|---|---|---|---|---| | layer | tool+model | **tool** | model | model | model | tool+model (**SaaS**) | | serving | gpu2i:30000 | gpu3i:8118 (PaddleX `/layout-parsing`) | gpu1i:8000 | gpu3i:8000 | gpu3i:8101 | **자체 GPU 없음** | | run.sh | `mineru-parse` | `ppstructure-parse` | `deepseek-parse` | `paddleocr-parse` | (재측정: paddleocr 클라 `--url …:8101 --model glm-ocr --prompt "Text Recognition:"`) | (미노출, curl) | | image px crop | ✓ 9 | ✓ 9 (크롭10) | bbox만 | ✗ | ✗ | ✓ **11 (base64)** | | formula LaTeX | ✓ `\mathrm{}` | ✓ **inline까지** | ✓ `H_2` | ✗ 평문 `2H2` | ✗ | ✗ 평문 **+ heading 오분류** | | structure | content_list | parsing_res_list (동급) | grounding(부분) | ✗ | ✗ | elements **5/12종**(caption·equation 0) | | spacing 공백비율 | 정상 | **0.12 붕괴** | 0.21 | 0.23 | 0.22 | **0.242 정상** | | 한국어 글자 | mosaic/焮 환각 | 보통(mobile-rec) | 우수 | 우수 | **최악 + 한자환각(磊嚣螽)** | **최상 · 텍스트층 환각 0**(물리학강의 샘플 한정) / **chart path 환각 확인** | > ⚠️ **이 표는 "2026-06-06 기록 기반 상대비교 + Upstage 1차 스크리닝"이다.** 앞 5열은 2026-06-06 > 기록 인용이고 raw artifact 가 없다(정량 재현성 debt, 재측정은 `deferred` — `NEXT.md` 6번). > 정량 순위로 인용하지 말 것. > > **gold 대조 진행분(2026-07-30)**: `물질생명인간` 1~4장 vision 전사 합본을 기준으로 Upstage vs > MinerU 정량 CER 산출 완료 — 단 이건 **vision silver 기준**이지 adjudicated 아니다. 그리고 그 > 과정에서 `diff_review` 정규화 비대칭 4종을 발견해 고쳤다(그전 숫자는 전부 무효). 계측 규칙은 > `scripts/diff_review.py` 의 "대칭 원칙" 주석이 SSOT, 정량 CER 은 `./run.sh cer-eval`. > **projection 3종을 함께 볼 것 — 각주 포함 여부로 순위가 뒤집힌다.** > > 채택 판정 = **GitHub 이슈 #5**(체크리스트 SSOT), 포인터는 `NEXT.md`. 서사·판단 근거는 > 봇로그 `20260606T130306`. **★ Upstage Document Parse (2026-07-30 측정, 6번째 엔진, 관리형 API)** — `POST /v1/document-digitization`, `model=document-parse`(→`document-parse-260128`), `ocr=force`, `base64_encoding=["figure"]`. 17p **12.4s** (0.73s/p). 키 = `~/.env.local`의 `UPSTAGE_API_KEY`(출력 금지). **글자 층 6엔진 중 1위**: 다섯 엔진이 *서로 다르게* 깨먹던 고유명사(톰슨·돌턴·슈뢰딩거·찐빵)를 **전부 맞힌 유일 엔진**, MinerU 한자환각 4건 자리 정확(`꺌岁月을`→`꿰뚫을`). **단 구조 층은 base 불가**: ① 수식 평문화 + `heading1` 오분류 (문서상 `equation` 카테고리는 LaTeX 지원 → 기능부재 아닌 **분류 실패**), ② 2단 캡션이 본문 문장 **한가운데를 가름**(`과학의 아버`+`그림 5-1: 돌턴`+`지라고`) — `caption` 카테고리 0건, ③ **인쇄 줄바꿈 그대로 보존**(432줄 중 306 지점 어절 분할, `데카르\n트는` → grep 오판 유발; 단 한국어는 붙임표가 없어 공백 없이 join 하면 대개 복원 = 후처리 흡수 가능), ④ heading1 오탐 7건 중 5건(본문조각·수식·캡션). `mode=enhanced`는 **구조 개선 0**(카테고리·오탐 동일), 대신 figure에 **영문 VLM 설명** 부착(텍스트 12.8k→23.5k) — 정본 금지, 검색색인/alt 용도. 원자료 = `scanpdf/work/물리학강의/upstage/README.md`. 입력 포맷에 **HWP/HWPX 포함**(미측정, 후속 대상). **Measured on 물리학강의 5강 (PDF p121–137).** Proper-noun failures **DON'T overlap** — this is the key: 톰슨 = MinerU `톈슨`(+mosaic환각)·Paddle 4변형·PP `통슨`·GLM `통속` / **DeepSeek ✓**; 돌턴 = **DeepSeek `돌탄`✗**·GLM✗전멸 / MinerU·Paddle·PP ✓; 찐빵 = MinerU 6변형·Paddle✗ / DeepSeek·PP ✓. **⚠️ GLM-OCR 함정**: OmniDocBench 94.6%(5엔진 중 SOTA 1등)인데 **한국어 스캔책에선 꼴찌** — 돌턴/톰슨/볼츠만 정상표기 0건, 한자 환각. 띄어쓰기만 보존. **한국어 책 제외.** OmniDocBench 점수 ≠ 한국어 충실도의 결정적 반례. 영문 문서엔 SOTA일 것. **★ PaddleOCR-VL has TWO serving modes** — 같은 모델, 다른 출력: - **모델 모드** (vLLM `/v1/chat/completions`, gpu3i:8000/8001): 순수 텍스트만. asset·구조·수식 없음. - **도구 모드** (PaddleX `/layout-parsing`, gpu3i:8119, `ppstructure_client.py --url …:8119`): **모델+도구 동시** — 텍스트 우수+띄어쓰기 보존(0.202)+asset 12개+구조 9종(vision_footnote/ display_formula/reference_content). 돌턴·볼츠만·굽은 ✓(GLM/DeepSeek/MinerU가 깨먹은 곳 맞힘). 약점: 느림(8.5s/p), 톰슨→통슨. **현 시점 단일 최강 base.** **현재 최선 (decision rule, the method):** - **Tool base = PaddleOCR-VL 도구모드(:8119)** — MinerU 환각도 PP mobile-rec 띄어쓰기붕괴(0.12)도 둘 다 회피하는 단일 최강. **MinerU = 빠른 대안 base**(asset+content_list, 속도 ↑; 텍스트는 oracle 교정). PP-StructureV3(mobile-rec)는 **kime 띄어쓰기 복원 전제**라 후순위 (scanbook ↔ textlint-ko 연결점). - **Body char oracle = Upstage `ocr`** (2026-07-30 갱신, **잠정 — 이슈 #5 gold 검증 전**). 역할 분리: - **`ocr`**($0.0015/p) = **저가 글자 oracle + word confidence 기반 후보 생성.** DP와 글자 결과 사실상 동일(유사도 0.979)한데 1/6.7 가격, 구조는 없음. confidence 최저값이 자기 이물질 (`볼Bal츠만`·`�`)을 지목 → candidate 자동생성 축. **이 자리의 1순위.** - **`document-parse`**($0.01/p) = **산문 문서의 구조+텍스트**(heading·각주·목록·표). 산문책 단독 base 후보. 수식·2단 도판 책에서는 구조 base 불가. - **`chart_recognition=false` 필수** — 도식/개념도 문서에서 **없는 수치를 생성**(칸트 도식 → `0.08/0.28/0.47`). 기본 true이고 `mode=enhanced`에서는 강제 활성이라 enhanced 자체를 피한다. - 유료 API이므로 책 전체가 아니라 **깨진 span 의 해당 쪽만** 뽑아 호출 (`mutool merge -o span.pdf <book>.pdf N-M`). 대안(무료·로컬) = DeepSeek(고유명사 강, 단 돌턴✗) 또는 PaddleOCR-VL(환각 없고 본문 깨끗). → 정확 토큰 → `corrections/<book>.json`. Proven: Guq은→굽은, mosaic→톰슨, 짧빵→찐빵, 꺌岁月→꿰뚫. - **고유명사 = multi-engine voting.** 엔진 불일치 토큰 = 오독 의심점 → 교정후보 자동생성 (차기 `engine_vote.py`). 한 엔진의 *반복* 오독은 못 잡지만(예: 시간펼침→시간필침 ×14), 엔진 *불일치* 는 그 자체로 신호. consistency≠accuracy 의 역(逆)활용. - **MEASURE first** on one chapter — predictions were wrong repeatedly. 점수표(OmniDocBench) ≠ 한국어 스캔책 고유명사 충실도. DeepSeek serving: `ssh gpu1i 'tmux ls | grep deepseek-ocr'`; `deepseek-parse` auto-tunnels `localhost:8000 → gpu1i:8000`. grounding prompt = `<image>\n<|grounding|>Convert the document to markdown.` ## Stage ② — post-process: `scripts/mineru2org.py` Deterministic structure-recovery converter (same input → byte-identical output), driven by the per-book config (`--corrections`) + `--content-list`. ```bash python3 scripts/mineru2org.py scanpdf/work/<book>/mineru/<book>001.md \ -o scanpdf/work/<book>/mineru/<book>-mineru.org \ --corrections scripts/corrections/<book>.json \ --content-list scanpdf/work/<book>/mineru/<book>001_content_list.json # Emits: <book>-mineru.org + .changes.log (every transform, counted) # + .candidates.log (uncertain char fixes, NOT applied) # + .merges.log (paragraph-merge decisions; §Paragraph splits) ``` Passes (all logged): surface (image `![]()`→`[[file:]]`, block `$$`→`\[\]`, inline `$$`→`\(\)`, footnote `$^{n}$` + unicode superscript `⁵⁸²³`→`[fn:n]`); HTML cleanup (`<details>`/mermaid removed, `<table>`→org table); **structure recovery** (chapter `*` / section `**` num+title merge / subsection `***` / false-heading demotion / front-matter+TOC cut / preface kept); **footnote defs** from `content_list.page_footnote` → `* 각주` section + orphan numeric paragraphs absorbed; **supervised paragraph-merge** (opt-in); corrections; epub header from meta. ## Stage ⑤ — the per-book config (the real per-book work) `scripts/corrections/<book>.json`. Copy `물질생명인간.json` as template: ```jsonc { "meta": { title, author, date, language, publisher, subject, uid }, // → epub #+keywords "structure": { "body_start": "<first chapter title>", // everything before = front matter, cut (preface kept) "chapters": [ { "num": "1장", "title": "..." }, ... ], "chapter_title_variants": { "<ocr/dash variant>": "<canonical>" }, "back_matter": ["참고문헌", "찾아보기"] // become * level; 찾아보기 internal headings dropped }, "safe_regex": [ { pattern, replace, desc } ], // AUTO. Must be PROVABLY safe (see strategy). "literal": [ { from, to, desc } ], // AUTO exact-string fixes (heading OCR, LaTeX). "candidate_regex": [ { pattern, desc } ], // LOG ONLY (.candidates.log). Never edits body. "paragraph_merge": { // OPT-IN supervised merge "enabled": false, // off until validated per book "categories": ["page_boundary", "samepage_break"], // never eq/image/table by default "overrides": [ { "tail": "<suffix>", "seam": "space|nospace|skip" } ] } } ``` Author it by **reading the parsed md**: heading layout, section numbering, recurring OCR misreads, index/reference layout. ## 🎯 Char-correction strategy (hard-won — do not regress) Central vocabulary is the highest-priority target: a key term mangled in the index is mangled in the body too.
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub