kordoc 4.3.0 → 4.4.0

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 (169) hide show
  1. package/NOTICE +176 -0
  2. package/README.md +936 -922
  3. package/THIRD_PARTY/apache-2.0.LICENSE +201 -0
  4. package/THIRD_PARTY/claw-hwp.LICENSE +21 -0
  5. package/THIRD_PARTY/hml-equation-parser.LICENSE +201 -0
  6. package/THIRD_PARTY/hml-equation-parser.txt +35 -0
  7. package/THIRD_PARTY/opendataloader-pdf.txt +32 -0
  8. package/THIRD_PARTY/pix2text.txt +17 -0
  9. package/THIRD_PARTY/rhwp-forms.txt +35 -0
  10. package/dist/{-DYHT3HWH.js → -R6NUMPRV.js} +11 -11
  11. package/dist/{chunk-3FFPHTXD.js → chunk-3H5X63BQ.js} +1 -1
  12. package/dist/chunk-3H5X63BQ.js.map +1 -0
  13. package/dist/{chunk-EFVAY5VE.js → chunk-5KLE3U23.js} +7 -4
  14. package/dist/chunk-5KLE3U23.js.map +1 -0
  15. package/dist/{chunk-6GBLFQMA.js → chunk-5RPYBC2Q.js} +1 -1
  16. package/dist/chunk-5RPYBC2Q.js.map +1 -0
  17. package/dist/{chunk-VXMLENCV.js → chunk-65DYCXGC.js} +4 -4
  18. package/dist/chunk-65DYCXGC.js.map +1 -0
  19. package/dist/{chunk-W34QSJFF.js → chunk-7FCNOKOR.js} +1 -1
  20. package/dist/chunk-7FCNOKOR.js.map +1 -0
  21. package/dist/{chunk-ZSL6MQVE.js → chunk-A73RMJ6B.js} +1 -1
  22. package/dist/chunk-A73RMJ6B.js.map +1 -0
  23. package/dist/{chunk-AL34DGS5.cjs → chunk-AB322K3O.cjs} +6 -6
  24. package/dist/chunk-AB322K3O.cjs.map +1 -0
  25. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  26. package/dist/{chunk-O5EK52TG.js → chunk-DZIXKL7E.js} +1 -1
  27. package/dist/chunk-DZIXKL7E.js.map +1 -0
  28. package/dist/{chunk-EZHW3RNQ.js → chunk-GHGZU2LQ.js} +2 -2
  29. package/dist/chunk-GHGZU2LQ.js.map +1 -0
  30. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  31. package/dist/{chunk-6XPXIG57.js → chunk-GZDOWYJM.js} +2 -2
  32. package/dist/chunk-GZDOWYJM.js.map +1 -0
  33. package/dist/{chunk-JFV7QT5T.cjs → chunk-H2KMJOB6.cjs} +2 -2
  34. package/dist/chunk-H2KMJOB6.cjs.map +1 -0
  35. package/dist/{chunk-6RAYTNQT.js → chunk-HFJF477F.js} +3 -3
  36. package/dist/chunk-HFJF477F.js.map +1 -0
  37. package/dist/{chunk-SPKBIFSK.js → chunk-HNRULYUH.js} +2 -2
  38. package/dist/chunk-HNRULYUH.js.map +1 -0
  39. package/dist/chunk-MOL7MDBG.js +0 -0
  40. package/dist/{chunk-7MFO4TKP.js → chunk-ONS7JKVA.js} +2 -2
  41. package/dist/chunk-ONS7JKVA.js.map +1 -0
  42. package/dist/{chunk-DRQUAYNT.js → chunk-P7YPCK7C.js} +2 -2
  43. package/dist/chunk-P7YPCK7C.js.map +1 -0
  44. package/dist/{chunk-GSMPTZC7.js → chunk-QXYB74QF.js} +24 -3
  45. package/dist/chunk-QXYB74QF.js.map +1 -0
  46. package/dist/{chunk-NMWXBJ5B.js → chunk-RZURSA4N.js} +6 -4
  47. package/dist/chunk-RZURSA4N.js.map +1 -0
  48. package/dist/{chunk-LPQWKQQQ.cjs → chunk-SKM6KZUH.cjs} +9 -9
  49. package/dist/chunk-SKM6KZUH.cjs.map +1 -0
  50. package/dist/{chunk-YNJDNP44.js → chunk-UAFSPWU7.js} +1 -1
  51. package/dist/chunk-UAFSPWU7.js.map +1 -0
  52. package/dist/{chunk-AUOEZKJE.cjs → chunk-UDGPM5R5.cjs} +26 -5
  53. package/dist/chunk-UDGPM5R5.cjs.map +1 -0
  54. package/dist/{chunk-WFOQFJI4.js → chunk-V35DRUJC.js} +2 -2
  55. package/dist/chunk-V35DRUJC.js.map +1 -0
  56. package/dist/{chunk-4DBCUF3C.js → chunk-W6CUD7V3.js} +3 -3
  57. package/dist/chunk-W6CUD7V3.js.map +1 -0
  58. package/dist/{chunk-US4WFSIQ.js → chunk-XCIC7U6Y.js} +24 -3
  59. package/dist/chunk-XCIC7U6Y.js.map +1 -0
  60. package/dist/{chunk-DRZUJ2RK.js → chunk-YOZ7ZRCD.js} +366 -51
  61. package/dist/chunk-YOZ7ZRCD.js.map +1 -0
  62. package/dist/{chunk-ARXNKC5D.js → chunk-YVYU267E.js} +3 -3
  63. package/dist/chunk-YVYU267E.js.map +1 -0
  64. package/dist/{chunk-MGGU3ZRK.cjs → chunk-ZV5OKQ3Z.cjs} +1 -1
  65. package/dist/chunk-ZV5OKQ3Z.cjs.map +1 -0
  66. package/dist/chunks-QMGCI5DG.js +10 -0
  67. package/dist/cli.js +28 -24
  68. package/dist/cli.js.map +1 -1
  69. package/dist/{formula-IWV5IJ3Y.cjs → formula-CG4S7TWO.cjs} +8 -8
  70. package/dist/formula-CG4S7TWO.cjs.map +1 -0
  71. package/dist/{formula-7ZPC54JO.js → formula-JLYS73QL.js} +2 -2
  72. package/dist/formula-JLYS73QL.js.map +1 -0
  73. package/dist/{formula-EQRHSMYW.js → formula-LIVQSCMM.js} +2 -2
  74. package/dist/formula-LIVQSCMM.js.map +1 -0
  75. package/dist/{image-ocr-XEJFXH6M.cjs → image-ocr-F2BQA26V.cjs} +11 -11
  76. package/dist/image-ocr-F2BQA26V.cjs.map +1 -0
  77. package/dist/{image-ocr-G2LYTEUH.js → image-ocr-U2DRRFL3.js} +5 -5
  78. package/dist/image-ocr-U2DRRFL3.js.map +1 -0
  79. package/dist/{image-ocr-R44RYDBU.js → image-ocr-XC52AQDV.js} +7 -7
  80. package/dist/image-ocr-XC52AQDV.js.map +1 -0
  81. package/dist/index.cjs +858 -537
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.d.cts +7 -0
  84. package/dist/index.d.ts +7 -0
  85. package/dist/index.js +373 -52
  86. package/dist/index.js.map +1 -1
  87. package/dist/mcp.js +24 -22
  88. package/dist/mcp.js.map +1 -1
  89. package/dist/{models-6VMAVZR6.js → models-6SIKLKRH.js} +3 -3
  90. package/dist/page-range-737B4EZW.js +0 -0
  91. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  92. package/dist/{parser-W3POOYQQ.js → parser-ESGFWWCT.js} +8 -8
  93. package/dist/parser-ESGFWWCT.js.map +1 -0
  94. package/dist/{parser-W3ZGQUCQ.cjs → parser-FFQN67O6.cjs} +25 -25
  95. package/dist/parser-FFQN67O6.cjs.map +1 -0
  96. package/dist/{parser-2G245MMN.js → parser-TFPGQWCC.js} +6 -6
  97. package/dist/parser-TFPGQWCC.js.map +1 -0
  98. package/dist/pdf-ocr-4R646OO6.js +12 -0
  99. package/dist/pdf-ocr-UQBZH3HE.cjs +13 -0
  100. package/dist/pdf-ocr-UQBZH3HE.cjs.map +1 -0
  101. package/dist/pdf-ocr-WE5TMRFU.js +15 -0
  102. package/dist/{profile-io-72R3B7KO.js → profile-io-O6BDCUJN.js} +3 -3
  103. package/dist/{rasterize-GNJQVURE.js → rasterize-V22VCCE7.js} +2 -2
  104. package/dist/rasterize-V22VCCE7.js.map +1 -0
  105. package/dist/{redact-W5K3ILQH.js → redact-7ILEAUTS.js} +2 -2
  106. package/dist/render-3BSVTTZE.js +10 -0
  107. package/dist/seal-6ZSEJVOD.js +10 -0
  108. package/dist/{setup-I4I75QJU.js → setup-GUQT5ELJ.js} +1 -1
  109. package/dist/setup-GUQT5ELJ.js.map +1 -0
  110. package/dist/{watch-2ADAJLIJ.js → watch-HGKBICED.js} +11 -11
  111. package/dist/watch-HGKBICED.js.map +1 -0
  112. package/package.json +103 -101
  113. package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +9 -9
  114. package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
  115. package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +24 -24
  116. package/dist/chunk-3FFPHTXD.js.map +0 -1
  117. package/dist/chunk-4DBCUF3C.js.map +0 -1
  118. package/dist/chunk-6GBLFQMA.js.map +0 -1
  119. package/dist/chunk-6RAYTNQT.js.map +0 -1
  120. package/dist/chunk-6XPXIG57.js.map +0 -1
  121. package/dist/chunk-7MFO4TKP.js.map +0 -1
  122. package/dist/chunk-AL34DGS5.cjs.map +0 -1
  123. package/dist/chunk-ARXNKC5D.js.map +0 -1
  124. package/dist/chunk-AUOEZKJE.cjs.map +0 -1
  125. package/dist/chunk-DRQUAYNT.js.map +0 -1
  126. package/dist/chunk-DRZUJ2RK.js.map +0 -1
  127. package/dist/chunk-EFVAY5VE.js.map +0 -1
  128. package/dist/chunk-EZHW3RNQ.js.map +0 -1
  129. package/dist/chunk-GSMPTZC7.js.map +0 -1
  130. package/dist/chunk-JFV7QT5T.cjs.map +0 -1
  131. package/dist/chunk-LPQWKQQQ.cjs.map +0 -1
  132. package/dist/chunk-MGGU3ZRK.cjs.map +0 -1
  133. package/dist/chunk-NMWXBJ5B.js.map +0 -1
  134. package/dist/chunk-O5EK52TG.js.map +0 -1
  135. package/dist/chunk-SPKBIFSK.js.map +0 -1
  136. package/dist/chunk-US4WFSIQ.js.map +0 -1
  137. package/dist/chunk-VXMLENCV.js.map +0 -1
  138. package/dist/chunk-W34QSJFF.js.map +0 -1
  139. package/dist/chunk-WFOQFJI4.js.map +0 -1
  140. package/dist/chunk-YNJDNP44.js.map +0 -1
  141. package/dist/chunk-ZSL6MQVE.js.map +0 -1
  142. package/dist/chunks-Q7T4SQGW.js +0 -10
  143. package/dist/formula-7ZPC54JO.js.map +0 -1
  144. package/dist/formula-EQRHSMYW.js.map +0 -1
  145. package/dist/formula-IWV5IJ3Y.cjs.map +0 -1
  146. package/dist/image-ocr-G2LYTEUH.js.map +0 -1
  147. package/dist/image-ocr-R44RYDBU.js.map +0 -1
  148. package/dist/image-ocr-XEJFXH6M.cjs.map +0 -1
  149. package/dist/parser-2G245MMN.js.map +0 -1
  150. package/dist/parser-W3POOYQQ.js.map +0 -1
  151. package/dist/parser-W3ZGQUCQ.cjs.map +0 -1
  152. package/dist/pdf-ocr-3GDTJSHF.js +0 -15
  153. package/dist/pdf-ocr-N7IU23UV.cjs +0 -13
  154. package/dist/pdf-ocr-N7IU23UV.cjs.map +0 -1
  155. package/dist/pdf-ocr-U7MEGNBZ.js +0 -12
  156. package/dist/rasterize-GNJQVURE.js.map +0 -1
  157. package/dist/render-6OW6U4L4.js +0 -10
  158. package/dist/seal-GTNLVBJX.js +0 -10
  159. package/dist/setup-I4I75QJU.js.map +0 -1
  160. package/dist/watch-2ADAJLIJ.js.map +0 -1
  161. /package/dist/{-DYHT3HWH.js.map → -R6NUMPRV.js.map} +0 -0
  162. /package/dist/{chunks-Q7T4SQGW.js.map → chunks-QMGCI5DG.js.map} +0 -0
  163. /package/dist/{models-6VMAVZR6.js.map → models-6SIKLKRH.js.map} +0 -0
  164. /package/dist/{pdf-ocr-3GDTJSHF.js.map → pdf-ocr-4R646OO6.js.map} +0 -0
  165. /package/dist/{pdf-ocr-U7MEGNBZ.js.map → pdf-ocr-WE5TMRFU.js.map} +0 -0
  166. /package/dist/{profile-io-72R3B7KO.js.map → profile-io-O6BDCUJN.js.map} +0 -0
  167. /package/dist/{redact-W5K3ILQH.js.map → redact-7ILEAUTS.js.map} +0 -0
  168. /package/dist/{render-6OW6U4L4.js.map → render-3BSVTTZE.js.map} +0 -0
  169. /package/dist/{seal-GTNLVBJX.js.map → seal-6ZSEJVOD.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** kordoc 공통 타입 정의 */\r\n\r\n// ─── 중간 표현 (Intermediate Representation) ─────────\r\n\r\nexport interface CellContext {\r\n text: string\r\n colSpan: number\r\n rowSpan: number\r\n /** HWP5 셀 열 주소 (0-based) — 병합 테이블 배치용 */\r\n colAddr?: number\r\n /** HWP5 셀 행 주소 (0-based) — 병합 테이블 배치용 */\r\n rowAddr?: number\r\n}\r\n\r\n/** 블록 타입 — v2.0에서 heading, list, image, separator 추가 */\r\nexport type IRBlockType = \"paragraph\" | \"table\" | \"heading\" | \"list\" | \"image\" | \"separator\"\r\n\r\n/** 인라인 강조 run-span — 문단 텍스트를 서식 단위로 쪼갠 조각 (텍스트 연결 = block.text) */\r\nexport interface IRSpan {\r\n text: string\r\n bold?: boolean\r\n italic?: boolean\r\n strike?: boolean\r\n code?: boolean\r\n}\r\n\r\nexport interface IRBlock {\r\n type: IRBlockType\r\n text?: string\r\n table?: IRTable\r\n /** 헤딩 레벨 (1-6), type=\"heading\"일 때 사용 */\r\n level?: number\r\n /** 원본 페이지 번호 (1-based) */\r\n pageNumber?: number\r\n /** 바운딩 박스 — PDF에서만 제공 */\r\n bbox?: BoundingBox\r\n /** 텍스트 스타일 정보 (선택) */\r\n style?: InlineStyle\r\n /** 리스트 타입, type=\"list\"일 때 사용 */\r\n listType?: \"ordered\" | \"unordered\"\r\n /** 중첩 리스트 아이템 */\r\n children?: IRBlock[]\r\n /** 하이퍼링크 URL */\r\n href?: string\r\n /** 각주/미주 텍스트 (인라인 삽입용) */\r\n footnoteText?: string\r\n /** 이미지 데이터 (type=\"image\"일 때) */\r\n imageData?: ImageData\r\n /** 인라인 강조 run-span (선택 — kordoc 생성 hwpx 왕복 채널 + 외래 실속성 볼드/이탤릭).\r\n * 존재하면 마크다운 변환이 **·*·` 마커를 재방출한다 */\r\n spans?: IRSpan[]\r\n /** 인용문 문단 (선택 — kordoc 생성 hwpx 왕복 채널) — 마크다운 변환이 \"> \" 접두 재방출 */\r\n quote?: boolean\r\n /**\r\n * 문단 들여쓰기(HWPUNIT, 선택) — HWPX paraPr `<hh:margin>` 자식요소형 hc:left\r\n * (+양수 hc:intent 첫줄분). 마크다운 방출엔 쓰지 않는 관찰 슬롯 — gongmun 리스트\r\n * depth 재유도·양식 분석 등 소비자 몫 (v4.0.4)\r\n */\r\n indent?: number\r\n /**\r\n * gongmun 리스트 단계(1~7, 선택) — indent를 levelIndent 단위로 역산한 소비 결과\r\n * (v4.0.5). md 리스트 문법과 충돌하는 부호('- '·'1) ') 문단에만 채워지며,\r\n * 마크다운 변환이 2칸/단계 선행 공백을 방출해 재생성 시 depth가 복원된다\r\n */\r\n listDepth?: number\r\n}\r\n\r\n/** 추출된 이미지 바이너리 데이터 */\r\nexport interface ImageData {\r\n /** 이미지 바이너리 */\r\n data: Uint8Array\r\n /** MIME 타입 (image/png, image/jpeg, image/gif, image/bmp, image/wmf, image/emf) */\r\n mimeType: string\r\n /** 원본 파일명 (있는 경우) */\r\n filename?: string\r\n}\r\n\r\n/** 바운딩 박스 — PDF 포인트 단위 (72pt = 1인치) */\r\nexport interface BoundingBox {\r\n page: number\r\n x: number\r\n y: number\r\n width: number\r\n height: number\r\n}\r\n\r\n/** 인라인 텍스트 스타일 */\r\nexport interface InlineStyle {\r\n bold?: boolean\r\n italic?: boolean\r\n /** 취소선 — 법령 개정문 등의 삭제 표시. 판정은 취소선 모양 whitelist (비트만 믿으면 오탐) */\r\n strike?: boolean\r\n fontSize?: number\r\n fontName?: string\r\n}\r\n\r\nexport interface IRTable {\r\n rows: number\r\n cols: number\r\n cells: IRCell[][]\r\n /** 첫 행을 헤더로 렌더링할지 여부 (현재: rows > 1이면 true — 의미적 감지가 아닌 레이아웃 힌트) */\r\n hasHeader: boolean\r\n /** 표 캡션 (예: \"표 1. 부서별 예산\") — v3.0 */\r\n caption?: string\r\n /**\r\n * 캡션 내부 블록 콘텐츠 — v4.2.8 (#55).\r\n * 캡션 안 중첩표·문단을 구조 그대로, 원문 순서대로 보존한다 (IRCell.blocks와 같은 계약).\r\n * 표가 있을 때만 채워지며, caption은 하위 호환용 평탄화 문자열로 계속 제공된다.\r\n */\r\n captionBlocks?: IRBlock[]\r\n}\r\n\r\nexport interface IRCell {\r\n text: string\r\n colSpan: number\r\n rowSpan: number\r\n /**\r\n * 셀 내부 블록 콘텐츠 — v3.0.\r\n * 중첩 표·이미지 등 구조 콘텐츠(또는 왕복 채널 span 문단)가 있는 셀에만 채워지며,\r\n * 그 안의 문단·표·이미지를 문서(원문) 순서대로 보존한다. 다중 문단뿐인 평문 셀은\r\n * blocks 없이 text 평탄화(문단을 `\\n`으로 결합)로만 제공된다 (blocks 무게 억제, #57).\r\n * 표와 텍스트가 한 줄에 번갈아 놓인 셀도 배치 순서를 따른다 (v4.2.3, #49).\r\n * blocks가 있으면 text는 blocks의 평탄화 텍스트(하위 호환용)다.\r\n */\r\n blocks?: IRBlock[]\r\n /** 제목 셀 여부 (HWP5 width_ref bit2 / HWPX header 속성) — v3.0 */\r\n isHeader?: boolean\r\n}\r\n\r\n// ─── 메타데이터 ─────────────────────────────────────\r\n\r\n/** 문서 메타데이터 — 각 포맷에서 추출 가능한 필드만 채워짐 */\r\nexport interface DocumentMetadata {\r\n /** 문서 제목 */\r\n title?: string\r\n /** 작성자 */\r\n author?: string\r\n /** 작성 프로그램 (예: \"한글 2020\", \"Adobe Acrobat\") */\r\n creator?: string\r\n /** 생성일시 (ISO 8601) */\r\n createdAt?: string\r\n /** 수정일시 (ISO 8601) */\r\n modifiedAt?: string\r\n /** 페이지/섹션 수 */\r\n pageCount?: number\r\n /** 문서 포맷 버전 (예: HWP \"5.1.0.1\") */\r\n version?: string\r\n /** 설명 */\r\n description?: string\r\n /** 키워드 */\r\n keywords?: string[]\r\n}\r\n\r\n// ─── 파싱 옵션 ──────────────────────────────────────\r\n\r\n/** 파싱 옵션 — parse() 함수에 전달 */\r\nexport interface ParseOptions {\r\n /**\r\n * 파싱할 페이지/섹션 범위 (1-based).\r\n * - 배열: [1, 2, 3]\r\n * - 문자열: \"1-3\", \"1,3,5-7\"\r\n *\r\n * PDF: 정확한 페이지 단위. HWP/HWPX: 섹션 단위 근사치.\r\n */\r\n pages?: number[] | string\r\n /** 이미지 기반 PDF OCR (선택).\r\n * - `true`: 내장 엔진(PP-OCRv5 korean, ~18MB 자동 다운로드)으로 OCR 필요 판정\r\n * 페이지만 인식 (스캔 페이지·글꼴 매핑 깨진 페이지). 정상 페이지는 파싱 결과 유지.\r\n * - `\"force\"`: 전 페이지를 내장 엔진으로 강제 OCR.\r\n * - 함수: 사용자 제공 OcrProvider (Claude Vision·Tesseract 등) — 판정은 `true`와 동일. */\r\n ocr?: boolean | \"force\" | OcrProvider\r\n /** 진행률 콜백 — current: 현재 페이지/섹션, total: 전체 수 */\r\n onProgress?: (current: number, total: number) => void\r\n /** PDF 머리글/바닥글 자동 제거 */\r\n removeHeaderFooter?: boolean\r\n /** 표 오른쪽 끝의 빈 열(서식 문서의 입력란) 보존 (#47).\r\n * 기본 false: 마크다운 가독성을 위해 후행 빈 열을 트림.\r\n * 양식 인식 경로(parse_form·fill)는 내부적으로 항상 켠다. */\r\n keepTrailingEmptyCols?: boolean\r\n /** 빈 문단(텍스트 없는 hp:p) 보존 (#57). 기본 false: 종전대로 빈 문단 제거.\r\n * 켜면 본문은 `text: \"\"` paragraph 블록으로, 표 셀은 빈 줄로 순서대로 보존해\r\n * \"원문 문단 수 = 줄 수\" 대응을 유지한다 (행 줄맞춤 서식 문서용).\r\n * 개체(표·이미지·글상자)만 있는 문단은 개체 출력이 따로 있어 대상이 아니다.\r\n * 현재 HWPX 경로 적용. */\r\n keepEmptyParagraphs?: boolean\r\n /** 원본 파일 경로 (DRM COM fallback에 필요, 내부 전용) */\r\n filePath?: string\r\n /**\r\n * PDF 수식 OCR 활성화 (기본 false).\r\n *\r\n * 활성화 시 각 PDF 페이지를 이미지로 렌더링 → YOLOv8 기반 수식 영역 검출 →\r\n * TrOCR 기반 LaTeX 인식. 감지된 수식은 `$...$` (inline) / `$$...$$` (display) 로\r\n * 블록 텍스트에 삽입된다.\r\n *\r\n * 필수 optional 의존성: `onnxruntime-node`, `@huggingface/transformers`,\r\n * `@hyzyla/pdfium`, `sharp`. 미설치 시 parse 에 실패하지 않고 **경고만** 남기고\r\n * 수식 인식은 skip 한다 (일반 텍스트 추출은 정상 동작).\r\n *\r\n * 모델(~155MB) 은 첫 사용 시 HuggingFace 에서 자동 다운로드 되어\r\n * `~/.cache/kordoc/models/pix2text/` 에 SHA-256 검증과 함께 저장된다.\r\n */\r\n formulaOcr?: boolean\r\n /**\r\n * 레이아웃 표 페이지 반복 헤더(러닝 헤더) 정리 휴리스틱 활성화 (기본 false).\r\n *\r\n * 구형 HWP5 문서가 페이지마다 재삽입한 짧은 번호매김 러닝 헤더\r\n * (\"2. 과제 구축 내용\")를 최초 1회만 남기고 이후 중복을 제거한다.\r\n * 다만 페이지 위치 정보가 없는 HWP5 특성상 이 휴리스틱은 정당하게 반복되는\r\n * 번호매김 문단(예: 붙임/별지별 재번호 \"1. 목적\")도 삭제할 수 있어 opt-in 으로\r\n * 둔다. 활성 시 제거가 발생하면 HIDDEN_TEXT_FILTERED 경고를 남긴다.\r\n */\r\n dedupeRunningHeaders?: boolean\r\n /**\r\n * 추출된 이미지를 마크다운에 base64 data URI 로 인라인 (기본 false).\r\n *\r\n * 활성화 시 `![image](image_001.bmp)` 참조를 `![image](data:image/png;base64,...)` 로\r\n * 치환한다. 임베드된 BMP 는 PNG 로 무손실 압축 후 인라인하여 용량을 크게 줄인다.\r\n * 별도 이미지 파일 없이 자체 완결형 마크다운이 되어 MCP/AI 에이전트 소비에 적합하다.\r\n * (현재 HWP5 경로 지원)\r\n */\r\n inlineImages?: boolean\r\n}\r\n\r\n// ─── 파싱 경고 ──────────────────────────────────────\r\n\r\n/** 파싱 중 스킵/실패한 요소 보고 */\r\nexport interface ParseWarning {\r\n /** 관련 페이지 번호 (알 수 있는 경우) */\r\n page?: number\r\n /** 경고 메시지 */\r\n message: string\r\n /** 구조화된 경고 코드 */\r\n code: WarningCode\r\n}\r\n\r\nexport type WarningCode =\r\n | \"SKIPPED_IMAGE\"\r\n | \"SKIPPED_OLE\"\r\n | \"TRUNCATED_TABLE\"\r\n | \"OCR_FALLBACK\"\r\n | \"UNSUPPORTED_ELEMENT\"\r\n | \"BROKEN_ZIP_RECOVERY\"\r\n | \"HIDDEN_TEXT_FILTERED\"\r\n | \"MALFORMED_XML\"\r\n | \"PARTIAL_PARSE\"\r\n | \"LENIENT_CFB_RECOVERY\"\r\n | \"NEEDS_OCR\"\r\n | \"OCR_FAILED\"\r\n | \"OCR_APPLIED\"\r\n | \"COM_EMPTY\"\r\n | \"DRM_COM_FALLBACK\"\r\n\r\n/** 문서 구조 (헤딩 트리) */\r\nexport interface OutlineItem {\r\n level: number\r\n text: string\r\n pageNumber?: number\r\n}\r\n\r\n// ─── 에러 코드 ──────────────────────────────────────\r\n\r\n/** 구조화된 에러 코드 — 프로그래밍적 에러 핸들링용 */\r\nexport type ErrorCode =\r\n | \"EMPTY_INPUT\"\r\n | \"UNSUPPORTED_FORMAT\"\r\n | \"ENCRYPTED\"\r\n | \"DRM_PROTECTED\"\r\n | \"CORRUPTED\"\r\n | \"DECOMPRESSION_BOMB\"\r\n | \"ZIP_BOMB\"\r\n | \"IMAGE_BASED_PDF\"\r\n | \"NO_SECTIONS\"\r\n | \"PARSE_ERROR\"\r\n | \"MISSING_DEPENDENCY\"\r\n\r\n// ─── 파싱 결과 (discriminated union) ────────────────\r\n\r\nexport type FileType = \"hwpx\" | \"hwp\" | \"hwp3\" | \"hwpml\" | \"pdf\" | \"xlsx\" | \"xls\" | \"docx\" | \"image\" | \"unknown\"\r\n\r\ninterface ParseResultBase {\r\n fileType: FileType\r\n /** 페이지/섹션 수 — PDF: 실제 페이지 수, HWP/HWPX: 섹션 수, XLSX: 시트 수 */\r\n pageCount?: number\r\n /** 이미지 기반 PDF 여부 (텍스트 추출 불가) */\r\n isImageBased?: boolean\r\n}\r\n\r\nexport interface ParseSuccess extends ParseResultBase {\r\n success: true\r\n /** 추출된 마크다운 텍스트 */\r\n markdown: string\r\n /**\r\n * 중간 표현 블록 (구조화된 데이터 접근용).\r\n * 블록은 문서(원문) 읽기 순서를 따른다 — 한 문단 안에 글자취급(treatAsChar)\r\n * 표와 텍스트가 섞여 있어도 배치 순서대로 방출된다 (v4.2.3, #50).\r\n */\r\n blocks: IRBlock[]\r\n /** 문서 메타데이터 */\r\n metadata?: DocumentMetadata\r\n /** 문서 구조 (헤딩 트리) — v2.0 */\r\n outline?: OutlineItem[]\r\n /** 파싱 중 발생한 경고 — v2.0 */\r\n warnings?: ParseWarning[]\r\n /** 추출된 이미지 목록 — 마크다운에서 파일명으로 참조됨 */\r\n images?: ExtractedImage[]\r\n /** 페이지별 텍스트 품질 신호 — PDF에서만 제공 */\r\n pageQuality?: PageQuality[]\r\n /** 문서 단위 품질 요약 — PDF에서만 제공 */\r\n qualitySummary?: DocumentQualitySummary\r\n}\r\n\r\n/** 페이지별 텍스트 품질 신호 (PDF 전용). 자세한 설명은 src/pdf/quality.ts */\r\nexport interface PageQuality {\r\n page: number\r\n textChars: number\r\n hangulRatio: number\r\n controlCharRatio: number\r\n replacementCharRatio: number\r\n puaRatio: number\r\n needsOcr: boolean\r\n ocrReason?: \"low_text\" | \"high_pua\" | \"high_control\" | \"high_replacement\" | \"garbled_hangul\"\r\n}\r\n\r\n/** 문서 단위 품질 요약 (PDF 전용). */\r\nexport interface DocumentQualitySummary {\r\n totalPages: number\r\n totalTextChars: number\r\n avgHangulRatio: number\r\n avgControlCharRatio: number\r\n avgReplacementCharRatio: number\r\n avgPuaRatio: number\r\n lowTextPageCount: number\r\n highPuaPageCount: number\r\n needsOcr: boolean\r\n ocrCandidatePages: number[]\r\n}\r\n\r\n/** 추출된 이미지 — ParseSuccess.images에 포함 */\r\nexport interface ExtractedImage {\r\n /** 마크다운에서 참조되는 파일명 (예: image_001.png) */\r\n filename: string\r\n /** 이미지 바이너리 */\r\n data: Uint8Array\r\n /** MIME 타입 */\r\n mimeType: string\r\n}\r\n\r\nexport interface ParseFailure extends ParseResultBase {\r\n success: false\r\n /** 오류 메시지 */\r\n error: string\r\n /** 구조화된 에러 코드 */\r\n code?: ErrorCode\r\n}\r\n\r\nexport type ParseResult = ParseSuccess | ParseFailure\r\n\r\n// ─── 문서 비교 (Diff) ───────────────────────────────\r\n\r\nexport type DiffChangeType = \"added\" | \"removed\" | \"modified\" | \"unchanged\"\r\n\r\nexport interface BlockDiff {\r\n type: DiffChangeType\r\n /** 원본 블록 (added이면 undefined) */\r\n before?: IRBlock\r\n /** 변경 후 블록 (removed이면 undefined) */\r\n after?: IRBlock\r\n /** modified 테이블의 셀 단위 diff */\r\n cellDiffs?: CellDiff[][]\r\n /** 유사도 (0-1) */\r\n similarity?: number\r\n}\r\n\r\nexport interface CellDiff {\r\n type: DiffChangeType\r\n before?: string\r\n after?: string\r\n}\r\n\r\nexport interface DiffResult {\r\n stats: { added: number; removed: number; modified: number; unchanged: number }\r\n diffs: BlockDiff[]\r\n}\r\n\r\n// ─── 라운드트립 패치 (v3.0) ─────────────────────────\r\n\r\n/** 패치 중 매핑 실패/미지원으로 건너뛴 항목 — silent 실패 금지 */\r\nexport interface PatchSkip {\r\n /** 건너뛴 사유 */\r\n reason: string\r\n /** 원본 쪽 내용 요약 (최대 80자) */\r\n before?: string\r\n /** 편집 쪽 내용 요약 (최대 80자) */\r\n after?: string\r\n /**\r\n * 부분 적용 표시 — 변경이 적용은 됐지만(applied 계상) 편집 원형 그대로는\r\n * 아님 (예: 셀 내 줄 추가를 마지막 문단에 병합). 완전 미적용 skip과 구분.\r\n */\r\n partial?: boolean\r\n}\r\n\r\n/** patchHwpx 옵션 */\r\nexport interface PatchOptions {\r\n /** 패치 후 재파싱 자동 검증 (기본 true) */\r\n verify?: boolean\r\n}\r\n\r\n/** patchHwpx / patchBlocks 결과 */\r\nexport interface PatchResult {\r\n success: boolean\r\n /** 패치된 HWPX (success=true) */\r\n data?: Uint8Array\r\n /** 적용된 변경 수 */\r\n applied: number\r\n /** 매핑 실패 항목 (이유 포함) */\r\n skipped: PatchSkip[]\r\n /**\r\n * 무손실 검증 (patchHwpx/patchHwp 전용): 패치본 재파싱 vs 편집 마크다운의\r\n * 잔차 diff — modified/added/removed가 0이어야 의도가 전부 반영된 것.\r\n * session.patchBlocks는 이 필드를 채우지 않는다 (changes 참조).\r\n */\r\n verification?: DiffResult\r\n /**\r\n * 변경 가시화 (session.patchBlocks 전용): 패치 전 → 후 문서 diff —\r\n * 적용된 편집 수만큼 modified가 나오는 것이 정상. verification과 의미가\r\n * 정반대이므로 혼용 금지.\r\n */\r\n changes?: DiffResult\r\n /** 실패 사유 (success=false) */\r\n error?: string\r\n}\r\n\r\n// ─── 양식 인식 ──────────────────────────────────────\r\n\r\nexport interface FormField {\r\n label: string\r\n value: string\r\n /** 0-based 소스 행 */\r\n row: number\r\n /** 0-based 소스 열 */\r\n col: number\r\n /** 매칭된 입력 키(정규화) — 모호 라벨 거부 가드(fillWithUniqueGuard)의 집계 기준 */\r\n key?: string\r\n}\r\n\r\nexport interface FormResult {\r\n fields: FormField[]\r\n /** 양식 확신도 (0-1) */\r\n confidence: number\r\n}\r\n\r\n// ─── OCR 프로바이더 ─────────────────────────────────\r\n\r\n/** 사용자 제공 OCR 함수 — 페이지 이미지를 받아 텍스트 반환.\r\n * PDF 경로는 항상 \"image/png\", 이미지 직접 입력 경로는 원본 mime 그대로 전달. */\r\nexport type OcrProvider = (\r\n pageImage: Uint8Array,\r\n pageNumber: number,\r\n mimeType: \"image/png\" | \"image/jpeg\" | \"image/webp\"\r\n) => Promise<string>\r\n\r\n// ─── Watch 모드 ─────────────────────────────────────\r\n\r\nexport interface WatchOptions {\r\n dir: string\r\n outDir?: string\r\n webhook?: string\r\n format?: \"markdown\" | \"json\"\r\n pages?: string\r\n silent?: boolean\r\n}\r\n\r\n// ─── 헤딩 감지 공통 임계값 ──────────────────────────\r\n\r\n/** 폰트 크기 비율 → heading level (전 파서 공통) */\r\nexport const HEADING_RATIO_H1 = 1.5\r\nexport const HEADING_RATIO_H2 = 1.3\r\nexport const HEADING_RATIO_H3 = 1.15\r\n\r\n// ─── 내부 파서 반환 타입 ─────────────────────────────\r\n\r\n/** 내부 파서가 index.ts에 반환하는 공통 타입 (HWP5/HWPX/PDF/XLSX/DOCX) */\r\nexport interface InternalParseResult {\r\n markdown: string\r\n blocks: IRBlock[]\r\n metadata?: DocumentMetadata\r\n outline?: OutlineItem[]\r\n warnings?: ParseWarning[]\r\n images?: ExtractedImage[]\r\n /** PDF 전용: 이미지 기반 PDF 여부 */\r\n isImageBased?: boolean\r\n /** PDF 전용: 페이지별 품질 신호 */\r\n pageQuality?: PageQuality[]\r\n /** PDF 전용: 문서 단위 품질 요약 */\r\n qualitySummary?: DocumentQualitySummary\r\n}\r\n"],"mappings":";;;AA2dO,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;","names":[]}
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- blocksToChunks
4
- } from "./chunk-SPKBIFSK.js";
5
- import "./chunk-GSMPTZC7.js";
6
- import "./chunk-DRQUAYNT.js";
7
- export {
8
- blocksToChunks
9
- };
10
- //# sourceMappingURL=chunks-Q7T4SQGW.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pdf/formula/postprocess.ts","../src/pdf/formula/detector.ts","../src/pdf/formula/recognizer.ts","../src/pdf/formula/pipeline.ts"],"sourcesContent":["/**\n * LaTeX 후처리 — Pix2Text `latex_ocr.py` 의 post_process 간소화 + 자체 필터\n *\n * 1) 후행 whitespace command 제거 (\\, \\: \\; \\! \\quad \\qquad \\enspace \\thinspace \\ )\n * 2) 연속 공백 → 1개\n * 3) 빈 그룹 반복 제거 (^{} _{} \\hat{} \\bar{} \\vec{} 등)\n * 4) \\cmd 뒤 영문자 공백 분리 (\\cdotd → \\cdot d, \\timesd → \\times d)\n * 5) isTrivialFormula — 다이어그램 단일 글자/반복/장식 오탐 제거\n */\n\nconst TRAILING_WHITESPACE_CMDS = [\n \"\\\\,\",\n \"\\\\:\",\n \"\\\\;\",\n \"\\\\!\",\n \"\\\\ \",\n \"\\\\quad\",\n \"\\\\qquad\",\n \"\\\\enspace\",\n \"\\\\thinspace\",\n] as const\n\nexport function postProcessLatex(latex: string): string {\n let s = stripTrailingWhitespace(latex)\n s = collapseSpaces(s)\n for (let i = 0; i < 10; i++) {\n const next = stripEmptyGroups(s)\n if (next === s) break\n s = next\n }\n s = fixLatexSpacing(s)\n s = normalizeFormulaSpacing(s)\n s = s.trim()\n // trivial 이면 빈 문자열 반환 — 상위(pipeline/parser) 에서 latex.trim() 비었을 때 skip.\n if (isTrivialFormula(s)) return \"\"\n return s\n}\n\nexport function stripTrailingWhitespace(s: string): string {\n let t = s\n // 바깥 loop: 한 번 제거 후 다시 체크 (중첩 \"\\\\, \\\\quad\" 같은 경우)\n for (;;) {\n const trimmed = t.replace(/[\\s]+$/, \"\")\n let changed = false\n for (const p of TRAILING_WHITESPACE_CMDS) {\n if (trimmed.endsWith(p)) {\n t = trimmed.slice(0, trimmed.length - p.length)\n changed = true\n break\n }\n }\n if (!changed) return trimmed\n }\n}\n\nexport function collapseSpaces(s: string): string {\n let out = \"\"\n let prevSpace = false\n for (const c of s) {\n if (/\\s/.test(c)) {\n if (!prevSpace) {\n out += \" \"\n prevSpace = true\n }\n } else {\n out += c\n prevSpace = false\n }\n }\n return out\n}\n\n/**\n * 빈 그룹 `{}` 또는 `{\\s+}` 를 찾아 선행하는 `^`, `_`, 또는 `\\cmd` 와 함께 제거.\n */\nexport function stripEmptyGroups(s: string): string {\n let out = \"\"\n let i = 0\n const bytes = s\n while (i < bytes.length) {\n const ch = bytes[i]\n if (ch === \"{\") {\n // 빈 { \\s* } 스캔\n let j = i + 1\n while (j < bytes.length && /\\s/.test(bytes[j])) j++\n if (j < bytes.length && bytes[j] === \"}\") {\n // 앞쪽 공백 제거\n while (out.endsWith(\" \") || out.endsWith(\"\\t\")) {\n out = out.slice(0, -1)\n }\n if (out.endsWith(\"^\") || out.endsWith(\"_\")) {\n out = out.slice(0, -1)\n } else {\n // \\cmd 형태인지 탐색\n let k = out.length\n while (k > 0 && /[A-Za-z]/.test(out[k - 1])) k--\n if (k > 0 && out[k - 1] === \"\\\\\" && k < out.length) {\n out = out.slice(0, k - 1)\n }\n // 아니면 아무것도 안 함 — 빈 {} 만 제거\n }\n i = j + 1\n continue\n }\n }\n out += ch\n i++\n }\n return out\n}\n\n/**\n * LaTeX 명령어 화이트리스트 — 공백 누락 감지에 사용.\n * MFR 이 `\\cdot d` 를 `\\cdotd` 로 합쳐 출력할 때, 어느 지점에서 명령어가 끝나는지\n * 알려진 커맨드명으로 판단한다. 완전한 리스트는 아니며 OCR 에서 실제 관찰된 케이스 중심.\n */\nconst KNOWN_LATEX_CMDS: ReadonlySet<string> = new Set([\n // 연산자\n \"cdot\", \"cdots\", \"ldots\", \"dots\", \"vdots\", \"ddots\",\n \"times\", \"div\", \"pm\", \"mp\", \"ast\", \"star\", \"circ\", \"bullet\",\n \"oplus\", \"ominus\", \"otimes\", \"odot\",\n // 관계\n \"approx\", \"equiv\", \"neq\", \"ne\", \"sim\", \"simeq\", \"cong\",\n \"leq\", \"geq\", \"le\", \"ge\", \"ll\", \"gg\", \"prec\", \"succ\", \"preceq\", \"succeq\",\n \"propto\", \"parallel\", \"perp\",\n // 집합/논리\n \"in\", \"notin\", \"ni\", \"subset\", \"supset\", \"subseteq\", \"supseteq\",\n \"cap\", \"cup\", \"bigcap\", \"bigcup\", \"emptyset\", \"varnothing\",\n \"forall\", \"exists\", \"nexists\", \"neg\", \"lnot\", \"land\", \"lor\", \"vee\", \"wedge\",\n // 그리스 소문자\n \"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \"varepsilon\",\n \"zeta\", \"eta\", \"theta\", \"vartheta\", \"iota\", \"kappa\", \"lambda\",\n \"mu\", \"nu\", \"xi\", \"omicron\", \"pi\", \"varpi\", \"rho\", \"varrho\",\n \"sigma\", \"varsigma\", \"tau\", \"upsilon\", \"phi\", \"varphi\",\n \"chi\", \"psi\", \"omega\",\n // 그리스 대문자\n \"Gamma\", \"Delta\", \"Theta\", \"Lambda\", \"Xi\", \"Pi\", \"Sigma\",\n \"Upsilon\", \"Phi\", \"Psi\", \"Omega\",\n // 화살표\n \"to\", \"gets\", \"mapsto\", \"rightarrow\", \"leftarrow\", \"leftrightarrow\",\n \"Rightarrow\", \"Leftarrow\", \"Leftrightarrow\", \"uparrow\", \"downarrow\",\n \"longrightarrow\", \"longleftarrow\", \"longmapsto\",\n // 큰 연산자\n \"sum\", \"prod\", \"coprod\", \"int\", \"iint\", \"iiint\", \"oint\", \"bigoplus\", \"bigotimes\",\n // 함수명\n \"sin\", \"cos\", \"tan\", \"sec\", \"csc\", \"cot\",\n \"arcsin\", \"arccos\", \"arctan\", \"sinh\", \"cosh\", \"tanh\",\n \"log\", \"ln\", \"lg\", \"exp\", \"lim\", \"liminf\", \"limsup\",\n \"sup\", \"inf\", \"max\", \"min\", \"arg\", \"det\", \"dim\", \"gcd\", \"deg\", \"hom\", \"ker\", \"mod\",\n // 특수 기호/수식\n \"infty\", \"partial\", \"nabla\", \"prime\", \"aleph\", \"ell\", \"hbar\", \"Re\", \"Im\",\n \"top\", \"bot\", \"angle\", \"vdash\", \"dashv\",\n // 기타\n \"left\", \"right\", \"big\", \"Big\", \"bigg\", \"Bigg\",\n])\n\n/**\n * `\\cmd` 뒤에 영문자가 바로 붙으면 공백 분리 (e.g. `\\cdotd` → `\\cdot d`, `\\timesd_{k}` → `\\times d_{k}`).\n *\n * MFR 이 좁은 영역에서 가끔 `\\cdot` 과 다음 변수 사이 공백을 누락. 그대로 두면 LaTeX 파서가\n * `\\cdotd` 를 undefined command 로 처리 (KaTeX: 에러 / TeX: 정의되지 않은 제어 시퀀스).\n * 알려진 LaTeX 명령어 prefix 중 가장 긴 것을 찾아 분할하면 렌더 안정성 확보.\n *\n * `\\cmd{..}` (영문자 뒤 `{`) 는 인자 포함 형태로 간주해 분리하지 않음.\n */\nexport function fixLatexSpacing(s: string): string {\n let out = \"\"\n let i = 0\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length && /[A-Za-z]/.test(s[i + 1])) {\n // \\cmd 최장일치\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n const full = s.slice(i + 1, j) // 명령어 이름 (앞 \\ 제거)\n const nextChar = j < s.length ? s[j] : \"\"\n\n // \\cmd{..} 형태 — 인자로 이어지므로 분리하지 않음\n if (nextChar === \"{\") {\n out += \"\\\\\" + full\n i = j\n continue\n }\n\n // 자체가 알려진 명령어이거나, 긴 prefix 가 없으면 그대로\n let splitAt = full.length\n if (!KNOWN_LATEX_CMDS.has(full) && full.length >= 3) {\n // 뒤에서부터 prefix 길이를 줄이며 가장 긴 known cmd 찾기\n for (let len = full.length - 1; len >= 2; len--) {\n if (KNOWN_LATEX_CMDS.has(full.slice(0, len))) {\n splitAt = len\n break\n }\n }\n }\n\n out += \"\\\\\" + full.slice(0, splitAt)\n if (splitAt < full.length) {\n out += \" \" + full.slice(splitAt)\n }\n i = j\n } else {\n out += s[i]\n i++\n }\n }\n return out\n}\n\n/**\n * trivial(noise) 수식 판정.\n *\n * true 인 케이스 (MFD 오탐 주범):\n * 1) 공백/중괄호 제거 후 2자 이하 (e.g. `O`, `a`, `.`, `n`)\n * 2) 단일 `\\cmd` (e.g. `\\imath`, `\\pi`, `\\eta`, `\\sigma`, `\\theta`, `\\emptyset`, `\\varPi`)\n * 3) 단일 `\\mathrm{..}` / `\\textrm{..}` / `\\operatorname{..}` 류 + 짧은 내용 (e.g. `\\mathrm{fcloc}`)\n * 4) 동일 토큰이 3회 이상 + 전체의 50% 이상 (e.g. `\\pm \\pm \\pm \\pm`, `\\cap \\exists \\exists \\rceil`)\n *\n * false 유지 (의미 있는 수식):\n * `O(1)`, `d_{k}=64`, `\\sqrt{d_{k}}`, `PE_{pos+k}`, 등\n */\nexport function isTrivialFormula(s: string): boolean {\n const t = s.trim()\n if (t.length === 0) return true\n\n // 1) 공백/중괄호 제거 후 길이 ≤ 2\n const stripped = t.replace(/[\\s{}]/g, \"\")\n if (stripped.length <= 2) return true\n\n // 2) 단일 \\cmd (e.g. \\imath, \\varPi, \\pi)\n if (/^\\\\[A-Za-z]+$/.test(t)) return true\n\n // 3) 단일 \\mathrm{..} / \\textrm{..} / \\operatorname{..} / \\mathit{..} / \\mathbf{..} / \\mathcal{..} + 짧은 내용\n if (\n /^\\\\(?:mathrm|textrm|text|operatorname|mathit|mathbf|mathcal|mathsf|mathtt)\\{[A-Za-z]{1,6}\\}$/.test(\n t,\n )\n )\n return true\n\n const tokens = tokenizeLatex(t)\n\n // 4) 반복 토큰 dominant (e.g. \"\\\\pm \\\\pm \\\\pm \\\\pm\")\n if (tokens.length >= 3) {\n const freq = new Map<string, number>()\n for (const tok of tokens) freq.set(tok, (freq.get(tok) ?? 0) + 1)\n let maxCount = 0\n for (const c of freq.values()) if (c > maxCount) maxCount = c\n if (maxCount >= 3 && maxCount / tokens.length >= 0.5) return true\n }\n\n // 5) 심볼만 구성된 짧은 식 — 토큰 2~4개이고 연산자/숫자 없음 (e.g. \"\\\\cap \\\\exists \\\\exists \\\\rceil\")\n // 의미 있는 수식은 대개 `=` 또는 숫자가 포함됨. 허용되는 연산자: = + - / * < > 숫자\n if (tokens.length >= 2 && tokens.length <= 4) {\n const hasOpOrNum = tokens.some((tok) =>\n /^[=+\\-/*<>]$/.test(tok) || /^[0-9]$/.test(tok),\n )\n if (!hasOpOrNum) return true\n }\n\n // 6) substring 반복 패턴 — 동일 5~15자 substring 이 3회 이상 + 커버리지 60%+\n // (e.g. \"\\\\alpha_{1}=\\\\alpha_{2}=\\\\alpha_{3}=...\" 의 `\\\\alpha_{` 반복,\n // \"c_{c}^{\\\\prime}\\\\phi_{c}^{\\\\prime}=c_{c}^{\\\\prime}...\" 의 `c_{c}^{\\\\prime}` 반복)\n if (hasHighRepetition(t)) return true\n\n // 7) MFR placeholder 인 `\\square` 포함 — 인식 실패 영역을 `\\square` 로 대체하는 특성\n // 정당한 수식에 `\\square` 가 나오는 경우는 거의 없음 (대부분 `\\Box`, `\\blacksquare` 등 사용)\n if (t.includes(\"\\\\square\")) return true\n\n // 8) 단독 숫자/실수 (e.g. \"$1.0$\", \"$42$\", \"$-3.14$\")\n // 공백/중괄호/백슬래시 제거 후 순수 숫자/부호/소수점만 남으면 trivial\n if (/^[-+]?\\d+\\.?\\d*$/.test(t.replace(/[\\s{}\\\\]/g, \"\"))) return true\n\n // 9) `(X)(X)` 또는 `{X}{X}` 연속 중복 — 동일 그룹 반복 (e.g. \"$C(T_{2})(T_{2})$\")\n // 한 단계 중첩 허용: `{k_{c}}` 같이 내부에 `{...}` 하나 포함 가능.\n if (/(\\([^()]{2,15}\\))\\s*\\1/.test(t)) return true\n if (/(\\{(?:[^{}]|\\{[^{}]*\\})+\\})\\s*\\1/.test(t)) return true\n\n // 10) 동일 인자 반복 — 괄호 인자 중 쉼표 구분 3개 중 2개 이상 동일 (e.g. `C(\\tau_{2},\\mu^{\\prime},\\mu^{\\prime})`)\n // 완전 일치 인자가 2회+ 반복이면 OCR 반복 오류로 간주\n const argMatch = t.match(/^[A-Za-z\\\\][A-Za-z]*\\(([^()]+)\\)$/)\n if (argMatch) {\n const args = argMatch[1].split(\",\").map((a) => a.trim())\n if (args.length >= 2) {\n const freq = new Map<string, number>()\n for (const a of args) if (a) freq.set(a, (freq.get(a) ?? 0) + 1)\n for (const [, c] of freq) {\n if (c >= 2 && c / args.length >= 0.5) return true\n }\n }\n }\n\n // 11) X/X 또는 \\frac{X}{X} — 분자=분모 = 1, 의미 없는 수식\n // 수식 **어디에나** 나타나면 trivial (e.g. \"$k<\\\\frac{\\\\eta}{\\\\eta}$\" 도 포함)\n // 정당한 수식에서 $\\\\frac{a}{a}$ 를 쓰는 경우는 거의 없음 (대수적으로 1).\n if (/\\\\frac\\{([^{}]+)\\}\\{\\1\\}/.test(t)) return true\n // X/X 꼴 (단일 변수 또는 \\cmd)\n if (/(\\\\[A-Za-z]+|\\b[A-Za-z])\\s*\\/\\s*\\1\\b/.test(t)) return true\n\n // 12) `\\begin{matrix}` 내부 `\\cdots` 여러 번 — MFR 이 다이어그램/표를 matrix 로 오인식\n // 본문 수식의 matrix 는 구체적 원소가 있어 `\\cdots` 가 2회 이상 나오는 경우 거의 없음\n if (/\\\\begin\\{(?:matrix|pmatrix|bmatrix|vmatrix)\\}/.test(t)) {\n const cdotsCount = (t.match(/\\\\cdots/g) ?? []).length\n if (cdotsCount >= 2) return true\n }\n\n // 13) 다이어그램 텍스트 레이블 — `\\mathrm{word}` 가 2회+ 포함된 짧은 식 (토큰 수 ≤ 12)\n // 또는 `[a-z]{1,3}_\\{\\mathrm{word}\\}` 꼴의 비정상 변수명 (e.g. `cl_{\\mathrm{model}}`)\n if (tokens.length <= 12) {\n const mathrmCount = (t.match(/\\\\mathrm\\{/g) ?? []).length\n if (mathrmCount >= 2) {\n // 연산자/등호/숫자가 거의 없어 \"단순 레이블\" 로 보이는지 추가 확인\n const hasRealMath = /[=+\\-*/<>^]/.test(t) && /\\d/.test(t)\n if (!hasRealMath) return true\n }\n }\n // 비정상 변수명: 2-3자 영문 접두 + _{\\mathrm{긴단어}} 단독 (e.g. `cl_{\\mathrm{model}}`, `to_{\\mathrm{max}}`)\n // 정상 변수명은 보통 단일 문자 (`d_{\\mathrm{model}}`, `W_{i}`) — 2자 이상이면 다이어그램 오인식\n if (/^[a-zA-Z]{2,3}_\\{\\\\mathrm\\{[a-zA-Z]{3,}\\}\\}$/.test(t)) return true\n\n // 14) `\\mathrm{word}` + 이항 연산자 + single 요소 꼴 — 다이어그램 \"word → value\" 레이블\n // (e.g. `\\mathrm{to}-\\infty`, `\\mathrm{to}+\\infty`)\n if (/^\\\\mathrm\\{[a-z]{2,}\\}[-+][-+]?(?:\\\\[a-zA-Z]+|[a-zA-Z0-9])$/.test(t)) return true\n\n // 15) `\\mathsf`, `\\mathtt`, `\\texttt` 는 본문 수식에 거의 쓰이지 않고 다이어그램 타이포그래피 오인식이 대부분\n // — 포함만으로 trivial (e.g. `\\mathtt{Welgnt}`, `\\mathsf{Tr}_{s}`, `\\texttt{wg}`)\n if (/\\\\(?:mathsf|mathtt|texttt)\\{/.test(t)) return true\n\n // 16) `\\begin{aligned}` 이지만 `=` 없음 — 정당한 aligned 는 항상 등호 포함 (여러 줄 equation)\n // 등호 없으면 OCR garbage 조합\n if (/\\\\begin\\{aligned\\}/.test(t) && !t.includes(\"=\")) return true\n\n // 17) `\\begin{matrix}` + `\\downarrow` 2회+ — 네트워크 architecture 다이어그램 오인식\n if (/\\\\begin\\{matrix\\}/.test(t) && (t.match(/\\\\downarrow/g) ?? []).length >= 2) return true\n\n return false\n}\n\n/**\n * substring 반복 탐지 — 동일한 N자 substring 이 3회 이상 나타나고\n * 그 반복 총 길이가 전체의 60% 이상이면 true.\n *\n * 5~15자 범위만 검사 (짧으면 정상 수식의 `^{2}` 같은 패턴도 걸림, 길면 노이즈 거의 없음).\n * 영문자 포함 substring 만 검사 (구두점만 반복은 정상 수식에도 많음).\n *\n * 정당한 수식은 다양한 구조로 거의 겹치지 않아 false-positive 낮음.\n */\nexport function hasHighRepetition(s: string): boolean {\n if (s.length < 15) return false\n\n for (let len = 5; len <= 15; len++) {\n // substring 길이 × 3회가 전체보다 길면 의미 없음\n if (len * 3 > s.length) break\n const seen = new Map<string, number>()\n for (let i = 0; i <= s.length - len; i++) {\n const sub = s.slice(i, i + len)\n if (!/[a-zA-Z]/.test(sub)) continue\n seen.set(sub, (seen.get(sub) ?? 0) + 1)\n }\n for (const [, count] of seen) {\n if (count < 3) continue\n // 겹치지 않는 점유율 추정: count*len (overlapping 포함이라 약간 과대)\n // 보수적 판정 위해 최소 3회 + 60% 커버리지\n if ((count * len) / s.length >= 0.6) return true\n }\n }\n return false\n}\n\n/**\n * LaTeX 를 단순 토큰 배열로 분할 — `\\cmd` 는 하나의 토큰, 그 외는 non-space 단일 문자.\n * isTrivialFormula 의 반복 감지용.\n */\nfunction tokenizeLatex(s: string): string[] {\n const result: string[] = []\n let i = 0\n while (i < s.length) {\n const c = s[i]\n if (c === \"\\\\\") {\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n if (j === i + 1 && j < s.length) j++ // `\\\\` 또는 `\\{` 같은 단일 escape\n result.push(s.slice(i, j))\n i = j\n } else if (/\\s/.test(c)) {\n i++\n } else {\n result.push(c)\n i++\n }\n }\n return result\n}\n\n/**\n * MFR tokenizer 가 LaTeX 토큰 사이에 삽입하는 과도한 공백을 정리.\n *\n * 예: `\\mathrm { m o d d }` → `\\mathrm{modd}`, `6 4` → `64`, `( Q, K, V )` → `(Q,K,V)`\n *\n * 규칙: 공백을 앞뒤 토큰 기준으로 유지/제거 결정.\n * - 직전이 `\\cmd` 이고 직후가 영문자 → **유지** (e.g. `\\cdot d`, `\\alpha b` — 공백 없으면 greedy 로 `\\cdotd` 가 명령어로 해석될 수 있음)\n * - 그 외 → **제거** (숫자/괄호/중괄호/첨자/구두점 주변 공백은 LaTeX 의미를 바꾸지 않음)\n *\n * `fixLatexSpacing` 이후에 호출되는 것을 전제 — 먼저 공백 누락을 복원한 뒤 과도한 공백을 걷어냄.\n */\nexport function normalizeFormulaSpacing(s: string): string {\n // `\\cmd`, 단일 escape, 공백, 일반 문자 단위로 토큰화 (공백도 토큰으로 유지)\n const tokens: string[] = []\n let i = 0\n while (i < s.length) {\n const c = s[i]\n if (c === \"\\\\\") {\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n if (j === i + 1 && j < s.length) j++ // 단일 escape (`\\\\`, `\\{` 등)\n tokens.push(s.slice(i, j))\n i = j\n } else if (/\\s/.test(c)) {\n tokens.push(\" \")\n i++\n } else {\n tokens.push(c)\n i++\n }\n }\n\n const out: string[] = []\n for (let k = 0; k < tokens.length; k++) {\n if (tokens[k] !== \" \") {\n out.push(tokens[k])\n continue\n }\n // 공백 토큰 — 유지 여부 결정\n // 연속 공백은 나중에 병합 (아래 로직은 앞뒤 non-space 토큰 기준)\n let prev = \"\"\n for (let p = k - 1; p >= 0; p--) {\n if (tokens[p] !== \" \") {\n prev = tokens[p]\n break\n }\n }\n let next = \"\"\n for (let q = k + 1; q < tokens.length; q++) {\n if (tokens[q] !== \" \") {\n next = tokens[q]\n break\n }\n }\n const prevIsCmd = /^\\\\[A-Za-z]+$/.test(prev)\n const nextIsAlpha = /^[A-Za-z]$/.test(next)\n if (prevIsCmd && nextIsAlpha) {\n // 앞 cmd 와 뒤 변수 분리용 공백 (연속 공백이더라도 하나만 남김)\n if (out.length === 0 || out[out.length - 1] !== \" \") {\n out.push(\" \")\n }\n }\n // 그 외 공백은 drop\n }\n\n // 앞/뒤 공백 제거\n while (out.length > 0 && out[0] === \" \") out.shift()\n while (out.length > 0 && out[out.length - 1] === \" \") out.pop()\n\n return out.join(\"\")\n}\n","/**\n * MFD (Mathematical Formula Detection) — YOLOv8 기반 수식 영역 검출\n *\n * 모델: breezedeus/pix2text-mfd (YOLOv8 small, imgsz=768, stride=32)\n * 출력: [1, 6, 12096] — (cx, cy, w, h, class0_score, class1_score) × anchors\n * - class 0 = embedding (inline 수식)\n * - class 1 = isolated (display 수식)\n *\n * 전처리: letterbox (긴 변 비율 유지 + 회색 패딩 114)\n * 후처리: conf ≥ 0.25 → class-per-class NMS (IoU ≥ 0.45)\n */\n\nimport type { InferenceSession, Tensor } from \"onnxruntime-node\"\nimport type { FormulaKind, PixelFrame, FormulaRegion } from \"./types.js\"\n\nconst MFD_IMG_SIZE = 768\nconst MFD_NUM_CLASSES = 2\nconst MFD_CHANNELS = 4 + MFD_NUM_CLASSES\n/** 기본 confidence 임계값 (Pix2Text 원본 0.25 — 누락은 적지만 noise 발생) */\nconst MFD_CONF_INLINE = 0.30\n/** display 수식 임계값 — diagram/figure 오탐 감소 목적으로 inline 보다 높게 */\nconst MFD_CONF_DISPLAY = 0.40\nconst MFD_IOU_THRESHOLD = 0.45\n/** 최소 bbox 면적 (px²) — 이보다 작으면 OCR noise 가능성 높음 */\nconst MFD_MIN_AREA = 80\nconst PAD_VALUE = 114 / 255\n\ninterface RawDetection {\n x1: number\n y1: number\n x2: number\n y2: number\n kind: FormulaKind\n score: number\n}\n\n/**\n * 단일 페이지 이미지에서 수식 영역 검출 (인식 없음 — recognizer 로 넘김).\n * bbox 는 원본 이미지 좌표계.\n */\nexport async function detectFormulaRegions(\n session: InferenceSession,\n frame: PixelFrame,\n ort: typeof import(\"onnxruntime-node\"),\n): Promise<Omit<FormulaRegion, \"latex\">[]> {\n const { scale, padX, padY, tensor } = letterbox(frame, MFD_IMG_SIZE)\n\n const input = new ort.Tensor(\"float32\", tensor, [1, 3, MFD_IMG_SIZE, MFD_IMG_SIZE])\n const feeds: Record<string, Tensor> = { images: input }\n const outputs = await session.run(feeds)\n\n const firstKey = Object.keys(outputs)[0]\n const out = outputs[firstKey]\n if (!out || out.type !== \"float32\") {\n throw new Error(\"MFD 출력 없음 또는 dtype 불일치\")\n }\n\n const outDims = out.dims\n if (outDims.length !== 3) {\n throw new Error(`MFD 출력 차원 예상 3, 실제 ${outDims.length}: [${outDims.join(\",\")}]`)\n }\n const channels = outDims[1]\n const anchors = outDims[2]\n if (channels !== MFD_CHANNELS) {\n throw new Error(`MFD 채널 수 예상 ${MFD_CHANNELS}, 실제 ${channels}`)\n }\n if (anchors <= 0) return []\n\n const data = out.data as Float32Array\n const candidates: RawDetection[] = []\n\n for (let a = 0; a < anchors; a++) {\n const cx = data[a]\n const cy = data[anchors + a]\n const w = data[2 * anchors + a]\n const h = data[3 * anchors + a]\n\n let bestCls = 0\n let bestScore = 0\n for (let c = 0; c < MFD_NUM_CLASSES; c++) {\n const s = data[(4 + c) * anchors + a]\n if (s > bestScore) {\n bestScore = s\n bestCls = c\n }\n }\n // 클래스별 임계값 — display 쪽은 diagram/figure 오탐 감소 목적으로 inline 보다 엄격.\n const threshold = bestCls === 1 ? MFD_CONF_DISPLAY : MFD_CONF_INLINE\n if (bestScore < threshold) continue\n\n // letterbox → 원본 좌표\n let x1 = (cx - w / 2 - padX) / scale\n let y1 = (cy - h / 2 - padY) / scale\n let x2 = (cx + w / 2 - padX) / scale\n let y2 = (cy + h / 2 - padY) / scale\n\n x1 = clamp(x1, 0, frame.width - 1)\n y1 = clamp(y1, 0, frame.height - 1)\n x2 = clamp(x2, 0, frame.width - 1)\n y2 = clamp(y2, 0, frame.height - 1)\n\n if (x2 - x1 < 2 || y2 - y1 < 2) continue\n // 너무 작은 bbox (픽셀 단위 noise 로 보이는 영역) 제외\n if ((x2 - x1) * (y2 - y1) < MFD_MIN_AREA) continue\n\n candidates.push({\n x1,\n y1,\n x2,\n y2,\n kind: bestCls === 1 ? \"display\" : \"inline\",\n score: bestScore,\n })\n }\n\n // 클래스별 NMS (혼합 클래스 bbox 간 중복은 허용 — Pix2Text 원본 동작)\n const kept: RawDetection[] = []\n for (const kind of [\"inline\", \"display\"] as FormulaKind[]) {\n const subset = candidates.filter((c) => c.kind === kind)\n kept.push(...nms(subset, MFD_IOU_THRESHOLD))\n }\n\n // 읽기 순서 정렬 (위→아래, 왼→오른쪽)\n kept.sort((a, b) => a.y1 - b.y1 || a.x1 - b.x1)\n\n return kept.map((d) => ({\n bbox: { x1: d.x1, y1: d.y1, x2: d.x2, y2: d.y2 },\n kind: d.kind,\n score: d.score,\n }))\n}\n\n/**\n * YOLOv8 letterbox 전처리 — RGBA 프레임을 target×target float32 CHW tensor 로.\n *\n * - 긴 변 기준으로 비율 유지 리사이즈\n * - 가운데 패딩 (회색 114)\n * - /255 정규화\n * - CHW 레이아웃\n */\nexport function letterbox(\n frame: PixelFrame,\n target: number,\n): { scale: number; padX: number; padY: number; tensor: Float32Array } {\n const w = frame.width\n const h = frame.height\n const scale = Math.min(target / w, target / h)\n const newW = Math.max(1, Math.round(w * scale))\n const newH = Math.max(1, Math.round(h * scale))\n const padX = (target - newW) / 2\n const padY = (target - newH) / 2\n const offX = Math.floor(padX)\n const offY = Math.floor(padY)\n\n const ts = target\n const tensor = new Float32Array(3 * ts * ts)\n tensor.fill(PAD_VALUE)\n\n // RGBA 원본 → 먼저 nearest-neighbor resize 한 뒤 복사.\n // (sharp 로 정확한 bilinear 가능하지만, 여기선 이미 렌더링된 bitmap 이 충분히 해상도 높음 —\n // 결과는 동일한 수준으로 수식 박스 위치 맞춤. Rust 구현도 Triangle 사용.)\n const src = frame.data\n const srcW = frame.width\n const srcH = frame.height\n\n for (let y = 0; y < newH; y++) {\n const sy = Math.min(srcH - 1, Math.floor((y + 0.5) / newH * srcH))\n for (let x = 0; x < newW; x++) {\n const sx = Math.min(srcW - 1, Math.floor((x + 0.5) / newW * srcW))\n const srcIdx = (sy * srcW + sx) * 4\n const r = src[srcIdx]\n const g = src[srcIdx + 1]\n const b = src[srcIdx + 2]\n\n const tx = x + offX\n const ty = y + offY\n const idx = ty * ts + tx\n tensor[idx] = r / 255\n tensor[ts * ts + idx] = g / 255\n tensor[2 * ts * ts + idx] = b / 255\n }\n }\n\n return { scale, padX, padY, tensor }\n}\n\nfunction nms(cands: RawDetection[], iouThreshold: number): RawDetection[] {\n const sorted = [...cands].sort((a, b) => b.score - a.score)\n const kept: RawDetection[] = []\n for (const cand of sorted) {\n let keep = true\n for (const k of kept) {\n if (iou(cand, k) > iouThreshold) {\n keep = false\n break\n }\n }\n if (keep) kept.push(cand)\n }\n return kept\n}\n\nfunction iou(\n a: { x1: number; y1: number; x2: number; y2: number },\n b: { x1: number; y1: number; x2: number; y2: number },\n): number {\n const x1 = Math.max(a.x1, b.x1)\n const y1 = Math.max(a.y1, b.y1)\n const x2 = Math.min(a.x2, b.x2)\n const y2 = Math.min(a.y2, b.y2)\n const interW = Math.max(0, x2 - x1)\n const interH = Math.max(0, y2 - y1)\n const inter = interW * interH\n const areaA = Math.max(0, a.x2 - a.x1) * Math.max(0, a.y2 - a.y1)\n const areaB = Math.max(0, b.x2 - b.x1) * Math.max(0, b.y2 - b.y1)\n const union = areaA + areaB - inter\n return union <= 0 ? 0 : inter / union\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n if (v < lo) return lo\n if (v > hi) return hi\n return v\n}\n\n// 테스트 용도로만 export\nexport const __internal = { nms, iou, letterbox }\n","/**\n * MFR (Mathematical Formula Recognition) — DeiT encoder + TrOCR decoder\n *\n * 모델: breezedeus/pix2text-mfr\n * - encoder: DeiT distilled, input 384×384 → output [1, 578, 384]\n * - decoder: TrOCR (no KV cache), vocab=1200, EOS=2\n *\n * 전처리 (DeiT): Catmull-Rom resize → /255 → (x - 0.5) / 0.5 == x*2 - 1\n *\n * 디코딩: greedy, start=[2], stop at 2 또는 max_new_tokens=256\n * decoder 는 매 스텝 전체 시퀀스를 재계산 (no KV cache — 모델 고정)\n */\n\nimport type { InferenceSession, Tensor } from \"onnxruntime-node\"\nimport type { PreTrainedTokenizer } from \"@huggingface/transformers\"\nimport { postProcessLatex } from \"./postprocess.js\"\nimport type { PixelFrame } from \"./types.js\"\n\nconst MFR_IMG_SIZE = 384\nconst MFR_ENC_HIDDEN = 384\nconst MFR_MAX_NEW_TOKENS = 256\nconst MFR_EOS_ID = 2\nconst MFR_PAD_ID = 0\n\nexport interface RecognizeDeps {\n encoder: InferenceSession\n decoder: InferenceSession\n tokenizer: PreTrainedTokenizer\n ort: typeof import(\"onnxruntime-node\")\n}\n\n/**\n * 단일 수식 crop 을 LaTeX 로 인식.\n * 입력 frame 은 이미 해당 영역만 잘린 RGBA 이미지이어야 한다 (recognizer 가 resize 수행).\n */\nexport async function recognizeFormula(\n deps: RecognizeDeps,\n crop: PixelFrame,\n): Promise<string> {\n const tensor = deitPreprocess(crop, MFR_IMG_SIZE)\n const { ort, encoder, decoder, tokenizer } = deps\n\n const pixelInput = new ort.Tensor(\"float32\", tensor, [1, 3, MFR_IMG_SIZE, MFR_IMG_SIZE])\n const encOut = await encoder.run({ pixel_values: pixelInput })\n\n const encKey =\n Object.keys(encOut).find((k) => k.includes(\"hidden\")) ?? Object.keys(encOut)[0]\n const encTensor = encOut[encKey]\n if (!encTensor || encTensor.type !== \"float32\") {\n throw new Error(\"MFR encoder 출력 없음\")\n }\n const encDims = encTensor.dims\n if (encDims.length !== 3) {\n throw new Error(`MFR encoder 차원 예상 3, 실제 ${encDims.length}`)\n }\n const encSeq = encDims[1]\n const encHidden = encDims[2]\n if (encHidden !== MFR_ENC_HIDDEN) {\n throw new Error(`MFR encoder hidden 예상 ${MFR_ENC_HIDDEN}, 실제 ${encHidden}`)\n }\n const encData = encTensor.data as Float32Array\n\n // greedy decode\n const tokens: number[] = [MFR_EOS_ID] // decoder_start_token_id\n\n for (let step = 0; step < MFR_MAX_NEW_TOKENS; step++) {\n const seqLen = tokens.length\n const idsArr = BigInt64Array.from(tokens.map((t) => BigInt(t)))\n const idsTensor = new ort.Tensor(\"int64\", idsArr, [1, seqLen])\n\n // encoder_hidden_states 는 매 스텝 동일 — 복사 필요 (Tensor 는 buffer 소유)\n const hidCopy = new Float32Array(encData)\n const hidTensor = new ort.Tensor(\"float32\", hidCopy, [1, encSeq, encHidden])\n\n const decOut = await decoder.run({\n input_ids: idsTensor,\n encoder_hidden_states: hidTensor,\n })\n\n const logitKey =\n Object.keys(decOut).find((k) => k.includes(\"logit\")) ?? Object.keys(decOut)[0]\n const logitsTensor = decOut[logitKey]\n if (!logitsTensor || logitsTensor.type !== \"float32\") {\n throw new Error(\"MFR decoder logits 없음\")\n }\n const dims = logitsTensor.dims\n if (dims.length !== 3) {\n throw new Error(`MFR decoder 차원 예상 3, 실제 ${dims.length}`)\n }\n const decSeq = dims[1]\n const vocab = dims[2]\n const logitsData = logitsTensor.data as Float32Array\n\n // 마지막 step logits 만\n const lastOffset = (decSeq - 1) * vocab\n let bestId = 0\n let bestVal = -Infinity\n for (let v = 0; v < vocab; v++) {\n const val = logitsData[lastOffset + v]\n if (val > bestVal) {\n bestVal = val\n bestId = v\n }\n }\n tokens.push(bestId)\n if (bestId === MFR_EOS_ID) break\n }\n\n // 첫 start 토큰 제외 + EOS/PAD 제거\n const body: number[] = []\n for (let i = 1; i < tokens.length; i++) {\n const t = tokens[i]\n if (t === MFR_EOS_ID) break\n if (t === MFR_PAD_ID) continue\n if (t < 0) continue\n body.push(t)\n }\n\n // Transformers.js tokenizer.decode 는 skip_special_tokens=true 기본\n const raw = tokenizer.decode(body, { skip_special_tokens: true })\n return postProcessLatex(raw)\n}\n\n/**\n * DeiT preprocess:\n * resize to 384×384 (bilinear)\n * (pixel/255 - 0.5) / 0.5 == pixel/127.5 - 1\n * CHW layout\n */\nexport function deitPreprocess(crop: PixelFrame, target: number): Float32Array {\n const ts = target\n const out = new Float32Array(3 * ts * ts)\n const { data: src, width: srcW, height: srcH } = crop\n\n // 단순 nearest (이미 수식 crop 은 300DPI 근방이라 충분). 필요시 sharp bilinear 로 교체.\n for (let y = 0; y < ts; y++) {\n const sy = Math.min(srcH - 1, Math.max(0, Math.floor(((y + 0.5) / ts) * srcH)))\n for (let x = 0; x < ts; x++) {\n const sx = Math.min(srcW - 1, Math.max(0, Math.floor(((x + 0.5) / ts) * srcW)))\n const srcIdx = (sy * srcW + sx) * 4\n const r = src[srcIdx]\n const g = src[srcIdx + 1]\n const b = src[srcIdx + 2]\n\n const idx = y * ts + x\n out[idx] = r / 127.5 - 1\n out[ts * ts + idx] = g / 127.5 - 1\n out[2 * ts * ts + idx] = b / 127.5 - 1\n }\n }\n return out\n}\n","/**\r\n * 수식 OCR 파이프라인 — PDFium 렌더 + MFD + MFR 통합\r\n *\r\n * 한 번 생성된 FormulaPipeline 인스턴스는 ONNX 세션을 재사용해 여러 PDF 에 적용 가능.\r\n * Docufinder 는 CLI 프로세스 단위로 새로 띄우기 때문에 세션 재사용은 PDF 내부 페이지 루프에만 적용됨.\r\n */\r\n\r\nimport type { PDFiumLibrary, PDFiumDocument } from \"@hyzyla/pdfium\"\r\nimport type { InferenceSession } from \"onnxruntime-node\"\r\nimport type { PreTrainedTokenizer } from \"@huggingface/transformers\"\r\n\r\n/** sharp 은 CommonJS `export =` 형태라 타입을 직접 import 하기 까다로움. 함수형 시그니처만 사용. */\r\ntype SharpFactory = (\r\n input: Uint8Array | Buffer,\r\n options?: { raw?: { width: number; height: number; channels: number } },\r\n) => {\r\n extract(region: { left: number; top: number; width: number; height: number }): {\r\n raw(): { toBuffer(): Promise<Buffer> }\r\n }\r\n}\r\n\r\nimport { detectFormulaRegions } from \"./detector.js\"\r\nimport { recognizeFormula } from \"./recognizer.js\"\r\nimport {\r\n getFormulaModelsDir,\r\n MFD_MODEL,\r\n MFR_ENCODER_MODEL,\r\n MFR_DECODER_MODEL,\r\n MFR_TOKENIZER,\r\n} from \"./models.js\"\r\nimport type { FormulaRegion, PixelFrame } from \"./types.js\"\r\nimport { join } from \"path\"\r\n\r\n/** PDF 페이지 렌더 해상도 (scale=2 → 약 144 DPI). 수식 인식에는 이 이상은 과함. */\r\nconst RENDER_SCALE = 2\r\n\r\nexport interface FormulaPipelineOptions {\r\n /** 수식 인식 페이지 스케일 (기본 2). 값을 올리면 작은 수식 인식률 ↑, 속도 ↓. */\r\n scale?: number\r\n /** 페이지별 최대 수식 수 (안전 상한). 기본 50. */\r\n maxRegionsPerPage?: number\r\n /** 페이지 하나당 타임아웃 (ms, 기본 60000 = 1분). 초과 시 해당 페이지 skip. */\r\n pageTimeoutMs?: number\r\n}\r\n\r\nexport interface PageFormulaResult {\r\n pageNumber: number\r\n /** 페이지 전체 렌더 이미지의 가로/세로 (원본 좌표계, scale 반영됨) */\r\n renderedWidth: number\r\n renderedHeight: number\r\n /** 원본 PDF 포인트 기준 너비/높이 (pdfjs 와 좌표 매핑용) */\r\n pdfWidth: number\r\n pdfHeight: number\r\n regions: FormulaRegion[]\r\n}\r\n\r\n/**\r\n * 수식 OCR 실행 컨텍스트. 처음 호출 시 무겁게 초기화 (ONNX 세션 로드),\r\n * 이후 runOnBuffer / runOnPages 를 여러 번 호출해 재사용 가능.\r\n *\r\n * 모든 의존성(onnxruntime-node, @huggingface/transformers, @hyzyla/pdfium, sharp)은\r\n * optional 이므로 dynamic import. 미설치 시 초기화에서 명확한 에러 메시지 반환.\r\n */\r\nexport class FormulaPipeline {\r\n private mfd: InferenceSession\r\n private encoder: InferenceSession\r\n private decoder: InferenceSession\r\n private tokenizer: PreTrainedTokenizer\r\n private ort: typeof import(\"onnxruntime-node\")\r\n private sharp: SharpFactory\r\n private pdfium: PDFiumLibrary\r\n private opts: Required<FormulaPipelineOptions>\r\n\r\n private constructor(parts: {\r\n mfd: InferenceSession\r\n encoder: InferenceSession\r\n decoder: InferenceSession\r\n tokenizer: PreTrainedTokenizer\r\n ort: typeof import(\"onnxruntime-node\")\r\n sharp: SharpFactory\r\n pdfium: PDFiumLibrary\r\n opts: Required<FormulaPipelineOptions>\r\n }) {\r\n this.mfd = parts.mfd\r\n this.encoder = parts.encoder\r\n this.decoder = parts.decoder\r\n this.tokenizer = parts.tokenizer\r\n this.ort = parts.ort\r\n this.sharp = parts.sharp\r\n this.pdfium = parts.pdfium\r\n this.opts = parts.opts\r\n }\r\n\r\n /**\r\n * 수식 OCR 엔진 초기화. 모델 파일이 로컬에 없으면 즉시 실패 — 호출자가\r\n * `ensureFormulaModels()` 를 먼저 돌려야 한다.\r\n */\r\n static async create(options?: FormulaPipelineOptions): Promise<FormulaPipeline> {\r\n const opts: Required<FormulaPipelineOptions> = {\r\n scale: options?.scale ?? RENDER_SCALE,\r\n maxRegionsPerPage: options?.maxRegionsPerPage ?? 50,\r\n pageTimeoutMs: options?.pageTimeoutMs ?? 60_000,\r\n }\r\n\r\n const [ortMod, sharpModRaw, hfMod, pdfiumMod] = await Promise.all([\r\n tryImport<typeof import(\"onnxruntime-node\")>(\r\n \"onnxruntime-node\",\r\n () => import(\"onnxruntime-node\"),\r\n ),\r\n tryImport<{ default?: SharpFactory } & SharpFactory>(\r\n \"sharp\",\r\n () => import(\"sharp\") as unknown as Promise<{ default?: SharpFactory } & SharpFactory>,\r\n ),\r\n tryImport<typeof import(\"@huggingface/transformers\")>(\r\n \"@huggingface/transformers\",\r\n () => import(\"@huggingface/transformers\"),\r\n ),\r\n tryImport<typeof import(\"@hyzyla/pdfium\")>(\r\n \"@hyzyla/pdfium\",\r\n () => import(\"@hyzyla/pdfium\"),\r\n ),\r\n ])\r\n // CJS `export =` + ESM interop → default 속성에 래핑될 때도, 안 될 때도 있음.\r\n const sharpAny = sharpModRaw as { default?: SharpFactory } | SharpFactory\r\n const sharpMod: SharpFactory =\r\n typeof sharpAny === \"function\"\r\n ? sharpAny\r\n : (sharpAny.default ?? (sharpAny as unknown as SharpFactory))\r\n\r\n const modelsDir = getFormulaModelsDir()\r\n const mfdPath = join(modelsDir, MFD_MODEL.filename)\r\n const encPath = join(modelsDir, MFR_ENCODER_MODEL.filename)\r\n const decPath = join(modelsDir, MFR_DECODER_MODEL.filename)\r\n const tokPath = join(modelsDir, MFR_TOKENIZER.filename)\r\n\r\n const sessionOpts: import(\"onnxruntime-node\").InferenceSession.SessionOptions = {\r\n graphOptimizationLevel: \"all\",\r\n executionProviders: [\"cpu\"],\r\n }\r\n\r\n // 각 세션은 I/O 바운드 아님 → 병렬 로드로 1~2초 단축\r\n const [mfd, encoder, decoder] = await Promise.all([\r\n ortMod.InferenceSession.create(mfdPath, sessionOpts),\r\n ortMod.InferenceSession.create(encPath, sessionOpts),\r\n ortMod.InferenceSession.create(decPath, sessionOpts),\r\n ])\r\n\r\n // Transformers.js 의 PreTrainedTokenizer 를 로컬 tokenizer.json 으로 로드.\r\n // AutoTokenizer.from_pretrained 는 HF hub 접근을 시도하므로 우회.\r\n const { readFile } = await import(\"fs/promises\")\r\n const tokenizerJson = JSON.parse(await readFile(tokPath, \"utf-8\"))\r\n const PretrainedCtor = hfMod.PreTrainedTokenizer as unknown as new (\r\n json: unknown,\r\n config: Record<string, unknown>,\r\n ) => PreTrainedTokenizer\r\n const tokenizer = new PretrainedCtor(tokenizerJson, {})\r\n\r\n const pdfium = await pdfiumMod.PDFiumLibrary.init()\r\n\r\n return new FormulaPipeline({\r\n mfd,\r\n encoder,\r\n decoder,\r\n tokenizer,\r\n ort: ortMod,\r\n sharp: sharpMod,\r\n pdfium,\r\n opts,\r\n })\r\n }\r\n\r\n /** 리소스 해제 — 더 이상 사용하지 않을 때 호출. */\r\n async destroy(): Promise<void> {\r\n // onnxruntime-node InferenceSession 은 release() 없음 (GC 의존).\r\n try {\r\n this.pdfium.destroy()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n /**\r\n * PDF 버퍼를 열어 페이지별 수식 영역을 인식한다.\r\n * 실패한 페이지는 skip (에러 전파 없음 — 로그만).\r\n *\r\n * @param pageFilter null 이면 전체 페이지. Set 이면 1-based 페이지 번호 일치만.\r\n */\r\n async runOnBuffer(\r\n buffer: ArrayBuffer | Uint8Array,\r\n pageFilter: Set<number> | null = null,\r\n onPageProgress?: (pageNumber: number, total: number) => void,\r\n ): Promise<PageFormulaResult[]> {\r\n const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)\r\n const doc: PDFiumDocument = await this.pdfium.loadDocument(view)\r\n try {\r\n const pages: PageFormulaResult[] = []\r\n for (const page of doc.pages()) {\r\n // pdfium page.number 는 0-based pageIndex — pdfjs 블록/pageFilter 는 1-based.\r\n // 환산 없이는 필터가 한 페이지 밀리고 수식이 이전 페이지 블록에 붙는다 (off-by-one).\r\n const pageNo = page.number + 1\r\n if (pageFilter && !pageFilter.has(pageNo)) continue\r\n\r\n onPageProgress?.(pageNo, doc.getPageCount())\r\n\r\n try {\r\n const result = await withTimeout(\r\n this.processPage(pageNo, page),\r\n this.opts.pageTimeoutMs,\r\n `formula page ${pageNo} timed out after ${this.opts.pageTimeoutMs}ms`,\r\n )\r\n if (result) pages.push(result)\r\n } catch (e) {\r\n // 페이지 단위 실패는 조용히 넘어간다 — 전체 PDF 파싱 실패 방지.\r\n process.stderr.write(\r\n `[kordoc-formula] page ${pageNo} skipped: ${(e as Error).message}\\n`,\r\n )\r\n }\r\n }\r\n return pages\r\n } finally {\r\n doc.destroy()\r\n }\r\n }\r\n\r\n private async processPage(\r\n pageNumber: number,\r\n page: import(\"@hyzyla/pdfium\").PDFiumPage,\r\n ): Promise<PageFormulaResult | null> {\r\n const { originalWidth: pdfWidth, originalHeight: pdfHeight } = page.getOriginalSize()\r\n\r\n const sharpCtor = this.sharp\r\n const rendered = await page.render({\r\n scale: this.opts.scale,\r\n render: async ({ data, width, height }) => {\r\n // 임시로 PNG 로 인코딩하지 않고 raw 그대로 반환 — 바로 쓸 거라서.\r\n return data\r\n },\r\n })\r\n // rendered.data 는 BGRA — sharp 로 RGBA 로 변환\r\n const { data: bgra, width: rw, height: rh } = rendered\r\n const rgba = bgraToRgba(bgra)\r\n\r\n const pageFrame: PixelFrame = { width: rw, height: rh, data: rgba }\r\n\r\n // 1) 수식 영역 검출\r\n const regions0 = await detectFormulaRegions(this.mfd, pageFrame, this.ort)\r\n if (regions0.length === 0) {\r\n return { pageNumber, renderedWidth: rw, renderedHeight: rh, pdfWidth, pdfHeight, regions: [] }\r\n }\r\n\r\n const capped = regions0.slice(0, this.opts.maxRegionsPerPage)\r\n const regions: FormulaRegion[] = []\r\n\r\n // 2) 각 영역 crop → 인식\r\n for (const r of capped) {\r\n const x1 = Math.floor(Math.max(0, r.bbox.x1))\r\n const y1 = Math.floor(Math.max(0, r.bbox.y1))\r\n const x2 = Math.ceil(Math.min(rw, r.bbox.x2))\r\n const y2 = Math.ceil(Math.min(rh, r.bbox.y2))\r\n const cw = x2 - x1\r\n const ch = y2 - y1\r\n if (cw < 4 || ch < 4) continue\r\n\r\n // sharp 로 raw RGBA 에서 crop → raw RGBA 반환\r\n const cropRgba = await sharpCtor(rgba, {\r\n raw: { width: rw, height: rh, channels: 4 },\r\n })\r\n .extract({ left: x1, top: y1, width: cw, height: ch })\r\n .raw()\r\n .toBuffer()\r\n\r\n const cropFrame: PixelFrame = { width: cw, height: ch, data: new Uint8Array(cropRgba) }\r\n\r\n let latex = \"\"\r\n try {\r\n latex = await recognizeFormula(\r\n {\r\n encoder: this.encoder,\r\n decoder: this.decoder,\r\n tokenizer: this.tokenizer,\r\n ort: this.ort,\r\n },\r\n cropFrame,\r\n )\r\n } catch (e) {\r\n process.stderr.write(\r\n `[kordoc-formula] recognize failed at page ${pageNumber} ${JSON.stringify(r.bbox)}: ${(e as Error).message}\\n`,\r\n )\r\n latex = \"\"\r\n }\r\n\r\n regions.push({ ...r, latex })\r\n }\r\n\r\n return {\r\n pageNumber,\r\n renderedWidth: rw,\r\n renderedHeight: rh,\r\n pdfWidth,\r\n pdfHeight,\r\n regions,\r\n }\r\n }\r\n}\r\n\r\nasync function tryImport<T>(name: string, loader: () => Promise<T>): Promise<T> {\r\n try {\r\n return await loader()\r\n } catch (e) {\r\n throw new Error(\r\n `수식 OCR 을 사용하려면 optional dependency '${name}' 이 필요합니다. ` +\r\n `\\`npm install ${name}\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n}\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, ms: number, msg: string): Promise<T> {\r\n // 타임아웃으로 race 가 끝난 뒤에도 원 promise 는 계속 실행된다 — 사후 reject 가\r\n // unhandled rejection(Node 기본 정책: 프로세스 종료)이 되지 않게 흡수\r\n promise.catch(() => {})\r\n let timer: NodeJS.Timeout | undefined\r\n try {\r\n return await Promise.race([\r\n promise,\r\n new Promise<never>((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(msg)), ms)\r\n }),\r\n ])\r\n } finally {\r\n if (timer) clearTimeout(timer)\r\n }\r\n}\r\n\r\n/** pdfium 의 BGRA 버퍼를 RGBA 로 변환 (Red ↔ Blue 스왑). */\r\nfunction bgraToRgba(bgra: Uint8Array): Uint8Array {\r\n const out = new Uint8Array(bgra.length)\r\n for (let i = 0; i < bgra.length; i += 4) {\r\n out[i] = bgra[i + 2] // R ← B\r\n out[i + 1] = bgra[i + 1] // G ← G\r\n out[i + 2] = bgra[i] // B ← R\r\n out[i + 3] = bgra[i + 3] // A ← A\r\n }\r\n return out\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pdf/formula/postprocess.ts","../src/pdf/formula/detector.ts","../src/pdf/formula/recognizer.ts","../src/pdf/formula/pipeline.ts"],"sourcesContent":["/**\n * LaTeX 후처리 — Pix2Text `latex_ocr.py` 의 post_process 간소화 + 자체 필터\n *\n * 1) 후행 whitespace command 제거 (\\, \\: \\; \\! \\quad \\qquad \\enspace \\thinspace \\ )\n * 2) 연속 공백 → 1개\n * 3) 빈 그룹 반복 제거 (^{} _{} \\hat{} \\bar{} \\vec{} 등)\n * 4) \\cmd 뒤 영문자 공백 분리 (\\cdotd → \\cdot d, \\timesd → \\times d)\n * 5) isTrivialFormula — 다이어그램 단일 글자/반복/장식 오탐 제거\n */\n\nconst TRAILING_WHITESPACE_CMDS = [\n \"\\\\,\",\n \"\\\\:\",\n \"\\\\;\",\n \"\\\\!\",\n \"\\\\ \",\n \"\\\\quad\",\n \"\\\\qquad\",\n \"\\\\enspace\",\n \"\\\\thinspace\",\n] as const\n\nexport function postProcessLatex(latex: string): string {\n let s = stripTrailingWhitespace(latex)\n s = collapseSpaces(s)\n for (let i = 0; i < 10; i++) {\n const next = stripEmptyGroups(s)\n if (next === s) break\n s = next\n }\n s = fixLatexSpacing(s)\n s = normalizeFormulaSpacing(s)\n s = s.trim()\n // trivial 이면 빈 문자열 반환 — 상위(pipeline/parser) 에서 latex.trim() 비었을 때 skip.\n if (isTrivialFormula(s)) return \"\"\n return s\n}\n\nexport function stripTrailingWhitespace(s: string): string {\n let t = s\n // 바깥 loop: 한 번 제거 후 다시 체크 (중첩 \"\\\\, \\\\quad\" 같은 경우)\n for (;;) {\n const trimmed = t.replace(/[\\s]+$/, \"\")\n let changed = false\n for (const p of TRAILING_WHITESPACE_CMDS) {\n if (trimmed.endsWith(p)) {\n t = trimmed.slice(0, trimmed.length - p.length)\n changed = true\n break\n }\n }\n if (!changed) return trimmed\n }\n}\n\nexport function collapseSpaces(s: string): string {\n let out = \"\"\n let prevSpace = false\n for (const c of s) {\n if (/\\s/.test(c)) {\n if (!prevSpace) {\n out += \" \"\n prevSpace = true\n }\n } else {\n out += c\n prevSpace = false\n }\n }\n return out\n}\n\n/**\n * 빈 그룹 `{}` 또는 `{\\s+}` 를 찾아 선행하는 `^`, `_`, 또는 `\\cmd` 와 함께 제거.\n */\nexport function stripEmptyGroups(s: string): string {\n let out = \"\"\n let i = 0\n const bytes = s\n while (i < bytes.length) {\n const ch = bytes[i]\n if (ch === \"{\") {\n // 빈 { \\s* } 스캔\n let j = i + 1\n while (j < bytes.length && /\\s/.test(bytes[j])) j++\n if (j < bytes.length && bytes[j] === \"}\") {\n // 앞쪽 공백 제거\n while (out.endsWith(\" \") || out.endsWith(\"\\t\")) {\n out = out.slice(0, -1)\n }\n if (out.endsWith(\"^\") || out.endsWith(\"_\")) {\n out = out.slice(0, -1)\n } else {\n // \\cmd 형태인지 탐색\n let k = out.length\n while (k > 0 && /[A-Za-z]/.test(out[k - 1])) k--\n if (k > 0 && out[k - 1] === \"\\\\\" && k < out.length) {\n out = out.slice(0, k - 1)\n }\n // 아니면 아무것도 안 함 — 빈 {} 만 제거\n }\n i = j + 1\n continue\n }\n }\n out += ch\n i++\n }\n return out\n}\n\n/**\n * LaTeX 명령어 화이트리스트 — 공백 누락 감지에 사용.\n * MFR 이 `\\cdot d` 를 `\\cdotd` 로 합쳐 출력할 때, 어느 지점에서 명령어가 끝나는지\n * 알려진 커맨드명으로 판단한다. 완전한 리스트는 아니며 OCR 에서 실제 관찰된 케이스 중심.\n */\nconst KNOWN_LATEX_CMDS: ReadonlySet<string> = new Set([\n // 연산자\n \"cdot\", \"cdots\", \"ldots\", \"dots\", \"vdots\", \"ddots\",\n \"times\", \"div\", \"pm\", \"mp\", \"ast\", \"star\", \"circ\", \"bullet\",\n \"oplus\", \"ominus\", \"otimes\", \"odot\",\n // 관계\n \"approx\", \"equiv\", \"neq\", \"ne\", \"sim\", \"simeq\", \"cong\",\n \"leq\", \"geq\", \"le\", \"ge\", \"ll\", \"gg\", \"prec\", \"succ\", \"preceq\", \"succeq\",\n \"propto\", \"parallel\", \"perp\",\n // 집합/논리\n \"in\", \"notin\", \"ni\", \"subset\", \"supset\", \"subseteq\", \"supseteq\",\n \"cap\", \"cup\", \"bigcap\", \"bigcup\", \"emptyset\", \"varnothing\",\n \"forall\", \"exists\", \"nexists\", \"neg\", \"lnot\", \"land\", \"lor\", \"vee\", \"wedge\",\n // 그리스 소문자\n \"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \"varepsilon\",\n \"zeta\", \"eta\", \"theta\", \"vartheta\", \"iota\", \"kappa\", \"lambda\",\n \"mu\", \"nu\", \"xi\", \"omicron\", \"pi\", \"varpi\", \"rho\", \"varrho\",\n \"sigma\", \"varsigma\", \"tau\", \"upsilon\", \"phi\", \"varphi\",\n \"chi\", \"psi\", \"omega\",\n // 그리스 대문자\n \"Gamma\", \"Delta\", \"Theta\", \"Lambda\", \"Xi\", \"Pi\", \"Sigma\",\n \"Upsilon\", \"Phi\", \"Psi\", \"Omega\",\n // 화살표\n \"to\", \"gets\", \"mapsto\", \"rightarrow\", \"leftarrow\", \"leftrightarrow\",\n \"Rightarrow\", \"Leftarrow\", \"Leftrightarrow\", \"uparrow\", \"downarrow\",\n \"longrightarrow\", \"longleftarrow\", \"longmapsto\",\n // 큰 연산자\n \"sum\", \"prod\", \"coprod\", \"int\", \"iint\", \"iiint\", \"oint\", \"bigoplus\", \"bigotimes\",\n // 함수명\n \"sin\", \"cos\", \"tan\", \"sec\", \"csc\", \"cot\",\n \"arcsin\", \"arccos\", \"arctan\", \"sinh\", \"cosh\", \"tanh\",\n \"log\", \"ln\", \"lg\", \"exp\", \"lim\", \"liminf\", \"limsup\",\n \"sup\", \"inf\", \"max\", \"min\", \"arg\", \"det\", \"dim\", \"gcd\", \"deg\", \"hom\", \"ker\", \"mod\",\n // 특수 기호/수식\n \"infty\", \"partial\", \"nabla\", \"prime\", \"aleph\", \"ell\", \"hbar\", \"Re\", \"Im\",\n \"top\", \"bot\", \"angle\", \"vdash\", \"dashv\",\n // 기타\n \"left\", \"right\", \"big\", \"Big\", \"bigg\", \"Bigg\",\n])\n\n/**\n * `\\cmd` 뒤에 영문자가 바로 붙으면 공백 분리 (e.g. `\\cdotd` → `\\cdot d`, `\\timesd_{k}` → `\\times d_{k}`).\n *\n * MFR 이 좁은 영역에서 가끔 `\\cdot` 과 다음 변수 사이 공백을 누락. 그대로 두면 LaTeX 파서가\n * `\\cdotd` 를 undefined command 로 처리 (KaTeX: 에러 / TeX: 정의되지 않은 제어 시퀀스).\n * 알려진 LaTeX 명령어 prefix 중 가장 긴 것을 찾아 분할하면 렌더 안정성 확보.\n *\n * `\\cmd{..}` (영문자 뒤 `{`) 는 인자 포함 형태로 간주해 분리하지 않음.\n */\nexport function fixLatexSpacing(s: string): string {\n let out = \"\"\n let i = 0\n while (i < s.length) {\n if (s[i] === \"\\\\\" && i + 1 < s.length && /[A-Za-z]/.test(s[i + 1])) {\n // \\cmd 최장일치\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n const full = s.slice(i + 1, j) // 명령어 이름 (앞 \\ 제거)\n const nextChar = j < s.length ? s[j] : \"\"\n\n // \\cmd{..} 형태 — 인자로 이어지므로 분리하지 않음\n if (nextChar === \"{\") {\n out += \"\\\\\" + full\n i = j\n continue\n }\n\n // 자체가 알려진 명령어이거나, 긴 prefix 가 없으면 그대로\n let splitAt = full.length\n if (!KNOWN_LATEX_CMDS.has(full) && full.length >= 3) {\n // 뒤에서부터 prefix 길이를 줄이며 가장 긴 known cmd 찾기\n for (let len = full.length - 1; len >= 2; len--) {\n if (KNOWN_LATEX_CMDS.has(full.slice(0, len))) {\n splitAt = len\n break\n }\n }\n }\n\n out += \"\\\\\" + full.slice(0, splitAt)\n if (splitAt < full.length) {\n out += \" \" + full.slice(splitAt)\n }\n i = j\n } else {\n out += s[i]\n i++\n }\n }\n return out\n}\n\n/**\n * trivial(noise) 수식 판정.\n *\n * true 인 케이스 (MFD 오탐 주범):\n * 1) 공백/중괄호 제거 후 2자 이하 (e.g. `O`, `a`, `.`, `n`)\n * 2) 단일 `\\cmd` (e.g. `\\imath`, `\\pi`, `\\eta`, `\\sigma`, `\\theta`, `\\emptyset`, `\\varPi`)\n * 3) 단일 `\\mathrm{..}` / `\\textrm{..}` / `\\operatorname{..}` 류 + 짧은 내용 (e.g. `\\mathrm{fcloc}`)\n * 4) 동일 토큰이 3회 이상 + 전체의 50% 이상 (e.g. `\\pm \\pm \\pm \\pm`, `\\cap \\exists \\exists \\rceil`)\n *\n * false 유지 (의미 있는 수식):\n * `O(1)`, `d_{k}=64`, `\\sqrt{d_{k}}`, `PE_{pos+k}`, 등\n */\nexport function isTrivialFormula(s: string): boolean {\n const t = s.trim()\n if (t.length === 0) return true\n\n // 1) 공백/중괄호 제거 후 길이 ≤ 2\n const stripped = t.replace(/[\\s{}]/g, \"\")\n if (stripped.length <= 2) return true\n\n // 2) 단일 \\cmd (e.g. \\imath, \\varPi, \\pi)\n if (/^\\\\[A-Za-z]+$/.test(t)) return true\n\n // 3) 단일 \\mathrm{..} / \\textrm{..} / \\operatorname{..} / \\mathit{..} / \\mathbf{..} / \\mathcal{..} + 짧은 내용\n if (\n /^\\\\(?:mathrm|textrm|text|operatorname|mathit|mathbf|mathcal|mathsf|mathtt)\\{[A-Za-z]{1,6}\\}$/.test(\n t,\n )\n )\n return true\n\n const tokens = tokenizeLatex(t)\n\n // 4) 반복 토큰 dominant (e.g. \"\\\\pm \\\\pm \\\\pm \\\\pm\")\n if (tokens.length >= 3) {\n const freq = new Map<string, number>()\n for (const tok of tokens) freq.set(tok, (freq.get(tok) ?? 0) + 1)\n let maxCount = 0\n for (const c of freq.values()) if (c > maxCount) maxCount = c\n if (maxCount >= 3 && maxCount / tokens.length >= 0.5) return true\n }\n\n // 5) 심볼만 구성된 짧은 식 — 토큰 2~4개이고 연산자/숫자 없음 (e.g. \"\\\\cap \\\\exists \\\\exists \\\\rceil\")\n // 의미 있는 수식은 대개 `=` 또는 숫자가 포함됨. 허용되는 연산자: = + - / * < > 숫자\n if (tokens.length >= 2 && tokens.length <= 4) {\n const hasOpOrNum = tokens.some((tok) =>\n /^[=+\\-/*<>]$/.test(tok) || /^[0-9]$/.test(tok),\n )\n if (!hasOpOrNum) return true\n }\n\n // 6) substring 반복 패턴 — 동일 5~15자 substring 이 3회 이상 + 커버리지 60%+\n // (e.g. \"\\\\alpha_{1}=\\\\alpha_{2}=\\\\alpha_{3}=...\" 의 `\\\\alpha_{` 반복,\n // \"c_{c}^{\\\\prime}\\\\phi_{c}^{\\\\prime}=c_{c}^{\\\\prime}...\" 의 `c_{c}^{\\\\prime}` 반복)\n if (hasHighRepetition(t)) return true\n\n // 7) MFR placeholder 인 `\\square` 포함 — 인식 실패 영역을 `\\square` 로 대체하는 특성\n // 정당한 수식에 `\\square` 가 나오는 경우는 거의 없음 (대부분 `\\Box`, `\\blacksquare` 등 사용)\n if (t.includes(\"\\\\square\")) return true\n\n // 8) 단독 숫자/실수 (e.g. \"$1.0$\", \"$42$\", \"$-3.14$\")\n // 공백/중괄호/백슬래시 제거 후 순수 숫자/부호/소수점만 남으면 trivial\n if (/^[-+]?\\d+\\.?\\d*$/.test(t.replace(/[\\s{}\\\\]/g, \"\"))) return true\n\n // 9) `(X)(X)` 또는 `{X}{X}` 연속 중복 — 동일 그룹 반복 (e.g. \"$C(T_{2})(T_{2})$\")\n // 한 단계 중첩 허용: `{k_{c}}` 같이 내부에 `{...}` 하나 포함 가능.\n if (/(\\([^()]{2,15}\\))\\s*\\1/.test(t)) return true\n if (/(\\{(?:[^{}]|\\{[^{}]*\\})+\\})\\s*\\1/.test(t)) return true\n\n // 10) 동일 인자 반복 — 괄호 인자 중 쉼표 구분 3개 중 2개 이상 동일 (e.g. `C(\\tau_{2},\\mu^{\\prime},\\mu^{\\prime})`)\n // 완전 일치 인자가 2회+ 반복이면 OCR 반복 오류로 간주\n const argMatch = t.match(/^[A-Za-z\\\\][A-Za-z]*\\(([^()]+)\\)$/)\n if (argMatch) {\n const args = argMatch[1].split(\",\").map((a) => a.trim())\n if (args.length >= 2) {\n const freq = new Map<string, number>()\n for (const a of args) if (a) freq.set(a, (freq.get(a) ?? 0) + 1)\n for (const [, c] of freq) {\n if (c >= 2 && c / args.length >= 0.5) return true\n }\n }\n }\n\n // 11) X/X 또는 \\frac{X}{X} — 분자=분모 = 1, 의미 없는 수식\n // 수식 **어디에나** 나타나면 trivial (e.g. \"$k<\\\\frac{\\\\eta}{\\\\eta}$\" 도 포함)\n // 정당한 수식에서 $\\\\frac{a}{a}$ 를 쓰는 경우는 거의 없음 (대수적으로 1).\n if (/\\\\frac\\{([^{}]+)\\}\\{\\1\\}/.test(t)) return true\n // X/X 꼴 (단일 변수 또는 \\cmd)\n if (/(\\\\[A-Za-z]+|\\b[A-Za-z])\\s*\\/\\s*\\1\\b/.test(t)) return true\n\n // 12) `\\begin{matrix}` 내부 `\\cdots` 여러 번 — MFR 이 다이어그램/표를 matrix 로 오인식\n // 본문 수식의 matrix 는 구체적 원소가 있어 `\\cdots` 가 2회 이상 나오는 경우 거의 없음\n if (/\\\\begin\\{(?:matrix|pmatrix|bmatrix|vmatrix)\\}/.test(t)) {\n const cdotsCount = (t.match(/\\\\cdots/g) ?? []).length\n if (cdotsCount >= 2) return true\n }\n\n // 13) 다이어그램 텍스트 레이블 — `\\mathrm{word}` 가 2회+ 포함된 짧은 식 (토큰 수 ≤ 12)\n // 또는 `[a-z]{1,3}_\\{\\mathrm{word}\\}` 꼴의 비정상 변수명 (e.g. `cl_{\\mathrm{model}}`)\n if (tokens.length <= 12) {\n const mathrmCount = (t.match(/\\\\mathrm\\{/g) ?? []).length\n if (mathrmCount >= 2) {\n // 연산자/등호/숫자가 거의 없어 \"단순 레이블\" 로 보이는지 추가 확인\n const hasRealMath = /[=+\\-*/<>^]/.test(t) && /\\d/.test(t)\n if (!hasRealMath) return true\n }\n }\n // 비정상 변수명: 2-3자 영문 접두 + _{\\mathrm{긴단어}} 단독 (e.g. `cl_{\\mathrm{model}}`, `to_{\\mathrm{max}}`)\n // 정상 변수명은 보통 단일 문자 (`d_{\\mathrm{model}}`, `W_{i}`) — 2자 이상이면 다이어그램 오인식\n if (/^[a-zA-Z]{2,3}_\\{\\\\mathrm\\{[a-zA-Z]{3,}\\}\\}$/.test(t)) return true\n\n // 14) `\\mathrm{word}` + 이항 연산자 + single 요소 꼴 — 다이어그램 \"word → value\" 레이블\n // (e.g. `\\mathrm{to}-\\infty`, `\\mathrm{to}+\\infty`)\n if (/^\\\\mathrm\\{[a-z]{2,}\\}[-+][-+]?(?:\\\\[a-zA-Z]+|[a-zA-Z0-9])$/.test(t)) return true\n\n // 15) `\\mathsf`, `\\mathtt`, `\\texttt` 는 본문 수식에 거의 쓰이지 않고 다이어그램 타이포그래피 오인식이 대부분\n // — 포함만으로 trivial (e.g. `\\mathtt{Welgnt}`, `\\mathsf{Tr}_{s}`, `\\texttt{wg}`)\n if (/\\\\(?:mathsf|mathtt|texttt)\\{/.test(t)) return true\n\n // 16) `\\begin{aligned}` 이지만 `=` 없음 — 정당한 aligned 는 항상 등호 포함 (여러 줄 equation)\n // 등호 없으면 OCR garbage 조합\n if (/\\\\begin\\{aligned\\}/.test(t) && !t.includes(\"=\")) return true\n\n // 17) `\\begin{matrix}` + `\\downarrow` 2회+ — 네트워크 architecture 다이어그램 오인식\n if (/\\\\begin\\{matrix\\}/.test(t) && (t.match(/\\\\downarrow/g) ?? []).length >= 2) return true\n\n return false\n}\n\n/**\n * substring 반복 탐지 — 동일한 N자 substring 이 3회 이상 나타나고\n * 그 반복 총 길이가 전체의 60% 이상이면 true.\n *\n * 5~15자 범위만 검사 (짧으면 정상 수식의 `^{2}` 같은 패턴도 걸림, 길면 노이즈 거의 없음).\n * 영문자 포함 substring 만 검사 (구두점만 반복은 정상 수식에도 많음).\n *\n * 정당한 수식은 다양한 구조로 거의 겹치지 않아 false-positive 낮음.\n */\nexport function hasHighRepetition(s: string): boolean {\n if (s.length < 15) return false\n\n for (let len = 5; len <= 15; len++) {\n // substring 길이 × 3회가 전체보다 길면 의미 없음\n if (len * 3 > s.length) break\n const seen = new Map<string, number>()\n for (let i = 0; i <= s.length - len; i++) {\n const sub = s.slice(i, i + len)\n if (!/[a-zA-Z]/.test(sub)) continue\n seen.set(sub, (seen.get(sub) ?? 0) + 1)\n }\n for (const [, count] of seen) {\n if (count < 3) continue\n // 겹치지 않는 점유율 추정: count*len (overlapping 포함이라 약간 과대)\n // 보수적 판정 위해 최소 3회 + 60% 커버리지\n if ((count * len) / s.length >= 0.6) return true\n }\n }\n return false\n}\n\n/**\n * LaTeX 를 단순 토큰 배열로 분할 — `\\cmd` 는 하나의 토큰, 그 외는 non-space 단일 문자.\n * isTrivialFormula 의 반복 감지용.\n */\nfunction tokenizeLatex(s: string): string[] {\n const result: string[] = []\n let i = 0\n while (i < s.length) {\n const c = s[i]\n if (c === \"\\\\\") {\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n if (j === i + 1 && j < s.length) j++ // `\\\\` 또는 `\\{` 같은 단일 escape\n result.push(s.slice(i, j))\n i = j\n } else if (/\\s/.test(c)) {\n i++\n } else {\n result.push(c)\n i++\n }\n }\n return result\n}\n\n/**\n * MFR tokenizer 가 LaTeX 토큰 사이에 삽입하는 과도한 공백을 정리.\n *\n * 예: `\\mathrm { m o d d }` → `\\mathrm{modd}`, `6 4` → `64`, `( Q, K, V )` → `(Q,K,V)`\n *\n * 규칙: 공백을 앞뒤 토큰 기준으로 유지/제거 결정.\n * - 직전이 `\\cmd` 이고 직후가 영문자 → **유지** (e.g. `\\cdot d`, `\\alpha b` — 공백 없으면 greedy 로 `\\cdotd` 가 명령어로 해석될 수 있음)\n * - 그 외 → **제거** (숫자/괄호/중괄호/첨자/구두점 주변 공백은 LaTeX 의미를 바꾸지 않음)\n *\n * `fixLatexSpacing` 이후에 호출되는 것을 전제 — 먼저 공백 누락을 복원한 뒤 과도한 공백을 걷어냄.\n */\nexport function normalizeFormulaSpacing(s: string): string {\n // `\\cmd`, 단일 escape, 공백, 일반 문자 단위로 토큰화 (공백도 토큰으로 유지)\n const tokens: string[] = []\n let i = 0\n while (i < s.length) {\n const c = s[i]\n if (c === \"\\\\\") {\n let j = i + 1\n while (j < s.length && /[A-Za-z]/.test(s[j])) j++\n if (j === i + 1 && j < s.length) j++ // 단일 escape (`\\\\`, `\\{` 등)\n tokens.push(s.slice(i, j))\n i = j\n } else if (/\\s/.test(c)) {\n tokens.push(\" \")\n i++\n } else {\n tokens.push(c)\n i++\n }\n }\n\n const out: string[] = []\n for (let k = 0; k < tokens.length; k++) {\n if (tokens[k] !== \" \") {\n out.push(tokens[k])\n continue\n }\n // 공백 토큰 — 유지 여부 결정\n // 연속 공백은 나중에 병합 (아래 로직은 앞뒤 non-space 토큰 기준)\n let prev = \"\"\n for (let p = k - 1; p >= 0; p--) {\n if (tokens[p] !== \" \") {\n prev = tokens[p]\n break\n }\n }\n let next = \"\"\n for (let q = k + 1; q < tokens.length; q++) {\n if (tokens[q] !== \" \") {\n next = tokens[q]\n break\n }\n }\n const prevIsCmd = /^\\\\[A-Za-z]+$/.test(prev)\n const nextIsAlpha = /^[A-Za-z]$/.test(next)\n if (prevIsCmd && nextIsAlpha) {\n // 앞 cmd 와 뒤 변수 분리용 공백 (연속 공백이더라도 하나만 남김)\n if (out.length === 0 || out[out.length - 1] !== \" \") {\n out.push(\" \")\n }\n }\n // 그 외 공백은 drop\n }\n\n // 앞/뒤 공백 제거\n while (out.length > 0 && out[0] === \" \") out.shift()\n while (out.length > 0 && out[out.length - 1] === \" \") out.pop()\n\n return out.join(\"\")\n}\n","/**\n * MFD (Mathematical Formula Detection) — YOLOv8 기반 수식 영역 검출\n *\n * 모델: breezedeus/pix2text-mfd (YOLOv8 small, imgsz=768, stride=32)\n * 출력: [1, 6, 12096] — (cx, cy, w, h, class0_score, class1_score) × anchors\n * - class 0 = embedding (inline 수식)\n * - class 1 = isolated (display 수식)\n *\n * 전처리: letterbox (긴 변 비율 유지 + 회색 패딩 114)\n * 후처리: conf ≥ 0.25 → class-per-class NMS (IoU ≥ 0.45)\n */\n\nimport type { InferenceSession, Tensor } from \"onnxruntime-node\"\nimport type { FormulaKind, PixelFrame, FormulaRegion } from \"./types.js\"\n\nconst MFD_IMG_SIZE = 768\nconst MFD_NUM_CLASSES = 2\nconst MFD_CHANNELS = 4 + MFD_NUM_CLASSES\n/** 기본 confidence 임계값 (Pix2Text 원본 0.25 — 누락은 적지만 noise 발생) */\nconst MFD_CONF_INLINE = 0.30\n/** display 수식 임계값 — diagram/figure 오탐 감소 목적으로 inline 보다 높게 */\nconst MFD_CONF_DISPLAY = 0.40\nconst MFD_IOU_THRESHOLD = 0.45\n/** 최소 bbox 면적 (px²) — 이보다 작으면 OCR noise 가능성 높음 */\nconst MFD_MIN_AREA = 80\nconst PAD_VALUE = 114 / 255\n\ninterface RawDetection {\n x1: number\n y1: number\n x2: number\n y2: number\n kind: FormulaKind\n score: number\n}\n\n/**\n * 단일 페이지 이미지에서 수식 영역 검출 (인식 없음 — recognizer 로 넘김).\n * bbox 는 원본 이미지 좌표계.\n */\nexport async function detectFormulaRegions(\n session: InferenceSession,\n frame: PixelFrame,\n ort: typeof import(\"onnxruntime-node\"),\n): Promise<Omit<FormulaRegion, \"latex\">[]> {\n const { scale, padX, padY, tensor } = letterbox(frame, MFD_IMG_SIZE)\n\n const input = new ort.Tensor(\"float32\", tensor, [1, 3, MFD_IMG_SIZE, MFD_IMG_SIZE])\n const feeds: Record<string, Tensor> = { images: input }\n const outputs = await session.run(feeds)\n\n const firstKey = Object.keys(outputs)[0]\n const out = outputs[firstKey]\n if (!out || out.type !== \"float32\") {\n throw new Error(\"MFD 출력 없음 또는 dtype 불일치\")\n }\n\n const outDims = out.dims\n if (outDims.length !== 3) {\n throw new Error(`MFD 출력 차원 예상 3, 실제 ${outDims.length}: [${outDims.join(\",\")}]`)\n }\n const channels = outDims[1]\n const anchors = outDims[2]\n if (channels !== MFD_CHANNELS) {\n throw new Error(`MFD 채널 수 예상 ${MFD_CHANNELS}, 실제 ${channels}`)\n }\n if (anchors <= 0) return []\n\n const data = out.data as Float32Array\n const candidates: RawDetection[] = []\n\n for (let a = 0; a < anchors; a++) {\n const cx = data[a]\n const cy = data[anchors + a]\n const w = data[2 * anchors + a]\n const h = data[3 * anchors + a]\n\n let bestCls = 0\n let bestScore = 0\n for (let c = 0; c < MFD_NUM_CLASSES; c++) {\n const s = data[(4 + c) * anchors + a]\n if (s > bestScore) {\n bestScore = s\n bestCls = c\n }\n }\n // 클래스별 임계값 — display 쪽은 diagram/figure 오탐 감소 목적으로 inline 보다 엄격.\n const threshold = bestCls === 1 ? MFD_CONF_DISPLAY : MFD_CONF_INLINE\n if (bestScore < threshold) continue\n\n // letterbox → 원본 좌표\n let x1 = (cx - w / 2 - padX) / scale\n let y1 = (cy - h / 2 - padY) / scale\n let x2 = (cx + w / 2 - padX) / scale\n let y2 = (cy + h / 2 - padY) / scale\n\n x1 = clamp(x1, 0, frame.width - 1)\n y1 = clamp(y1, 0, frame.height - 1)\n x2 = clamp(x2, 0, frame.width - 1)\n y2 = clamp(y2, 0, frame.height - 1)\n\n if (x2 - x1 < 2 || y2 - y1 < 2) continue\n // 너무 작은 bbox (픽셀 단위 noise 로 보이는 영역) 제외\n if ((x2 - x1) * (y2 - y1) < MFD_MIN_AREA) continue\n\n candidates.push({\n x1,\n y1,\n x2,\n y2,\n kind: bestCls === 1 ? \"display\" : \"inline\",\n score: bestScore,\n })\n }\n\n // 클래스별 NMS (혼합 클래스 bbox 간 중복은 허용 — Pix2Text 원본 동작)\n const kept: RawDetection[] = []\n for (const kind of [\"inline\", \"display\"] as FormulaKind[]) {\n const subset = candidates.filter((c) => c.kind === kind)\n kept.push(...nms(subset, MFD_IOU_THRESHOLD))\n }\n\n // 읽기 순서 정렬 (위→아래, 왼→오른쪽)\n kept.sort((a, b) => a.y1 - b.y1 || a.x1 - b.x1)\n\n return kept.map((d) => ({\n bbox: { x1: d.x1, y1: d.y1, x2: d.x2, y2: d.y2 },\n kind: d.kind,\n score: d.score,\n }))\n}\n\n/**\n * YOLOv8 letterbox 전처리 — RGBA 프레임을 target×target float32 CHW tensor 로.\n *\n * - 긴 변 기준으로 비율 유지 리사이즈\n * - 가운데 패딩 (회색 114)\n * - /255 정규화\n * - CHW 레이아웃\n */\nexport function letterbox(\n frame: PixelFrame,\n target: number,\n): { scale: number; padX: number; padY: number; tensor: Float32Array } {\n const w = frame.width\n const h = frame.height\n const scale = Math.min(target / w, target / h)\n const newW = Math.max(1, Math.round(w * scale))\n const newH = Math.max(1, Math.round(h * scale))\n const padX = (target - newW) / 2\n const padY = (target - newH) / 2\n const offX = Math.floor(padX)\n const offY = Math.floor(padY)\n\n const ts = target\n const tensor = new Float32Array(3 * ts * ts)\n tensor.fill(PAD_VALUE)\n\n // RGBA 원본 → 먼저 nearest-neighbor resize 한 뒤 복사.\n // (sharp 로 정확한 bilinear 가능하지만, 여기선 이미 렌더링된 bitmap 이 충분히 해상도 높음 —\n // 결과는 동일한 수준으로 수식 박스 위치 맞춤. Rust 구현도 Triangle 사용.)\n const src = frame.data\n const srcW = frame.width\n const srcH = frame.height\n\n for (let y = 0; y < newH; y++) {\n const sy = Math.min(srcH - 1, Math.floor((y + 0.5) / newH * srcH))\n for (let x = 0; x < newW; x++) {\n const sx = Math.min(srcW - 1, Math.floor((x + 0.5) / newW * srcW))\n const srcIdx = (sy * srcW + sx) * 4\n const r = src[srcIdx]\n const g = src[srcIdx + 1]\n const b = src[srcIdx + 2]\n\n const tx = x + offX\n const ty = y + offY\n const idx = ty * ts + tx\n tensor[idx] = r / 255\n tensor[ts * ts + idx] = g / 255\n tensor[2 * ts * ts + idx] = b / 255\n }\n }\n\n return { scale, padX, padY, tensor }\n}\n\nfunction nms(cands: RawDetection[], iouThreshold: number): RawDetection[] {\n const sorted = [...cands].sort((a, b) => b.score - a.score)\n const kept: RawDetection[] = []\n for (const cand of sorted) {\n let keep = true\n for (const k of kept) {\n if (iou(cand, k) > iouThreshold) {\n keep = false\n break\n }\n }\n if (keep) kept.push(cand)\n }\n return kept\n}\n\nfunction iou(\n a: { x1: number; y1: number; x2: number; y2: number },\n b: { x1: number; y1: number; x2: number; y2: number },\n): number {\n const x1 = Math.max(a.x1, b.x1)\n const y1 = Math.max(a.y1, b.y1)\n const x2 = Math.min(a.x2, b.x2)\n const y2 = Math.min(a.y2, b.y2)\n const interW = Math.max(0, x2 - x1)\n const interH = Math.max(0, y2 - y1)\n const inter = interW * interH\n const areaA = Math.max(0, a.x2 - a.x1) * Math.max(0, a.y2 - a.y1)\n const areaB = Math.max(0, b.x2 - b.x1) * Math.max(0, b.y2 - b.y1)\n const union = areaA + areaB - inter\n return union <= 0 ? 0 : inter / union\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n if (v < lo) return lo\n if (v > hi) return hi\n return v\n}\n\n// 테스트 용도로만 export\nexport const __internal = { nms, iou, letterbox }\n","/**\n * MFR (Mathematical Formula Recognition) — DeiT encoder + TrOCR decoder\n *\n * 모델: breezedeus/pix2text-mfr\n * - encoder: DeiT distilled, input 384×384 → output [1, 578, 384]\n * - decoder: TrOCR (no KV cache), vocab=1200, EOS=2\n *\n * 전처리 (DeiT): Catmull-Rom resize → /255 → (x - 0.5) / 0.5 == x*2 - 1\n *\n * 디코딩: greedy, start=[2], stop at 2 또는 max_new_tokens=256\n * decoder 는 매 스텝 전체 시퀀스를 재계산 (no KV cache — 모델 고정)\n */\n\nimport type { InferenceSession, Tensor } from \"onnxruntime-node\"\nimport type { PreTrainedTokenizer } from \"@huggingface/transformers\"\nimport { postProcessLatex } from \"./postprocess.js\"\nimport type { PixelFrame } from \"./types.js\"\n\nconst MFR_IMG_SIZE = 384\nconst MFR_ENC_HIDDEN = 384\nconst MFR_MAX_NEW_TOKENS = 256\nconst MFR_EOS_ID = 2\nconst MFR_PAD_ID = 0\n\nexport interface RecognizeDeps {\n encoder: InferenceSession\n decoder: InferenceSession\n tokenizer: PreTrainedTokenizer\n ort: typeof import(\"onnxruntime-node\")\n}\n\n/**\n * 단일 수식 crop 을 LaTeX 로 인식.\n * 입력 frame 은 이미 해당 영역만 잘린 RGBA 이미지이어야 한다 (recognizer 가 resize 수행).\n */\nexport async function recognizeFormula(\n deps: RecognizeDeps,\n crop: PixelFrame,\n): Promise<string> {\n const tensor = deitPreprocess(crop, MFR_IMG_SIZE)\n const { ort, encoder, decoder, tokenizer } = deps\n\n const pixelInput = new ort.Tensor(\"float32\", tensor, [1, 3, MFR_IMG_SIZE, MFR_IMG_SIZE])\n const encOut = await encoder.run({ pixel_values: pixelInput })\n\n const encKey =\n Object.keys(encOut).find((k) => k.includes(\"hidden\")) ?? Object.keys(encOut)[0]\n const encTensor = encOut[encKey]\n if (!encTensor || encTensor.type !== \"float32\") {\n throw new Error(\"MFR encoder 출력 없음\")\n }\n const encDims = encTensor.dims\n if (encDims.length !== 3) {\n throw new Error(`MFR encoder 차원 예상 3, 실제 ${encDims.length}`)\n }\n const encSeq = encDims[1]\n const encHidden = encDims[2]\n if (encHidden !== MFR_ENC_HIDDEN) {\n throw new Error(`MFR encoder hidden 예상 ${MFR_ENC_HIDDEN}, 실제 ${encHidden}`)\n }\n const encData = encTensor.data as Float32Array\n\n // greedy decode\n const tokens: number[] = [MFR_EOS_ID] // decoder_start_token_id\n\n for (let step = 0; step < MFR_MAX_NEW_TOKENS; step++) {\n const seqLen = tokens.length\n const idsArr = BigInt64Array.from(tokens.map((t) => BigInt(t)))\n const idsTensor = new ort.Tensor(\"int64\", idsArr, [1, seqLen])\n\n // encoder_hidden_states 는 매 스텝 동일 — 복사 필요 (Tensor 는 buffer 소유)\n const hidCopy = new Float32Array(encData)\n const hidTensor = new ort.Tensor(\"float32\", hidCopy, [1, encSeq, encHidden])\n\n const decOut = await decoder.run({\n input_ids: idsTensor,\n encoder_hidden_states: hidTensor,\n })\n\n const logitKey =\n Object.keys(decOut).find((k) => k.includes(\"logit\")) ?? Object.keys(decOut)[0]\n const logitsTensor = decOut[logitKey]\n if (!logitsTensor || logitsTensor.type !== \"float32\") {\n throw new Error(\"MFR decoder logits 없음\")\n }\n const dims = logitsTensor.dims\n if (dims.length !== 3) {\n throw new Error(`MFR decoder 차원 예상 3, 실제 ${dims.length}`)\n }\n const decSeq = dims[1]\n const vocab = dims[2]\n const logitsData = logitsTensor.data as Float32Array\n\n // 마지막 step logits 만\n const lastOffset = (decSeq - 1) * vocab\n let bestId = 0\n let bestVal = -Infinity\n for (let v = 0; v < vocab; v++) {\n const val = logitsData[lastOffset + v]\n if (val > bestVal) {\n bestVal = val\n bestId = v\n }\n }\n tokens.push(bestId)\n if (bestId === MFR_EOS_ID) break\n }\n\n // 첫 start 토큰 제외 + EOS/PAD 제거\n const body: number[] = []\n for (let i = 1; i < tokens.length; i++) {\n const t = tokens[i]\n if (t === MFR_EOS_ID) break\n if (t === MFR_PAD_ID) continue\n if (t < 0) continue\n body.push(t)\n }\n\n // Transformers.js tokenizer.decode 는 skip_special_tokens=true 기본\n const raw = tokenizer.decode(body, { skip_special_tokens: true })\n return postProcessLatex(raw)\n}\n\n/**\n * DeiT preprocess:\n * resize to 384×384 (bilinear)\n * (pixel/255 - 0.5) / 0.5 == pixel/127.5 - 1\n * CHW layout\n */\nexport function deitPreprocess(crop: PixelFrame, target: number): Float32Array {\n const ts = target\n const out = new Float32Array(3 * ts * ts)\n const { data: src, width: srcW, height: srcH } = crop\n\n // 단순 nearest (이미 수식 crop 은 300DPI 근방이라 충분). 필요시 sharp bilinear 로 교체.\n for (let y = 0; y < ts; y++) {\n const sy = Math.min(srcH - 1, Math.max(0, Math.floor(((y + 0.5) / ts) * srcH)))\n for (let x = 0; x < ts; x++) {\n const sx = Math.min(srcW - 1, Math.max(0, Math.floor(((x + 0.5) / ts) * srcW)))\n const srcIdx = (sy * srcW + sx) * 4\n const r = src[srcIdx]\n const g = src[srcIdx + 1]\n const b = src[srcIdx + 2]\n\n const idx = y * ts + x\n out[idx] = r / 127.5 - 1\n out[ts * ts + idx] = g / 127.5 - 1\n out[2 * ts * ts + idx] = b / 127.5 - 1\n }\n }\n return out\n}\n","/**\r\n * 수식 OCR 파이프라인 — PDFium 렌더 + MFD + MFR 통합\r\n *\r\n * 한 번 생성된 FormulaPipeline 인스턴스는 ONNX 세션을 재사용해 여러 PDF 에 적용 가능.\r\n * Docufinder 는 CLI 프로세스 단위로 새로 띄우기 때문에 세션 재사용은 PDF 내부 페이지 루프에만 적용됨.\r\n */\r\n\r\nimport type { PDFiumLibrary, PDFiumDocument } from \"@hyzyla/pdfium\"\r\nimport type { InferenceSession } from \"onnxruntime-node\"\r\nimport type { PreTrainedTokenizer } from \"@huggingface/transformers\"\r\n\r\n/** sharp 은 CommonJS `export =` 형태라 타입을 직접 import 하기 까다로움. 함수형 시그니처만 사용. */\r\ntype SharpFactory = (\r\n input: Uint8Array | Buffer,\r\n options?: { raw?: { width: number; height: number; channels: number } },\r\n) => {\r\n extract(region: { left: number; top: number; width: number; height: number }): {\r\n raw(): { toBuffer(): Promise<Buffer> }\r\n }\r\n}\r\n\r\nimport { detectFormulaRegions } from \"./detector.js\"\r\nimport { recognizeFormula } from \"./recognizer.js\"\r\nimport {\r\n getFormulaModelsDir,\r\n MFD_MODEL,\r\n MFR_ENCODER_MODEL,\r\n MFR_DECODER_MODEL,\r\n MFR_TOKENIZER,\r\n} from \"./models.js\"\r\nimport type { FormulaRegion, PixelFrame } from \"./types.js\"\r\nimport { join } from \"path\"\r\n\r\n/** PDF 페이지 렌더 해상도 (scale=2 → 약 144 DPI). 수식 인식에는 이 이상은 과함. */\r\nconst RENDER_SCALE = 2\r\n\r\nexport interface FormulaPipelineOptions {\r\n /** 수식 인식 페이지 스케일 (기본 2). 값을 올리면 작은 수식 인식률 ↑, 속도 ↓. */\r\n scale?: number\r\n /** 페이지별 최대 수식 수 (안전 상한). 기본 50. */\r\n maxRegionsPerPage?: number\r\n /** 페이지 하나당 타임아웃 (ms, 기본 60000 = 1분). 초과 시 해당 페이지 skip. */\r\n pageTimeoutMs?: number\r\n}\r\n\r\nexport interface PageFormulaResult {\r\n pageNumber: number\r\n /** 페이지 전체 렌더 이미지의 가로/세로 (원본 좌표계, scale 반영됨) */\r\n renderedWidth: number\r\n renderedHeight: number\r\n /** 원본 PDF 포인트 기준 너비/높이 (pdfjs 와 좌표 매핑용) */\r\n pdfWidth: number\r\n pdfHeight: number\r\n regions: FormulaRegion[]\r\n}\r\n\r\n/**\r\n * 수식 OCR 실행 컨텍스트. 처음 호출 시 무겁게 초기화 (ONNX 세션 로드),\r\n * 이후 runOnBuffer / runOnPages 를 여러 번 호출해 재사용 가능.\r\n *\r\n * 모든 의존성(onnxruntime-node, @huggingface/transformers, @hyzyla/pdfium, sharp)은\r\n * optional 이므로 dynamic import. 미설치 시 초기화에서 명확한 에러 메시지 반환.\r\n */\r\nexport class FormulaPipeline {\r\n private mfd: InferenceSession\r\n private encoder: InferenceSession\r\n private decoder: InferenceSession\r\n private tokenizer: PreTrainedTokenizer\r\n private ort: typeof import(\"onnxruntime-node\")\r\n private sharp: SharpFactory\r\n private pdfium: PDFiumLibrary\r\n private opts: Required<FormulaPipelineOptions>\r\n\r\n private constructor(parts: {\r\n mfd: InferenceSession\r\n encoder: InferenceSession\r\n decoder: InferenceSession\r\n tokenizer: PreTrainedTokenizer\r\n ort: typeof import(\"onnxruntime-node\")\r\n sharp: SharpFactory\r\n pdfium: PDFiumLibrary\r\n opts: Required<FormulaPipelineOptions>\r\n }) {\r\n this.mfd = parts.mfd\r\n this.encoder = parts.encoder\r\n this.decoder = parts.decoder\r\n this.tokenizer = parts.tokenizer\r\n this.ort = parts.ort\r\n this.sharp = parts.sharp\r\n this.pdfium = parts.pdfium\r\n this.opts = parts.opts\r\n }\r\n\r\n /**\r\n * 수식 OCR 엔진 초기화. 모델 파일이 로컬에 없으면 즉시 실패 — 호출자가\r\n * `ensureFormulaModels()` 를 먼저 돌려야 한다.\r\n */\r\n static async create(options?: FormulaPipelineOptions): Promise<FormulaPipeline> {\r\n const opts: Required<FormulaPipelineOptions> = {\r\n scale: options?.scale ?? RENDER_SCALE,\r\n maxRegionsPerPage: options?.maxRegionsPerPage ?? 50,\r\n pageTimeoutMs: options?.pageTimeoutMs ?? 60_000,\r\n }\r\n\r\n const [ortMod, sharpModRaw, hfMod, pdfiumMod] = await Promise.all([\r\n tryImport<typeof import(\"onnxruntime-node\")>(\r\n \"onnxruntime-node\",\r\n () => import(\"onnxruntime-node\"),\r\n ),\r\n tryImport<{ default?: SharpFactory } & SharpFactory>(\r\n \"sharp\",\r\n () => import(\"sharp\") as unknown as Promise<{ default?: SharpFactory } & SharpFactory>,\r\n ),\r\n tryImport<typeof import(\"@huggingface/transformers\")>(\r\n \"@huggingface/transformers\",\r\n () => import(\"@huggingface/transformers\"),\r\n ),\r\n tryImport<typeof import(\"@hyzyla/pdfium\")>(\r\n \"@hyzyla/pdfium\",\r\n () => import(\"@hyzyla/pdfium\"),\r\n ),\r\n ])\r\n // CJS `export =` + ESM interop → default 속성에 래핑될 때도, 안 될 때도 있음.\r\n const sharpAny = sharpModRaw as { default?: SharpFactory } | SharpFactory\r\n const sharpMod: SharpFactory =\r\n typeof sharpAny === \"function\"\r\n ? sharpAny\r\n : (sharpAny.default ?? (sharpAny as unknown as SharpFactory))\r\n\r\n const modelsDir = getFormulaModelsDir()\r\n const mfdPath = join(modelsDir, MFD_MODEL.filename)\r\n const encPath = join(modelsDir, MFR_ENCODER_MODEL.filename)\r\n const decPath = join(modelsDir, MFR_DECODER_MODEL.filename)\r\n const tokPath = join(modelsDir, MFR_TOKENIZER.filename)\r\n\r\n const sessionOpts: import(\"onnxruntime-node\").InferenceSession.SessionOptions = {\r\n graphOptimizationLevel: \"all\",\r\n executionProviders: [\"cpu\"],\r\n }\r\n\r\n // 각 세션은 I/O 바운드 아님 → 병렬 로드로 1~2초 단축\r\n const [mfd, encoder, decoder] = await Promise.all([\r\n ortMod.InferenceSession.create(mfdPath, sessionOpts),\r\n ortMod.InferenceSession.create(encPath, sessionOpts),\r\n ortMod.InferenceSession.create(decPath, sessionOpts),\r\n ])\r\n\r\n // Transformers.js 의 PreTrainedTokenizer 를 로컬 tokenizer.json 으로 로드.\r\n // AutoTokenizer.from_pretrained 는 HF hub 접근을 시도하므로 우회.\r\n const { readFile } = await import(\"fs/promises\")\r\n const tokenizerJson = JSON.parse(await readFile(tokPath, \"utf-8\"))\r\n const PretrainedCtor = hfMod.PreTrainedTokenizer as unknown as new (\r\n json: unknown,\r\n config: Record<string, unknown>,\r\n ) => PreTrainedTokenizer\r\n const tokenizer = new PretrainedCtor(tokenizerJson, {})\r\n\r\n const pdfium = await pdfiumMod.PDFiumLibrary.init()\r\n\r\n return new FormulaPipeline({\r\n mfd,\r\n encoder,\r\n decoder,\r\n tokenizer,\r\n ort: ortMod,\r\n sharp: sharpMod,\r\n pdfium,\r\n opts,\r\n })\r\n }\r\n\r\n /** 리소스 해제 — 더 이상 사용하지 않을 때 호출. */\r\n async destroy(): Promise<void> {\r\n // onnxruntime-node InferenceSession 은 release() 없음 (GC 의존).\r\n try {\r\n this.pdfium.destroy()\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n /**\r\n * PDF 버퍼를 열어 페이지별 수식 영역을 인식한다.\r\n * 실패한 페이지는 skip (에러 전파 없음 — 로그만).\r\n *\r\n * @param pageFilter null 이면 전체 페이지. Set 이면 1-based 페이지 번호 일치만.\r\n */\r\n async runOnBuffer(\r\n buffer: ArrayBuffer | Uint8Array,\r\n pageFilter: Set<number> | null = null,\r\n onPageProgress?: (pageNumber: number, total: number) => void,\r\n ): Promise<PageFormulaResult[]> {\r\n const view = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)\r\n const doc: PDFiumDocument = await this.pdfium.loadDocument(view)\r\n try {\r\n const pages: PageFormulaResult[] = []\r\n for (const page of doc.pages()) {\r\n // pdfium page.number 는 0-based pageIndex — pdfjs 블록/pageFilter 는 1-based.\r\n // 환산 없이는 필터가 한 페이지 밀리고 수식이 이전 페이지 블록에 붙는다 (off-by-one).\r\n const pageNo = page.number + 1\r\n if (pageFilter && !pageFilter.has(pageNo)) continue\r\n\r\n onPageProgress?.(pageNo, doc.getPageCount())\r\n\r\n try {\r\n const result = await withTimeout(\r\n this.processPage(pageNo, page),\r\n this.opts.pageTimeoutMs,\r\n `formula page ${pageNo} timed out after ${this.opts.pageTimeoutMs}ms`,\r\n )\r\n if (result) pages.push(result)\r\n } catch (e) {\r\n // 페이지 단위 실패는 조용히 넘어간다 — 전체 PDF 파싱 실패 방지.\r\n process.stderr.write(\r\n `[kordoc-formula] page ${pageNo} skipped: ${(e as Error).message}\\n`,\r\n )\r\n }\r\n }\r\n return pages\r\n } finally {\r\n doc.destroy()\r\n }\r\n }\r\n\r\n private async processPage(\r\n pageNumber: number,\r\n page: import(\"@hyzyla/pdfium\").PDFiumPage,\r\n ): Promise<PageFormulaResult | null> {\r\n const { originalWidth: pdfWidth, originalHeight: pdfHeight } = page.getOriginalSize()\r\n\r\n const sharpCtor = this.sharp\r\n const rendered = await page.render({\r\n scale: this.opts.scale,\r\n render: async ({ data, width, height }) => {\r\n // 임시로 PNG 로 인코딩하지 않고 raw 그대로 반환 — 바로 쓸 거라서.\r\n return data\r\n },\r\n })\r\n // rendered.data 는 BGRA — sharp 로 RGBA 로 변환\r\n const { data: bgra, width: rw, height: rh } = rendered\r\n const rgba = bgraToRgba(bgra)\r\n\r\n const pageFrame: PixelFrame = { width: rw, height: rh, data: rgba }\r\n\r\n // 1) 수식 영역 검출\r\n const regions0 = await detectFormulaRegions(this.mfd, pageFrame, this.ort)\r\n if (regions0.length === 0) {\r\n return { pageNumber, renderedWidth: rw, renderedHeight: rh, pdfWidth, pdfHeight, regions: [] }\r\n }\r\n\r\n const capped = regions0.slice(0, this.opts.maxRegionsPerPage)\r\n const regions: FormulaRegion[] = []\r\n\r\n // 2) 각 영역 crop → 인식\r\n for (const r of capped) {\r\n const x1 = Math.floor(Math.max(0, r.bbox.x1))\r\n const y1 = Math.floor(Math.max(0, r.bbox.y1))\r\n const x2 = Math.ceil(Math.min(rw, r.bbox.x2))\r\n const y2 = Math.ceil(Math.min(rh, r.bbox.y2))\r\n const cw = x2 - x1\r\n const ch = y2 - y1\r\n if (cw < 4 || ch < 4) continue\r\n\r\n // sharp 로 raw RGBA 에서 crop → raw RGBA 반환\r\n const cropRgba = await sharpCtor(rgba, {\r\n raw: { width: rw, height: rh, channels: 4 },\r\n })\r\n .extract({ left: x1, top: y1, width: cw, height: ch })\r\n .raw()\r\n .toBuffer()\r\n\r\n const cropFrame: PixelFrame = { width: cw, height: ch, data: new Uint8Array(cropRgba) }\r\n\r\n let latex = \"\"\r\n try {\r\n latex = await recognizeFormula(\r\n {\r\n encoder: this.encoder,\r\n decoder: this.decoder,\r\n tokenizer: this.tokenizer,\r\n ort: this.ort,\r\n },\r\n cropFrame,\r\n )\r\n } catch (e) {\r\n process.stderr.write(\r\n `[kordoc-formula] recognize failed at page ${pageNumber} ${JSON.stringify(r.bbox)}: ${(e as Error).message}\\n`,\r\n )\r\n latex = \"\"\r\n }\r\n\r\n regions.push({ ...r, latex })\r\n }\r\n\r\n return {\r\n pageNumber,\r\n renderedWidth: rw,\r\n renderedHeight: rh,\r\n pdfWidth,\r\n pdfHeight,\r\n regions,\r\n }\r\n }\r\n}\r\n\r\nasync function tryImport<T>(name: string, loader: () => Promise<T>): Promise<T> {\r\n try {\r\n return await loader()\r\n } catch (e) {\r\n throw new Error(\r\n `수식 OCR 을 사용하려면 optional dependency '${name}' 이 필요합니다. ` +\r\n `\\`npm install ${name}\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n}\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, ms: number, msg: string): Promise<T> {\r\n // 타임아웃으로 race 가 끝난 뒤에도 원 promise 는 계속 실행된다 — 사후 reject 가\r\n // unhandled rejection(Node 기본 정책: 프로세스 종료)이 되지 않게 흡수\r\n promise.catch(() => {})\r\n let timer: NodeJS.Timeout | undefined\r\n try {\r\n return await Promise.race([\r\n promise,\r\n new Promise<never>((_, reject) => {\r\n timer = setTimeout(() => reject(new Error(msg)), ms)\r\n }),\r\n ])\r\n } finally {\r\n if (timer) clearTimeout(timer)\r\n }\r\n}\r\n\r\n/** pdfium 의 BGRA 버퍼를 RGBA 로 변환 (Red ↔ Blue 스왑). */\r\nfunction bgraToRgba(bgra: Uint8Array): Uint8Array {\r\n const out = new Uint8Array(bgra.length)\r\n for (let i = 0; i < bgra.length; i += 4) {\r\n out[i] = bgra[i + 2] // R ← B\r\n out[i + 1] = bgra[i + 1] // G ← G\r\n out[i + 2] = bgra[i] // B ← R\r\n out[i + 3] = bgra[i + 3] // A ← A\r\n }\r\n return out\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["c:\\github_project\\kordoc\\dist\\formula-IWV5IJ3Y.cjs"],"names":[],"mappings":"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CA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,wBAAA;AACA,QAAA;AACA,UAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,UAAA;AACA,YAAA;AACA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"C:\\github_project\\kordoc\\dist\\formula-IWV5IJ3Y.cjs","sourcesContent":[null]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ocr/image-ocr.ts"],"sourcesContent":["/**\r\n * 이미지 직접 입력 OCR — PNG/JPEG/WebP 를 PDF 래핑 없이 바로 파싱한다.\r\n *\r\n * 이미지는 텍스트층이 없으므로 OCR 이 항상 필요하다 — `--ocr` 플래그 없이도\r\n * 내장 엔진(PP-OCRv5 korean)을 기본 적용하고, OcrProvider 가 주어지면 위임한다.\r\n * 좌표는 216dpi(스케일 3) 가정으로 PDF pt 공간에 환산해 기존 블록 파이프라인\r\n * (괘선 감지 → 선 기반 표 → 클러스터 → xy-cut)을 그대로 태운다.\r\n *\r\n * 디코딩은 optional dependency `sharp` — 미설치면 MISSING_DEPENDENCY 안내.\r\n */\r\n\r\nimport type { IRBlock, ParseOptions, ParseWarning } from \"../types.js\"\r\nimport { KordocError } from \"../utils.js\"\r\nimport { getOcrEngine } from \"./engine.js\"\r\nimport { ensureOcrModels } from \"./models.js\"\r\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\r\nimport { ocrItemsToBlocks } from \"./pdf-ocr.js\"\r\n\r\n/** 좌표 환산 스케일 (px/pt) — PDF OCR 렌더(216dpi)와 동일 기준 */\r\nconst IMAGE_SCALE = 3\r\n\r\nexport interface ImageOcrResult {\r\n blocks: IRBlock[]\r\n warnings: ParseWarning[]\r\n}\r\n\r\n/** 이미지 버퍼 → OCR → IRBlock[] (표 괘선 감지 포함) */\r\nexport async function parseImageDocument(\r\n buffer: ArrayBuffer,\r\n options?: ParseOptions,\r\n): Promise<ImageOcrResult> {\r\n const warnings: ParseWarning[] = []\r\n\r\n // 사용자 OcrProvider — 원본 바이트 그대로 위임 (종전 PDF 경로와 같은 계약)\r\n if (typeof options?.ocr === \"function\") {\r\n const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer))\r\n if (!text.trim()) {\r\n warnings.push({ page: 1, message: \"OCR 결과 없음\", code: \"OCR_FAILED\" })\r\n return { blocks: [], warnings }\r\n }\r\n return { blocks: [{ type: \"paragraph\", text: text.trim(), pageNumber: 1 }], warnings }\r\n }\r\n\r\n const { data, width, height } = await decodeToRgba(buffer)\r\n\r\n await ensureOcrModels(p => {\r\n if (p.phase === \"download\" && p.downloaded === 0) {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\r\n }\r\n })\r\n const engine = await getOcrEngine()\r\n const items = await engine.recognizePage(data, width, height)\r\n if (items.length === 0) {\r\n warnings.push({ page: 1, message: \"이미지에서 텍스트를 인식하지 못했습니다\", code: \"OCR_FAILED\" })\r\n return { blocks: [], warnings }\r\n }\r\n\r\n const pdfW = width / IMAGE_SCALE\r\n const pdfH = height / IMAGE_SCALE\r\n const ruling = detectRulingLines(data, width, height, IMAGE_SCALE)\r\n const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH)\r\n return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings }\r\n}\r\n\r\n/** sharp 로 RGBA 디코딩 — 미설치는 MISSING_DEPENDENCY 로 분류되도록 안내 메시지 throw */\r\nasync function decodeToRgba(\r\n buffer: ArrayBuffer,\r\n): Promise<{ data: Uint8Array; width: number; height: number }> {\r\n type SharpFactory = (input: Buffer) => {\r\n ensureAlpha(): { raw(): { toBuffer(opts: { resolveWithObject: true }): Promise<{ data: Buffer; info: { width: number; height: number } }> } }\r\n }\r\n let sharp: SharpFactory\r\n try {\r\n const mod = (await import(\"sharp\")) as unknown as SharpFactory | { default?: SharpFactory }\r\n sharp = typeof mod === \"function\" ? mod : (mod.default ?? (mod as unknown as SharpFactory))\r\n } catch (e) {\r\n // KordocError + \"optional dependency\" 문구 → sanitizeError 메시지 보존 + MISSING_DEPENDENCY 분류\r\n throw new KordocError(\r\n \"이미지 파싱에는 optional dependency 'sharp' 가 필요합니다. \" +\r\n `\\`npm install sharp\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true })\r\n return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height }\r\n}\r\n\r\n/** OcrProvider 계약용 mime 판별 */\r\nfunction detectImageMime(buffer: ArrayBuffer): \"image/png\" | \"image/jpeg\" | \"image/webp\" {\r\n const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength))\r\n if (b[0] === 0xff && b[1] === 0xd8) return \"image/jpeg\"\r\n if (b[0] === 0x52 && b[1] === 0x49) return \"image/webp\"\r\n return \"image/png\"\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAmBA,IAAM,cAAc;AAQpB,eAAsB,mBACpB,QACA,SACyB;AACzB,QAAM,WAA2B,CAAC;AAGlC,MAAI,OAAO,SAAS,QAAQ,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,WAAW,MAAM,GAAG,GAAG,gBAAgB,MAAM,CAAC;AACjF,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,eAAS,KAAK,EAAE,MAAM,GAAG,SAAS,iCAAa,MAAM,aAAa,CAAC;AACnE,aAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,IAChC;AACA,WAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,KAAK,KAAK,GAAG,YAAY,EAAE,CAAC,GAAG,SAAS;AAAA,EACvF;AAEA,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,MAAM,aAAa,MAAM;AAEzD,QAAM,gBAAgB,OAAK;AACzB,QAAI,EAAE,UAAU,cAAc,EAAE,eAAe,GAAG;AAChD,cAAQ,OAAO,MAAM,gBAAgB,EAAE,KAAK,IAAI,sCAAa,EAAE,KAAK,MAAM;AAAA,CAAU;AAAA,IACtF;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,MAAM;AAC5D,MAAI,MAAM,WAAW,GAAG;AACtB,aAAS,KAAK,EAAE,MAAM,GAAG,SAAS,mHAAyB,MAAM,aAAa,CAAC;AAC/E,WAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,SAAS;AACtB,QAAM,SAAS,kBAAkB,MAAM,OAAO,QAAQ,WAAW;AACjE,QAAM,aAAa,iBAAiB,QAAQ,aAAa,IAAI;AAC7D,SAAO,EAAE,QAAQ,iBAAiB,OAAO,GAAG,MAAM,MAAM,aAAa,UAAU,GAAG,SAAS;AAC7F;AAGA,eAAe,aACb,QAC8D;AAI9D,MAAI;AACJ,MAAI;AACF,UAAM,MAAO,MAAM,OAAO,OAAO;AACjC,YAAQ,OAAO,QAAQ,aAAa,MAAO,IAAI,WAAY;AAAA,EAC7D,SAAS,GAAG;AAEV,UAAM,IAAI;AAAA,MACR,0MAC4C,EAAY,OAAO;AAAA,IACjE;AAAA,EACF;AACA,QAAM,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAChH,SAAO,EAAE,MAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,GAAG,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACvH;AAGA,SAAS,gBAAgB,QAAgE;AACvF,QAAM,IAAI,IAAI,WAAW,QAAQ,GAAG,KAAK,IAAI,IAAI,OAAO,UAAU,CAAC;AACnE,MAAI,EAAE,CAAC,MAAM,OAAQ,EAAE,CAAC,MAAM,IAAM,QAAO;AAC3C,MAAI,EAAE,CAAC,MAAM,MAAQ,EAAE,CAAC,MAAM,GAAM,QAAO;AAC3C,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ocr/image-ocr.ts"],"sourcesContent":["/**\r\n * 이미지 직접 입력 OCR — PNG/JPEG/WebP 를 PDF 래핑 없이 바로 파싱한다.\r\n *\r\n * 이미지는 텍스트층이 없으므로 OCR 이 항상 필요하다 — `--ocr` 플래그 없이도\r\n * 내장 엔진(PP-OCRv5 korean)을 기본 적용하고, OcrProvider 가 주어지면 위임한다.\r\n * 좌표는 216dpi(스케일 3) 가정으로 PDF pt 공간에 환산해 기존 블록 파이프라인\r\n * (괘선 감지 → 선 기반 표 → 클러스터 → xy-cut)을 그대로 태운다.\r\n *\r\n * 디코딩은 optional dependency `sharp` — 미설치면 MISSING_DEPENDENCY 안내.\r\n */\r\n\r\nimport type { IRBlock, ParseOptions, ParseWarning } from \"../types.js\"\r\nimport { KordocError } from \"../utils.js\"\r\nimport { getOcrEngine } from \"./engine.js\"\r\nimport { ensureOcrModels } from \"./models.js\"\r\nimport { detectRulingLines, rulingToPdfLines } from \"./ruling-lines.js\"\r\nimport { ocrItemsToBlocks } from \"./pdf-ocr.js\"\r\n\r\n/** 좌표 환산 스케일 (px/pt) — PDF OCR 렌더(216dpi)와 동일 기준 */\r\nconst IMAGE_SCALE = 3\r\n\r\nexport interface ImageOcrResult {\r\n blocks: IRBlock[]\r\n warnings: ParseWarning[]\r\n}\r\n\r\n/** 이미지 버퍼 → OCR → IRBlock[] (표 괘선 감지 포함) */\r\nexport async function parseImageDocument(\r\n buffer: ArrayBuffer,\r\n options?: ParseOptions,\r\n): Promise<ImageOcrResult> {\r\n const warnings: ParseWarning[] = []\r\n\r\n // 사용자 OcrProvider — 원본 바이트 그대로 위임 (종전 PDF 경로와 같은 계약)\r\n if (typeof options?.ocr === \"function\") {\r\n const text = await options.ocr(new Uint8Array(buffer), 1, detectImageMime(buffer))\r\n if (!text.trim()) {\r\n warnings.push({ page: 1, message: \"OCR 결과 없음\", code: \"OCR_FAILED\" })\r\n return { blocks: [], warnings }\r\n }\r\n return { blocks: [{ type: \"paragraph\", text: text.trim(), pageNumber: 1 }], warnings }\r\n }\r\n\r\n const { data, width, height } = await decodeToRgba(buffer)\r\n\r\n await ensureOcrModels(p => {\r\n if (p.phase === \"download\" && p.downloaded === 0) {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 다운로드 중 (~${p.spec.sizeMb}MB)...\\n`)\r\n }\r\n })\r\n const engine = await getOcrEngine()\r\n const items = await engine.recognizePage(data, width, height)\r\n if (items.length === 0) {\r\n warnings.push({ page: 1, message: \"이미지에서 텍스트를 인식하지 못했습니다\", code: \"OCR_FAILED\" })\r\n return { blocks: [], warnings }\r\n }\r\n\r\n const pdfW = width / IMAGE_SCALE\r\n const pdfH = height / IMAGE_SCALE\r\n const ruling = detectRulingLines(data, width, height, IMAGE_SCALE)\r\n const extraLines = rulingToPdfLines(ruling, IMAGE_SCALE, pdfH)\r\n return { blocks: ocrItemsToBlocks(items, 1, pdfW, pdfH, IMAGE_SCALE, extraLines), warnings }\r\n}\r\n\r\n/** sharp 로 RGBA 디코딩 — 미설치는 MISSING_DEPENDENCY 로 분류되도록 안내 메시지 throw */\r\nasync function decodeToRgba(\r\n buffer: ArrayBuffer,\r\n): Promise<{ data: Uint8Array; width: number; height: number }> {\r\n type SharpFactory = (input: Buffer) => {\r\n ensureAlpha(): { raw(): { toBuffer(opts: { resolveWithObject: true }): Promise<{ data: Buffer; info: { width: number; height: number } }> } }\r\n }\r\n let sharp: SharpFactory\r\n try {\r\n const mod = (await import(\"sharp\")) as unknown as SharpFactory | { default?: SharpFactory }\r\n sharp = typeof mod === \"function\" ? mod : (mod.default ?? (mod as unknown as SharpFactory))\r\n } catch (e) {\r\n // KordocError + \"optional dependency\" 문구 → sanitizeError 메시지 보존 + MISSING_DEPENDENCY 분류\r\n throw new KordocError(\r\n \"이미지 파싱에는 optional dependency 'sharp' 가 필요합니다. \" +\r\n `\\`npm install sharp\\` 후 다시 실행하세요. 원인: ${(e as Error).message}`,\r\n )\r\n }\r\n const { data, info } = await sharp(Buffer.from(buffer)).ensureAlpha().raw().toBuffer({ resolveWithObject: true })\r\n return { data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength), width: info.width, height: info.height }\r\n}\r\n\r\n/** OcrProvider 계약용 mime 판별 */\r\nfunction detectImageMime(buffer: ArrayBuffer): \"image/png\" | \"image/jpeg\" | \"image/webp\" {\r\n const b = new Uint8Array(buffer, 0, Math.min(12, buffer.byteLength))\r\n if (b[0] === 0xff && b[1] === 0xd8) return \"image/jpeg\"\r\n if (b[0] === 0x52 && b[1] === 0x49) return \"image/webp\"\r\n return \"image/png\"\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,IAAM,cAAc;AAQpB,eAAsB,mBACpB,QACA,SACyB;AACzB,QAAM,WAA2B,CAAC;AAGlC,MAAI,OAAO,SAAS,QAAQ,YAAY;AACtC,UAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,WAAW,MAAM,GAAG,GAAG,gBAAgB,MAAM,CAAC;AACjF,QAAI,CAAC,KAAK,KAAK,GAAG;AAChB,eAAS,KAAK,EAAE,MAAM,GAAG,SAAS,iCAAa,MAAM,aAAa,CAAC;AACnE,aAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,IAChC;AACA,WAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,KAAK,KAAK,GAAG,YAAY,EAAE,CAAC,GAAG,SAAS;AAAA,EACvF;AAEA,QAAM,EAAE,MAAM,OAAO,OAAO,IAAI,MAAM,aAAa,MAAM;AAEzD,QAAM,gBAAgB,OAAK;AACzB,QAAI,EAAE,UAAU,cAAc,EAAE,eAAe,GAAG;AAChD,cAAQ,OAAO,MAAM,gBAAgB,EAAE,KAAK,IAAI,sCAAa,EAAE,KAAK,MAAM;AAAA,CAAU;AAAA,IACtF;AAAA,EACF,CAAC;AACD,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,QAAQ,MAAM,OAAO,cAAc,MAAM,OAAO,MAAM;AAC5D,MAAI,MAAM,WAAW,GAAG;AACtB,aAAS,KAAK,EAAE,MAAM,GAAG,SAAS,mHAAyB,MAAM,aAAa,CAAC;AAC/E,WAAO,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,OAAO,QAAQ;AACrB,QAAM,OAAO,SAAS;AACtB,QAAM,SAAS,kBAAkB,MAAM,OAAO,QAAQ,WAAW;AACjE,QAAM,aAAa,iBAAiB,QAAQ,aAAa,IAAI;AAC7D,SAAO,EAAE,QAAQ,iBAAiB,OAAO,GAAG,MAAM,MAAM,aAAa,UAAU,GAAG,SAAS;AAC7F;AAGA,eAAe,aACb,QAC8D;AAI9D,MAAI;AACJ,MAAI;AACF,UAAM,MAAO,MAAM,OAAO,OAAO;AACjC,YAAQ,OAAO,QAAQ,aAAa,MAAO,IAAI,WAAY;AAAA,EAC7D,SAAS,GAAG;AAEV,UAAM,IAAI;AAAA,MACR,0MAC4C,EAAY,OAAO;AAAA,IACjE;AAAA,EACF;AACA,QAAM,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,KAAK,CAAC;AAChH,SAAO,EAAE,MAAM,IAAI,WAAW,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,GAAG,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACvH;AAGA,SAAS,gBAAgB,QAAgE;AACvF,QAAM,IAAI,IAAI,WAAW,QAAQ,GAAG,KAAK,IAAI,IAAI,OAAO,UAAU,CAAC;AACnE,MAAI,EAAE,CAAC,MAAM,OAAQ,EAAE,CAAC,MAAM,IAAM,QAAO;AAC3C,MAAI,EAAE,CAAC,MAAM,MAAQ,EAAE,CAAC,MAAM,GAAM,QAAO;AAC3C,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["c:\\github_project\\kordoc\\dist\\image-ocr-XEJFXH6M.cjs"],"names":[],"mappings":"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","file":"C:\\github_project\\kordoc\\dist\\image-ocr-XEJFXH6M.cjs","sourcesContent":[null]}