5초간의 침묵

칠레의 한 독자가 가입한 뒤, Angeles Durini의 어린이 소설 "¿Quién le tiene miedo a Demetrio Latov?" 74페이지 분량의 PDF를 업로드하고 오디오북 생성을 클릭했습니다. 15초 뒤 이메일이 도착했습니다. "오디오북이 준비되었습니다."

그러나 실제로는 그렇지 않았습니다. 파일은 5.6초 길이였고, 아무 내용도 들어 있지 않았습니다.

이런 종류의 버그는 프로덕션에서만 잡히는 종류입니다. 우리가 그동안 사용한 테스트 PDF에는 모두 텍스트가 임베드되어 있었지만, 그녀의 파일은 그렇지 않았기 때문입니다. 그 책은 2012년에 Adobe Acrobat Pro로 한 페이지씩 스캔되었고, 모든 페이지가 이미지로 저장되어 있었습니다. 우리의 파이프라인에게 그 PDF는 빈 페이지 74장이었던 것입니다.

핵심 요점: PDF가 스캔본(텍스트 레이어가 없는 이미지 전용)일 때, 대부분의 AI 오디오북 생성기는 조용히 비어 있거나 의미 없는 오디오를 만들어냅니다. 실제 텍스트 추출에는 OCR이 필요하지만, 기본값으로 OCR을 실행하는 오디오북 도구는 거의 없습니다.

왜 스캔된 PDF가 오디오북 파이프라인을 망가뜨리는가

PDF는 완전히 다른 두 가지 방식으로 텍스트를 담을 수 있습니다.

평판 스캐너, 휴대폰 카메라, 또는 오래된 디지털화 프로젝트(Google Books, archive.org, 퍼블릭 도메인 재인쇄본, 중고 어린이 책 등)에서 나온 것은 대부분 두 번째 유형에 속합니다. 사람 눈에는 똑같아 보이지만, 소프트웨어에게는 근본적으로 다릅니다.

실패한 업로드를 살펴보니, 우리 PDF 파서는 74페이지 책 전체에서 딱 17바이트의 쓰레기 데이터만 반환했습니다 — 문자가 아닌 제어 바이트였습니다. 그러자 파이프라인은 그 17바이트를 충실히 TTS에 넣어 5초간의 웅얼거리는 출력물을 만들었고, 독자에게 오디오북이 준비되었다고 이메일을 보냈습니다.

우리가 구축한 것

해결책은 개념적으로 단순합니다. PDF에 쓸 만한 텍스트가 없는지 감지한 다음, 모든 페이지를 OCR한다. 구현에는 설명할 만한 몇 가지 요소가 있습니다.

1. 희소 텍스트 감지기

모든 업로드에 무작정 OCR을 돌리기 전에, 네이티브 추출의 결과를 먼저 확인합니다. PDF 전체가 200자 미만을 반환하거나, 4페이지 이상에서 페이지당 평균 30자 미만일 경우 스캔본으로 간주하고 OCR 경로로 넘어갑니다. 일반적인 텍스트 PDF — 90% 이상의 경우 — 는 절대 느린 경로를 타지 않습니다.

2. pypdfium2 + tesseract (전부 Apache 2.0)

각 페이지를 pypdfium2(Google의 PDFium 엔진을 감싼 Python 래퍼, Apache 2.0)로 2.5배 스케일 — 약 180 DPI, 안정적인 문자 인식에 충분한 해상도 — 로 렌더링합니다. 각 이미지는 다국어 모델이 로드된 tesseract를 거칩니다. eng+spa+por+fra+deu+pol+ita+tur. Tesseract는 글리프 모양으로부터 실제 언어를 알아냅니다.

우리는 의도적으로 PyMuPDF — 가장 인기 있는 Python PDF 라이브러리 — 에서 빠져나왔습니다. AGPL 라이선스가 호스팅 서비스에는 부담스럽기 때문입니다. pypdfium2로 옮기는 데 반나절이 걸렸고, 법적 절벽을 완전히 제거할 수 있었습니다. 상용 제품에서 PDF 관련 작업을 한다면 알아둘 만한 정보입니다.

3. 언어 자동 감지

