Hello community,

here is the log from the commit of package python-precise-runner for 
openSUSE:Factory checked in at 2019-06-06 18:15:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-precise-runner (Old)
 and      /work/SRC/openSUSE:Factory/.python-precise-runner.new.4811 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-precise-runner"

Thu Jun  6 18:15:49 2019 rev:2 rq:707125 version:0.3.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-precise-runner/python-precise-runner.changes  
    2018-07-31 16:00:20.695642714 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-precise-runner.new.4811/python-precise-runner.changes
    2019-06-06 18:15:49.812712244 +0200
@@ -1,0 +2,6 @@
+Mon Jun  3 10:29:36 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 0.3.1:
+  * Upstream changelog mentions only massive number of improvements
+
+-------------------------------------------------------------------

Old:
----
  precise-runner-0.2.1.tar.gz

New:
----
  precise-runner-0.3.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-precise-runner.spec ++++++
--- /var/tmp/diff_new_pack.XrrFte/_old  2019-06-06 18:15:50.700711985 +0200
+++ /var/tmp/diff_new_pack.XrrFte/_new  2019-06-06 18:15:50.704711983 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-precise-runner
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,20 +12,23 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-precise-runner
-Version:        0.2.1
+Version:        0.3.1
 Release:        0
 Summary:        Wrapper to use Mycroft Precise Wake Word Listener
 License:        Apache-2.0
 Group:          Development/Languages/Python
 URL:            http://github.com/MycroftAI/mycroft-precise
 Source:         
https://files.pythonhosted.org/packages/source/p/precise-runner/precise-runner-%{version}.tar.gz
+# https://github.com/MycroftAI/mycroft-precise/issues/74
 Source99:       
https://raw.githubusercontent.com/MycroftAI/mycroft-precise/dev/LICENSE
+BuildRequires:  %{python_module PyAudio}
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -47,6 +50,9 @@
 %python_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
+%check
+%pytest
+
 %files %{python_files}
 %doc README.md
 %license LICENSE

++++++ precise-runner-0.2.1.tar.gz -> precise-runner-0.3.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/PKG-INFO 
new/precise-runner-0.3.1/PKG-INFO
--- old/precise-runner-0.2.1/PKG-INFO   2018-06-19 01:43:54.000000000 +0200
+++ new/precise-runner-0.3.1/PKG-INFO   2019-05-15 09:34:33.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: precise-runner
-Version: 0.2.1
+Version: 0.3.1
 Summary: Wrapper to use Mycroft Precise Wake Word Listener
 Home-page: http://github.com/MycroftAI/mycroft-precise
 Author: Matthew Scholefield
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/README.md 
new/precise-runner-0.3.1/README.md
--- old/precise-runner-0.2.1/README.md  2018-04-18 07:12:20.000000000 +0200
+++ new/precise-runner-0.3.1/README.md  2019-05-01 08:04:54.000000000 +0200
@@ -12,7 +12,8 @@
 
 ```bash
 ARCH=x86_64
-wget 
https://github.com/MycroftAI/precise-data/raw/dist/$ARCH/precise-engine.tar.gz
+VERSION=0.3.0
+wget 
https://github.com/MycroftAI/mycroft-precise/releases/download/$VERSION/precise-all_${VERSION}_${ARCH}.tar.gz
 tar xvf precise-engine.tar.gz
 ```
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/precise_runner/__init__.py 
new/precise-runner-0.3.1/precise_runner/__init__.py
--- old/precise-runner-0.2.1/precise_runner/__init__.py 2018-06-18 
23:16:33.000000000 +0200
+++ new/precise-runner-0.3.1/precise_runner/__init__.py 2019-05-15 
09:33:10.000000000 +0200
@@ -1,3 +1,3 @@
 from .runner import PreciseRunner, PreciseEngine, ReadWriteStream
 
-__version__ = '0.2.1'
+__version__ = '0.3.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/precise_runner/runner.py 
new/precise-runner-0.3.1/precise_runner/runner.py
--- old/precise-runner-0.2.1/precise_runner/runner.py   2018-06-12 
20:57:40.000000000 +0200
+++ new/precise-runner-0.3.1/precise_runner/runner.py   2019-05-15 
09:32:34.000000000 +0200
@@ -1,5 +1,5 @@
 # Python 2 + 3
