본문으로 건너뛰기

스캔 PDF를 EPUB으로 바꾸면 각주가 엉뚱한 곳을 가리키는 이유

모든 페이지를 LLM에 맡기던 방식에서 JEV로 의심스러운 페이지만 고르는 방식까지, 스캔 도서의 각주 관계를 다듬어 온 과정입니다.

오래된 책의 본문 참조와 각주가 가는 선으로 연결되고 옆에는 다시 배치된 읽기 페이지가 있다
개념 삽화: 변환 후에도 본문 참조와 각주의 관계를 보존해야 합니다.

저는 스캔한 책의 PDF를 읽고 검색하고 정리하기 편한 Markdown이나 EPUB으로 바꾸기 위해 PDF Craft를 개발했습니다. 이미지를 글자로 인식하는 것만으로는 충분하지 않습니다. 본문의 숫자, 동그라미 기호, 별표가 원본 페이지 아래의 올바른 주석으로 이어져야 합니다. 글이 화면에 맞게 재배치되어도 이 관계가 사라지면 읽는 데 필요한 정보가 빠집니다.

절판 도서, 학술 자료, 개인 소장 책을 정리할 때 특히 중요합니다. 변환 결과는 작은 화면에서 검색하고 복사하며 읽을 수 있어야 하고, 본문의 표시에서 주석 전문을 찾을 수 있어야 합니다. 결과를 확인할 때는 스캔 PDF를 EPUB으로 바꾸는 안내수식 및 각주 점검 목록을 참고할 수 있습니다.

OCR은 글자를 읽지만 역할까지 알지는 못합니다

OCR은 페이지의 문자를 찾을 수 있어도 그 문자가 책에서 무슨 역할을 하는지는 항상 알지 못합니다. 페이지 아래의 작은 글은 각주일 수도 있고 아래까지 이어진 본문일 수도 있습니다. 동그라미 숫자는 참조 표시일 수도, 평범한 목록 번호일 수도 있습니다. 주석 하나가 두 영역으로 나뉘거나 다음 페이지로 넘어가기도 합니다.

관계를 한 번만 잘못 판단해도 참조할 곳이 없는 표시, 합쳐진 두 주석, 문장 속에 들어간 쪽수, 다음 페이지의 머리말로 이어진 앞 페이지의 마지막 문장이 생깁니다. 각주는 오래전부터 PDF Craft에서 가장 어려운 문제 중 하나였습니다.

첫 시도: LLM이 모든 페이지를 읽게 하기

약 1년 전에는 전통적인 프로그램이 의미를 이해하기 어렵다면 대규모 언어 모델에 각 페이지를 맡기면 된다고 생각했습니다. 모델은 작은 글이 본문을 설명하는지, 별표나 로마 숫자가 참조 표시인지 파악하고, 앞뒤 맥락으로 문장이 페이지를 넘어 이어지는지도 판단할 수 있었습니다.

한 페이지에서는 매력적이었지만 긴 책에서는 수백 페이지가 곧 수백 번의 호출과 대기, 실패 시 재시도가 되었습니다. 페이지 경계를 판단하려면 주변 문맥까지 넣어야 해서 입력도 길어졌습니다. 대부분의 페이지는 이미 맞았는데, 비싼 모델이 다시 읽고 ‘수정할 것 없음’이라고 답하는 시간이 많았습니다. 사용자도 처리가 진행 중인지 한 페이지에서 멈췄는지 알기 어려웠습니다.

먼저 규칙 기반 흐름을 완성하기

이후 버전에서는 주요 작업을 OCR과 결정적인 규칙으로 다시 옮겼습니다. 본문과 각주를 구분하고, 자연스러운 문단을 합치고, 주석을 항목별로 나눈 뒤 본문의 표시와 연결합니다. 빠르고 안정적이며 반복 실행할 수 있고 대부분의 페이지에서 잘 작동합니다.

하지만 책의 편집 방식은 다양합니다. 각주가 페이지 아래나 단 사이에 있을 수 있고, 표시는 숫자나 기호일 수 있습니다. 머리말과 쪽수가 인식된 본문에 섞이기도 합니다. 어떤 예외는 문장 뜻을 이해해야 해결됩니다. 규칙만으로는 일부를 놓치고, 모든 페이지를 LLM에 맡기면 너무 느리고 비쌉니다.

전환점: JEV에 재작업이 아닌 점검 맡기기

기존 처리 흐름을 버릴 필요는 없었습니다. 더 면밀히 볼 페이지만 찾아내는 빠른 품질 검사가 필요했습니다. JEV에는 좁은 질문 하나만 던집니다. 이 페이지의 분석 결과를 수정 없이 통과시켜도 되는가? JEV는 글을 다시 쓰거나 주석마다 설명하지 않고, 페이지를 계속 처리할지 LLM으로 보낼지 판단하는 데 쓸 확률을 반환합니다.