독자의 책은 스페인어였지만, UI 로케일은 영어였습니다. 그래서 수정 전이라면 설사 OCR이 작동했더라도 파이프라인은 스페인어 텍스트를 영어 음성(로봇 같고 발음이 어긋난)으로 합성했을 것입니다. 이제는 언어 감지 자체에 OCR된 텍스트를 사용합니다. 샘플 3페이지를 거친 뒤, langdetect가 콘텐츠를 분류하고 적절한 음성을 선택합니다 — 이 경우에는 라틴 아메리카 스페인어였습니다.

4. 정직한 실패 경로

OCR을 거쳐도 여전히 100자 미만이 복원된다면(장식 전용 PDF, 손상된 파일 등), 이제는 침묵을 만드는 대신 명확한 오류를 발생시킵니다. "이 PDF에는 추출 가능한 텍스트가 없습니다. EPUB, TXT 또는 텍스트 기반 PDF를 업로드해 주세요." 오디오북 작업은 실패로 표시되고, 이메일은 발송되지 않으며, 크레딧도 차감되지 않습니다.

스캔된 PDF가 있으신가요? 지금 바로 시도해 보세요.

MimicReader는 매월 첫 1시간의 오디오가 무료입니다. 카드 등록 없이. 텍스트든 스캔본이든 PDF를 던져 주세요 — 나머지는 우리가 알아서 하겠습니다.

무료로 시작

그 결과

우리는 독자의 PDF를 재구축된 파이프라인으로 다시 돌렸습니다. 5분간의 OCR이 74페이지의 스캔본에서 144,710자의 깨끗한 스페인어를 뽑아냈습니다. 파이프라인은 그것을 1,127개 세그먼트로 청크 분할하고, 읽기 동기화 기능 — 오디오에 맞춰 단어별 하이라이트 — 까지 포함된 2시간 43분 분량의 오디오북을 만들어냈습니다. 우리는 그녀에게 스페인어로 이메일을 보내고, 첫 시도에 대해 사과했으며, 비용은 우리가 부담했습니다.

전체 재생성에는 실제 시간으로 약 90분이 걸렸습니다. OCR이 약 5분, 텍스트-음성 변환이 80분, 오디오 노멀라이제이션(EBU R128)과 M4A 마무리에 몇 분이 더 들었습니다. 텍스트 PDF보다는 느리지만, 작동합니다. 이전에는 아예 작동하지 않았습니다.

책장에 스캔본이 가득하다면 어떤 의미일까

스캔된 책을 쌓아두고 계셨다면 — 오래된 재인쇄본, 절판된 소설, archive.org에서 받은 퍼블릭 도메인 디지털화본, 할머니의 요리책을 직접 스캔한 것 등 — 더 이상 종이에 갇혀 있을 필요가 없습니다. 업로드하세요. OCR은 우리가 해드립니다.

현재 우리는 12개 언어로 OCR을 지원합니다. 영어, 스페인어, 포르투갈어, 프랑스어, 독일어, 폴란드어, 이탈리아어, 터키어, 아랍어, 일본어, 한국어, 힌디어. 오디오북 자체는 23개 음성 언어 중 어느 것으로도 생성할 수 있습니다. 스캔된 책이 우리가 아직 OCR하지 않는 언어로 되어 있다면, 알려 주세요 — tesseract 언어 팩 추가는 몇 분이면 됩니다.

상용 라이선스에 관한 메모

우리가 사용하는 OCR 스택 전체 — tesseract, pypdfium2, pytesseract — 는 Apache 2.0입니다. 비슷한 것을 만들고 있다면 이 점이 중요합니다. PyMuPDF는 Python에서 PDF 렌더링에 손쉬운 선택지이지만, AGPL 라이선스 때문에 프로덕션에서 사용하면 SaaS 전체를 오픈소스화해야 합니다. pypdfium2 + tesseract는 라이선스 부담 없이 동일한 기능을 제공합니다.

우리를 더 좋게 만든 버그

대부분의 프로덕션 버그는 테스트에서 잡힙니다. 이번 것은 그렇지 않았습니다. "PDF는 텍스트를 담고 있다"라는 가정이 우리가 사용한 모든 개발용 파일에서 성립했기 때문입니다. 칠레의 실제 독자가 플랫폼에 첫 1시간을 보내면서야 비로소 그 가정이 드러났습니다.

그러니 실제 독자분들께 감사드립니다. 여러분은 우리가 찾을 수 없는 버그를 찾아주십니다.