kordoc 4.15.5 → 4.15.7

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 (139) hide show
  1. package/README.md +82 -1
  2. package/dist/{-PQUI4OJT.js → -H6WNRHK6.js} +11 -11
  3. package/dist/{chunk-3TZ63JNS.cjs → chunk-4ANWGSUT.cjs} +817 -143
  4. package/dist/chunk-4ANWGSUT.cjs.map +1 -0
  5. package/dist/{chunk-B3YQ5QED.js → chunk-6ULM2YCN.js} +57 -9
  6. package/dist/{chunk-B3YQ5QED.js.map → chunk-6ULM2YCN.js.map} +1 -1
  7. package/dist/{chunk-VUO5LNN4.js → chunk-AWXXLLIG.js} +2 -2
  8. package/dist/{chunk-FWOCNMXB.js → chunk-C572DIHX.js} +17 -7
  9. package/dist/chunk-C572DIHX.js.map +1 -0
  10. package/dist/{chunk-JPIHOEAS.js → chunk-F5FHYJKJ.js} +8 -2
  11. package/dist/{chunk-JPIHOEAS.js.map → chunk-F5FHYJKJ.js.map} +1 -1
  12. package/dist/{chunk-JQ74UURE.js → chunk-IHCQ4IE7.js} +2 -2
  13. package/dist/{chunk-VEYIBWBB.cjs → chunk-J6ZU7AIR.cjs} +9 -3
  14. package/dist/chunk-J6ZU7AIR.cjs.map +1 -0
  15. package/dist/{chunk-NHPF6QDB.js → chunk-KJSD2WNF.js} +2 -2
  16. package/dist/{chunk-LHDPC4B2.js → chunk-L5MDTA6T.js} +2 -2
  17. package/dist/{chunk-3PDCVDSO.js → chunk-NVG2GQNA.js} +1 -1
  18. package/dist/chunk-NVG2GQNA.js.map +1 -0
  19. package/dist/{chunk-KSZEQL2D.js → chunk-NZMPU24H.js} +42 -47
  20. package/dist/chunk-NZMPU24H.js.map +1 -0
  21. package/dist/{chunk-4G5RVBH4.js → chunk-O5SDUPB2.js} +5 -4
  22. package/dist/chunk-O5SDUPB2.js.map +1 -0
  23. package/dist/{chunk-DQZOA66I.cjs → chunk-OE6XLTMC.cjs} +54 -59
  24. package/dist/chunk-OE6XLTMC.cjs.map +1 -0
  25. package/dist/{chunk-OAZ5VSWD.js → chunk-ORMMGTNK.js} +2 -2
  26. package/dist/{chunk-SW7NE36W.cjs → chunk-R45AG5K6.cjs} +3 -3
  27. package/dist/{chunk-SW7NE36W.cjs.map → chunk-R45AG5K6.cjs.map} +1 -1
  28. package/dist/{chunk-LUXORVFU.js → chunk-S7PEBTU3.js} +148 -38
  29. package/dist/chunk-S7PEBTU3.js.map +1 -0
  30. package/dist/{chunk-XTYA5X3L.js → chunk-TRB6OYMU.js} +2 -2
  31. package/dist/{chunk-JWT457FN.js → chunk-UGSRP7E2.js} +3 -3
  32. package/dist/{chunk-U6SS43O6.js → chunk-W2UTB3RG.js} +1 -1
  33. package/dist/chunk-W2UTB3RG.js.map +1 -0
  34. package/dist/{chunk-76VZXCH4.js → chunk-WHZUJH2O.js} +42 -47
  35. package/dist/chunk-WHZUJH2O.js.map +1 -0
  36. package/dist/{chunk-CDNJUEDS.js → chunk-WMLGS5QL.js} +752 -78
  37. package/dist/chunk-WMLGS5QL.js.map +1 -0
  38. package/dist/{chunk-FHKYKEC5.js → chunk-WQWXQVOQ.js} +8 -2
  39. package/dist/{chunk-FHKYKEC5.js.map → chunk-WQWXQVOQ.js.map} +1 -1
  40. package/dist/{chunk-NAJM2T6Z.js → chunk-X3PBLSV5.js} +752 -78
  41. package/dist/chunk-X3PBLSV5.js.map +1 -0
  42. package/dist/{chunk-TUNTHZWR.js → chunk-YFHV4QP3.js} +2 -2
  43. package/dist/{chunk-CND4NRNF.cjs → chunk-YNJLZVEO.cjs} +1 -1
  44. package/dist/chunk-YNJLZVEO.cjs.map +1 -0
  45. package/dist/{chunk-Z5YZWPEW.js → chunk-ZWPRA2SE.js} +2 -2
  46. package/dist/{chunk-AM6YQ7BI.cjs → chunk-ZXAH4AFS.cjs} +61 -13
  47. package/dist/chunk-ZXAH4AFS.cjs.map +1 -0
  48. package/dist/{chunk-MJS54STB.js → chunk-ZYJY44BT.js} +57 -9
  49. package/dist/{chunk-MJS54STB.js.map → chunk-ZYJY44BT.js.map} +1 -1
  50. package/dist/chunks-PPHEGDUD.js +10 -0
  51. package/dist/cli.js +54 -33
  52. package/dist/cli.js.map +1 -1
  53. package/dist/{formula-EKOIBQT2.js → formula-CUSB5R3P.js} +4 -4
  54. package/dist/{formula-7BMWLUMS.js → formula-UKLCJINT.js} +3 -3
  55. package/dist/{formula-UOLHHJGZ.cjs → formula-YJIUNSWW.cjs} +9 -9
  56. package/dist/{formula-UOLHHJGZ.cjs.map → formula-YJIUNSWW.cjs.map} +1 -1
  57. package/dist/{image-ocr-T5W6AYKW.cjs → image-ocr-BMCOWLLB.cjs} +14 -14
  58. package/dist/{image-ocr-T5W6AYKW.cjs.map → image-ocr-BMCOWLLB.cjs.map} +1 -1
  59. package/dist/{image-ocr-7DOSKZNG.js → image-ocr-OEEGTGDU.js} +6 -6
  60. package/dist/{image-ocr-ZKOYKBQ4.js → image-ocr-S5OLK6WH.js} +8 -8
  61. package/dist/index.cjs +769 -649
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +9 -0
  64. package/dist/index.d.ts +9 -0
  65. package/dist/index.js +154 -34
  66. package/dist/index.js.map +1 -1
  67. package/dist/mcp.js +29 -23
  68. package/dist/mcp.js.map +1 -1
  69. package/dist/{model-bundle-UDR6TOD3.js → model-bundle-A6QPDJZ3.js} +5 -5
  70. package/dist/{models-JZ26T7JC.js → models-GAP4U6WU.js} +5 -5
  71. package/dist/{parser-XV7BDDU7.js → parser-BCN3SZZC.js} +825 -40
  72. package/dist/parser-BCN3SZZC.js.map +1 -0
  73. package/dist/{parser-OX3IX7HS.cjs → parser-DZMXH4V5.cjs} +940 -155
  74. package/dist/parser-DZMXH4V5.cjs.map +1 -0
  75. package/dist/{parser-Q45CANCD.js → parser-MRTO7R2Y.js} +826 -41
  76. package/dist/parser-MRTO7R2Y.js.map +1 -0
  77. package/dist/pdf-ocr-4V7U52JI.js +18 -0
  78. package/dist/pdf-ocr-A3Q4YMCG.js +15 -0
  79. package/dist/pdf-ocr-CZDODSMI.cjs +16 -0
  80. package/dist/{pdf-ocr-T44M4GLB.cjs.map → pdf-ocr-CZDODSMI.cjs.map} +1 -1
  81. package/dist/{profile-io-L4JERYGJ.js → profile-io-XAZ2MDXD.js} +3 -3
  82. package/dist/{rasterize-KMB75PGP.js → rasterize-2YKKVEIR.js} +3 -3
  83. package/dist/{redact-doc-DUNZJ2F2.js → redact-doc-XPV546P6.js} +11 -11
  84. package/dist/{render-VE2AGJ7P.js → render-ASDQSRPX.js} +7 -7
  85. package/dist/seal-3XWSKD6C.js +10 -0
  86. package/dist/{setup-5T7KZPTH.js → setup-M3MH2DHU.js} +3 -3
  87. package/dist/visual-Z6BCNJMU.js +20 -0
  88. package/dist/{watch-JEHOT5II.js → watch-3DB2LMAP.js} +12 -12
  89. package/package.json +1 -1
  90. package/dist/chunk-3PDCVDSO.js.map +0 -1
  91. package/dist/chunk-3TZ63JNS.cjs.map +0 -1
  92. package/dist/chunk-4G5RVBH4.js.map +0 -1
  93. package/dist/chunk-76VZXCH4.js.map +0 -1
  94. package/dist/chunk-AM6YQ7BI.cjs.map +0 -1
  95. package/dist/chunk-CDNJUEDS.js.map +0 -1
  96. package/dist/chunk-CND4NRNF.cjs.map +0 -1
  97. package/dist/chunk-DQZOA66I.cjs.map +0 -1
  98. package/dist/chunk-FWOCNMXB.js.map +0 -1
  99. package/dist/chunk-KSZEQL2D.js.map +0 -1
  100. package/dist/chunk-LUXORVFU.js.map +0 -1
  101. package/dist/chunk-NAJM2T6Z.js.map +0 -1
  102. package/dist/chunk-U6SS43O6.js.map +0 -1
  103. package/dist/chunk-VEYIBWBB.cjs.map +0 -1
  104. package/dist/chunks-NUJV66HJ.js +0 -10
  105. package/dist/parser-OX3IX7HS.cjs.map +0 -1
  106. package/dist/parser-Q45CANCD.js.map +0 -1
  107. package/dist/parser-XV7BDDU7.js.map +0 -1
  108. package/dist/pdf-ocr-AYZ2WMQX.js +0 -15
  109. package/dist/pdf-ocr-J6WDNIGL.js +0 -18
  110. package/dist/pdf-ocr-T44M4GLB.cjs +0 -16
  111. package/dist/seal-DJ6P57ZU.js +0 -10
  112. package/dist/visual-WMQZXP2G.js +0 -20
  113. /package/dist/{-PQUI4OJT.js.map → -H6WNRHK6.js.map} +0 -0
  114. /package/dist/{chunk-VUO5LNN4.js.map → chunk-AWXXLLIG.js.map} +0 -0
  115. /package/dist/{chunk-JQ74UURE.js.map → chunk-IHCQ4IE7.js.map} +0 -0
  116. /package/dist/{chunk-NHPF6QDB.js.map → chunk-KJSD2WNF.js.map} +0 -0
  117. /package/dist/{chunk-LHDPC4B2.js.map → chunk-L5MDTA6T.js.map} +0 -0
  118. /package/dist/{chunk-OAZ5VSWD.js.map → chunk-ORMMGTNK.js.map} +0 -0
  119. /package/dist/{chunk-XTYA5X3L.js.map → chunk-TRB6OYMU.js.map} +0 -0
  120. /package/dist/{chunk-JWT457FN.js.map → chunk-UGSRP7E2.js.map} +0 -0
  121. /package/dist/{chunk-TUNTHZWR.js.map → chunk-YFHV4QP3.js.map} +0 -0
  122. /package/dist/{chunk-Z5YZWPEW.js.map → chunk-ZWPRA2SE.js.map} +0 -0
  123. /package/dist/{chunks-NUJV66HJ.js.map → chunks-PPHEGDUD.js.map} +0 -0
  124. /package/dist/{formula-EKOIBQT2.js.map → formula-CUSB5R3P.js.map} +0 -0
  125. /package/dist/{formula-7BMWLUMS.js.map → formula-UKLCJINT.js.map} +0 -0
  126. /package/dist/{image-ocr-7DOSKZNG.js.map → image-ocr-OEEGTGDU.js.map} +0 -0
  127. /package/dist/{image-ocr-ZKOYKBQ4.js.map → image-ocr-S5OLK6WH.js.map} +0 -0
  128. /package/dist/{model-bundle-UDR6TOD3.js.map → model-bundle-A6QPDJZ3.js.map} +0 -0
  129. /package/dist/{models-JZ26T7JC.js.map → models-GAP4U6WU.js.map} +0 -0
  130. /package/dist/{pdf-ocr-AYZ2WMQX.js.map → pdf-ocr-4V7U52JI.js.map} +0 -0
  131. /package/dist/{pdf-ocr-J6WDNIGL.js.map → pdf-ocr-A3Q4YMCG.js.map} +0 -0
  132. /package/dist/{profile-io-L4JERYGJ.js.map → profile-io-XAZ2MDXD.js.map} +0 -0
  133. /package/dist/{rasterize-KMB75PGP.js.map → rasterize-2YKKVEIR.js.map} +0 -0
  134. /package/dist/{redact-doc-DUNZJ2F2.js.map → redact-doc-XPV546P6.js.map} +0 -0
  135. /package/dist/{render-VE2AGJ7P.js.map → render-ASDQSRPX.js.map} +0 -0
  136. /package/dist/{seal-DJ6P57ZU.js.map → seal-3XWSKD6C.js.map} +0 -0
  137. /package/dist/{setup-5T7KZPTH.js.map → setup-M3MH2DHU.js.map} +0 -0
  138. /package/dist/{visual-WMQZXP2G.js.map → visual-Z6BCNJMU.js.map} +0 -0
  139. /package/dist/{watch-JEHOT5II.js.map → watch-3DB2LMAP.js.map} +0 -0
