diff --git a/.github/workflows/python-demos.yml b/.github/workflows/python-demos.yml index 447747af3..fd19c5667 100644 --- a/.github/workflows/python-demos.yml +++ b/.github/workflows/python-demos.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] include: - os: ubuntu-latest platform: linux @@ -46,7 +46,26 @@ jobs: python-version: ${{ matrix.python-version }} - name: Pre-build dependencies - run: python -m pip install --upgrade pip + run: | + python -m pip install --upgrade pip + pip install wheel + + # ************** REMOVE AFTER RELEASE ******************** + - name: ppn + working-directory: resources/porcupine/binding/python + run: | + python setup.py sdist bdist_wheel && pip install dist/pvporcupine-3.0.0-py3-none-any.whl + + - name: rhn + working-directory: resources/rhino/binding/python + run: | + python setup.py sdist bdist_wheel && pip install dist/pvrhino-3.0.0-py3-none-any.whl + + - name: pv + working-directory: sdk/python + run: | + python setup.py sdist bdist_wheel && pip install dist/picovoice-3.0.0-py3-none-any.whl + # ******************************************************** - name: Install dependencies run: pip install -r requirements.txt @@ -85,6 +104,28 @@ jobs: with: submodules: recursive + - name: Pre-build dependencies + run: | + python3 -m pip install --upgrade pip + pip3 install wheel + + # ************** REMOVE AFTER RELEASE ******************** + - name: ppn + working-directory: resources/porcupine/binding/python + run: | + pip3 uninstall -y pvporcupine && python3 setup.py sdist bdist_wheel && pip3 install dist/pvporcupine-3.0.0-py3-none-any.whl + + - name: rhn + working-directory: resources/rhino/binding/python + run: | + pip3 uninstall -y pvrhino && python3 setup.py sdist bdist_wheel && pip3 install dist/pvrhino-3.0.0-py3-none-any.whl + + - name: pv + working-directory: sdk/python + run: | + pip3 uninstall -y picovoice && python3 setup.py sdist bdist_wheel && pip3 install dist/picovoice-3.0.0-py3-none-any.whl + # ******************************************************** + - name: Install dependencies run: pip3 install -r requirements.txt diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index ed7546e90..fca74ba4b 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -34,7 +34,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v3 @@ -51,6 +51,18 @@ jobs: python -m pip install --upgrade pip pip install wheel + # ************** REMOVE AFTER RELEASE ******************** + - name: ppn + working-directory: resources/porcupine/binding/python + run: | + pip install wheel && python setup.py sdist bdist_wheel && pip install dist/pvporcupine-3.0.0-py3-none-any.whl + + - name: rhn + working-directory: resources/rhino/binding/python + run: | + python setup.py sdist bdist_wheel && pip install dist/pvrhino-3.0.0-py3-none-any.whl + # ******************************************************** + - name: Install dependencies run: pip3 install -r requirements.txt @@ -75,6 +87,18 @@ jobs: python3 -m pip install --upgrade pip pip3 install wheel + # ************** REMOVE AFTER RELEASE ******************** + - name: ppn + working-directory: resources/porcupine/binding/python + run: | + pip3 uninstall -y pvporcupine && python3 setup.py sdist bdist_wheel && pip3 install dist/pvporcupine-3.0.0-py3-none-any.whl + + - name: rhn + working-directory: resources/rhino/binding/python + run: | + pip3 uninstall -y pvrhino && python3 setup.py sdist bdist_wheel && pip3 install dist/pvrhino-3.0.0-py3-none-any.whl + # ******************************************************** + - name: Install dependencies run: pip3 install -r requirements.txt diff --git a/demo/python/requirements.txt b/demo/python/requirements.txt index 807b30980..e378f906a 100644 --- a/demo/python/requirements.txt +++ b/demo/python/requirements.txt @@ -1,2 +1,2 @@ -picovoice==2.2.1 +picovoice==3.0.0 pvrecorder==1.2.1 diff --git a/demo/python/setup.py b/demo/python/setup.py index 57e8219be..61e6b2f97 100644 --- a/demo/python/setup.py +++ b/demo/python/setup.py @@ -39,7 +39,7 @@ setuptools.setup( name="picovoicedemo", - version="2.2.4", + version="3.0.0", author="Picovoice Inc.", author_email="hello@picovoice.ai", description="Picovoice demos.", @@ -47,7 +47,7 @@ long_description_content_type="text/markdown", url="https://github.com/Picovoice/picovoice", packages=["picovoicedemo"], - install_requires=["picovoice==2.2.1", "pvrecorder==1.2.1"], + install_requires=["picovoice==3.0.0", "pvrecorder==1.2.1"], include_package_data=True, classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/demo/tkinter/requirements.txt b/demo/tkinter/requirements.txt index a64d464dc..21bee5096 100644 --- a/demo/tkinter/requirements.txt +++ b/demo/tkinter/requirements.txt @@ -1,2 +1,2 @@ -picovoice==2.2.1 -pvrecorder==1.1.2 \ No newline at end of file +picovoice==3.0.0 +pvrecorder==1.2.1 \ No newline at end of file diff --git a/sdk/python/_picovoice.py b/sdk/python/_picovoice.py index f4d32130c..671a5ebf3 100644 --- a/sdk/python/_picovoice.py +++ b/sdk/python/_picovoice.py @@ -1,5 +1,5 @@ # -# Copyright 2020-2022 Picovoice Inc. +# Copyright 2020-2023 Picovoice Inc. # # You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" # file accompanying this source. @@ -261,6 +261,17 @@ def process(self, pcm: Sequence[int]) -> None: except pvrhino.RhinoError as e: raise _PPN_RHN_ERROR_TO_PICOVOICE_ERROR[type(e)] from e + def reset(self) -> None: + """ + Resets the internal state of Picovoice. It should be called before processing a new stream of audio + or when Picovoice was stopped whilst processing a stream of audio. + """ + try: + self._is_wake_word_detected = False + self._rhino.reset() + except pvrhino.RhinoError as e: + raise _PPN_RHN_ERROR_TO_PICOVOICE_ERROR[type(e)] from e + @property def sample_rate(self) -> int: """Audio sample rate accepted by Picovoice.""" @@ -277,7 +288,7 @@ def frame_length(self) -> int: def version(self) -> str: """Version""" - return '2.2.0' + return '3.0.0' @property def context_info(self) -> str: diff --git a/sdk/python/requirements.txt b/sdk/python/requirements.txt index f90bbdc12..41528ba5a 100644 --- a/sdk/python/requirements.txt +++ b/sdk/python/requirements.txt @@ -1,4 +1,4 @@ parameterized -pvporcupine==2.2.1 -pvrhino==2.2.1 +pvporcupine==3.0.0 +pvrhino==3.0.0 setuptools \ No newline at end of file diff --git a/sdk/python/setup.py b/sdk/python/setup.py index 3bd15bd08..9347f06e3 100644 --- a/sdk/python/setup.py +++ b/sdk/python/setup.py @@ -1,5 +1,5 @@ # -# Copyright 2020-2022 Picovoice Inc. +# Copyright 2020-2023 Picovoice Inc. # # You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" # file accompanying this source. @@ -33,7 +33,7 @@ setuptools.setup( name="picovoice", - version="2.2.1", + version="3.0.0", author="Picovoice Inc.", author_email="hello@picovoice.ai", description="Picovoice is an end-to-end platform for building voice products on your terms.", @@ -41,7 +41,7 @@ long_description_content_type="text/markdown", url="https://github.com/Picovoice/picovoice", packages=["picovoice"], - install_requires=["pvporcupine==2.2.1", "pvrhino==2.2.1"], + install_requires=["pvporcupine==3.0.0", "pvrhino==3.0.0"], include_package_data=True, classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/sdk/python/test_picovoice.py b/sdk/python/test_picovoice.py index 84570de2a..cf16aa5d4 100644 --- a/sdk/python/test_picovoice.py +++ b/sdk/python/test_picovoice.py @@ -26,7 +26,7 @@ class PicovoiceTestData: def __init__(self): - self.picovoiceInstance = None + self.picovoice = None self.is_wake_word_detected = False self.inference = None @@ -41,6 +41,15 @@ def inference_callback(self, inference): self.inference = inference +class PicovoiceResetTestData(PicovoiceTestData): + def __init__(self): + super().__init__() + + def wake_word_callback(self): + self.is_wake_word_detected = True + self.picovoice.reset() + + class PicovoiceTestCase(unittest.TestCase): @staticmethod def _concatenate(language, context, keyword): @@ -66,9 +75,8 @@ def __read_file(file_name, sample_rate): return frames[::channels] - def run_picovoice(self, language, keyword, context, audio_file_name, intent, slots): - test_data = PicovoiceTestData() - picovoice = Picovoice( + def run_picovoice(self, language, keyword, context, audio_file_name, intent, slots, test_data): + test_data.picovoice = Picovoice( access_key=sys.argv[1], keyword_path=pv_keyword_paths_by_language(language)[keyword], context_path=context_path(context, language), @@ -80,17 +88,20 @@ def run_picovoice(self, language, keyword, context, audio_file_name, intent, slo audio = \ self.__read_file( os.path.join(os.path.dirname(__file__), '../../resources/audio_samples', audio_file_name), - picovoice.sample_rate) + test_data.picovoice.sample_rate) for _ in range(2): test_data.reset() - for i in range(len(audio) // picovoice.frame_length): - frame = audio[i * picovoice.frame_length:(i + 1) * picovoice.frame_length] - picovoice.process(frame) + for i in range(len(audio) // test_data.picovoice.frame_length): + frame = audio[i * test_data.picovoice.frame_length:(i + 1) * test_data.picovoice.frame_length] + test_data.picovoice.process(frame) self.assertTrue(test_data.is_wake_word_detected) - self.assertEqual(test_data.inference.intent, intent) - self.assertEqual(test_data.inference.slots, slots) + if intent is None and slots is None: + self.assertIsNone(test_data.inference) + else: + self.assertEqual(test_data.inference.intent, intent) + self.assertEqual(test_data.inference.slots, slots) @parameterized.expand(test_parameters) def test_picovoice(self, language, keyword, context, audio_file_name, intent, slots): @@ -100,12 +111,24 @@ def test_picovoice(self, language, keyword, context, audio_file_name, intent, sl context=context, audio_file_name=audio_file_name, intent=intent, - slots=slots) + slots=slots, + test_data=PicovoiceTestData()) + + def test_reset(self): + test_param = test_parameters[0] + self.run_picovoice( + language=test_param[0], + keyword=test_param[1], + context=test_param[2], + audio_file_name=test_param[3], + intent=None, + slots=None, + test_data=PicovoiceResetTestData()) if __name__ == '__main__': if len(sys.argv) != 2: - print("usage: test_porcupine.py ${ACCESS_KEY}") + print("usage: test_picovoice.py ${ACCESS_KEY}") exit(1) unittest.main(argv=sys.argv[:1])