diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 4456c978..cf6f30ba 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -57,7 +57,7 @@ jobs: run: | python -m pip install .[dev,whisper-local,faster-whisper,google-cloud,openai,groq,vosk] - name: Set up vosk model - run: pipx run setup_vosk.py + run: sprc download vosk - name: Test with unittest run: | pytest --doctest-modules -v speech_recognition/recognizers/ tests/ diff --git a/README.rst b/README.rst index f2905e1c..9af7bfc3 100644 --- a/README.rst +++ b/README.rst @@ -59,8 +59,6 @@ The `library reference `__ for information about installing languages, compiling PocketSphinx, and building language packs from online resources. This document is also included under ``reference/pocketsphinx.rst``. -You have to install Vosk models for using Vosk. `Here `__ are models avaiable. You have to place them in models folder of your project, like "your-project-folder/models/your-vosk-model" - Examples -------- @@ -146,7 +144,8 @@ You can install it with ``python3 -m pip install SpeechRecognition[vosk]``. You also have to install Vosk Models: -`Here `__ are models avaiable for download. You have to place them in models folder of your project, like "your-project-folder/models/your-vosk-model" +`Here `__ are models available for download. You have to place them in the ``model`` directory of your project, like "your-project-folder/model". +You can also run ``sprc download vosk`` to download the default model. Google Cloud Speech Library for Python (for Google Cloud Speech-to-Text API users) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/setup.py b/setup.py index efd463ea..69f4aab6 100644 --- a/setup.py +++ b/setup.py @@ -75,4 +75,7 @@ def run(self): "standard-aifc; python_version>='3.13'", "audioop-lts; python_version>='3.13'", ], + entry_points={ + "console_scripts": ["sprc=speech_recognition.cli:main"], + }, ) diff --git a/setup_vosk.py b/setup_vosk.py deleted file mode 100644 index b8b5877d..00000000 --- a/setup_vosk.py +++ /dev/null @@ -1,51 +0,0 @@ -# /// script -# requires-python = ">=3.9" -# dependencies = [ -# "requests", -# "tqdm", -# ] -# /// -import os -import shutil -import tempfile -import zipfile - -import requests -from tqdm import tqdm - - -def setup_vosk_model(model_url: str, model_dir: str) -> None: - model_filename = os.path.basename(model_url) - model_name = os.path.splitext(model_filename)[0] - - print(f"Downloading model {model_filename} ...") - response = requests.get(model_url, stream=True) - response.raise_for_status() - total_size = int(response.headers.get("content-length", 0)) - - with tempfile.TemporaryDirectory() as temp_dir: - download_path = os.path.join(temp_dir, model_filename) - with open(download_path, "wb") as f: - with tqdm(total=total_size, unit="B", unit_scale=True) as pbar: - for chunk in response.iter_content(chunk_size=8192): - if chunk: - f.write(chunk) - pbar.update(len(chunk)) - - print("Unzip model...") - with zipfile.ZipFile(download_path, "r") as zip_ref: - zip_ref.extractall(temp_dir) - - extracted_dir = os.path.join(temp_dir, model_name) - if os.path.exists(model_dir): - shutil.rmtree(model_dir) - shutil.copytree(extracted_dir, model_dir) - - print(f"Setup complete! Model is placed in the directory: {model_dir}") - - -if __name__ == "__main__": - model_url = ( - "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip" - ) - setup_vosk_model(model_url, "model") diff --git a/speech_recognition/cli.py b/speech_recognition/cli.py new file mode 100644 index 00000000..925fb314 --- /dev/null +++ b/speech_recognition/cli.py @@ -0,0 +1,69 @@ +import argparse +import os +import shutil +import tempfile +import zipfile +from urllib.request import urlopen + +from tqdm import tqdm + + +def download_vosk_model(url: str, model_dir: str) -> None: + model_filename = os.path.basename(url) + model_name = os.path.splitext(model_filename)[0] + + print(f"Downloading model {model_filename} ...") + with urlopen(url) as response: + total_size = int(response.headers.get("Content-Length", 0)) + with tempfile.TemporaryDirectory() as temp_dir: + download_path = os.path.join(temp_dir, model_filename) + with open(download_path, "wb") as f, tqdm( + total=total_size, unit="B", unit_scale=True + ) as pbar: + while True: + chunk = response.read(8192) + if not chunk: + break + f.write(chunk) + pbar.update(len(chunk)) + + print("Unzip model...") + with zipfile.ZipFile(download_path, "r") as zip_ref: + zip_ref.extractall(temp_dir) + + extracted_dir = os.path.join(temp_dir, model_name) + if os.path.exists(model_dir): + shutil.rmtree(model_dir) + shutil.copytree(extracted_dir, model_dir) + + print(f"Setup complete! Model is placed in the directory: {model_dir}") + + +def main(argv=None) -> None: + parser = argparse.ArgumentParser(prog="sprc") + subparsers = parser.add_subparsers(dest="command") + + download_parser = subparsers.add_parser("download") + download_subparsers = download_parser.add_subparsers(dest="target") + + vosk_parser = download_subparsers.add_parser("vosk") + vosk_parser.add_argument( + "--url", + default="https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip", + ) + vosk_parser.add_argument("--dir", default="model") + + def _download_vosk(args): + download_vosk_model(args.url, args.dir) + + vosk_parser.set_defaults(func=_download_vosk) + + args = parser.parse_args(argv) + if hasattr(args, "func"): + args.func(args) + else: + parser.print_help() + + +if __name__ == "__main__": + main()