From 9ba497b984307adee70f8134143f6201e9855f97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Thu, 19 Mar 2020 09:07:12 +0100 Subject: [PATCH 1/5] Add numpy==1.16 --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a55da05..c306be0 100644 --- a/setup.py +++ b/setup.py @@ -69,8 +69,9 @@ setup( 'precise-calc-threshold=precise.scripts.calc_threshold:main', ] }, + package_data={'precise': ['data/activate.wav']}, install_requires=[ - 'numpy', + 'numpy==1.16', 'tensorflow>=1.13,<1.14', # Must be on piwheels 'sonopy', 'pyaudio', From 16886403320a154325308c6c0cfa451ed3978cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Tue, 24 Mar 2020 08:39:50 +0100 Subject: [PATCH 2/5] Fix usage of activation sound when using pip install --- MANIFEST.in | 1 + {data => precise/data}/activate.wav | Bin precise/util.py | 3 +-- setup.py | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 MANIFEST.in rename {data => precise/data}/activate.wav (100%) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..20b9a7a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include precise/data/activate.wav diff --git a/data/activate.wav b/precise/data/activate.wav similarity index 100% rename from data/activate.wav rename to precise/data/activate.wav diff --git a/precise/util.py b/precise/util.py index 9b597b6..7845c18 100644 --- a/precise/util.py +++ b/precise/util.py @@ -80,8 +80,7 @@ def play_audio(filename: str): def activate_notify(): audio = 'data/activate.wav' - audio = abspath(dirname(abspath(__file__)) + '/../' + audio) - + audio = join(dirname(abspath(__file__)), audio) play_audio(audio) diff --git a/setup.py b/setup.py index c306be0..44a9916 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ setup( 'precise-calc-threshold=precise.scripts.calc_threshold:main', ] }, - package_data={'precise': ['data/activate.wav']}, + include_package_data=True, install_requires=[ 'numpy==1.16', 'tensorflow>=1.13,<1.14', # Must be on piwheels From 2a15272ba391e8a37c31d2a1bcc1def07d2ad36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Wed, 1 Apr 2020 09:16:34 +0200 Subject: [PATCH 3/5] Add __init__.py to test folders --- test/__init__.py | 13 +++++++++++++ test/scripts/__init__.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 test/__init__.py create mode 100644 test/scripts/__init__.py diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..844f62f --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2019 Mycroft AI Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/scripts/__init__.py b/test/scripts/__init__.py new file mode 100644 index 0000000..844f62f --- /dev/null +++ b/test/scripts/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2019 Mycroft AI Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. From a99d229b0c519d20074c2a1674161fd63489653f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Wed, 1 Apr 2020 09:42:04 +0200 Subject: [PATCH 4/5] Add Dockerfile for running the unittests Build the docker with the command docker build -f test/Dockerfile -t precise-test . --- test/Dockerfile | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 test/Dockerfile diff --git a/test/Dockerfile b/test/Dockerfile new file mode 100644 index 0000000..fb3e000 --- /dev/null +++ b/test/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.7-slim +ENV TERM linux +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get update && apt-get -y install git python3-scipy cython libhdf5-dev python3-h5py portaudio19-dev swig libpulse-dev libatlas-base-dev +ADD . mycroft-precise +WORKDIR mycroft-precise +RUN pip install . +RUN pip install pytest +ENV PYTHONPATH /mycroft-precise +ENTRYPOINT ["pytest"] From 6345c50b414b2e316622969bbde18b095c7bd0a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Thu, 9 Apr 2020 07:32:15 +0200 Subject: [PATCH 5/5] Add docstrings and clean up test slightly --- test/scripts/dummy_audio_folder.py | 8 +++++++- test/scripts/test_combined.py | 15 ++++++++++++--- test/scripts/test_engine.py | 4 ++++ test/scripts/test_train.py | 13 +++++++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/test/scripts/dummy_audio_folder.py b/test/scripts/dummy_audio_folder.py index aeeaba0..ae30b76 100644 --- a/test/scripts/dummy_audio_folder.py +++ b/test/scripts/dummy_audio_folder.py @@ -35,8 +35,14 @@ class DummyAudioFolder: return min + (max - min) * np.random.random() * pr.buffer_t def generate_samples(self, folder, name, value, duration): + """Generate sample file. + + The file is generated in the specified folder, with the specified name, + dummy value and duration. + """ for i in range(self.count): - save_audio(join(folder, name.format(i)), np.array([value] * int(duration * pr.sample_rate))) + save_audio(join(folder, name.format(i)), + np.array([value] * int(duration * pr.sample_rate))) def subdir(self, *parts): folder = self.path(*parts) diff --git a/test/scripts/test_combined.py b/test/scripts/test_combined.py index 6d02ead..175a8cc 100644 --- a/test/scripts/test_combined.py +++ b/test/scripts/test_combined.py @@ -26,18 +26,27 @@ def read_content(filename): def test_combined(train_folder, train_script): + """Test a "normal" development cycle, train, evaluate and calc threshold. + """ train_script.run() params_file = train_folder.model + '.params' assert isfile(train_folder.model) assert isfile(params_file) - EvalScript.create(folder=train_folder.root, models=[train_folder.model]).run() + EvalScript.create(folder=train_folder.root, + models=[train_folder.model]).run() + # Ensure that the graph script generates a numpy savez file out_file = train_folder.path('outputs.npz') - graph_script = GraphScript.create(folder=train_folder.root, models=[train_folder.model], output_file=out_file) + graph_script = GraphScript.create(folder=train_folder.root, + models=[train_folder.model], + output_file=out_file) graph_script.run() assert isfile(out_file) + # Esure the params are updated after threshold is calculated params_before = read_content(params_file) - CalcThresholdScript.create(folder=train_folder.root, model=train_folder.model, input_file=out_file).run() + CalcThresholdScript.create(folder=train_folder.root, + model=train_folder.model, + input_file=out_file).run() assert params_before != read_content(params_file) diff --git a/test/scripts/test_engine.py b/test/scripts/test_engine.py index 560548f..09129cd 100755 --- a/test/scripts/test_engine.py +++ b/test/scripts/test_engine.py @@ -36,6 +36,10 @@ class FakeStdout: def test_engine(train_folder, train_script): + """ + Test t hat the output format of the engina matches a decimal form in the + range 0.0 - 1.0. + """ train_script.run() with open(glob.glob(join(train_folder.root, 'wake-word', '*.wav'))[0], 'rb') as f: data = f.read() diff --git a/test/scripts/test_train.py b/test/scripts/test_train.py index 696c5d7..20e1ccb 100644 --- a/test/scripts/test_train.py +++ b/test/scripts/test_train.py @@ -22,15 +22,20 @@ from test.scripts.dummy_audio_folder import DummyAudioFolder class DummyTrainFolder(DummyAudioFolder): def __init__(self, count=10): super().__init__(count) - self.generate_samples(self.subdir('wake-word'), 'ww-{}.wav', 1.0, self.rand(0, 2 * pr.buffer_t)) - self.generate_samples(self.subdir('not-wake-word'), 'nww-{}.wav', 0.0, self.rand(0, 2 * pr.buffer_t)) - self.generate_samples(self.subdir('test', 'wake-word'), 'ww-{}.wav', 1.0, self.rand(0, 2 * pr.buffer_t)) - self.generate_samples(self.subdir('test', 'not-wake-word'), 'nww-{}.wav', 0.0, self.rand(0, 2 * pr.buffer_t)) + self.generate_samples(self.subdir('wake-word'), 'ww-{}.wav', 1.0, + self.rand(0, 2 * pr.buffer_t)) + self.generate_samples(self.subdir('not-wake-word'), 'nww-{}.wav', 0.0, + self.rand(0, 2 * pr.buffer_t)) + self.generate_samples(self.subdir('test', 'wake-word'), 'ww-{}.wav', + 1.0, self.rand(0, 2 * pr.buffer_t)) + self.generate_samples(self.subdir('test', 'not-wake-word'), + 'nww-{}.wav', 0.0, self.rand(0, 2 * pr.buffer_t)) self.model = self.path('model.net') class TestTrain: def test_run_basic(self): + """Run a training and check that a model is generated.""" folders = DummyTrainFolder(10) script = TrainScript.create(model=folders.model, folder=folders.root) script.run()