Package: obgp
Welcome to the Open Book Genome Project (OBGP) Sequencer™, an open-source Book Processing Pipeline of responsibly vetted community "modules" which classify, sequence, and fingerprint book fulltext to reveal public insights about Books.QuickstartWant to get started immediately?Try theOBGP Sequencer™ Google Colab Notebook:How it WorksEach month, the OBGP Sequencer™ gets run against the fulltext of more than 1M books, generating valuable public insights for book lovers and researchers around the globe. OBGP Sequencer™ consists of carefully vetted community-contributedmoduleswhich aim to responsiblyhelp increase the discoverability and usefulness of books, e.g.:Identifying urls, isbns, and citations within the textGenerating word frequency mappingsGuessing grade reading levelsWho we areOBGP is an independent, community-run, not-for-profit committee of open-source and book enthusiasts who want to responsibly further the effort of making books as useful and accessible as possible.InstallationProductionIf you want to run the OBGP Sequencer™ pipeline, run:pip install obgpLocal Developmentgit clone https://github.com/Open-Book-Genome-Project/sequencer.git  # get the code
virtualenv venv && source venv/bin/activate  # setup a virtual environment
cd sequencer  # change into project directory
pip install -e .  # install the library (and re-run in project root as you make changes)Docker UsageFirst, create a directory calledobgp_dirif it doesn't already exist.mkdir -p obgp_dirNext, while in the sequencer directory, run:export OBGP_S3=~/.config/ia.ini OBGP_DIR=./obgp_dir;docker-compose upUsedocker container lsto get container ID.
Thendocker exec -it obgp /bin/shreplacing the container ID with the actual IDYou should now be in the container shell and can execute commands!UsageOnce you've install either the production code or build your developer code, you may proceed to start python and import therunner.pipelinewith whatever modules you'd like.Let's say you want to process the bookhttps://archive.org/details/hpmorwhich has identifierhpmoron Archive.org. First, you would define your Sequencer as follows:frombgpimportSequencer,STOP_WORDSfrombgp.modules.termsimportNGramProcessor,WordFreqModules=Sequencer({'words':NGramProcessor(modules={'term_freq':WordFreqModule()},n=1,stop_words=STOP_WORDS)})Then, you would pass this book identifier into the Sequencer to sequence the book to get back a genome Sequence object:genome=s.sequence('hpmor')genome.resultsSaving & Uploading ResultsIf yourinternetarchivetool is configured against an account with sufficient permissions, you can then upload your genome results back to an Archive.org item (we'll arbitrarily pick the identifierbgp) by running:>>> genome.write_results_to_item('bgp')This will upload thegenome.resultsas json to <book_identifier>_results.json (e.g.hpmor_results.json) unless otherwise specified by overriding params.You will then be able to see your filehpmor_results.jsonwithin thebgpitem's file downloads:https://archive.org/download/bgpIf you want to run a default test to make sure everything works, try:frombgpimportDEFAULT_SEQUENCERgenome=DEFAULT_SEQUENCER.sequence('9780262517638OpenAccess')genome.resultsUsing pipeline.pyThis pipeline allows a user to sequence a list of books from a jsonl in the following format:{"identifier": "samplebook"}
{"identifier": "9780262517638OpenAccess"}The pipeline then automatically chooses the most probable isbn for the book and attempts to update ia metadata accordingly while keeping a filesystem based database of all these actions.RecordFilesystem ActionHow do we determine which books we've successfully uploaded a genomeTouchesGENOME_UPDATED_{identifier}How do we determine the ISBNs of all books we’ve sequenced so farTouchesISBN_1234567890_{identifier}How do we determine which books were sequenced but had no ISBNTouchesUPDATE_NONE_{identifier}How do we know which books attempted updating but failedUPDATE_FAILED_{identifier}How do we know which books succeeded at updating and succeedUPDATE_SUCCEED_{identifier}How do we know if item already has isbn metadata and is skippedUPDATE_CONFLICT_{identifier}How do we know how many new urls were found in a bookURLS_{number_of_urls}_{identifier}The user can can grep and pipe to wc -l which tells them how many for each status and lists those itemsExample UsageHere is a archive item with the identifiersamplebook. It has an isbn in the text of the book but no isbn metadata.There is a jsonl file with the items to be sequenced listed on new lines.{"identifier": "samplebook"}
{"identifier": "9780262517638OpenAccess"}To use the pipeline, runpython pipeline.py samplebook.jsonlYou can specify the amount of pipeline processes to run concurrently with--p {number of processes}as a parameter. For example:python pipeline.py --p 4 samplebook.jsonlIf wetree results/bgp_resultsnow we get:results/bgp_results
├── 9780262517638OpenAccess
│   ├── ISBN_9780262517638_9780262517638OpenAccess
│   ├── UPDATE_CONFLICT_9780262517638OpenAccess
│   ├── URLS_290_9780262517638OpenAccess
│   └── book_genome.json
└── samplebook
    ├── ISBN_0787959529_samplebook
    ├── UPDATE_SUCCEED_samplebook
    ├── URLS_0_samplebook
    └── book_genome.json