-# Copyright 2018 Mycroft AI Inc.
+# 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.
@@ -13,6 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 import atexit
+
+import time
 from subprocess import PIPE, Popen
 from threading import Thread, Event
 
@@ -72,17 +74,31 @@
 
 
 class ReadWriteStream(object):
-    """Class used to support writing binary audio data at any pace"""
-    def __init__(self, s=b''):
+    """
+    Class used to support writing binary audio data at any pace,
+    optionally chopping when the buffer gets too large
+    """
+    def __init__(self, s=b'', chop_samples=-1):
         self.buffer = s
         self.write_event = Event()
+        self.chop_samples = chop_samples
+
+    def __len__(self):
+        return len(self.buffer)
 
     def read(self, n=-1, timeout=None):
         if n == -1:
             n = len(self.buffer)
+        if 0 < self.chop_samples < len(self.buffer):
+            samples_left = len(self.buffer) % self.chop_samples
+            self.buffer = self.buffer[-samples_left:]
+        return_time = 1e10 if timeout is None else (
+                timeout + time.time()
+        )
         while len(self.buffer) < n:
             self.write_event.clear()
-            self.write_event.wait(timeout)
+            if not self.write_event.wait(return_time - time.time()):
+                return b''
         chunk = self.buffer[:n]
         self.buffer = self.buffer[n:]
         return chunk
@@ -92,6 +108,36 @@
         self.write_event.set()
 
 
+class TriggerDetector:
+    """
+    Reads predictions and detects activations
+    This prevents multiple close activations from occurring when
+    the predictions look like ...!!!..!!...
+    """
+    def __init__(self, chunk_size, sensitivity=0.5, trigger_level=3):
+        self.chunk_size = chunk_size
+        self.sensitivity = sensitivity
+        self.trigger_level = trigger_level
+        self.activation = 0
+
+    def update(self, prob):
+        # type: (float) -> bool
+        """Returns whether the new prediction caused an activation"""
+        chunk_activated = prob > 1.0 - self.sensitivity
+
+        if chunk_activated or self.activation < 0:
+            self.activation += 1
+            has_activated = self.activation > self.trigger_level
+            if has_activated or chunk_activated and self.activation < 0:
+                self.activation = -(8 * 2048) // self.chunk_size
+
+            if has_activated:
+                return True
+        elif self.activation > 0:
+            self.activation -= 1
+        return False
+
+
 class PreciseRunner(object):
     """
     Wrapper to use Precise. Example:
@@ -107,8 +153,7 @@
         engine (Engine): Object containing info on the binary engine
         trigger_level (int): Number of chunk activations needed to trigger 
on_activation
                        Higher values add latency but reduce false positives
-        sensitivity (float): From 0.0 to 1.0, relates to the network output 
level required
-                             to consider a chunk "active"
+        sensitivity (float): From 0.0 to 1.0, how sensitive the network should 
be
         stream (BinaryIO): Binary audio stream to read 16000 Hz 1 channel int16
                            audio from. If not given, the microphone is used
         on_prediction (Callable): callback for every new prediction
@@ -119,31 +164,26 @@
                  on_prediction=lambda x: None, on_activation=lambda: None):
         self.engine = engine
         self.trigger_level = trigger_level
-        self.sensitivity = sensitivity
         self.stream = stream
         self.on_prediction = on_prediction
         self.on_activation = on_activation
         self.chunk_size = engine.chunk_size
-        self.read_divisor = 1
 
         self.pa = None
         self.thread = None
         self.running = False
         self.is_paused = False
+        self.detector = TriggerDetector(self.chunk_size, sensitivity, 
trigger_level)
         atexit.register(self.stop)
 
-    def _calc_read_divisor(self):
+    def _wrap_stream_read(self, stream):
         """
         pyaudio.Stream.read takes samples as n, not bytes
