Pięć sekund ciszy
Czytelniczka z Chile założyła konto, wgrała 74-stronicowy PDF z powieścią dla dzieci — "¿Quién le tiene miedo a Demetrio Latov?" autorstwa Angeles Durini — i kliknęła Wygeneruj audiobook. Piętnaście sekund później pojawił się mail: "Twój audiobook jest gotowy."
Nie był. Plik trwał 5,6 sekundy. Nie zawierał niczego.
To rodzaj błędu, który łapie się dopiero na produkcji, bo testowe PDF-y, których używaliśmy, miały osadzony tekst. Jej PDF nie miał. Książka została zeskanowana, strona po stronie, w 2012 roku za pomocą Adobe Acrobat Pro — i każda strona była zapisana jako obraz. Dla naszego pipeline'u PDF był 74 pustymi stronami.
Dlaczego skanowane PDF-y psują pipeline'y audiobooków
PDF może przechowywać tekst na dwa zupełnie różne sposoby:
- Tekstowe PDF-y — słowa są zapisane jako rzeczywiste znaki z czcionką i pozycją. Każda biblioteka (pypdf, pdfminer, pypdfium2) potrafi je wyciągnąć w milisekundach.
- Obrazkowe PDF-y (skany) — strony to obrazy JPEG lub TIFF osadzone wewnątrz opakowania PDF. Dla biblioteki do ekstrakcji tekstu te strony zawierają zero znaków.
Wszystko, co pochodzi ze skanera płaskiego, aparatu w telefonie albo starego projektu digitalizacyjnego (Google Books, archive.org, reedycje z domeny publicznej, używane książki dla dzieci) zwykle należy do drugiego rodzaju. Dla ludzkiego oka wyglądają identycznie. Dla oprogramowania są radykalnie różne.
Gdy zbadaliśmy nieudane wgranie, nasz parser PDF zwrócił dokładnie 17 znaków śmieci — bajty kontrolne, nie litery — dla całej 74-stronicowej książki. Pipeline posłusznie podał te 17 bajtów do silnika TTS i wyprodukował 5 sekund wymamrotanego dźwięku. A potem wysłał czytelniczce mail z informacją, że jej audiobook jest gotowy.
Co zbudowaliśmy
Poprawka jest koncepcyjnie prosta: wykryj, gdy PDF nie ma użytecznego tekstu, a potem zrób OCR każdej strony. Implementacja ma kilka elementów wartych opisania.
1. Detektor rzadkiego tekstu
Zanim rzucimy się do OCR przy każdym wgraniu, sprawdzamy wynik natywnej ekstrakcji. Jeśli cały PDF zwrócił mniej niż 200 znaków, albo średnia jest mniejsza niż 30 znaków na stronę na 4+ stronach, traktujemy go jako skan i przechodzimy do OCR. Normalne tekstowe PDF-y — ponad 90% przypadków — nigdy nie uruchamiają wolnej ścieżki.
2. pypdfium2 + tesseract (Apache 2.0 na całej linii)
Renderujemy każdą stronę za pomocą pypdfium2 (pythonowy wrapper wokół silnika PDFium od Google, Apache 2.0) w skali 2,5× — około 180 DPI, co wystarcza do niezawodnego rozpoznawania znaków. Każdy obraz przechodzi przez tesseract z załadowanym modelem wielojęzycznym: eng+spa+por+fra+deu+pol+ita+tur. Tesseract sam rozpoznaje rzeczywisty język po kształcie glifów.
Celowo zrezygnowaliśmy z PyMuPDF — najpopularniejszej pythonowej biblioteki PDF — bo jej licencja AGPL jest niewygodna dla usługi hostowanej. Przesiadka na pypdfium2 zajęła popołudnie i całkowicie usunęła klif prawny. Warto wiedzieć, jeśli budujesz cokolwiek związanego z PDF-ami dla komercyjnego produktu.
3. Automatyczne wykrywanie języka
Książka czytelniczki była po hiszpańsku, ale lokalizacja jej interfejsu to angielski — więc przed naszą poprawką, nawet gdyby OCR zadziałał, pipeline zsyntetyzowałby hiszpański tekst angielskim głosem (robotycznie, z błędną wymową). Teraz samo wykrywanie języka korzysta z tekstu po OCR. Po 3 próbkach stron langdetect klasyfikuje treść i wybiera właściwy głos — w tym przypadku hiszpański latynoamerykański.
4. Uczciwa ścieżka błędu
Jeśli OCR nadal odzyska mniej niż 100 znaków (PDF-y czysto dekoracyjne, zepsute pliki), teraz rzucamy jasny błąd zamiast generować ciszę: "Ten PDF nie ma tekstu możliwego do wyodrębnienia. Wgraj proszę EPUB, TXT albo tekstowy PDF." Zadanie audiobooka jest oznaczane jako nieudane, mail się nie wysyła, kredyty nie są pobierane.
Masz skanowany PDF? Spróbuj teraz.
MimicReader jest darmowy przez pierwszą godzinę audio każdego miesiąca. Bez karty. Wrzuć dowolny PDF — tekstowy lub skanowany — a my zajmiemy się resztą.
Zacznij za darmoWynik
Puściliśmy ponownie PDF czytelniczki przez przebudowany pipeline. Pięć minut OCR wyciągnęło 144 710 znaków czystego hiszpańskiego z jej 74 zeskanowanych stron. Pipeline podzielił je na 1 127 segmentów i wyprodukował audiobook na 2 godziny 43 minuty z synchronizacją read-along — podświetleniami słowo po słowie powiązanymi z dźwiękiem. Napisaliśmy do niej maila po hiszpańsku, na nasz koszt, i przeprosiliśmy za pierwszą próbę.
Cała regeneracja zajęła około 90 minut czasu rzeczywistego: mniej więcej 5 minut na OCR, 80 minut na syntezę mowy, kilka minut na normalizację dźwięku (EBU R128) i finalizację M4A. To wolniej niż tekstowy PDF — ale działa. Wcześniej nie działało w ogóle.
Co to znaczy, jeśli masz półkę pełną skanów
Jeśli gromadziłeś skanowane książki — stare reedycje, powieści, których nie ma już w druku, digitalizacje z domeny publicznej z archive.org, własne skany książki kucharskiej babci — nie utknęły już na papierze. Wgraj je. My zrobimy OCR.
Obecnie robimy OCR w 12 językach: angielski, hiszpański, portugalski, francuski, niemiecki, polski, włoski, turecki, arabski, japoński, koreański, hindi. Sam audiobook można wygenerować w dowolnym z 23 języków głosu. Jeśli twoja skanowana książka jest w języku, którego jeszcze nie obsługujemy w OCR, napisz do nas — dodanie paczki językowej tesseract zajmuje kilka minut.
Słowo o licencjonowaniu komercyjnym
Cały stos OCR, którego używamy — tesseract, pypdfium2, pytesseract — jest na Apache 2.0. To ma znaczenie, jeśli budujesz coś podobnego: PyMuPDF jest łatwym wyborem do renderowania PDF w Pythonie, ale jego licencja AGPL wymaga, byś otworzył kod całego swojego SaaS-a, jeśli używasz go na produkcji. pypdfium2 + tesseract daje te same możliwości bez prawnego kaca.
Błąd, który nas ulepszył
Większość bugów produkcyjnych łapie się w testach. Tego nie złapaliśmy, bo założenie — "PDF-y zawierają tekst" — sprawdzało się dla każdego dev pliku, jakiego kiedykolwiek używaliśmy. Trzeba było prawdziwej czytelniczki z Chile, w jej pierwszej godzinie na platformie, by to wyszło.
Także dzięki, prawdziwi czytelnicy. Znajdujecie bugi, których my nie potrafimy.