mdbook-binder 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. mdbook_binder-0.1.0/LICENSE +21 -0
  2. mdbook_binder-0.1.0/PKG-INFO +329 -0
  3. mdbook_binder-0.1.0/README.md +304 -0
  4. mdbook_binder-0.1.0/pyproject.toml +48 -0
  5. mdbook_binder-0.1.0/setup.cfg +4 -0
  6. mdbook_binder-0.1.0/src/book_binder/__init__.py +3 -0
  7. mdbook_binder-0.1.0/src/book_binder/check.py +92 -0
  8. mdbook_binder-0.1.0/src/book_binder/cli.py +103 -0
  9. mdbook_binder-0.1.0/src/book_binder/editor/__init__.py +12 -0
  10. mdbook_binder-0.1.0/src/book_binder/editor/html_editor.py +329 -0
  11. mdbook_binder-0.1.0/src/book_binder/editor/image_editor.py +286 -0
  12. mdbook_binder-0.1.0/src/book_binder/editor/server.py +469 -0
  13. mdbook_binder-0.1.0/src/book_binder/html_book.py +226 -0
  14. mdbook_binder-0.1.0/src/book_binder/manifest.py +352 -0
  15. mdbook_binder-0.1.0/src/book_binder/pdf_book.py +316 -0
  16. mdbook_binder-0.1.0/src/book_binder/render.py +148 -0
  17. mdbook_binder-0.1.0/src/book_binder/templates/editor/editor.css +332 -0
  18. mdbook_binder-0.1.0/src/book_binder/templates/editor/editor.js +886 -0
  19. mdbook_binder-0.1.0/src/book_binder/templates/editor/index.html +295 -0
  20. mdbook_binder-0.1.0/src/book_binder/templates/html_book.css +131 -0
  21. mdbook_binder-0.1.0/src/book_binder/templates/html_book.js +114 -0
  22. mdbook_binder-0.1.0/src/book_binder/templates/pdf_book.js +83 -0
  23. mdbook_binder-0.1.0/src/book_binder/templates/pdf_override.css +127 -0
  24. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/PKG-INFO +329 -0
  25. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/SOURCES.txt +30 -0
  26. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/dependency_links.txt +1 -0
  27. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/entry_points.txt +2 -0
  28. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/requires.txt +17 -0
  29. mdbook_binder-0.1.0/src/mdbook_binder.egg-info/top_level.txt +1 -0
  30. mdbook_binder-0.1.0/tests/test_check.py +51 -0
  31. mdbook_binder-0.1.0/tests/test_html_book.py +54 -0
  32. mdbook_binder-0.1.0/tests/test_manifest.py +75 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sungwoo Kim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,329 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdbook-binder