-        so read(n) should be read(n // sample_depth
+        so read(n) should be read(n // sample_depth)
         """
-        try:
-            import pyaudio
-            if isinstance(self.stream, pyaudio.Stream):
-                return 2
-        except ImportError:
-            pass
-        return 1
+        import pyaudio
+        if getattr(stream.read, '__func__', None) is pyaudio.Stream.read:
+            stream.read = lambda x: pyaudio.Stream.read(stream, x // 2, False)
 
     def start(self):
         """Start listening from stream"""
@@ -154,12 +194,12 @@
                 16000, 1, paInt16, True, frames_per_buffer=self.chunk_size
             )
 
-        self.read_divisor = self._calc_read_divisor()
+        self._wrap_stream_read(self.stream)
 
         self.engine.start()
         self.running = True
         self.is_paused = False
-        self.thread = Thread(target=self._handle_predictions)
+        self.thread = Thread(target=self._handle_predictions, daemon=True)
         self.thread.daemon = True
         self.thread.start()
 
@@ -187,24 +227,13 @@
 
     def _handle_predictions(self):
         """Continuously check Precise process output"""
-        activation = 0
         while self.running:
-            chunk = self.stream.read(self.chunk_size // self.read_divisor)
+            chunk = self.stream.read(self.chunk_size)
 
             if self.is_paused:
                 continue
 
             prob = self.engine.get_prediction(chunk)
             self.on_prediction(prob)
-            chunk_activated = prob > 1 - self.sensitivity
-
-            if chunk_activated or activation < 0:
-                activation += 1
-                has_activated = activation > self.trigger_level
-                if has_activated:
-                    self.on_activation()
-
-                if has_activated or chunk_activated and activation < 0:
-                    activation = -(8 * 2048) // self.chunk_size
-            elif activation > 0:
-                activation -= 1
+            if self.detector.update(prob):
+                self.on_activation()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/precise-runner-0.2.1/precise_runner.egg-info/PKG-INFO 
new/precise-runner-0.3.1/precise_runner.egg-info/PKG-INFO
--- old/precise-runner-0.2.1/precise_runner.egg-info/PKG-INFO   2018-06-19 
01:43:54.000000000 +0200
+++ new/precise-runner-0.3.1/precise_runner.egg-info/PKG-INFO   2019-05-15 
09:34:33.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: precise-runner
-Version: 0.2.1
+Version: 0.3.1
 Summary: Wrapper to use Mycroft Precise Wake Word Listener
 Home-page: http://github.com/MycroftAI/mycroft-precise
 Author: Matthew Scholefield
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/precise-runner-0.2.1/precise_runner.egg-info/SOURCES.txt 
new/precise-runner-0.3.1/precise_runner.egg-info/SOURCES.txt
--- old/precise-runner-0.2.1/precise_runner.egg-info/SOURCES.txt        
2018-06-19 01:43:54.000000000 +0200
+++ new/precise-runner-0.3.1/precise_runner.egg-info/SOURCES.txt        
2019-05-15 09:34:33.000000000 +0200
@@ -2,9 +2,11 @@
 setup.py
 precise_runner/__init__.py
 precise_runner/runner.py
+precise_runner/util.py
 precise_runner.egg-info/PKG-INFO
 precise_runner.egg-info/SOURCES.txt
 precise_runner.egg-info/dependency_links.txt
 precise_runner.egg-info/requires.txt
 precise_runner.egg-info/top_level.txt
-precise_runner.egg-info/zip-safe
\ No newline at end of file
+precise_runner.egg-info/zip-safe
+test/test_runner.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/setup.py 
new/precise-runner-0.3.1/setup.py
--- old/precise-runner-0.2.1/setup.py   2018-04-18 07:12:20.000000000 +0200
+++ new/precise-runner-0.3.1/setup.py   2019-03-20 16:53:04.000000000 +0100
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-# Copyright 2018 Mycroft AI Inc.
+# 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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/precise-runner-0.2.1/test/test_runner.py 
new/precise-runner-0.3.1/test/test_runner.py
--- old/precise-runner-0.2.1/test/test_runner.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/precise-runner-0.3.1/test/test_runner.py        2019-05-13 
18:42:32.000000000 +0200
@@ -0,0 +1,18 @@
+from precise_runner import ReadWriteStream
+
+
+class TestReadWriteStream:
+    def test_read_write(self):
+        s = ReadWriteStream(b'1234567890')
+        assert s.read(2) == b'12'
+        assert s.read(2) == b'34'
+        s.write(b'hi')
+        assert s.read() == b'567890hi'
+        s.write(b'hello')
+        assert s.read() == b'hello'
+        assert s.read(1, timeout=0.1) == b''
+
+    def test_chop(self):
+        s = ReadWriteStream(chop_samples=10)
+        s.write(b'1234567890hello')
+        assert s.read(5) == b'hello'


Reply via email to