From fb9a518360d796dcf6450c936b38dc768e5fb5f8 Mon Sep 17 00:00:00 2001 From: baxtree Date: Mon, 27 Jan 2025 09:54:53 +0000 Subject: [PATCH 1/2] use pyproject toml and support TF 2.15 --- .github/workflows/ci-pipeline.yml | 14 ++- Pipfile | 97 ----------------- README.md | 7 +- pyproject.toml | 168 +++++++++++++++++++++++++++++- requirements-arm64.txt | 60 ----------- requirements-dev.txt | 18 ---- requirements-llm.txt | 5 - requirements-site.txt | 2 - requirements-stretch.txt | 2 - requirements.txt | 60 ----------- setup.py | 124 ---------------------- site/source/usage.rst | 7 +- subaligner/_version.py | 5 +- subaligner/llm.py | 5 + subaligner/translator.py | 39 ++++++- 15 files changed, 225 insertions(+), 388 deletions(-) delete mode 100644 Pipfile delete mode 100644 requirements-arm64.txt delete mode 100644 requirements-dev.txt delete mode 100644 requirements-llm.txt delete mode 100644 requirements-site.txt delete mode 100644 requirements-stretch.txt delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2c8b464..a135c20 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -28,19 +28,17 @@ jobs: sudo apt-get -y install espeak libespeak1 libespeak-dev espeak-data sudo apt-get -y install libsndfile-dev python -m pip install --upgrade pip - python -m pip install --upgrade setuptools wheel - cat requirements.txt | xargs -L 1 pip install - cat requirements-stretch.txt | xargs -L 1 pip install - cat requirements-llm.txt | xargs -L 1 pip install - cat requirements-dev.txt | xargs -L 1 pip install - cat requirements-site.txt | xargs -L 1 pip install - pip install -e . --ignore-installed + pip install -e . + pip install -e ".[stretch]" + pip install -e ".[llm]" + pip install -e ".[dev]" + pip install -e ".[site]" - name: Type checking run: | python -m mypy --follow-imports=normal subaligner - name: Linting run: | - pycodestyle subaligner tests examples misc bin/subaligner bin/subaligner_1pass bin/subaligner_2pass bin/subaligner_batch bin/subaligner_convert bin/subaligner_train bin/subaligner_tune setup.py --ignore=E203,E501,W503 --exclude="subaligner/lib" + pycodestyle subaligner tests examples misc bin/subaligner bin/subaligner_1pass bin/subaligner_2pass bin/subaligner_batch bin/subaligner_convert bin/subaligner_train bin/subaligner_tune setup.py --ignore=E203,E501,E902,W503 --exclude="subaligner/lib" - name: Linting docstring run: | darglint -v 2 subaligner diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 9bff21d..0000000 --- a/Pipfile +++ /dev/null @@ -1,97 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -mock = "==2.0.0" -coverage = "==4.5.1" -tox = "~=3.23.0" -pycodestyle = "==2.5.0" -twine = ">=3.1.1" -snakeviz = "==2.1.0" -line-profiler = "==3.0.2" -scikit-build = "==0.11.1" -radish-bdd = "~=0.13.3" -pex = "<=2.1.80" -mypy = "==0.790" -parameterized = "==0.8.1" -pylint = "~=2.17.2" -pygments = "~=2.7.4" -sphinx = "==3.3.1" -sphinx-rtd-theme = "==0.5.0" -typing-extensions = "==4.5.0" - -[packages] -astor = "==0.7.1" -astroid = "~=2.5.6" -beautifulsoup4 = "<4.9.0" -bleach = "==3.3.0" -cachetools = "==3.1.1" -captionstransformer = "~=1.2.1" -certifi = "==2023.7.22" -chardet = "~=3.0.4" -cloudpickle = "==0.5.3" -cycler = "==0.10.0" -decorator = "==4.3.0" -distributed = "==2021.10.0" -filelock = "<4.0.0" -google-pasta = "~=0.2" -graphviz = "==0.8.3" -HeapDict = "==1.0.0" -h5py = "<4.0.0" -html5lib = "==1.0b9" -hyperopt = "==0.2.4" -idna = "==2.8" -isort = "==4.3.4" -joblib = ">=1.2.0" -Keras-Applications = ">=1.0.8" -Keras-Preprocessing = ">=1.0.9" -le-pycaption = "==2.2.0a1" -librosa = "<0.10.0" -locket = "==0.2.0" -Markdown = "==2.6.11" -mccabe = "==0.6.1" -numba = ">=0.50.0" -numpy = "<1.24.0" -oauthlib = "==3.1.0" -openai-whisper = "==20240930" -pbr = "==4.0.2" -pkgconfig = "~=1.5.5" -pluggy = "==0.13.1" -pyasn1 = "==0.4.8" -pyasn1-modules = "==0.2.7" -pybind11 = "~=2.11.1" -pycountry = "~=20.7.3" -pydot = "==1.2.4" -pydot-ng = "==1.0.0" -pydotplus = "==2.0.2" -pylint = "==2.5.0" -pyparsing = "==2.2.0" -pyprof2calltree = "==1.4.3" -pysrt = "==1.1.1" -pysubs2 = "<=1.4.2" -python-dateutil = "==2.7.2" -pytz = "==2018.4" -PyYAML = ">=4.2b1" -rsa = "==4.7" -scipy = "<1.11.0" -scikit-learn = ">=0.19.1" -sentencepiece = "~=0.1.95" -setuptools = "<65.0.0" -six = "~=1.15.0" -tensorflow = ">=1.15.5,<2.12" -termcolor = "==1.1.0" -toml = "==0.10.0" -toolz = "==0.9.0" -torch = "<2.3.0" -torchaudio = "<2.3.0" -transformers = "<4.27.0" -urllib3 = "~=1.26.5" -wrapt = "==1.14.0" -Werkzeug = ">=0.15.3" -zict = "==0.1.3" -aeneas = "==1.7.3.0" - -[requires] -python_version = "3.8" diff --git a/README.md b/README.md index c60856e..ea0b01d 100644 --- a/README.md +++ b/README.md @@ -131,9 +131,10 @@ $ subaligner --languages $ subaligner -m single -v video.mp4 -s subtitle.srt -t src,tgt $ subaligner -m dual -v video.mp4 -s subtitle.srt -t src,tgt $ subaligner -m script -v test.mp4 -s subtitle.txt -o subtitle_aligned.srt -t src,tgt -$ subaligner -m dual -v video.mp4 -tr helsinki-nlp -o subtitle_aligned.srt -t src,tgt -$ subaligner -m dual -v video.mp4 -tr facebook-mbart -tf large -o subtitle_aligned.srt -t src,tgt -$ subaligner -m dual -v video.mp4 -tr whisper -tf small -o subtitle_aligned.srt -t src,eng +$ subaligner -m dual -v video.mp4 -s subtitle.srt -tr helsinki-nlp -o subtitle_aligned.srt -t src,tgt +$ subaligner -m dual -v video.mp4 -s subtitle.srt -tr facebook-mbart -tf large -o subtitle_aligned.srt -t src,tgt +$ subaligner -m dual -v video.mp4 -s subtitle.srt -tr facebook-m2m100 -tf small -o subtitle_aligned.srt -t src,tgt +$ subaligner -m dual -v video.mp4 -s subtitle.srt -tr whisper -tf small -o subtitle_aligned.srt -t src,eng ``` ``` # Transcribe audiovisual files and generate translated subtitles diff --git a/pyproject.toml b/pyproject.toml index c0f3762..74923e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,169 @@ [build-system] -requires = ["setuptools<65.0.0", "wheel", "Cython"] +requires = ["setuptools<65.0.0", "setuptools-scm", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "subaligner" +version = "0.3.9" +authors = [ + { name = "Xi Bai", email = "xi.bai.ed@gmail.com" } +] +description = "Automatically synchronize and translate subtitles, or create new ones by transcribing, using pre-trained DNNs, Forced Alignments and Transformers." +readme = { file = "README.md", content-type = "text/markdown" } +urls = { "Homepage" = "https://github.com/baxtree/subaligner", "Documentation" = "https://subaligner.readthedocs.io/en/latest/", "Source" = "https://github.com/baxtree/subaligner" } +classifiers = [ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Intended Audience :: Developers", + "Topic :: Utilities" +] +dependencies = [ + "astor==0.7.1", + "beautifulsoup4<4.9.0", + "bleach==3.3.0", + "cachetools==3.1.1", + "captionstransformer~=1.2.1", + "certifi==2023.7.22", + "chardet~=3.0.4", + "cloudpickle~=1.6.0", + "cycler==0.10.0", + "decorator==4.3.0", + "distributed==2021.10.0", + "filelock<4.0.0", + "google-pasta~=0.2", + "graphviz==0.8.3", + "HeapDict==1.0.0", + "h5py<4.0.0", + "html5lib==1.0b9", + "hyperopt==0.2.4", + "idna==2.8", + "isort==4.3.4", + "joblib>=1.2.0", + "le-pycaption==2.2.0a1", + "librosa<0.10.0", + "locket==0.2.0", + "Markdown==2.6.11", + "mccabe==0.6.1", + "networkx>=2.5.1", + "numba>=0.50.0", + "numpy<1.27.0", + "oauthlib==3.1.0", + "pbr==4.0.2", + "pkgconfig~=1.5.5", + "pluggy==0.13.1", + "pyasn1==0.4.8", + "pyasn1-modules==0.2.7", + "pybind11~=2.11.1", + "pycountry~=20.7.3", + "pydot==1.2.4", + "pydot-ng==1.0.0", + "pydotplus==2.0.2", + "pyprof2calltree==1.4.3", + "pysrt==1.1.2", + "pysubs2~=1.6.1", + "pytz==2018.4", + "PyYAML>=4.2b1", + "rsa==4.7", + "scipy<1.12.0", + "scikit-learn<1.2.0", + "six~=1.15.0", + "tensorflow>=1.15.5,<2.16.0", + "termcolor==1.1.0", + "toml==0.10.0", + "toolz==0.9.0", + "urllib3~=1.26.5", + "wrapt==1.14.0", + "Werkzeug>=0.15.3", + "zict==0.1.3" +] +requires-python = ">=3.8,<3.12" + +[project.optional-dependencies] +harmony = [ + "aeneas~=1.7.3.0", + "dtw-python~=1.5.3", + "sentencepiece~=0.1.95", + "torch<2.3.0", + "torchaudio<2.3.0", + "transformers<4.37.0", + "openai-whisper==20240930" +] +dev = [ + "aeneas~=1.7.3.0", + "dtw-python~=1.5.3", + "sentencepiece~=0.1.95", + "torch<2.3.0", + "torchaudio<2.3.0", + "transformers<4.37.0", + "openai-whisper==20240930", + "mock==4.0.3", + "coverage==5.5", + "tox~=3.23.0", + "pycodestyle==2.12.1", + "twine<4.0.0", + "snakeviz==2.1.0", + "line-profiler~=4.1.2", + "scikit-build==0.11.1", + "radish-bdd~=0.13.3", + "pex<=2.1.80", + "mypy==1.3.0", + "types-requests==2.27.9", + "types-setuptools==64.0.1", + "typing-extensions==4.5.0", + "parameterized==0.8.1", + "pylint~=2.17.2", + "pygments==2.7.4", + "darglint~=1.8.1" +] +docs = [ + "sphinx==6.2.1", + "sphinx-rtd-theme==2.0.0" +] +stretch = [ + "aeneas~=1.7.3.0", + "dtw-python~=1.5.3" +] +llm = [ + "sentencepiece~=0.1.95", + "torch<2.3.0", + "torchaudio<2.3.0", + "transformers<4.37.0", + "openai-whisper==20240930" +] + +[project.scripts] +subaligner = "subaligner.__main__:main" +subaligner_1pass = "subaligner.subaligner_1pass.__main__:main" +subaligner_2pass = "subaligner.subaligner_2pass.__main__:main" +subaligner_batch = "subaligner.subaligner_batch.__main__:main" +subaligner_convert = "subaligner.subaligner_convert.__main__:main" +subaligner_train = "subaligner.subaligner_train.__main__:main" +subaligner_tune = "subaligner.subaligner_tune.__main__:main" + +[tool.setuptools.packages.find] +include = [ + "subaligner", + "subaligner.lib", + "subaligner.subaligner_1pass", + "subaligner.subaligner_2pass", + "subaligner.subaligner_batch", + "subaligner.subaligner_convert", + "subaligner.subaligner_train", + "subaligner.subaligner_tune", + "subaligner.models.training.model", + "subaligner.models.training.weights", + "subaligner.models.training.config", +] + +[tool.setuptools.package-data] +"subaligner.models.training.model" = ["model.hdf5"] +"subaligner.models.training.weights" = ["weights.hdf5"] +"subaligner.models.training.config" = ["hyperparameters.json"] [tool.pydoclint] -style = 'sphinx' -exclude = '\.git|\.tox' +style = "sphinx" +exclude = "\\.git|\\.tox" require-return-section-when-returning-nothing = true diff --git a/requirements-arm64.txt b/requirements-arm64.txt deleted file mode 100644 index 6935ec9..0000000 --- a/requirements-arm64.txt +++ /dev/null @@ -1,60 +0,0 @@ -astor==0.7.1 -beautifulsoup4<4.9.0 -bleach==3.3.0 -cachetools==3.1.1 -captionstransformer~=1.2.1 -certifi==2023.7.22 -chardet==3.0.4 -cloudpickle~=1.6.0 -cycler==0.10.0 -decorator==4.3.0 -distributed==2021.10.0 -filelock<4.0.0 -google-auth-oauthlib==0.4.2 -google-pasta~=0.2 -graphviz==0.8.3 -HeapDict==1.0.0 -h5py<4.0.0 -html5lib==1.0b9 -hyperopt==0.2.4 -idna==2.8 -isort==4.3.4 -joblib>=1.2.0 -keras~=2.12.0 -le-pycaption==2.2.0a1 -librosa<0.10.0 -locket==0.2.0 -Markdown==2.6.11 -mccabe==0.6.1 -networkx>=2.5.1 -numba>=0.50.0 -numpy<1.24.0 -oauthlib==3.1.0 -pbr==4.0.2 -pluggy==0.13.1 -protobuf<4.0 -psutil==5.6.7 -pyasn1==0.4.8 -pyasn1-modules==0.2.7 -pybind11~=2.11.1 -pycountry~=20.7.3 -pydot==1.2.4 -pydot-ng==1.0.0 -pydotplus==2.0.2 -pyprof2calltree==1.4.3 -pysrt==1.1.2 -pysubs2~=1.6.1 -pytz==2018.4 -PyYAML>=4.2b1 -rsa==4.7 -scipy<1.11.0 -scikit-learn<1.2.0 -setuptools>=41.0.0,<65.0.0 -six~=1.15.0 -tensorflow-macos~=2.12.0 -termcolor==1.1.0 -toml==0.10.0 -toolz==0.9.0 -urllib3~=1.26.5 -Werkzeug>=0.15.3 -zict==0.1.3 \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 6496359..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,18 +0,0 @@ -mock==4.0.3 -coverage==5.5 -tox~=3.23.0 -pycodestyle==2.5.0 -twine<4.0.0 -snakeviz==2.1.0 -line-profiler~=4.1.2 -scikit-build==0.11.1 -radish-bdd~=0.13.3 -pex<=2.1.80 -mypy==1.3.0 -types-requests==2.27.9 -types-setuptools==64.0.1 -typing-extensions==4.5.0 -parameterized==0.8.1 -pylint~=2.17.2 -pygments==2.7.4 -darglint~=1.8.1 \ No newline at end of file diff --git a/requirements-llm.txt b/requirements-llm.txt deleted file mode 100644 index 6d807fa..0000000 --- a/requirements-llm.txt +++ /dev/null @@ -1,5 +0,0 @@ -sentencepiece~=0.1.95 -torch<2.3.0 -torchaudio<2.3.0 -transformers<4.37.0 -openai-whisper==20240930 \ No newline at end of file diff --git a/requirements-site.txt b/requirements-site.txt deleted file mode 100644 index 9cd5c3f..0000000 --- a/requirements-site.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx==6.2.1 -sphinx-rtd-theme==2.0.0 \ No newline at end of file diff --git a/requirements-stretch.txt b/requirements-stretch.txt deleted file mode 100644 index 8f97d64..0000000 --- a/requirements-stretch.txt +++ /dev/null @@ -1,2 +0,0 @@ -aeneas~=1.7.3.0 -dtw-python~=1.5.3 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1e60906..0000000 --- a/requirements.txt +++ /dev/null @@ -1,60 +0,0 @@ -astor==0.7.1 -beautifulsoup4<4.9.0 -bleach==3.3.0 -cachetools==3.1.1 -captionstransformer~=1.2.1 -certifi==2023.7.22 -chardet~=3.0.4 -cloudpickle~=1.6.0 -cycler==0.10.0 -decorator==4.3.0 -distributed==2021.10.0 -filelock<4.0.0 -google-pasta~=0.2 -graphviz==0.8.3 -HeapDict==1.0.0 -h5py<4.0.0 -html5lib==1.0b9 -hyperopt==0.2.4 -idna==2.8 -isort==4.3.4 -joblib>=1.2.0 -Keras-Applications>=1.0.8 -Keras-Preprocessing>=1.0.9 -le-pycaption==2.2.0a1 -librosa<0.10.0 -locket==0.2.0 -Markdown==2.6.11 -mccabe==0.6.1 -networkx>=2.5.1 -numba>=0.50.0 -numpy<1.27.0 -oauthlib==3.1.0 -pbr==4.0.2 -pkgconfig~=1.5.5 -pluggy==0.13.1 -pyasn1==0.4.8 -pyasn1-modules==0.2.7 -pybind11~=2.11.1 -pycountry~=20.7.3 -pydot==1.2.4 -pydot-ng==1.0.0 -pydotplus==2.0.2 -pyprof2calltree==1.4.3 -pysrt==1.1.2 -pysubs2~=1.6.1 -pytz==2018.4 -PyYAML>=4.2b1 -rsa==4.7 -scipy<1.12.0 -scikit-learn<1.2.0 -setuptools<65.0.0 -six~=1.15.0 -tensorflow>=1.15.5,<2.13 -termcolor==1.1.0 -toml==0.10.0 -toolz==0.9.0 -urllib3~=1.26.5 -wrapt==1.14.0 -Werkzeug>=0.15.3 -zict==0.1.3 diff --git a/setup.py b/setup.py deleted file mode 100644 index 8965d87..0000000 --- a/setup.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import os -import sys -from platform import architecture, machine -from setuptools import setup -from wheel.bdist_wheel import bdist_wheel - -with open(os.path.join(os.getcwd(), "subaligner", "_version.py")) as f: - exec(f.read()) - -with open("README.md") as readme_file: - readme = readme_file.read() - -if sys.platform == "darwin" and machine() == "arm64": - with open("requirements-arm64.txt") as requirements_file: - requirements = requirements_file.read().splitlines()[::-1] -else: - with open("requirements.txt") as requirements_file: - requirements = requirements_file.read().splitlines()[::-1] - -with open("requirements-stretch.txt") as stretch_requirements_file: - stretch_requirements = stretch_requirements_file.read().splitlines()[::-1] - -with open("requirements-site.txt") as docs_requirements_file: - docs_requirements = docs_requirements_file.read().splitlines()[::-1] - -with open("requirements-llm.txt") as llm_requirements_file: - llm_requirements = llm_requirements_file.read().splitlines()[::-1] - -with open("requirements-dev.txt") as dev_requirements_file: - dev_requirements = dev_requirements_file.read().splitlines()[::-1] - -EXTRA_DEPENDENCIES = { - "harmony": stretch_requirements + llm_requirements, - "dev": dev_requirements + stretch_requirements + llm_requirements + docs_requirements, - "docs": docs_requirements, - "stretch": stretch_requirements, - "translation": llm_requirements, # for backward compatibility and now deprecated with "llm" - "llm": llm_requirements, -} - -architecture = architecture()[0] if sys.platform == "win32" else machine() - - -class bdist_wheel_local(bdist_wheel): - - def get_tag(self): - python = f"py{sys.version_info.major}{sys.version_info.minor}" - if sys.platform == "darwin" and architecture == "arm64": - os_arch = "macosx_11_0_arm64" - else: - os_arch = "any" - return python, "none", os_arch - - -setup(name="subaligner", - version=__version__, - author="Xi Bai", - author_email="xi.bai.ed@gmail.com", - classifiers=[ - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Intended Audience :: Developers", - "Topic :: Utilities", - ], - license="MIT", - url="https://github.com/baxtree/subaligner", - description="Automatically synchronize and translate subtitles, or create new ones by transcribing, using pre-trained DNNs, Forced Alignments and Transformers.", - long_description=readme + "\n\n", - long_description_content_type="text/markdown", - project_urls={ - "Documentation": "https://subaligner.readthedocs.io/en/latest/", - "Source": "https://github.com/baxtree/subaligner", - }, - python_requires=">=3.8,<3.12", - wheel=True, - package_dir={"subaligner": "subaligner"}, - packages=[ - "subaligner", - "subaligner.lib", - "subaligner.subaligner_1pass", - "subaligner.subaligner_2pass", - "subaligner.subaligner_batch", - "subaligner.subaligner_convert", - "subaligner.subaligner_train", - "subaligner.subaligner_tune", - "subaligner.models.training.model", - "subaligner.models.training.weights", - "subaligner.models.training.config", - ], - package_data={ - "subaligner.models.training.model": ["model.hdf5"], - "subaligner.models.training.weights": ["weights.hdf5"], - "subaligner.models.training.config": ["hyperparameters.json"], - }, - install_requires=requirements, - test_suite="tests.subaligner", - extras_require=EXTRA_DEPENDENCIES, - scripts=[ - "bin/subaligner", - "bin/subaligner_1pass", - "bin/subaligner_2pass", - "bin/subaligner_batch", - "bin/subaligner_convert", - "bin/subaligner_train", - "bin/subaligner_tune", - ], - entry_points={ - "console_scripts": [ - "subaligner=subaligner.__main__:main", - "subaligner_1pass=subaligner.subaligner_1pass.__main__:main", - "subaligner_2pass=subaligner.subaligner_2pass.__main__:main", - "subaligner_batch=subaligner.subaligner_batch.__main__:main", - "subaligner_convert=subaligner.subaligner_convert.__main__:main", - "subaligner_train=subaligner.subaligner_train.__main__:main", - "subaligner_tune=subaligner.subaligner_tune.__main__:main", - ] - }, - cmdclass={"bdist_wheel": bdist_wheel_local}) diff --git a/site/source/usage.rst b/site/source/usage.rst index f30e0ba..754e922 100644 --- a/site/source/usage.rst +++ b/site/source/usage.rst @@ -51,9 +51,10 @@ Make sure you have got the virtual environment activated upfront. (.venv) $ subaligner -m single -v video.mp4 -s subtitle.srt -t src,tgt (.venv) $ subaligner -m dual -v video.mp4 -s subtitle.srt -t src,tgt (.venv) $ subaligner -m script -v test.mp4 -s subtitle.txt -o subtitle_aligned.srt -t src,tgt - (.venv) $ subaligner -m dual -v video.mp4 -tr helsinki-nlp -o subtitle_aligned.srt -t src,tgt - (.venv) $ subaligner -m dual -v video.mp4 -tr facebook-mbart -tf large -o subtitle_aligned.srt -t src,tgt - (.venv) $ subaligner -m dual -v video.mp4 -tr whisper -tf small -o subtitle_aligned.srt -t src,eng + (.venv) $ subaligner -m dual -v video.mp4 -s subtitle.srt -tr helsinki-nlp -o subtitle_aligned.srt -t src,tgt + (.venv) $ subaligner -m dual -v video.mp4 -s subtitle.srt -tr facebook-mbart -tf large -o subtitle_aligned.srt -t src,tgt + (.venv) $ subaligner -m dual -v video.mp4 -s subtitle.srt -tr facebook-m2m100 -tf small -o subtitle_aligned.srt -t src,tgt + (.venv) $ subaligner -m dual -v video.mp4 -s subtitle.srt -tr whisper -tf small -o subtitle_aligned.srt -t src,eng **Transcribe audiovisual files and generate translated subtitles**:: diff --git a/subaligner/_version.py b/subaligner/_version.py index 723f0f2..6b05094 100644 --- a/subaligner/_version.py +++ b/subaligner/_version.py @@ -1,2 +1,3 @@ -"""The semver for the current release.""" -__version__ = "0.3.8" +import importlib.metadata + +__version__ = importlib.metadata.version("subaligner") diff --git a/subaligner/llm.py b/subaligner/llm.py index 36927bd..c0d2128 100644 --- a/subaligner/llm.py +++ b/subaligner/llm.py @@ -9,6 +9,7 @@ class TranslationRecipe(Enum): HELSINKI_NLP = "helsinki-nlp" WHISPER = "whisper" FACEBOOK_MBART = "facebook-mbart" + FACEBOOK_M2M100 = "facebook-m2m100" class WhisperFlavour(Enum): @@ -34,3 +35,7 @@ class HelsinkiNLPFlavour(Enum): class FacebookMbartFlavour(Enum): LARGE = "large" + + +class FacebookM2m100Flavour(Enum): + SMALL = "small" diff --git a/subaligner/translator.py b/subaligner/translator.py index 4d1d2f8..8c55a3a 100644 --- a/subaligner/translator.py +++ b/subaligner/translator.py @@ -12,10 +12,12 @@ MarianTokenizer, MBart50TokenizerFast, MBartForConditionalGeneration, + M2M100ForConditionalGeneration, + M2M100Tokenizer, ) from whisper.tokenizer import LANGUAGES from .singleton import Singleton -from .llm import TranslationRecipe, HelsinkiNLPFlavour, WhisperFlavour, FacebookMbartFlavour +from .llm import TranslationRecipe, HelsinkiNLPFlavour, WhisperFlavour, FacebookMbartFlavour, FacebookM2m100Flavour from .utils import Utils from .subtitle import Subtitle from .logger import Logger @@ -147,6 +149,27 @@ def translate(self, new_subs[index].text = translated_texts[index] self.__LOGGER.info("Subtitle translated") return new_subs + elif self.__recipe == TranslationRecipe.FACEBOOK_M2M100.value: + src_lang, tgt_lang = language_pair if language_pair is not None else (self.__src_language, self.__tgt_language) + self.__tokenizer.src_lang = Utils.get_iso_639_alpha_2(src_lang) + lang_code = Utils.get_iso_639_alpha_2(tgt_lang) + if src_lang is None or tgt_lang is None: + raise NotImplementedError( + f"Language pair of {src_lang} and {src_lang} is not supported by {self.__recipe}") + translated_texts = [] + self.__lang_model.eval() + new_subs = deepcopy(subs) + src_texts = [sub.text for sub in new_subs] + num_of_batches = math.ceil(len(src_texts) / Translator.__TRANSLATING_BATCH_SIZE) + self.__LOGGER.info("Translating %s subtitle cue(s)..." % len(src_texts)) + for batch in tqdm(Translator.__batch(src_texts, Translator.__TRANSLATING_BATCH_SIZE), total=num_of_batches): + input_ids = self.__tokenizer(batch, return_tensors=Translator.__TENSOR_TYPE, padding=True) + translated = self.__lang_model.generate(**input_ids, forced_bos_token_id=self.__tokenizer.get_lang_id(lang_code)) + translated_texts.extend([self.__tokenizer.decode(t, skip_special_tokens=True) for t in translated]) + for index in range(len(new_subs)): + new_subs[index].text = translated_texts[index] + self.__LOGGER.info("Subtitle translated") + return new_subs else: return [] @@ -178,6 +201,13 @@ def __initialise_model(self, src_lang: str, tgt_lang: str, recipe: str, flavour: self.__download_mbart_model(flavour) else: raise NotImplementedError(f"Unknown {recipe} flavour: {flavour}") + elif recipe == TranslationRecipe.FACEBOOK_M2M100.value: + if flavour in [f.value for f in FacebookM2m100Flavour]: + self.__download_m2m100_model(flavour) + else: + raise NotImplementedError(f"Unknown {recipe} flavour: {flavour}") + else: + raise NotImplementedError(f"Unknown recipe: {recipe}") def __download_mt_model(self, src_lang: str, tgt_lang: str, flavour: str) -> bool: try: @@ -216,6 +246,13 @@ def __download_mbart_model(self, flavour: str) -> None: self.__lang_model = MBartForConditionalGeneration.from_pretrained(mbart_model_name) self.__LOGGER.debug("mBART model %s downloaded" % mbart_model_name) + def __download_m2m100_model(self, flavour: str) -> None: + m2m100_model_name = "facebook/m2m100_418M" if flavour == "small" else "facebook/m2m100_418M" + self.__LOGGER.debug("Trying to download the M2M100 model %s" % m2m100_model_name) + self.__tokenizer = M2M100Tokenizer.from_pretrained(m2m100_model_name) + self.__lang_model = M2M100ForConditionalGeneration.from_pretrained(m2m100_model_name) + self.__LOGGER.debug("M2M100 model %s downloaded" % m2m100_model_name) + def __download_by_mt_name(self, mt_model_name: str) -> None: self.__LOGGER.debug("Trying to download the MT model %s" % mt_model_name) self.__tokenizer = MarianTokenizer.from_pretrained(mt_model_name) From 6f0ee944b20e943c7f33944a7fe38792132238f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 10:25:25 +0000 Subject: [PATCH 2/2] Bump idna from 2.8 to 3.7 Bumps [idna](https://github.com/kjd/idna) from 2.8 to 3.7. - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v2.8...v3.7) --- updated-dependencies: - dependency-name: idna dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 74923e1..72c92e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "h5py<4.0.0", "html5lib==1.0b9", "hyperopt==0.2.4", - "idna==2.8", + "idna==3.7", "isort==4.3.4", "joblib>=1.2.0", "le-pycaption==2.2.0a1",