package/README.md CHANGED
@@ -11,6 +11,8 @@ HWP 3.x/5.x, HWPX, HWPML, PDF, XLS, XLSX, DOCX, 이미지(PNG/JPG/WebP) — 관
11
11
 
12
12
  [English](./README-EN.md)
13
13
 
14
+ > 📊 **PDF 공개 벤치(opendataloader-bench, 200문서) 종합 0.937(OCR 0.960·OCR+plain 0.967) — 공개된 12개 PDF 파서(상용 포함) 모두보다 높고, 쪽당 0.03초.** 한국 공문서는 원본 HWPX를 정답으로 채점해 HWPX 표 13,041개 전부 칸까지 일치합니다. → [성능 한눈에 보기](#-성능-한눈에-보기)
15
+
14
16
  [![Kordoc 활용하기 — 영상 보기](./docs/video-demo.jpg)](https://youtu.be/Q13GmgDcIw0)
15
17
 
16
18
  <sub>▶ 클릭하면 유튜브에서 재생됩니다.</sub>
@@ -73,7 +75,7 @@ MCP 등록 대신 스킬(SKILL.md) 형태로 쓰려면:
73
75
  단순한 텍스트 추출을 넘어, **공문서 처리를 위한 모든 과정**을 자동화합니다.
74
76
 
75
77
  * **📄 어떤 문서든 마크다운으로**: `HWP3` (구버전), `HWP`(5.x), `HWPX`, `HWPML`, `PDF`, `XLS`, `XLSX`, `DOCX` 파일은 물론 `PNG`/`JPG`/`WebP` 이미지(자동 OCR)까지 즉시 `Markdown`으로 변환합니다. AI(LLM)가 문서를 읽고 분석하기 가장 좋은 상태로 만들어줍니다.
76
- * **📊 복잡한 표(Table) 복원 — 숫자로 잠금**: 병합·중첩 표를 구조 그대로 살립니다. HWPX 코퍼스 291문서 **표 1,673/1,673·셀 27,714/27,714 무손실**(독립 추출기 대조 게이트 1.0), 동일문서 hwpx↔pdf 대조(6쌍 69표)는 **매칭 98.6%·완전일치 65.2%**. 선 없는 PDF 표도 감지해 복원하고, 법령 개정안 PDF의 신구조문대비표도 통째로 살립니다 (v3.16.2).
78
+ * **📊 복잡한 표(Table) 복원 — 숫자로 잠금**: 병합·중첩 표를 구조 그대로 살립니다. HWPX 코퍼스 2,286문서 **표 13,041/13,041 칸까지 무손실**(독립 추출기 대조 게이트 1.0), 같은 문서를 PDF로 내보내 원본 HWPX와 대조하면(716쌍 2,692표) **표 찾기 98.9%·칸까지 완전 일치 94.2%**. 선 없는 PDF 표도 감지해 복원하고, 법령 개정안 PDF의 신구조문대비표도 통째로 살립니다 (v3.16.2).
77
79
  * **🔍 신구대조표 자동 생성**: 두 문서의 차이점을 분석하여 무엇이 바뀌었는지 한눈에 보여줍니다. (HWP와 HWPX 간의 비교도 가능!)
78
80
  * **📝 마크다운을 다시 HWPX로**: AI가 작성한 내용을 다시 보고서 양식(`HWPX`)으로 되돌려줍니다. 이제 복사-붙여넣기 노가다에서 해방되세요.
79
81
  * **🏛️ 정부 표준 공문서 생성 (v4.0)**: 실제 정부 양식 16종 + 실결재 기안문 60건을 전수 디코드·대조해 만든 공문서 엔진. 개조식 보고서(표지·목차 배너·로마숫자 장헤더·쪽번호·결재란), 기안문(별지 제1호서식 두문·결문, "끝." 자동), 공고문·보도자료 프리셋, 항목부호 8단계(1. 가. 1) 가)…) 자동, 공문서 표기법 검수 19룰(`kordoc lint`)까지 — 한글 COM 실렌더로 조판까지 실측 검증했습니다.