3
+ Version: 0.1.0
4
+ Summary: 임의의 마크다운 코퍼스를 검색 가능한 단일 HTML 도서와 PDF(단권/병합)로 변환하고, 결과 HTML을 편집하는 범용 애플리케이션
5
+ Author-email: Sungwoo Kim <sungwoo.kim@gmail.com>
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: markdown>=3.5
11
+ Requires-Dist: beautifulsoup4>=4.12
12
+ Requires-Dist: markdownify>=0.11
13
+ Requires-Dist: pyyaml>=6.0
14
+ Requires-Dist: click>=8.1
15
+ Provides-Extra: pdf
16
+ Requires-Dist: playwright>=1.40; extra == "pdf"
17
+ Requires-Dist: pypdf>=4.0; extra == "pdf"
18
+ Provides-Extra: editor
19
+ Requires-Dist: flask>=3.0; extra == "editor"
20
+ Requires-Dist: pillow>=10.0; extra == "editor"
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8.0; extra == "dev"
23
+ Requires-Dist: ruff>=0.4; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # Book-binder
27
+
28
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
29
+
30
+ **임의의 마크다운 코퍼스를 검색 가능한 단일 HTML 도서와 PDF(단권/병합)로 변환하고,
31
+ 결과 HTML을 편집하는 범용 애플리케이션.**
32
+
33
+ ---
34
+
35
+ ## 목차
36
+
37
+ - [1. 프로젝트 개요](#1-프로젝트-개요)
38
+ - [왜 만들었나](#왜-만들었나)
39
+ - [아키텍처](#아키텍처)
40
+ - [설계 원칙](#설계-원칙)
41
+ - [파일 구조](#파일-구조)
42
+ - [2. 핵심 기능 및 사용법](#2-핵심-기능-및-사용법)
43
+ - [순서 해석 — 3단계 우선순위](#순서-해석--3단계-우선순위)
44
+ - [book.yaml 설정](#bookyaml-설정)
45
+ - [빌드 전 사전 점검 — check](#빌드-전-사전-점검--check)
46
+ - [HTML 도서 빌드](#html-도서-빌드)
47
+ - [PDF 빌드 — 개별/병합](#pdf-빌드--개별병합)
48
+ - [HTML 편집](#html-편집)
49
+ - [3. 설치 가이드](#3-설치-가이드)
50
+ - [알려진 한계](#알려진-한계)
51
+ - [라이선스](#라이선스)
52
+
53
+ ---
54
+
55
+ ## 1. 프로젝트 개요
56
+
57
+ ### 왜 만들었나
58
+
59
+ `Book_forge/Book`, `Agent-Evaluator/Media/Book`, `Agent-Evaluator/Media/AOO` 세
60
+ 프로젝트에 각각 `build_book.py`/`build_pdf_chapters.py`(총 ~5,600줄)가 따로
61
+ 존재했다 — 전부 같은 조상에서 복붙된 뒤 서로 다르게 갈라진 **사실상 동일한
62
+ 엔진의 사본**이었다. 목차 정의는 책마다 손으로 유지하는 Python 리스트였고,
63
+ 이미지 임베드 방식·콜아웃 인식 규칙도 세 곳이 미묘하게 달랐다.
64
+
65
+ Book-binder는 이 엔진을 한 곳으로 뽑아낸 **독립 애플리케이션**이다. 세 프로젝트
66
+ 중 어느 하나도 이 빌드 엔진을 소유하지 않고, 전부 이 패키지를 의존성으로
67
+ 참조한다. 목표는 세 가지였다.
68
+
69
+ 1. 마크다운 문서를 HTML 도서·PDF 도서로 만드는 **일반화된** 애플리케이션 —
70
+ 새 마크다운 파일이 추가돼도 코드 수정 없이 반영되어야 한다.
71
+ 2. HTML 도서는 이미지·다이어그램을 바이너리(base64)로 포함해 검색이 가능해야
72
+ 하고, PDF는 단권 또는 병합(merge)을 지원해야 한다.
73
+ 3. 생성된 HTML 도서는 (Lecture_forge의 `edit_book.py` 기반) 편집이 가능해야
74
+ 한다.
75
+
76
+ ### 아키텍처
77
+
78
+ ```mermaid
79
+ flowchart TD
80
+ A["마크다운 코퍼스\n(임의의 디렉토리)"] --> B["manifest.py\nBookConfig(book.yaml) + resolve()\n3단계 순서 해석"]
81
+ B --> C["render.py\nmd_to_html / demote_headings\n(콜아웃·로케일 config 주입)"]
82
+ C --> D["html_book.py\n사이드바 · 검색 · base64 이미지\n섹션 id 충돌 자동 회피"]
83
+ C --> E["pdf_book.py\nPlaywright 청크 캡처\n개별 PDF / --merge 단권"]
84
+ D --> F["editor/\nLectureHTMLEditor·ImageEditor 포크\n(lecture-forge 비의존)"]
85
+ G["check.py\n빌드 전 사전 점검"] -.-> B
86
+
87
+ style D fill:#4527a0,color:#fff
88
+ style E fill:#00897b,color:#fff
89
+ style F fill:#5e35b1,color:#fff
90
+ ```
91
+
92
+ `html_book.py`가 출력하는 `<section class="chapter-section" id="{slug}">`
93
+ 구조는 `editor/`가 의존하는 **유일한 불변 계약**이다 — 다른 무엇을 바꾸더라도
94
+ 이 마크업 계약은 유지해야 편집기가 섹션을 인식한다.
95
+
96
+ ### 설계 원칙
97
+
98
+ 1. **순서 해석은 3단계 우선순위**로 자동 결정된다 — 코드 수정 없이 새
99
+ 마크다운 파일이 반영되도록 하는 것이 핵심 목표다.
100
+ 1. 명시적 `book.yaml`(`order.manifest` 또는 `order.files`)
101
+ 2. `book.yaml`이 없어도 루트에 ` ```toc ` 펜스 매니페스트(Book-forge 목차
102
+ 포맷)가 있으면 자동 채택
103
+ 3. `Part_<로마숫자>_.../Chapter_<NN>_...` 명명 규칙 감지
104
+ 4. 위 전부 실패 시 디렉토리 트리 전체를 자연정렬(natural sort)해 전부
105
+ 포함 — "새 파일이 조용히 누락되는 일"을 구조적으로 없애는 최종 폴백
106
+ 2. **책마다 다른 값(제목/저자/언어/제외 패턴/콜아웃 마커/커스텀 CSS)은 전부
107
+ `book.yaml`로 외부화** — 렌더링 엔진(`render.py`) 코드는 어떤 코퍼스에도
108
+ 수정 없이 동작해야 한다.
109
+ 3. **섹션 ID는 기본적으로 H1/파일명 slug 자동 생성**, 충돌 시 자동으로
110
+ `-2`/`-3` 접미사를 붙인다 — 수작업 매핑 테이블은 "예쁜 URL을 원할 때만
111
+ 쓰는 선택적 오버라이드"로 격하한다.
112
+ 4. **편집기는 lecture-forge에 비의존** — `Lecture_forge`의
113
+ `LectureHTMLEditor`/`ImageEditor`를 포크하되 벡터스토어 기반 이미지 추천
114
+ 등 강의 특화 기능은 제외했다.
115
+
116
+ ### 파일 구조
117
+
118
+ ```
119
+ Book_binder/
120
+ ├── pyproject.toml
121
+ ├── LICENSE
122
+ ├── README.md
123
+ ├── src/book_binder/
124
+ │ ├── manifest.py # BookConfig(book.yaml) + resolve()/resolve_verbose()
125
+ │ ├── render.py # md_to_html / demote_headings / 콜아웃·로케일
126
+ │ ├── html_book.py # HTML 도서 빌더 (사이드바/검색/base64 이미지)
127
+ │ ├── pdf_book.py # PDF 빌더 (청크 캡처 + 개별/병합)
128
+ │ ├── check.py # 빌드 전 사전 점검
129
+ │ ├── cli.py # book-binder CLI (check/build html/build pdf/edit)
130
+ │ ├── editor/ # Lecture_forge 포크 — lecture-forge 비의존
131
+ │ │ ├── html_editor.py # BookHTMLEditor — 섹션 CRUD
132
+ │ │ ├── image_editor.py # 이미지/다이어그램 편집
133
+ │ │ └── server.py # Flask 편집 API 서버
134
+ │ └── templates/
135
+ │ ├── html_book.css/js # HTML 도서 사이드바·검색·mermaid
136
+ │ ├── pdf_override.css/js # PDF 전용 레이아웃 오버라이드
137
+ │ └── editor/ # 편집 SPA (index.html/editor.css/editor.js)
138
+ └── tests/
139
+ ├── test_manifest.py # 3단계 순서 해석 (5건)
140
+ ├── test_html_book.py # 섹션 id 충돌 회피·이미지 임베드 (3건)
141
+ └── test_check.py # 사전 점검 (4건)
142
+ ```
143
+
144
+ ---
145
+
146
+ ## 2. 핵심 기능 및 사용법
147
+
148
+ ### 순서 해석 — 3단계 우선순위
149
+
150
+ 명령은 코퍼스가 무엇이든 동일하다(`book-binder build html <root>`) — 코퍼스가
151
+ 이미 가진 정보(매니페스트/명명 규칙)에 따라 내부적으로 다른 우선순위가 자동
152
+ 선택된다.
153
+
154
+ ```bash
155
+ # book.yaml도, 매니페스트도, Part/Chapter 명명 규칙도 없는 새 폴더
156
+ book-binder build html ~/Docs/my-notes
157
+ # → 3순위(자연정렬)가 자동 적용, 최소한 파일이 빠지는 일은 없다
158
+ ```
159
+
160
+ ### book.yaml 설정
161
+
162
+ 코퍼스 루트에 선택적으로 둔다 — 없어도 전부 기본값/자동 감지로 동작한다.
163
+
164
+ ```yaml
165
+ title: "실전 AI 에이전트 하네스 엔지니어링"
166
+ author: "Sungwoo Kim"
167
+ language: ko # ko/en — 검색 UI 문자열 로케일
168
+
169
+ order: # 1순위 — 있으면 이걸로 순서 확정
170
+ files: [00_서문.md, Part_I_.../Chapter_01_*.md, ...]
171
+ # 또는: manifest: 01_목차.md ( ```toc 펜스 매니페스트 파일 지정 )
172
+
173
+ exclude: # 챕터가 아닌 문서 제외 (glob 패턴)
174
+ - "README.md"
175
+ - "IMAGES.md"
176
+
177
+ callouts:
178
+ tip_markers: ["👨‍💻", "📋", "📊", "🔧", "🚨", "💡"] # 없으면 전부 blockquote로 렌더
179
+
180
+ section_id_overrides: # 파일 stem → 원하는 URL slug (선택)
181
+ "Chapter_01_서론": "intro"
182
+
183
+ custom_css: custom.css # 코퍼스 루트 기준 상대 경로 (선택)
184
+ # 코퍼스별 raw-HTML 다이어그램(@@HTML_START@@ 블록)이
185
+ # 쓰는 커스텀 클래스는 범용 템플릿에 넣을 수 없으므로,
186
+ # 여기 지정한 CSS 파일 내용을 HTML/PDF 빌드 모두에 그대로 얹는다.
187
+ ```
188
+
189
+ ### 빌드 전 사전 점검 — check
190
+
191
+ 실제로 HTML을 렌더링하지 않고 원본 마크다운만 훑어 빠르게 확인한다 — 챕터가
192
+ 아닌 문서(예: 집필 가이드 `.md`)가 잘못 포함되는 것을 빌드 후에야 발견하는
193
+ 일을 줄인다.
194
+
195
+ ```bash
196
+ book-binder check ~/Docs/my-book
197
+ ```
198
+
199
+ ```
200
+ 순서 해석: 2순위: Part/Chapter 명명 규칙 감지
201
+ 챕터 수: 44개
202
+
203
+ [Part I]
204
+ - Part_I_기초/Chapter_01_...md
205
+ ...
206
+
207
+ ⚠️ 같은 제목을 쓰는 챕터 1건 (빌드 시 id에 -2, -3... 자동 부여됨):
208
+ - "개요": Part_I_.../Chapter_01_x.md, Part_II_.../Chapter_01_y.md
209
+ ```
210
+
211
+ ### HTML 도서 빌드
212
+
213
+ ```bash
214
+ book-binder build html <코퍼스_루트> [--out out.html] [--title ...] [--language ko|en]
215
+ ```
216
+
217
+ - 이미지를 base64 data URI로 인라인 임베드 — 이미지 폴더 없이도 단일 파일로
218
+ 완전히 독립적으로 열린다(다른 PC로 옮기거나 이메일 첨부해도 그대로 열림).
219
+ - 인페이지 전문 검색(하이라이트·이전/다음 이동), Mermaid 다이어그램 렌더링,
220
+ 사이드바 목차 자동 생성.
221
+ - 서로 다른 Part의 챕터 제목이 우연히 같아도(예: "개요") 섹션 id 충돌을
222
+ 자동으로 회피한다.
223
+ - 빌드 끝에 누락된 이미지 참조를 한 번에 모아 요약 출력한다.
224
+
225
+ ### PDF 빌드 — 개별/병합
226
+
227
+ ```bash
228
+ book-binder build pdf <코퍼스_루트> # 챕터별 개별 A4 PDF
229
+ book-binder build pdf <코퍼스_루트> --merge [이름] # 단권으로 병합
230
+ book-binder build pdf <코퍼스_루트> --out-dir <디렉토리> # 출력 위치 지정
231
+ ```
232
+
233
+ 각 챕터를 Playwright/Chromium으로 독립 렌더링한다. 긴 Mermaid 다이어그램은
234
+ 청크 단위로 스크린샷 캡처해 삽입해 페이지 경계에서 잘리는 문제를 피한다.
235
+ 병합도 각 챕터를 동일한 코드 경로로 개별 렌더링한 뒤 pypdf로 PDF 객체
236
+ 레벨에서 합쳐, 개별 생성과 병합 생성의 폰트 크기·다이어그램 해상도가 항상
237
+ 동일하다.
238
+
239
+ ### HTML 편집
240
+
241
+ ```bash
242
+ book-binder edit <html_경로> [--port 5757] [--out edited.html] [--no-browser]
243
+ ```
244
+
245
+ 브라우저에서 섹션 단위로 마크다운 편집(EasyMDE), 이미지/다이어그램 목록·삭제·
246
+ 교체, 이미지 업로드/갤러리를 제공한다. `<section id="{slug}">` 구조에만
247
+ 의존하므로 어떤 코퍼스로 만든 HTML이든 동일하게 동작한다.
248
+
249
+ ---
250
+
251
+ ## 3. 설치 가이드
252
+
253
+ Book-binder는 아직 PyPI에 배포되지 않았다 — 저장소를 직접 받아 설치한다.
254
+
255
+ ### 사전 준비
256
+
257
+ - **Python 3.11 이상**
258
+ - **PDF 빌드(`[pdf]` extra)를 쓸 경우**: Playwright Chromium의 런타임 공유
259
+ 라이브러리가 필요하다. `python -m playwright install --with-deps chromium`
260
+ 하나로 브라우저와 OS 의존성을 한 번에 설치하는 것을 권장한다. 리눅스에서
261
+ `--with-deps`를 못 쓰는 제한된 환경이라면 Ubuntu 22.04/24.04 기준 아래
262
+ 패키지가 대략 필요하다(버전에 따라 패키지명이 다를 수 있어 참고용):
263
+
264
+ ```bash
265
+ sudo apt install -y \
266
+ libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
267
+ libdrm2 libdbus-1-3 libxcb1 libxkbcommon0 libx11-6 \
268
+ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 \
269
+ libgbm1 libpango-1.0-0 libcairo2 libasound2
270
+ ```
271
+
272
+ macOS는 별도 시스템 패키지 없이 `playwright install chromium`만으로 충분하다.
273
+
274
+ ### 설치
275
+
276
+ ```bash
277
+ git clone git@github.com:bullpeng72/book-binder.git
278
+ cd book-binder
279
+ python3 -m venv .venv && source .venv/bin/activate
280
+
281
+ pip install -e . # 코어만 — HTML 빌드/check/편집(수동 조합)
282
+ pip install -e ".[pdf]" # + Playwright/pypdf (PDF 빌드용)
283
+ pip install -e ".[editor]" # + Flask/Pillow (웹 편집기용)
284
+ pip install -e ".[dev]" # + pytest/ruff (개발용)
285
+ pip install -e ".[pdf,editor,dev]" # 전체 기능
286
+
287
+ python -m playwright install --with-deps chromium # [pdf] 설치 시 1회
288
+ ```
289
+
290
+ ### 빠른 시작
291
+
292
+ ```bash
293
+ book-binder check ~/Docs/my-book # 1. 빌드 전 사전 점검
294
+ book-binder build html ~/Docs/my-book --out out.html # 2. HTML 도서 빌드
295
+ book-binder edit out.html # 3. 브라우저에서 편집
296
+ book-binder build pdf ~/Docs/my-book --merge # 4. (선택) 단권 PDF
297
+ ```
298
+
299
+ ### 개발
300
+
301
+ ```bash
302
+ pip install -e ".[dev,pdf,editor]"
303
+ pytest tests/ -q # 12개 테스트 (manifest 5 + html_book 3 + check 4)
304
+ ruff check src tests
305
+ ```
306
+
307
+ ---
308
+
309
+ ## 알려진 한계
310
+
311
+ - **PDF/HTML 부분 빌드 미지원**: 원본 `build_pdf_chapters.py`가 갖고 있던
312
+ "파일/패턴 지정 부분 변환"은 아직 이식하지 않았다 — 항상 코퍼스 전체를
313
+ 대상으로 빌드한다.
314
+ - **마크다운 스캐폴딩(정형 스텁 생성) 미포함**: 의도적으로 범위에서 제외했다
315
+ (Book-forge 자체 저작 파이프라인과 중복 방지 목적) — 새 챕터 파일은 손으로
316
+ 작성해야 한다.
317
+ - **`Part_<로마숫자>_...` 명명 규칙 감지(2순위)는 `Appendix/`만 특별 취급**:
318
+ 그 외 비-Part 디렉토리는 3순위 자연정렬로만 잡힌다 — 필요하면 `book.yaml`의
319
+ `order.files`로 명시하는 게 안전하다.
320
+ - **`pdf_book.py`/`editor/`는 자동화된 회귀 테스트가 없다**: 실제 코퍼스로
321
+ 수동 검증(Flask test client, Playwright 실제 렌더링)은 마쳤지만
322
+ `manifest.py`/`html_book.py`/`check.py`만큼 pytest로 고정돼 있지는 않다.
323
+ - **PyPI 미배포**: 현재는 git clone + 로컬 편집 가능 설치만 지원한다.
324
+
325
+ ---
326
+
327
+ ## 라이선스
328
+
329
+ MIT — [LICENSE](LICENSE) 참고.
@@ -0,0 +1,304 @@
1
+ # Book-binder
2
+
3
+ [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
4
+
5
+ **임의의 마크다운 코퍼스를 검색 가능한 단일 HTML 도서와 PDF(단권/병합)로 변환하고,
6
+ 결과 HTML을 편집하는 범용 애플리케이션.**
7
+
8
+ ---
9
+
10
+ ## 목차
11
+
12
+ - [1. 프로젝트 개요](#1-프로젝트-개요)
13
+ - [왜 만들었나](#왜-만들었나)
14
+ - [아키텍처](#아키텍처)
15
+ - [설계 원칙](#설계-원칙)
16
+ - [파일 구조](#파일-구조)
17
+ - [2. 핵심 기능 및 사용법](#2-핵심-기능-및-사용법)
18
+ - [순서 해석 — 3단계 우선순위](#순서-해석--3단계-우선순위)
19
+ - [book.yaml 설정](#bookyaml-설정)
20
+ - [빌드 전 사전 점검 — check](#빌드-전-사전-점검--check)
21
+ - [HTML 도서 빌드](#html-도서-빌드)
22
+ - [PDF 빌드 — 개별/병합](#pdf-빌드--개별병합)
23
+ - [HTML 편집](#html-편집)
24
+ - [3. 설치 가이드](#3-설치-가이드)
25
+ - [알려진 한계](#알려진-한계)
26
+ - [라이선스](#라이선스)
27
+
28
+ ---
29
+
30
+ ## 1. 프로젝트 개요
31
+
32
+ ### 왜 만들었나
33
+
34
+ `Book_forge/Book`, `Agent-Evaluator/Media/Book`, `Agent-Evaluator/Media/AOO` 세
35
+ 프로젝트에 각각 `build_book.py`/`build_pdf_chapters.py`(총 ~5,600줄)가 따로
36
+ 존재했다 — 전부 같은 조상에서 복붙된 뒤 서로 다르게 갈라진 **사실상 동일한
37
+ 엔진의 사본**이었다. 목차 정의는 책마다 손으로 유지하는 Python 리스트였고,
38
+ 이미지 임베드 방식·콜아웃 인식 규칙도 세 곳이 미묘하게 달랐다.
39
+
40
+ Book-binder는 이 엔진을 한 곳으로 뽑아낸 **독립 애플리케이션**이다. 세 프로젝트
41
+ 중 어느 하나도 이 빌드 엔진을 소유하지 않고, 전부 이 패키지를 의존성으로
42
+ 참조한다. 목표는 세 가지였다.
43
+
44
+ 1. 마크다운 문서를 HTML 도서·PDF 도서로 만드는 **일반화된** 애플리케이션 —
45
+ 새 마크다운 파일이 추가돼도 코드 수정 없이 반영되어야 한다.
46
+ 2. HTML 도서는 이미지·다이어그램을 바이너리(base64)로 포함해 검색이 가능해야
47
+ 하고, PDF는 단권 또는 병합(merge)을 지원해야 한다.
48
+ 3. 생성된 HTML 도서는 (Lecture_forge의 `edit_book.py` 기반) 편집이 가능해야
49
+ 한다.
50
+
51
+ ### 아키텍처
52
+
53
+ ```mermaid
54
+ flowchart TD
55
+ A["마크다운 코퍼스\n(임의의 디렉토리)"] --> B["manifest.py\nBookConfig(book.yaml) + resolve()\n3단계 순서 해석"]
56
+ B --> C["render.py\nmd_to_html / demote_headings\n(콜아웃·로케일 config 주입)"]
57
+ C --> D["html_book.py\n사이드바 · 검색 · base64 이미지\n섹션 id 충돌 자동 회피"]
58
+ C --> E["pdf_book.py\nPlaywright 청크 캡처\n개별 PDF / --merge 단권"]
59
+ D --> F["editor/\nLectureHTMLEditor·ImageEditor 포크\n(lecture-forge 비의존)"]
60
+ G["check.py\n빌드 전 사전 점검"] -.-> B
61
+
62
+ style D fill:#4527a0,color:#fff
63
+ style E fill:#00897b,color:#fff
64
+ style F fill:#5e35b1,color:#fff
65
+ ```
66
+
67
+ `html_book.py`가 출력하는 `<section class="chapter-section" id="{slug}">`
68
+ 구조는 `editor/`가 의존하는 **유일한 불변 계약**이다 — 다른 무엇을 바꾸더라도
69
+ 이 마크업 계약은 유지해야 편집기가 섹션을 인식한다.
70
+
71
+ ### 설계 원칙
72
+
73
+ 1. **순서 해석은 3단계 우선순위**로 자동 결정된다 — 코드 수정 없이 새
74
+ 마크다운 파일이 반영되도록 하는 것이 핵심 목표다.
75
+ 1. 명시적 `book.yaml`(`order.manifest` 또는 `order.files`)
76
+ 2. `book.yaml`이 없어도 루트에 ` ```toc ` 펜스 매니페스트(Book-forge 목차
77
+ 포맷)가 있으면 자동 채택
78
+ 3. `Part_<로마숫자>_.../Chapter_<NN>_...` 명명 규칙 감지
79
+ 4. 위 전부 실패 시 디렉토리 트리 전체를 자연정렬(natural sort)해 전부
80
+ 포함 — "새 파일이 조용히 누락되는 일"을 구조적으로 없애는 최종 폴백
81
+ 2. **책마다 다른 값(제목/저자/언어/제외 패턴/콜아웃 마커/커스텀 CSS)은 전부
82
+ `book.yaml`로 외부화** — 렌더링 엔진(`render.py`) 코드는 어떤 코퍼스에도
83
+ 수정 없이 동작해야 한다.
84
+ 3. **섹션 ID는 기본적으로 H1/파일명 slug 자동 생성**, 충돌 시 자동으로
85
+ `-2`/`-3` 접미사를 붙인다 — 수작업 매핑 테이블은 "예쁜 URL을 원할 때만
86
+ 쓰는 선택적 오버라이드"로 격하한다.
87
+ 4. **편집기는 lecture-forge에 비의존** — `Lecture_forge`의
88
+ `LectureHTMLEditor`/`ImageEditor`를 포크하되 벡터스토어 기반 이미지 추천
89
+ 등 강의 특화 기능은 제외했다.
90
+
91
+ ### 파일 구조
92
+
93
+ ```
94
+ Book_binder/
95
+ ├── pyproject.toml
96
+ ├── LICENSE
97
+ ├── README.md
98
+ ├── src/book_binder/
99
+ │ ├── manifest.py # BookConfig(book.yaml) + resolve()/resolve_verbose()
100
+ │ ├── render.py # md_to_html / demote_headings / 콜아웃·로케일
101
+ │ ├── html_book.py # HTML 도서 빌더 (사이드바/검색/base64 이미지)
102
+ │ ├── pdf_book.py # PDF 빌더 (청크 캡처 + 개별/병합)
103
+ │ ├── check.py # 빌드 전 사전 점검
104
+ │ ├── cli.py # book-binder CLI (check/build html/build pdf/edit)
105
+ │ ├── editor/ # Lecture_forge 포크 — lecture-forge 비의존
106
+ │ │ ├── html_editor.py # BookHTMLEditor — 섹션 CRUD
107
+ │ │ ├── image_editor.py # 이미지/다이어그램 편집
108
+ │ │ └── server.py # Flask 편집 API 서버
109
+ │ └── templates/
110
+ │ ├── html_book.css/js # HTML 도서 사이드바·검색·mermaid
111
+ │ ├── pdf_override.css/js # PDF 전용 레이아웃 오버라이드
112
+ │ └── editor/ # 편집 SPA (index.html/editor.css/editor.js)
113
+ └── tests/
114
+ ├── test_manifest.py # 3단계 순서 해석 (5건)
115
+ ├── test_html_book.py # 섹션 id 충돌 회피·이미지 임베드 (3건)
116
+ └── test_check.py # 사전 점검 (4건)
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 2. 핵심 기능 및 사용법
122
+
123
+ ### 순서 해석 — 3단계 우선순위
124
+
125
+ 명령은 코퍼스가 무엇이든 동일하다(`book-binder build html <root>`) — 코퍼스가
126
+ 이미 가진 정보(매니페스트/명명 규칙)에 따라 내부적으로 다른 우선순위가 자동
127
+ 선택된다.
128
+
129
+ ```bash
130
+ # book.yaml도, 매니페스트도, Part/Chapter 명명 규칙도 없는 새 폴더
131
+ book-binder build html ~/Docs/my-notes
132
+ # → 3순위(자연정렬)가 자동 적용, 최소한 파일이 빠지는 일은 없다
133
+ ```
134
+
135
+ ### book.yaml 설정
136
+
137
+ 코퍼스 루트에 선택적으로 둔다 — 없어도 전부 기본값/자동 감지로 동작한다.
138
+
139
+ ```yaml
140
+ title: "실전 AI 에이전트 하네스 엔지니어링"
141
+ author: "Sungwoo Kim"
142
+ language: ko # ko/en — 검색 UI 문자열 로케일
143
+
144
+ order: # 1순위 — 있으면 이걸로 순서 확정
145
+ files: [00_서문.md, Part_I_.../Chapter_01_*.md, ...]
146
+ # 또는: manifest: 01_목차.md ( ```toc 펜스 매니페스트 파일 지정 )
147
+
148
+ exclude: # 챕터가 아닌 문서 제외 (glob 패턴)
149
+ - "README.md"
150
+ - "IMAGES.md"
151
+
152
+ callouts:
153
+ tip_markers: ["👨‍💻", "📋", "📊", "🔧", "🚨", "💡"] # 없으면 전부 blockquote로 렌더
154
+
155
+ section_id_overrides: # 파일 stem → 원하는 URL slug (선택)
156
+ "Chapter_01_서론": "intro"
157
+
158
+ custom_css: custom.css # 코퍼스 루트 기준 상대 경로 (선택)
159
+ # 코퍼스별 raw-HTML 다이어그램(@@HTML_START@@ 블록)이
160
+ # 쓰는 커스텀 클래스는 범용 템플릿에 넣을 수 없으므로,
161
+ # 여기 지정한 CSS 파일 내용을 HTML/PDF 빌드 모두에 그대로 얹는다.
162
+ ```
163
+
164
+ ### 빌드 전 사전 점검 — check
165
+
166
+ 실제로 HTML을 렌더링하지 않고 원본 마크다운만 훑어 빠르게 확인한다 — 챕터가
167
+ 아닌 문서(예: 집필 가이드 `.md`)가 잘못 포함되는 것을 빌드 후에야 발견하는
168
+ 일을 줄인다.
169
+
170
+ ```bash
171
+ book-binder check ~/Docs/my-book
172
+ ```
173
+
174
+ ```
175
+ 순서 해석: 2순위: Part/Chapter 명명 규칙 감지
176
+ 챕터 수: 44개
177
+
178
+ [Part I]
179
+ - Part_I_기초/Chapter_01_...md
180
+ ...
181
+
182
+ ⚠️ 같은 제목을 쓰는 챕터 1건 (빌드 시 id에 -2, -3... 자동 부여됨):
183
+ - "개요": Part_I_.../Chapter_01_x.md, Part_II_.../Chapter_01_y.md
184
+ ```
185
+
186
+ ### HTML 도서 빌드
187
+
188
+ ```bash
189
+ book-binder build html <코퍼스_루트> [--out out.html] [--title ...] [--language ko|en]
190
+ ```
191
+
192
+ - 이미지를 base64 data URI로 인라인 임베드 — 이미지 폴더 없이도 단일 파일로
193
+ 완전히 독립적으로 열린다(다른 PC로 옮기거나 이메일 첨부해도 그대로 열림).
194
+ - 인페이지 전문 검색(하이라이트·이전/다음 이동), Mermaid 다이어그램 렌더링,
195
+ 사이드바 목차 자동 생성.
196
+ - 서로 다른 Part의 챕터 제목이 우연히 같아도(예: "개요") 섹션 id 충돌을
197
+ 자동으로 회피한다.
198
+ - 빌드 끝에 누락된 이미지 참조를 한 번에 모아 요약 출력한다.
199
+
200
+ ### PDF 빌드 — 개별/병합
201
+
202
+ ```bash
203
+ book-binder build pdf <코퍼스_루트> # 챕터별 개별 A4 PDF
204
+ book-binder build pdf <코퍼스_루트> --merge [이름] # 단권으로 병합
205
+ book-binder build pdf <코퍼스_루트> --out-dir <디렉토리> # 출력 위치 지정
206
+ ```
207
+
208
+ 각 챕터를 Playwright/Chromium으로 독립 렌더링한다. 긴 Mermaid 다이어그램은
209
+ 청크 단위로 스크린샷 캡처해 삽입해 페이지 경계에서 잘리는 문제를 피한다.
210
+ 병합도 각 챕터를 동일한 코드 경로로 개별 렌더링한 뒤 pypdf로 PDF 객체
211
+ 레벨에서 합쳐, 개별 생성과 병합 생성의 폰트 크기·다이어그램 해상도가 항상
212
+ 동일하다.
213
+
214
+ ### HTML 편집
215
+
216
+ ```bash
217
+ book-binder edit <html_경로> [--port 5757] [--out edited.html] [--no-browser]
218
+ ```
219
+
220
+ 브라우저에서 섹션 단위로 마크다운 편집(EasyMDE), 이미지/다이어그램 목록·삭제·
221
+ 교체, 이미지 업로드/갤러리를 제공한다. `<section id="{slug}">` 구조에만
222
+ 의존하므로 어떤 코퍼스로 만든 HTML이든 동일하게 동작한다.
223
+
224
+ ---
225
+
226
+ ## 3. 설치 가이드
227
+
228
+ Book-binder는 아직 PyPI에 배포되지 않았다 — 저장소를 직접 받아 설치한다.
229
+
230
+ ### 사전 준비
231
+
232
+ - **Python 3.11 이상**
233
+ - **PDF 빌드(`[pdf]` extra)를 쓸 경우**: Playwright Chromium의 런타임 공유
234
+ 라이브러리가 필요하다. `python -m playwright install --with-deps chromium`
235
+ 하나로 브라우저와 OS 의존성을 한 번에 설치하는 것을 권장한다. 리눅스에서
236
+ `--with-deps`를 못 쓰는 제한된 환경이라면 Ubuntu 22.04/24.04 기준 아래
237
+ 패키지가 대략 필요하다(버전에 따라 패키지명이 다를 수 있어 참고용):
238
+
239
+ ```bash
240
+ sudo apt install -y \
241
+ libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
242
+ libdrm2 libdbus-1-3 libxcb1 libxkbcommon0 libx11-6 \
243
+ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 \
244
+ libgbm1 libpango-1.0-0 libcairo2 libasound2
245
+ ```
246
+
247
+ macOS는 별도 시스템 패키지 없이 `playwright install chromium`만으로 충분하다.
248
+
249
+ ### 설치
250
+
251
+ ```bash
252
+ git clone git@github.com:bullpeng72/book-binder.git
253
+ cd book-binder
254
+ python3 -m venv .venv && source .venv/bin/activate
255
+
256
+ pip install -e . # 코어만 — HTML 빌드/check/편집(수동 조합)
257
+ pip install -e ".[pdf]" # + Playwright/pypdf (PDF 빌드용)
258
+ pip install -e ".[editor]" # + Flask/Pillow (웹 편집기용)
259
+ pip install -e ".[dev]" # + pytest/ruff (개발용)
260
+ pip install -e ".[pdf,editor,dev]" # 전체 기능
261
+
262
+ python -m playwright install --with-deps chromium # [pdf] 설치 시 1회
263
+ ```
264
+
265
+ ### 빠른 시작
266
+
267
+ ```bash
268
+ book-binder check ~/Docs/my-book # 1. 빌드 전 사전 점검
269
+ book-binder build html ~/Docs/my-book --out out.html # 2. HTML 도서 빌드
270
+ book-binder edit out.html # 3. 브라우저에서 편집
271
+ book-binder build pdf ~/Docs/my-book --merge # 4. (선택) 단권 PDF
272
+ ```
273
+
274
+ ### 개발
275
+
276
+ ```bash
277
+ pip install -e ".[dev,pdf,editor]"
278
+ pytest tests/ -q # 12개 테스트 (manifest 5 + html_book 3 + check 4)
279
+ ruff check src tests
280
+ ```
281
+
282
+ ---
283
+
284
+ ## 알려진 한계
285
+
286
+ - **PDF/HTML 부분 빌드 미지원**: 원본 `build_pdf_chapters.py`가 갖고 있던
287
+ "파일/패턴 지정 부분 변환"은 아직 이식하지 않았다 — 항상 코퍼스 전체를
288
+ 대상으로 빌드한다.
289
+ - **마크다운 스캐폴딩(정형 스텁 생성) 미포함**: 의도적으로 범위에서 제외했다
290
+ (Book-forge 자체 저작 파이프라인과 중복 방지 목적) — 새 챕터 파일은 손으로
291
+ 작성해야 한다.
292
+ - **`Part_<로마숫자>_...` 명명 규칙 감지(2순위)는 `Appendix/`만 특별 취급**:
293
+ 그 외 비-Part 디렉토리는 3순위 자연정렬로만 잡힌다 — 필요하면 `book.yaml`의
294
+ `order.files`로 명시하는 게 안전하다.
295
+ - **`pdf_book.py`/`editor/`는 자동화된 회귀 테스트가 없다**: 실제 코퍼스로
296
+ 수동 검증(Flask test client, Playwright 실제 렌더링)은 마쳤지만
297
+ `manifest.py`/`html_book.py`/`check.py`만큼 pytest로 고정돼 있지는 않다.
298
+ - **PyPI 미배포**: 현재는 git clone + 로컬 편집 가능 설치만 지원한다.
299
+
300
+ ---
301
+
302
+ ## 라이선스
303
+
304
+ MIT — [LICENSE](LICENSE) 참고.