py-BookBundler: un’API per il bundling tra cartaceo e digitale

TL; DR: Ho sviluppato (e pubblicato in opensource) il prototipo di una webapp che permette a un editore di offrire una copia dell’ebook a chi possiede una copia del libro di carta. Esistono già approcci che tentano di risolvere la questione, alcuni efficaci e alcuni meno; io ho pensato che si potesse provare un sistema più semplice, ad esempio chiedere all’utente di fare una foto a una pagina specifica del libro, che viene analizzata dal server per verificare che si tratti effettivamente della pagina richiesta. py-BookBundler è un’applicazione che fa questo, e lo fa funzionando come API REST.

Really, TL; DR: Guarda, qui c’è un gattino buffissimo!

Premessa: ancora sul bundling

Come spesso accade, alcuni argomenti “caldi” dell’editoria digitale tornano inaspettatamente d’attualità quando meno te lo aspetteresti. È il caso del bundling tra libro cartaceo e libro digitale, di cui nell’ultimo mese si è parlato diffusamente (ne ho parlato io, qui e qui, ma soprattutto se n’è parlato sul blog di Marco Dominici e su Finzioni (dai quali sono stato definito un “blogger”: speravo che avessero un’opinione un po’ migliore del sottoscritto).

L’opinione diffusa è sintetizzabile con «ma sai che è proprio una buona idea? bisognerebbe proprio cominciare a farlo!». Manco a dirlo, la settimana scorsa Amazon ha annunciato l’iniziativa MatchBook, accolta col consueto miscuglio di entusiasmo e catastrofismo (è un riflesso condizionato del publishing, ormai; mi chiedo quanto ci faccia bene questo atteggiamento di polarizzazione tra entusiasmo-a-tutti-i-costi e dio-mio-vogliono-uccidere-il-libro-bisogna-fermarli). Credo che sul punto dell’iniziativa non ci sia molto da dire, mi sono espresso più volte in favore di tale abbinamento e il meccanismo di Amazon è esattamente quello che proponevo come soluzione ottima: la libreria tiene traccia degli acquirenti del cartaceo e gli propone l’ebook a prezzo scontato. La teoria è già stata sviscerata meglio di me da altri, e tutti siamo in condizione di formarci un’opinione sulla materia (i più spericolati potrebbero addirittura ricredersi e – con rispetto parlando – cambiare idea; don’t try this at home, kids).

L’aspetto che più mi intriga della questione oltre alle chiacchiere, quindi, non è il se, bensì il come. Lavorando per e/o avevo sperimentato un sistema di redeem a coupon, un codice promozionale stampato su un cartoncino, da inserire sul nostro sito e scaricare una sola volta una copia dell’ebook corrispondente. Un’altra possibilità l’hanno sperimentata in Utet, proponendo come “chiave” due o tre parole pescate da coordinate specifiche di una pagina del cartaceo. Sistema già più intelligente. Mi sono però chiesto se fosse possibile e praticabile un modo più semplice per l’utente, che al contempo garantisse all’editore un ragionevole margine di sicurezza che un libro cartaceo fosse realmente nelle mani dell’utente. Sfogliando i feed ho letto di un editore americano che stava spedendo l’ebook ai lettori che inviassero per posta elettronica una foto del libro. Ecco, mi son detto, questa è una buona idea: una foto del libro uguale un ebook; ma non posso accettare una foto qualsiasi, voglio poterti chiedere una pagina specifica del libro; e già che ci siamo non voglio controllare a mano se la foto che mi hai allegato è una foto del libro per cui mi chiedi l’ebook. py-BookBundler fa proprio questo.

Un’ipotesi di lavoro: tecnicalità

L’applicazione è sviluppata in Pyhton sul framework Flask, un web application framework veramente minimale, che stavo valutando per progetti Jython e che offre un ottimo punto di partenza per implementare velocemente delle API di tipo REST. Poiché uno dei possibili sistemi per accedere al sistema potrebbe essere un’applicazione per smartphone, oppure un’integrazione col sito web di un editore, il paradigma REST offre una buona flessibilità nell’approccio al problema.

L’operatore inserisce il “riferimento” della pubblicazione, cioè il target che l’utente deve “matchare” con la sua foto al libro. Si tratta naturalmente della pagina prescelta tratta dal libro. È possibile caricare un file di testo che rappresenta – linea per linea – la pagina (con isbn e numero di pagina come intestazioni), attraverso una piccola utility da eseguire in CLI, oppure caricare un’immagine della pagina e lasciare che venga passata all’OCR. L’operatore si suppone autenticato: nel codice di app.py uso HTTP Basic, ma con l’approccio AOP con decoratori di Python è semplice implementare un protocollo diverso, ad esempio Digest o OAuth. Il contenuto della pagina, insieme a identificatore e numero di pagina a cui fa riferimento, viene poi inserito in un database (nel caso specifico si tratta di mongo, il più famoso dei NoSQL). L’utente finale può sfogliare il catalogo delle risorse disponibili e accedere a una pagina che propone di caricare una foto della pagina obiettivo tratta dal libro in suo possesso. La foto della pagina viene elaborata sul server da tesseract-ocr, un OCR opensource attualmente sviluppato da Google, che avevo sperimentato tempo fa per alcuni esperimenti di conversione epub da fonti TIFF. I risultati furono inaspettatamente buoni, anche se non perfetti. Proprio perché è difficile che una fotografia di una pagina corrisponda perfettamente col contenuto immesso dall’operatore, il sistema analizza i risultati e procede a un confronto di prossimità riga per riga, usando il modulo difflib della libreria standard di Python. Se i testi raggiungono un sufficiente livello di somiglianza (impostabile, in percentuale, a piacere tramite un parametro), viene restituito un esito positivo.

Il codice è commentato come meglio ho potuto, ed è – com’è noto – la documentazione più precisa e aggiornata.

Caveat e cose da fare

L’applicazione è una bozza, pur funzionante anche se priva di tesseract-ocr, che dovete installare a parte (ci sono pacchetti per tutte le distribuzioni Linux, per OSX va compilato dai sorgenti), e passibile di molti miglioramenti. Andrebbe ad esempio wrappata in un container wsgi adatto (non il server HTTP di base compreso in flask.app).

Allo stato attuale l’applicazione espone endpoint pubblici, tranne la creazione della risorsa. Un’applicazione reale dovrebbe almeno chiedere all’utente di registrarsi, magari con un login via Twitter, per cui esiste un modulo OAuth (in Flask non è comodo come con Tornado), e tenere così traccia dell’uso e dei download.

Nella bozza che ho pubblicato viene restituito un semplice template success/fail a seguito della richiesta di match, e non viene offerto un link per scaricare alcun ebook (l’implementazione dipende ovviamente da molti fattori); idealmente, un responso positivo dovrebbe generare un token monouso attraverso cui autorizzare la richiesta di download della risorsa, trasmesso ad esempio attraverso un X-Header HTTP. Oppure, più semplicemente, spedire il link o la risorsa stessa a un indirizzo email. Se la risorsa è un epub, si potrebbe aggiungere un watermark (nell’ultima release di py-clave c’è una feature che fa proprio questo).

Il processo di OCR viene gestito durante la richiesta POST, può richiedere dai 7 ai 12 secondi per essere completato ed è piuttosto pesante computazionalmente. Idealmente, il task dovrebbe essere delegato a un’altra applicazione attraverso una job queue e restituire il risultato all’utente in modo asincrono. Esistono inoltre OCR proprietari molto più efficienti di tesseract.

Conclusioni

Py-BookBundler è da considerarsi come un proof of concept, l’illustrazione di un’ipotesi di lavoro secondo me non sufficientemente esplorata, almeno in Italia. Come raccontavo a Ivan in un’intervista su Apogeo:

[…] quello che mi sta davvero a cuore è riportare al centro del dibattito il tema della tecnologia al servizio della funzione editoriale, stimolando proposte e offrendo una base di partenza concreta su cui poter lavorare e reagire alla stagnazione che sta vivendo l’evoluzione dell’editoria digitale.

Anche questo progetto è pubblicato sotto licenza MIT, che garantisce la massima libertà nella modifica e nell’uso del codice. Commenti, feedback, critiche e contributi sono vivamente incoraggiati.

 

Gabriele

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>