@@ -89,6 +91,82 @@ MCP 등록 대신 스킬(SKILL.md) 형태로 쓰려면:
89
91
 
90
92
  ---
91
93
 
94
+ ## 📊 성능 한눈에 보기
95
+
96
+ ### PDF → Markdown: 공개 벤치 12개 엔진보다 높습니다
97
+
98
+ [opendataloader-bench](https://github.com/opendataloader-project/opendataloader-bench)는 PDF 200쪽(논문·보고서·슬라이드·포스터·스캔)을 사람이 만든 정답과 비교해 **읽기 순서(NID)·표 구조(TEDS)·제목 위계(MHS)** 를 점수로 내는 공개 벤치입니다. 1.0이 정답과 똑같다는 뜻입니다.
99
+
100
+ | 순위 | 엔진 | 종합 | 읽기 순서 | 표 | 제목 | 쪽당 시간 |
101
+ | ---: | --- | ---: | ---: | ---: | ---: | ---: |
102
+ | **1** | **kordoc 기본값** | **0.937** | **0.938** | **0.936** | **0.933** | **0.03초** |
103
+ | 참고 | kordoc `plain: true` (그림 자리 표시·링크 URL 없이) | 0.946 | 0.947 | 0.937 | 0.940 | 0.03초 |
104
+ | 참고 | kordoc `ocr: true` (그림 속 글까지) | 0.960 | 0.960 | 0.979 | 0.949 | 0.46초 |
105
+ | 참고 | kordoc `ocr: true, plain: true` | 0.967 | 0.968 | 0.981 | 0.956 | 0.46초 |
106
+ | 참고 | kordoc `plain: true, htmlTables: true` | 0.949 | 0.954 | 0.940 | 0.943 | 0.03초 |
107
+ | 참고 | kordoc `ocr: true, plain: true, htmlTables: true` | 0.971 | 0.975 | 0.983 | 0.958 | 0.46초 |
108
+ | 2 | opendataloader-hybrid | 0.907 | 0.934 | 0.928 | 0.821 | 0.46초 |
109
+ | 3 | nutrient (상용) | 0.885 | 0.925 | 0.708 | 0.819 | 0.01초 |
110
+ | 4 | docling | 0.882 | 0.898 | 0.887 | 0.824 | 0.76초 |
111
+ | 5 | marker | 0.861 | 0.890 | 0.808 | 0.796 | 53.9초 |
112
+ | 6 | unstructured-hires | 0.841 | 0.904 | 0.588 | 0.749 | 3.01초 |
113
+ | 7 | edgeparse | 0.837 | 0.894 | 0.717 | 0.706 | 0.04초 |
114
+ | 8 | mineru | 0.831 | 0.857 | 0.873 | 0.743 | 5.96초 |
115
+ | 9 | opendataloader | 0.831 | 0.902 | 0.489 | 0.739 | 0.02초 |
116
+ | 10 | pymupdf4llm | 0.732 | 0.885 | 0.401 | 0.412 | 0.09초 |
117
+ | 11 | unstructured | 0.686 | 0.882 | 0.000 | 0.388 | 0.08초 |
118
+ | 12 | markitdown | 0.589 | 0.844 | 0.273 | 0.000 | 0.11초 |
119
+ | 13 | liteparse | 0.576 | 0.866 | 0.000 | 0.000 | 1.06초 |
120
+
121
+ - 기본값만으로 **종합·읽기 순서·표·제목 네 항목 모두 1위**입니다. GPU·클라우드 API·LLM 없이 Node.js 하나로, 쪽당 0.04초에 돕니다.
122
+ - `ocr: true`를 켜면 차트·로고·스캔처럼 **그림 속 글자까지** 로컬에서 읽어 0.960이 됩니다. `plain: true`는 그림 자리 표시·링크 URL·밑줄/굵게 표기를 빼 색인·RAG 용 글만 냅니다(정답지가 이런 표기를 담지 않아 점수도 오릅니다). 기본값은 OCR을 돌리지 않고, 그림·스캔 쪽이 있으면 `NEEDS_OCR`·`SKIPPED_IMAGE` 경고로 알려 `ocr: true`로 다시 파싱할 수 있게 합니다.
123
+ - 다른 엔진 점수는 벤치 저장소가 공개한 결과(Apple M4 32GB)이고, kordoc은 같은 PDF·같은 정답·**수정하지 않은 원본 채점기**로 재었습니다(Apple M4 24GB, 200문서 한 프로세스 순차 8초). 벤치 저장소의 opendataloader-hybrid 예측을 같은 채점기로 다시 채점하면 0.9066으로 공개 점수와 같습니다. 재현: `node bench/odl-bench.mjs <벤치 클론>` → 벤치의 `src/evaluator.py`.
124
+ - 벤치 저장소에 결과만 PR 로 올라온 상용 LM-Kit One(미병합 #34)은 OCR 없이 0.948·OCR 0.963입니다. 표 칸을 정답지와 같은 HTML 모양(`<td> 글 </td>`, 머리행도 `<td>`)으로 내는 차이가 OCR 없는 쪽 격차의 대부분이고, 같은 서식으로 맞춰 비교하면 kordoc `plain` 0.951·LM-Kit 0.948이고, 표를 들여쓴 HTML 로 내는 `htmlTables` 를 켜면 kordoc 이 OCR 없이 0.949·OCR 0.971 로 두 줄 모두 앞섭니다.
125
+
126
+ ### 한국 공문서: 원본 HWPX를 정답으로 채점합니다
127
+
128
+ 한글(HWPX)로 쓴 원본과 그 문서를 PDF로 내보낸 파일이 짝으로 있는 공문서를 모아, **원본 HWPX를 정답**으로 삼아 PDF에서 뽑은 글과 표를 잽니다. 보도자료·결재문서·법령 서식·예산서 등 실제 정부 문서입니다.
129
+
130
+ | 분야 | 규모 | 결과 |
131
+ | --- | --- | --- |
132
+ | HWPX 본문·표 | 2,286문서, 표 13,041개 | 글 누락 0 · 표 13,041개 전부 칸까지 일치 · 읽기 순서 100% |
133
+ | HWP 5.x | HWPX와 짝 1,120쌍 | HWPX 결과와 전부 일치 |
134
+ | PDF 글 | 751쌍 (HWPX 정답) | 글자 재현율 99.5% · 정확도 97.0% · 읽기 순서 98.3% |
135
+ | PDF 표 | 716쌍, 표 2,692개 (HWPX 정답) | 표 찾기 98.9% · 칸까지 완전 일치 94.2% · 칸 F1 0.966 |
136
+ | PDF 전체 | 1,911문서 (텍스트층 채점 1,724) | 글 커버리지 99.8% |
137
+ | 스캔 OCR (내장, 로컬 CPU) | 54문서 104쪽 (216dpi 렌더) | 글자 재현율 98.1% · 한글 재현율 99.3% · 정확도 97.5% · 쪽당 0.9초 |
138
+ | DOCX·XLSX·XLS·HML | 88문서 | 글·숫자 누락 0 |
139
+ | Markdown → HWPX → Markdown 왕복 | 83건 | 글·표·제목·수식 손실 0 |
140
+
141
+ 모든 수치는 `npm run bench:gate`로 재현되며, 배포(`npm publish`) 때마다 이 게이트를 통과해야만 올라갑니다.
142
+
143
+ ### HWP·HWPX → Markdown: HwpForge와 같은 채점기로
144
+
145
+ 같은 코퍼스를 [HwpForge](https://github.com/ai-screams/HwpForge) 0.16.6(`to_md`, lossy)과 kordoc으로 각각 Markdown으로 바꾸고, **원본 HWPX XML을 정답**으로 같은 채점기에 넣었습니다(표는 두 출력 모두 같은 Markdown 표 파서로 격자화, 1열 표는 양쪽 모두 표 채점에서 제외).
146
+
147
+ | | kordoc | HwpForge 0.16.6 |
148
+ | --- | ---: | ---: |
149
+ | HWPX 2,305문서 — 변환 실패 | **0** | 123 |
150
+ | HWPX — 글 재현율 (변환 성공 문서만) | **100.00%** (100.00%) | 59.23% (98.64%) |
151
+ | HWPX — 표 완전 일치 (9,123표) | **100.0%** (9,122) | 32.2% |
152
+ | HWPX — 칸 F1 | **1.000** | 0.428 |
153
+ | HWP 5.x 1,108문서 — 변환 실패 | **0** | 19 |
154
+ | HWP — 글 재현율 | **100.00%** | 86.41% |
155
+ | HWP — 표 완전 일치 (3,111표) | **100%** | 27.0% |
156
+ | HWP — 칸 F1 | **1.000** | 0.349 |
157
+
158
+ HwpForge는 생성·편집 중심 라이브러리이고, Markdown 표가 파이프 표뿐이라 병합 칸을 표현하지 못하는 점이 표 점수 차이의 대부분입니다. 1열 표(코퍼스 1,288개)는 제목·본문 상자 43%, 빈 여백 행 틀 28%, 목록형 3%인 꾸밈 틀이라 표로 낼지 줄 글로 낼지는 표현 선택이고, 그 글은 글 재현율이 채점합니다. 1열 표를 넣으면 HWPX 10,392표 kordoc 90.6%·HwpForge 36.0%, HWP 3,500표 92.8%·32.1%입니다. HWP 문서 수는 짝 HWPX가 배포용 암호라 정답이 없는 1건을 뺀 값입니다. 재현: `bench/hwpforge-bench.py` → `node bench/compare-md-parsers.mjs <출력 폴더>` (1열 표 포함은 `--include-single-col`).
159
+
160
+ ---
161
+
162
+ ## v4.15.7 변경사항
163
+
164
+ 표 안의 표와 PDF 글 복원을 넓혔습니다. HWP5 표는 같은 문서의 HWPX 와 같은 모양으로 나오고(여러 쪽 본문 상자만 문단으로 풂), 3~8단 중첩표가 HWPX·HWP5·PDF 모두 단 수 그대로 남습니다. HWP·HWPX → Markdown 표는 1열 표를 뺀 채점에서 HWP 3,111/3,111·HWPX 9,122/9,123 이 일치합니다. PDF 는 배경에 가려진 글 제외, 세로쓰기 글상자, 자간 벌린 영문, TeX 수식 글꼴 기호, 장 번호 제목, 칸에 줄마다 적은 숫자 목록을 바로잡아 ODL 200 기본 0.937·`ocr: true` 0.960 이 됐습니다. 새 옵션 `plain`(그림 자리 표시·링크 URL·강조 표기 없이 글 위주)과 `htmlTables`(모든 표를 들여쓴 HTML 로)를 켜면 OCR 없이 0.949·OCR 0.971 입니다. 이슈 #91~#95(희소 XLSX·누름틀 안내문·암호 HWPX Windows 멈춤·`-o` 그림 링크·`generate --image-dir` 한글 이름)를 고쳤습니다.
165
+
166
+ ## v4.15.6 변경사항
167
+
168
+ PDF 구조 복원을 한 단계 더 올려 ODL 공개 PDF 200문서 종합이 0.905513(4.15.5)에서 **0.934509**로 올랐습니다(읽기 순서 0.938·표 0.931·제목 0.926, 공개 12개 엔진 중 최고). 워드·슬라이드 표(음영 칸·투명 글상자·위아래 괘선만 있는 여러 줄 머리), 작은 대문자·옛 숫자 글리프, 여백의 세로 도장, 사이드바 소제목, 칸 안 영문 줄바꿈과 줄마다 쪼개진 링크를 바로잡았습니다. `ocr: true`는 차트·로고 같은 그림 속 글까지 영역마다 읽어 0.952이고, 기본값에서 OCR이 필요한 쪽은 경고에 다시 파싱하는 방법(`ocr: true` / `--ocr`)을 알려줍니다. 한국 공문서 게이트(표 exact 2,536/2,692·글 recall 99.49%)는 그대로 유지했습니다.
169
+
92
170
  ## v4.15.5 변경사항
93
171
 
94
172
  PDF 표 경계와 두 단 지면 읽기 순서를 복원했습니다. 세로선만 내려 그은 머리·합계 행, 머리행만 음영 상자로 두른 표, 가로 괘선만 있는 학술지 표를 한 표로 읽고, 두 단 지면에서는 그림 옆 캡션을 먼저, 각주를 두 단 본문 뒤에 읽습니다. ODL 공개 PDF 200문서 종합은 0.775354(4.15.4)에서 0.905513으로 올랐습니다. PDF 제목 오탐 두 유형(#89)과 없는 입력 파일의 실패 코드(`FILE_NOT_FOUND`, #88)도 바로잡았습니다. 세부 지표와 OCR 게이트 기준 재산정 사유는 [CHANGELOG](CHANGELOG.md)를 참고하세요.
@@ -150,6 +228,8 @@ PDF 표 복원과 대형 입력의 안정성을 보완했습니다.
150
228
  - **💲 본문의 `$` 가 수식이 되지 않습니다**: 한글 문서(HWPX·HWP·HWP3)의 리터럴 `$` 는 `\$` 로 내고 `$…$` 는 수식에만 씁니다. "echo $HOME $PATH" 같은 글이 마크다운 렌더러에서 수식으로 바뀌던 것. 역슬래시 뒤 구두점("C:\.Pls")에서 역슬래시가 사라지던 것도 고쳤습니다.
151
229
  - **📝 미기입 누름틀 안내문을 빼고 읽습니다**: 한컴이 화면에만 흐리게 보이고 인쇄하지 않는 HWPX 안내문을 마크다운에서 뺍니다(블록 글에는 남김). 누름틀을 채우면 수정 표시를 켭니다.
152
230
  - **🖼️ 이미지 끄기** (`images: false` / `--no-images`): 결과에 이미지 바이트를 싣지 않습니다. 그림 자리 표시(`![image](…)`)와 본문 글자는 그대로라 그림 위치는 알 수 있습니다. PDF 는 PNG 인코딩을 건너뜁니다. 그림 많은 PDF 실측: JSON 출력 200MB → 9.5MB, CPU 시간 30% 감소.
231
+ - **🧹 글 위주 출력** (`plain: true` / `--plain`): 그림 자리 표시·링크 URL·밑줄(`<u>`)·굵게(`**`) 표기를 빼고 제목·목록·표 구조와 글만 냅니다. 이미지 파일을 저장하지 않는 색인·RAG 용.
232
+ - **🧾 HTML 표** (`htmlTables: true` / `--html-tables`): 파이프 표까지 모든 표를 HTML 로, 태그마다 한 줄씩 들여써 냅니다(첫 행 `<th>`). HTML 표만 다루는 소비자용.
153
233
  - **🚀 상주 파싱 워커** (`kordoc parse-worker`): 프로세스를 띄워 둔 채 stdin 요청 한 줄마다 한 줄 JSON 을 돌려줍니다. 파일마다 node 를 새로 띄우지 않아 대량 색인에 알맞습니다. 응답에 메모리 사용량(`rss`)을 실어 호스트가 워커 교체 시점을 정할 수 있습니다.
154
234
 
155
235
  ## v4.14.2 변경사항
@@ -965,6 +1045,7 @@ reflow 조판되며 `--no-reflow`로 끌 수 있습니다 (`--highlight 예산,
965
1045
 
966
1046
  ```typescript
967
1047
  const result = await parse(buffer, { images: false }) // 이미지 바이트 없이 (그림 자리 표시는 남김)
1048
+ const plain = await parse(buffer, { plain: true, htmlTables: true }) // 글 위주 + 모든 표를 들여쓴 HTML 로
968
1049
  ```
969
1050
 
970
1051
  CLI 는 `kordoc 문서.pdf --format json --no-images`. 대량 변환은 `kordoc parse-worker` 를 띄워 두고
@@ -50,17 +50,17 @@ import {
50
50
  unknownFontWarnings,
51
51
  usesGaejosikMunche,
52
52
  validateHwpx
53
- } from "./chunk-LUXORVFU.js";
53
+ } from "./chunk-S7PEBTU3.js";
54
54
  import {
55
55
  blocksToPages
56
- } from "./chunk-VUO5LNN4.js";
56
+ } from "./chunk-AWXXLLIG.js";
57
57
  import {
58
58
  applySplices,
59
59
  buildParagraphSplices,
60
60
  buildRangeSplices,
61
61
  placeSealHwpx,
62
62
  scanSectionXml
63
- } from "./chunk-JWT457FN.js";
63
+ } from "./chunk-UGSRP7E2.js";
64
64
  import {
65
65
  DEFAULT_REDACT_RULES,
66
66
  redactMarkdown,
@@ -68,7 +68,7 @@ import {
68
68
  } from "./chunk-3WSNLH4B.js";
69
69
  import {
70
70
  blocksToChunks
71
- } from "./chunk-LHDPC4B2.js";
71
+ } from "./chunk-L5MDTA6T.js";
72
72
  import {
73
73
  SPACE_EM_FIXED,
74
74
  SPACE_EM_FONT,
@@ -93,20 +93,20 @@ import {
93
93
  renderSceneToHtml,
94
94
  simulateWrap,
95
95
  simulateWrapKeepWord
96
- } from "./chunk-FWOCNMXB.js";
96
+ } from "./chunk-C572DIHX.js";
97
97
  import "./chunk-7FCNOKOR.js";
98
- import "./chunk-3PDCVDSO.js";
98
+ import "./chunk-NVG2GQNA.js";
99
99
  import "./chunk-VQFA55IC.js";
100
- import "./chunk-4G5RVBH4.js";
100
+ import "./chunk-O5SDUPB2.js";
101
101
  import {
102
102
  blocksToMarkdown,
103
103
  flattenLayoutTables,
104
104
  hasStructuredCellContent
105
- } from "./chunk-76VZXCH4.js";
106
- import "./chunk-TUNTHZWR.js";
105
+ } from "./chunk-WHZUJH2O.js";
106
+ import "./chunk-YFHV4QP3.js";
107
107
  import {
108
108
  VERSION
109
- } from "./chunk-JPIHOEAS.js";
109
+ } from "./chunk-F5FHYJKJ.js";
110
110
  export {
111
111
  BUILTIN_TEMPLATES,
112
112
  DEFAULT_REDACT_RULES,
@@ -196,4 +196,4 @@ export {
196
196
  usesGaejosikMunche,
197
197
  validateHwpx
198
198
  };
199
- //# sourceMappingURL=-PQUI4OJT.js.map
199
+ //# sourceMappingURL=-H6WNRHK6.js.map