검토 단위는 개별 주석이 아니라 페이지 전체입니다. 알고리즘이 주석 하나를 완전히 누락했다면 발견된 주석만 확인해서는 찾을 수 없습니다. 페이지를 보면 빠진 참조, 잘못된 소속, 비정상적인 페이지 연결, 본문에 섞인 쪽수를 의심할 여지가 있습니다. 잘못 경고해서 모델 검사를 한 번 더 하는 편이 오류를 EPUB에 그대로 넣는 것보다 낫습니다. 다만 임계값은 더 많은 자료로 조정해야 합니다.

flowchart TB
  accTitle: 페이지 점검에서 제약 있는 수정까지
  accDescr: OCR과 규칙이 먼저 페이지를 처리하고 JEV가 그대로 통과시킬지 판단합니다. 의심스러운 페이지는 LLM이 수정한 뒤 프로그램의 무결성 검사를 받습니다. 실패하면 다시 시도합니다.
  A[OCR과 규칙] --> B{JEV: 페이지를 신뢰할까?}
  B -- 예 --> F[장 조립과 출력]
  B -- 아니요 --> C[LLM이 현재 페이지만 수정]
  C --> D{무결성 검사}
  D -- 통과 --> F
  D -- 재시도 --> C
페이지 점검에서 제약 있는 수정까지

LLM의 수정 범위를 엄격하게 제한하기

의심스러운 페이지에 대해 LLM은 앞 페이지, 현재 페이지, 다음 페이지의 텍스트 구조를 봅니다. 수정은 가운데 페이지만 할 수 있습니다. 양옆은 문장이 페이지를 넘어 이어지는지 이해하는 맥락입니다. 이 단계에서는 이미지를 보내지 않습니다. OCR이 텍스트, 위치, 배치 정보를 남겼으므로 여기서는 OCR을 다시 하는 것이 아니라 의미를 교정합니다.

모델은 본문, 각주, 쪽수의 분류를 바꾸고 문단 연결과 참조 관계를 고칠 수 있습니다. 원문을 마음대로 바꾸거나 페이지 구조를 수정할 수는 없습니다. 이후 프로그램은 각주 인덱스의 순서, 본문 표시와 주석의 대응, 페이지 경계 양쪽의 일관성, 지정된 텍스트에서 표시 위치를 모호함 없이 찾을 수 있는지 확인합니다. 실패하면 구체적인 오류를 돌려주고 전체 결과를 다시 제출하도록 합니다. 재시도를 줄이려고 검사를 완화하지는 않습니다.

26페이지 샘플이 보여 준 점

각주가 많은 26페이지 테스트 PDF에서 JEV는 6페이지를 LLM에 보냈습니다. 여섯 페이지 모두 첫 제출에서 무결성 검사를 통과했고, 원래 맞았던 본문 참조와 주석의 관계 22쌍도 그대로 유지됐습니다.

실제 수정은 작지만 읽기에 중요한 것들이었습니다. 인쇄된 쪽수가 본문으로 인식됐고, 그중 하나가 두 문단을 잘못 이어 주었으며, 도입 문장이 뒤따르는 들여쓴 인용문과 합쳐져 있었습니다. 모델은 뜻과 들여쓰기를 참고해 다시 나눴습니다.

이는 단일 샘플의 관찰이지 모든 책의 정확도나 비용을 뜻하지 않습니다. 좋은 수정 단계는 이미 맞는 부분을 보존하고 근거가 있는 문제만 고쳐야 한다는 점을 확인했습니다.

비싼 판단은 필요한 곳에만 쓰기

규칙은 대부분의 확정적인 작업을, JEV는 의심스러운 페이지 선별을, LLM은 의미 이해가 필요한 소수의 수정을 담당합니다. 프로그램 검사는 최종 구조를 지킵니다. 수정된 페이지는 같은 장 조립 및 Markdown·EPUB 출력 흐름으로 돌아갑니다.

앞으로 더 많은 언어, 편집 방식, 두꺼운 책에서 JEV의 누락률과 LLM 검토 임계값을 살펴야 합니다. 그래도 여백에 숨은 몇 가지 오류를 찾으려고 LLM이 책 전체를 읽을 필요는 없어졌습니다. 자신의 책을 바꾸려면 PDF Craft 변환 화면에서 각주가 있는 짧은 샘플을 먼저 처리하고 본문 표시, 주석 전문, 페이지를 넘는 문단을 확인해 보세요.

내 문서에 적용해 보기

대표 파일로 먼저 시험하고 결과를 확인한 뒤, 자료에 맞는 처리 방식을 선택하세요.

작업 공간 열기