2 directories, 8 filesIf we check the metadata for the book on archive.org again we can see that the isbn field has been updated.There is also a file generated namedURLS_0_samplebookwhich indicates that 0 non 'archive.org' were extracted.In the case of another item like9780262517638OpenAccess, the filename indicates that 290 new urls were extracted. If we look at the contents of that file we will see all the unique urls extracted separated by newlines.http://blogs.law.harvard.edu/pamphlet/2009/05/29/what-percentage
http://www.sherpa.ac.uk/romeo
http://www.library.yale.edu/~llicense/listarchives/0405/msg00038
http://dash.harvard.edu/bitstream/handle/l/4552050/suber_nofee
http://dx.doi.org/10.1371/journal.pone.0013636
http://doctorrw.blogspot.com/2007/05/tabloid-based-medicine
... etc.The9780262517638OpenAccessdirectory also shows that a url was extracted with theISBN_9780262517638_9780262517638OpenAccessrecord, but was the ia item was not updated because a isbn already existed with theUPDATE_CONFLICT_9780262517638OpenAccessContributing a ModulePleaseread the whitepaperand look through our community list ofproposed or requested modulesPropose a "module"by creating a github issueGet the code: Fork this git repository and clone it to your workspace. Create a new branch for your module (named after its corresponding github issue number and title: e.g.git checkout -b 12/module/find-isbns). InstallCreate a new moduleto themodules/directoryTest your module locally usingInternet Archive's unrestricted collection of ~800k booksopen a Pull Requestso your contribution may be reviewed.Technical OverviewBook Genome Project extends/overloads @jjjake'sinternetarchivetool (invisibly using bad practices) in bgp/init.py with functions to fetch xml / plaintext (in a smart, memoized way)Programmer builds a Sequencer (which is a list) of Sequences (a Sequence essentially does 1-pass on the data). Currently, the only sequences we have are 1gram and 2gram and these could be done in a single pass.Each Sequence specified a list of modules to get run as it stepsThe result is the top-level Sequencer can print out its.resultsas a dictSequencers, Processors & ModulesASequencertells the Book Genome Project what tasks should be run and what results should be derived when processing a book's genome.When a OGBP Sequencer is defined, it is loaded with a list of Processors, and these Processors with Modules.A Processor is an abstraction which is responsible for fetching a specific representation of a Book (e.g. plaintext, xml, abbyy), splitting it into predefined logical units (e.g. characters, words, sentences, paragraphs, pages, chapters, entire text), stepping over each of these logical units, and sending them to it's registered Modules.One example hypothetrical Processor might be calledXMLSentenceProcessor. This Processor may be responsible for fetching (i.e. downloading) a Book in XML format with word-level markup. Therun()method of the Processor's interface might parse and split the structured XML data into sentences, iterate through each sentence, and forward them to each of its registered Modules for processing. This hypotheticalSentenceProcessormight be loaded with several Modules, such as aTotalSentenceCountModuleand anSentenceWordCountStatsModulewhich, respectively, keeps track of the total number of sentences within the book and calculates the average number of words per sentence, etc.In many cases a developer may find that the package's out-of-the-boxbgp.DEFAULT_SEQUENCERis a great place to start, either as a Sequencer to run or a good example for extending.Genome SchemaThis is the reference schema used in genome json files:{"metadata":{"identifier":"(ia identifier)","version":"(commit)","timestamp":"r(Unix Epoch)","sequence_time":"r(sequence process seconds)","source":{"txt":{"time":"r(txt download seconds)","bytes":"r(txt bytes)"},"xml":{"time":"r(xml download seconds)","bytes":"r(xml bytes)"}},"processors":{"1gram":{"tokenization_time":"r(1gram tokenization process seconds)","total_tokens":"r(1gram count)","total_time":"r(1gram processor process seconds)","modules":{"urls":{"time":"r(url process seconds)"},"1grams":{"time":"r(1gram frequency process seconds)"}}},"2gram":{"tokenization_time":"r(2gram tokenization process seconds)","total_tokens":"r(2gram count)","total_time":"r(2gram processor process seconds)","modules":{"2grams":{"time":"r(2gram frequency process seconds)"}}},"fulltext":{"total_time":"r(fulltext processor process seconds)","modules":{"readinglevel":{"time":"r(reading level process seconds)"}}},"pagetypes":{"total_time":"r(pagetype processor process seconds)","modules":{"copyright_page":{"time":"r(copyright page process seconds)"},"backpage_isbn":{"time":"r(copyright page process seconds)"}}}}},"urls":["(url)"],"1grams":[["(1gram)","r(1gram frequency)"]],"2grams":[["(2gram)","r(2gram frequency)"]],"readinglevel":{"readability":{"flesch_kincaid_score":"r(flesch kincaid score)","smog_score":"r(smog score)"},"lexile":{"min_age":"(Lower age in range)","max_age":"(Upper age in range)"}},"copyright_page":[{"page":"(copyright page)","isbns":["(isbn)"]}],"backpage_isbn":["(isbn)"]}Public Testing Data setsHere's a corpus of ~800k Archive.org item identifiers of public domain books (of varying quality/appearance/language) which may be used for testing your module:https://archive.org/download/869k-public-domain-book-urls-dataset/2017-12-26_public-domain-books-dataset_800k-identifiers.csv(~19mb)Questions?Pleaseopen an issueandrequest a slack invite