From a818cd9f176a0de32def8fccd22c51b6471befe9 Mon Sep 17 00:00:00 2001 From: "david.scripka" Date: Fri, 17 Oct 2025 22:00:16 -0400 Subject: [PATCH 1/2] Bump python version to 3.10+, switch tflite to new ai-edge-litert --- .gitignore | 15 +++++++++++++ openwakeword/custom_verifier_model.py | 2 +- openwakeword/data.py | 4 ++-- openwakeword/model.py | 6 +++--- openwakeword/utils.py | 6 +++--- pyproject.toml | 2 +- setup.py | 31 +++++++++++++++------------ tests/test_models.py | 7 +++++- 8 files changed, 48 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index b6e4761..1e20d39 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,18 @@ dmypy.json # Pyre type checker .pyre/ + +# Most notebooks +notebooks/ +!notebooks/automatic_model_training.ipynb +!notebooks/converting_google_speech_embedding_model.ipynb +!notebooks/performance_metrics.ipynb +!notebooks/training_models.ipynb +!training_tutorial_data + +# Most example files +examples/ +!examples/audio/activation.wav + +# archive files +archive/ diff --git a/openwakeword/custom_verifier_model.py b/openwakeword/custom_verifier_model.py index 1c8c55f..3a9396e 100644 --- a/openwakeword/custom_verifier_model.py +++ b/openwakeword/custom_verifier_model.py @@ -62,7 +62,7 @@ def get_reference_clip_features( # Get predictions for _ in range(N): # Load clip - if type(reference_clip) == str: + if isinstance(reference_clip, str): sr, dat = scipy.io.wavfile.read(reference_clip) else: dat = reference_clip diff --git a/openwakeword/data.py b/openwakeword/data.py index c43da5d..7a95306 100755 --- a/openwakeword/data.py +++ b/openwakeword/data.py @@ -803,8 +803,8 @@ class mmap_batch_generator: self.n_per_class = {} for lbl, shape in self.shapes.items(): dummy_data = np.random.random((10, self.shapes[lbl][1], self.shapes[lbl][2])) - if self.data_transform_funcs.get(lbl, None): - scale_factor = self.data_transform_funcs.get(lbl, None)(dummy_data).shape[0]/10 + if (transform_func := self.data_transform_funcs.get(lbl, None)): + scale_factor = transform_func(dummy_data).shape[0]/10 ratio = self.shapes[lbl][0]/sum([i[0] for i in self.shapes.values()]) self.n_per_class[lbl] = max(1, int(int(batch_size*ratio)/scale_factor)) diff --git a/openwakeword/model.py b/openwakeword/model.py index 6029963..1296ac1 100755 --- a/openwakeword/model.py +++ b/openwakeword/model.py @@ -111,7 +111,7 @@ class Model(): # Do imports for inference framework if inference_framework == "tflite": try: - import tflite_runtime.interpreter as tflite + import ai_edge_litert.interpreter as tflite def tflite_predict(tflite_interpreter, input_index, output_index, x): tflite_interpreter.set_tensor(input_index, x) @@ -127,8 +127,8 @@ class Model(): inference_framework = "onnx" wakeword_models = [i.replace('.tflite', '.onnx') for i in wakeword_models] else: - raise ValueError("Tried to import the tflite runtime for provided tflite models, but it was not found. " - "Please install it using `pip install tflite-runtime`") + raise ValueError("Tried to import the LiteRT runtime for provided LiteRT models, but it was not found. " + "Please install it using `pip install ai-edge-litert`") if inference_framework == "onnx": try: diff --git a/openwakeword/utils.py b/openwakeword/utils.py index 4964706..5f64e03 100644 --- a/openwakeword/utils.py +++ b/openwakeword/utils.py @@ -94,10 +94,10 @@ class AudioFeatures(): elif inference_framework == "tflite": try: - import tflite_runtime.interpreter as tflite + import ai_edge_litert.interpreter as tflite except ImportError: - raise ValueError("Tried to import the TFLite runtime, but it was not found." - "Please install it using `pip install tflite-runtime`") + raise ValueError("Tried to import the LiteRT runtime, but it was not found." + "Please install it using `pip install ai-edge-litert`") if melspec_model_path == "": melspec_model_path = os.path.join(pathlib.Path(__file__).parent.resolve(), diff --git a/pyproject.toml b/pyproject.toml index d420f04..470f653 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ authors = [ ] description = "An open-source audio wake word (or phrase) detection framework with a focus on performance and simplicity" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.10" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: Apache Software License", diff --git a/setup.py b/setup.py index df0a666..f6df9f7 100644 --- a/setup.py +++ b/setup.py @@ -4,19 +4,20 @@ import setuptools with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() + # Build extras_requires based on platform def build_additional_requires(): - py_version = platform.python_version()[0:3].replace('.', "") - if platform.system() == "Linux" and platform.machine() == "x86_64": - additional_requires=[ - f"speexdsp_ns @ https://github.com/dscripka/openWakeWord/releases/download/v0.1.1/speexdsp_ns-0.1.2-cp{py_version}-cp{py_version}-linux_x86_64.whl", - ] - elif platform.system() == "Linux" and platform.machine() == "aarch64": - additional_requires=[ - f"speexdsp_ns @ https://github.com/dscripka/openWakeWord/releases/download/v0.1.1/speexdsp_ns-0.1.2-cp{py_version}-cp{py_version}-linux_aarch64.whl", - ], - elif platform.system() == "Windows" and platform.machine() == "x86_64": - additional_requires=[ + # py_version = platform.python_version()[0:3].replace('.', "") + # if platform.system() == "Linux" and platform.machine() == "x86_64": + # additional_requires=[ + # f"speexdsp_ns @ https://github.com/dscripka/openWakeWord/releases/download/v0.1.1/speexdsp_ns-0.1.2-cp{py_version}-cp{py_version}-linux_x86_64.whl", + # ] + # elif platform.system() == "Linux" and platform.machine() == "aarch64": + # additional_requires=[ + # f"speexdsp_ns @ https://github.com/dscripka/openWakeWord/releases/download/v0.1.1/speexdsp_ns-0.1.2-cp{py_version}-cp{py_version}-linux_aarch64.whl", + # ], + if platform.system() == "Windows" and platform.machine() == "x86_64": + additional_requires = [ 'PyAudioWPatch' ] else: @@ -24,12 +25,14 @@ def build_additional_requires(): return additional_requires + setuptools.setup( name="openwakeword", version="0.6.0", install_requires=[ 'onnxruntime>=1.10.0,<2', - 'tflite-runtime>=2.8.0,<3; platform_system == "Linux"', + 'ai-edge-litert>=2.0.2,<3; platform_system == "Linux" or platform_system == "Darwin"', + 'speexdsp-ns>=0.1.2,<1; platform_system == "Linux"', 'tqdm>=4.0,<5.0', 'scipy>=1.3,<2', 'scikit-learn>=1,<2', @@ -40,7 +43,7 @@ setuptools.setup( 'pytest>=7.2.0,<8', 'pytest-cov>=2.10.1,<3', 'pytest-flake8>=1.1.1,<2', - 'flake8>=4.0,<4.1', + 'flake8>=5.0,<7.1', 'pytest-mypy>=0.10.0,<1', 'types-requests', 'types-PyYAML', @@ -90,5 +93,5 @@ setuptools.setup( ], packages=setuptools.find_packages(), include_package_data=True, - python_requires=">=3.7", + python_requires=">=3.10", ) \ No newline at end of file diff --git a/tests/test_models.py b/tests/test_models.py index b3907ff..92a1d05 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -53,12 +53,17 @@ class TestModels: os.path.join("openwakeword", "resources", "models", "alexa_v0.1.onnx") ], inference_framework="onnx") + # Prediction on random data + prediction = owwModel.predict(np.random.randint(-1000, 1000, 1280).astype(np.int16)) + assert prediction["alexa_v0.1"] >= 0 and prediction["alexa_v0.1"] <= 1 + owwModel = openwakeword.Model(wakeword_models=[ os.path.join("openwakeword", "resources", "models", "alexa_v0.1.tflite") ], inference_framework="tflite") # Prediction on random data - owwModel.predict(np.random.randint(-1000, 1000, 1280).astype(np.int16)) + prediction = owwModel.predict(np.random.randint(-1000, 1000, 1280).astype(np.int16)) + assert prediction["alexa_v0.1"] >= 0 and prediction["alexa_v0.1"] <= 1 def test_predict_with_different_frame_sizes(self): # Test with binary model From b02327d87c40c7593362d4b02483eb24812605ef Mon Sep 17 00:00:00 2001 From: "david.scripka" Date: Fri, 17 Oct 2025 22:09:07 -0400 Subject: [PATCH 2/2] bump workflow python versions --- .github/workflows/build_and_publish_to_pypi.yml | 4 ++-- .github/workflows/tests.yml | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_and_publish_to_pypi.yml b/.github/workflows/build_and_publish_to_pypi.yml index bee4a13..3235de7 100755 --- a/.github/workflows/build_and_publish_to_pypi.yml +++ b/.github/workflows/build_and_publish_to_pypi.yml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Set up Python 3.8 + - name: Set up Python 3.10 uses: actions/setup-python@v3 with: - python-version: "3.8" + python-version: "3.10" - name: Install pypa/build run: >- python -m diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ffc7c50..a82d633 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8"] + python-version: ["3.10"] steps: - uses: actions/checkout@v3 @@ -28,7 +28,6 @@ jobs: sudo apt-get install libspeexdsp-dev python -m pip install --upgrade pip pip install -e .[test] - pip install https://github.com/dscripka/openWakeWord/releases/download/v0.1.1/speexdsp_ns-0.1.2-cp38-cp38-linux_x86_64.whl - name: Test with pytest run: | pytest @@ -37,7 +36,7 @@ jobs: runs-on: windows-latest strategy: matrix: - python-version: ["3.8"] + python-version: ["3.10"] steps: - uses: actions/checkout@v3