{"id":15651497,"url":"https://github.com/readbeyond/lachesis","last_synced_at":"2025-04-30T19:48:22.220Z","repository":{"id":57447863,"uuid":"77442399","full_name":"readbeyond/lachesis","owner":"readbeyond","description":"lachesis automates the segmentation of a transcript into closed captions","archived":false,"fork":false,"pushed_at":"2017-01-26T21:10:21.000Z","size":152,"stargazers_count":33,"open_issues_count":0,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-30T19:23:11.680Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/readbeyond.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-27T09:13:38.000Z","updated_at":"2025-03-23T13:57:31.000Z","dependencies_parsed_at":"2022-09-26T17:30:32.728Z","dependency_job_id":null,"html_url":"https://github.com/readbeyond/lachesis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/readbeyond%2Flachesis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/readbeyond%2Flachesis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/readbeyond%2Flachesis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/readbeyond%2Flachesis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/readbeyond","download_url":"https://codeload.github.com/readbeyond/lachesis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251774057,"owners_count":21641719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-03T12:38:45.158Z","updated_at":"2025-04-30T19:48:22.197Z","avatar_url":"https://github.com/readbeyond.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lachesis\n\n**lachesis** automates the segmentation of a transcript into closed captions\n\n* Version: 0.0.3\n* Date: 2017-01-26\n* Developed by: [Alberto Pettarin](http://www.albertopettarin.it/)\n* License: the GNU Affero General Public License Version 3 (AGPL v3)\n* Contact: [info@readbeyond.it](mailto:info@readbeyond.it)\n\n**DO NOT USE THIS PACKAGE IN PRODUCTION UNTIL IT REACHES v1.0.0 !!!**\n\n\n## Goal\n\n**lachesis** automates the segmentation\nof a transcript into closed captions (CCs).\n\nThe general idea is that\nwriting a transcription (raw text) is\neasier and faster than writing CCs,\nespecially if you need to respect constraints\nlike a certain minimum/maximum number of characters per line,\na maximum number of lines per CC, etc.\n\nYou can transcribe your video into raw text\nand ``lachesis`` will take on the job of\nsegmenting the text into CCs for you.\nOnce you have the CCs,\nyou can use a [forced aligner](https://github.com/pettarin/forced-alignment-tools/)\nlike [aeneas](https://github.com/readbeyond/aeneas/)\nto align them with the audio of your video,\nobtaining a subtitle file (SRT, TTML, VTT, etc.).\n\nWith ``lachesis`` and a forced aligner,\nthe manual labor for producing CCs for a video\nis reduced to a. transcribing the video in raw text form,\nand b. checking the final CCs and audio alignment.\nInstead of transcribing from scratch,\nyou can even start by checking/editing a rough transcription\nmade by an automated speech recognition engine,\nlike the \"automatic CCs\" from YouTube,\nspeeding the process up further.\n\nThe \"magic\" behind ``lachesis`` consists\nin combining machine learning techniques like\n[conditional random fields](https://en.wikipedia.org/wiki/Conditional_random_field)\n(CRF)\nand classical NLP tools like\n[POS tagging](https://en.wikipedia.org/wiki/Part-of-speech_tagging)\nand\n[sentence segmentation](https://en.wikipedia.org/wiki/Text_segmentation)\nto split the text into CC lines.\nThe machine learning models are learned\nfrom existing, manually-edited, high-quality CCs,\nlike those of\n[TED](https://www.youtube.com/user/TEDtalksDirector)/[TEDx](https://www.youtube.com/user/TEDxTalks)\ntalks on YouTube.\nThe NLP tools come from the well-established,\nfree NLP libraries for Python listed below.\n\nIn summary, ``lachesis`` contains the following major functions:\n\n* download closed captions from YouTube;\n* parse closed caption TTML files (downloaded from YouTube);\n* add POS tags to a given text or closed caption file;\n* segment a given text into sentences;\n* segment a given text into closed captions (several algorithms are available);\n* train and use machine learning models to segment raw text into CC lines.\n\n\n## Installation\n\n**DO NOT USE THIS PACKAGE IN PRODUCTION UNTIL IT REACHES v1.0.0 !!!**\n\n```bash\npip install lachesis\n```\n\n### Installing dependencies\n\nYou might need additional packages,\ndepending on how you plan to use ``lachesis``:\n\n* ``lxml \u003e= 3.6.0`` for reading or downloading TTML files;\n* ``youtube-dl \u003e= 2017.1.16`` for downloading TTML files;\n* ``python-crfsuite \u003e= 0.9.1`` for training and using CRF-based splitters.\n\nBy design choice, none of the above dependencies\nis installed by ``pip install lachesis``.\nIf you want to install them all, you can use:\n\n```bash\npip install lachesis[full]\n```\n\nAlternatively, manually install only the dependencies you need.\n(You can do it before or after installing ``lachesis``,\nthe order does not matter.)\n\n\n### Installing NLP Libraries\n\nIn addition to the dependencies listed above,\nto perform POS tagging and sentence segmentation\n``lachesis`` can use one or more of the following libraries:\n\n* ``Pattern`` (install with ``pip install pattern``, [see here](http://www.clips.ua.ac.be/pattern))\n* ``NLTK`` (install with ``pip install nltk``, [see here](http://www.nltk.org/))\n* ``spaCy`` (install with ``pip install spacy``, [see here](https://spacy.io/))\n* ``UDPipe`` (install with ``pip install ufal.udpipe``, [see here](https://ufal.mff.cuni.cz/))\n\nIf you want to install them all, you can use:\n\n```bash\npip install lachesis[nlp]\n```\n\nor ``[fullnlp]`` if you also want ``[full]`` as above.\n\nEach NLP library also needs language models\nwhich you need to download/install separately.\nConsult the documentation of your NLP library for details.\n\n``lachesis`` expects the following directories in your home directory\n(you can symlink them, if you installed each NLP library in a different place):\n\n* ``~/lachesis_data/nltk_data`` for ``NLTK`` ([see here](http://www.nltk.org/data.html));\n* ``~/lachesis_data/spacy_data`` for ``spaCy`` ([see here](https://spacy.io/docs/usage/));\n* ``~/lachesis_data/udpipe_data`` for ``UDPipe`` ([see here](https://ufal.mff.cuni.cz/udpipe)).\n\nThe NLP library ``Pattern`` does not need a separate download\nof its language models, as they are bundled in the file\nyou download when installing through ``pip install pattern``.\n\nThe following table summarizes the languages supported by each library\nin their standard language models pack.\n(Additional languages might be supported by third party projects/downloads\nor added over time.)\n\n| Language / Library    | Pattern   | NLTK  | spaCy | UDPipe    |\n|-----------------------|-----------|-------|-------|-----------|\n| Arabic                |           |       |       | ✓         |\n| Basque                |           |       |       | ✓         |\n| Bulgarian             |           |       |       | ✓         |\n| Croatian              |           |       |       | ✓         |\n| Czech                 |           | ✓     |       | ✓         |\n| Danish                |           | ✓     |       | ✓         |\n| Dutch                 | ✓         | ✓     |       | ✓         |\n| English               | ✓         | ✓     | ✓     | ✓         |\n| Estonian              |           | ✓     |       | ✓         |\n| Finnish               |           | ✓     |       | ✓         |\n| French                | ✓         | ✓     |       | ✓         |\n| German                | ✓         | ✓     | ✓     | ✓         |\n| Gothic                |           |       |       | ✓         |\n| Greek                 |           | ✓     |       | ✓         |\n| Greek (ancient)       |           |       |       | ✓         |\n| Hebrew                |           |       |       | ✓         |\n| Hindi                 |           |       |       | ✓         |\n| Hungarian             |           |       |       | ✓         |\n| Indonesian            |           |       |       | ✓         |\n| Irish                 |           |       |       | ✓         |\n| Italian               | ✓         | ✓     |       | ✓         |\n| Latin                 |           |       |       | ✓         |\n| Norwegian             |           | ✓     |       | ✓         |\n| Old Church Slavonic   |           |       |       | ✓         |\n| Persian               |           |       |       | ✓         |\n| Polish                |           | ✓     |       | ✓         |\n| Portuguese            |           | ✓     |       | ✓         |\n| Romanian              |           |       |       | ✓         |\n| Slovenian             |           | ✓     |       | ✓         |\n| Spanish               | ✓         | ✓     |       | ✓         |\n| Swedish               |           | ✓     |       | ✓         |\n| Tamil                 |           |       |       | ✓         |\n| Turkish               |           | ✓     |       |           |\n\n\n## Usage\n\n### Download closed captions from YouTube\n\n```python\nfrom lachesis.downloaders import Downloader\nfrom lachesis.language import Language\n\n# set URL of the video and language of the CCs\nurl = u\"http://www.youtube.com/watch?v=NSL_xx2Qnyc\"\nlanguage = Language.ENGLISH\n\n# download automatic CC, do not save to file\noptions = { \"auto\": True }\ndoc = Downloader.download_closed_captions(url, language, options)\nprint(doc)\n\n# download manually-edited CC, saving the raw TTML file to disk\noptions = { \"auto\": False, \"output_file_path\": \"/tmp/ccs.ttml\" }\ndoc = Downloader.download_closed_captions(url, language, options)\nprint(doc)\n```\n\n### Parse an existing TTML file downloaded from YouTube\n\n```python\nfrom lachesis.downloaders import Downloader\n\n# parse a given TTML file downloaded from YouTube\nifp = \"/tmp/ccs.ttml\"\ndoc = Downloader.read_closed_captions(ifp, options={u\"downloader\": u\"youtube\"})\nprint(doc.language)\n\n# print several representations of the CCs\nprint(doc.raw_string)                       # multi line string, similar to SRT but w/o ids or times\nprint(doc.raw_flat_clean_string)            # single line string, w/o CC line marks\nprint(doc.raw.string(flat=True, eol=u\"|\"))  # single line string, CC lines separated by '|' characters\n```\n\n### Tokenize, split sentences, and POS tagging\n\n```python\nfrom lachesis.elements import Document\nfrom lachesis.language import Language\nfrom lachesis.nlpwrappers import NLPEngine\n\n# work on this Unicode string\ns = u\"Hello, World. This is a second sentence, with a comma too! And a third sentence.\"\n\n# but you can also pass a list with pre-split sentences\n# s = [u\"Hello World.\", u\"This is a second sentence.\", u\"Third one, bla bla\"]\n\n# create a Text object from the Unicode string\ndoc = Document(raw=s, language=Language.ENGLISH)\n\n# tokenize, split sentences, and POS tagging\n# the best available NLP library will be chosen\nnlp1 = NLPEngine()\nnlp1.analyze(doc)\n\n# the text has been divided into tokens, grouped in sentences\nfor s in doc.sentences:\n    print(s)                                        # raw\n    print(s.string(tagged=True))                    # tagged\n    print(s.string(raw=True, eol=u\"|\", eos=u\"\"))    # raw w/o CC line and sentence marks\n\n# explicitly specify the NLP library NLTK,\n# other options include: \"pattern\", \"spacy\", \"udpipe\"\nnlp2 = NLPEngine()\nnlp2.analyze(doc, wrapper=u\"nltk\")\n...\n\n# if you need to analyze many documents,\n# preload (and keep in cache) an NLP library,\n# even different ones for different languages\nnlp3 = NLPEngine(preload=[\n    (u\"en\", u\"spacy\"),\n    (u\"de\", u\"nltk\"),\n    (u\"it\", u\"pattern\"),\n    (u\"fr\", u\"udpipe\")\n])\nnlp3.analyze(doc)\n...\n```\n\n### Split into closed captions\n\n```python\nfrom lachesis.elements import Document\nfrom lachesis.language import Language\nfrom lachesis.nlpwrappers import NLPEngine\nfrom lachesis.splitters import CRFSplitter\nfrom lachesis.splitters import GreedySplitter\n\n# create a document from a raw string\ns = u\"Hello, World. This is a second sentence, with a comma too! And a third sentence.\"\ndoc = Document(raw=s, language=Language.ENGLISH)\n\n# analyze it using the NLP library Pattern\nnlpe = NLPEngine()\nnlpe.analyze(doc, wrapper=u\"pattern\")\n\n# feed the document into the CRF splitter (max 42 chars/line, max 2 lines/cc)\nspl = CRFSplitter(doc.language, 42, 2)\nspl.split(doc)\n\n# print the segmented CCs\nfor cc in doc.ccs:\n    for line in cc.elements:\n        print(line)\n    print(u\"\")\n\n# the default location for CRF model files is ~/lachesis_data/crf_data/\n# but you can also specify a different path\nspl = CRFSplitter(doc.language, 42, 2, model_file_path=\"/tmp/yourmodel.crfsuite\")\nspl.split(doc)\n\n# if you do not have pycrfsuite installed\n# or the CRF model file for the document language,\n# you can use the GreedySplitter\ngs = GreedySplitter(doc.language, 42, 2)\ngs.split(doc)\n\n```\n\n### Train a CRF model to segment raw text into CC lines\n\n```bash\n$ # /tmp/ccs/train contains several TTML files to learn from\n$ # you can download them from YouTube using lachesis (see above)\n$ ls /tmp/ccs/train\n0001.ttml\n0002.ttml\n...\n\n$ # extract features and labels from them:\n$ python -m lachesis.ml.crf dump eng /tmp/ccs/train/ /tmp/ccs/train.pickle\n...\n\n$ # train the CRF model:\n$ python -m lachesis.ml.crf train eng /tmp/ccs/train.pickle /tmp/ccs/model.crfsuite\n...\n\n$ # evaluate the model on the training set\n$ python -m lachesis.ml.crf test eng /tmp/ccs/train.pickle /tmp/ccs/model.crfsuite\n...\n\n$ # you might want to evaluate on a test set, disjoint from the training set,\n$ # that is, the test set contains CCs not seen during the training:\n$ ls /tmp/css/test\n1001.ttml\n1002.ttml\n...\n$ python -m lachesis.ml.crf dump eng /tmp/ccs/test/ /tmp/ccs/test.pickle\n$ python -m lachesis.ml.crf test eng /tmp/ccs/test.pickle /tmp/ccs/model.crfsuite\n...\n$ # now you can build a CRFSplitter\n$ # with model_file_path=\"/tmp/ccs/model.crfsuite\" as shown above\n\n```\n\nTODO: decide and document where pre-trained model files can be downloaded\n\n\n## License\n\n**lachesis** is released under the terms of the\nGNU Affero General Public License Version 3.\nSee the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freadbeyond%2Flachesis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freadbeyond%2Flachesis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freadbeyond%2Flachesis/lists"}