internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: MycroftAI/mycroft-core

Issue:
Listener waits too long and too often for more sound
Often when saying short queries in which the listener hasn't detected enough total noise it sits there waiting for more when in fact you are actually done speaking. To resolve this we should decrease the minimum seconds of noise and put a limit to how long it will wait (perhaps 3-4 seconds).



Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py
--- a/mycroft/client/speech/mic.py
+++ b/mycroft/client/speech/mic.py
@@ -126,12 +126,16 @@ class ResponsiveRecognizer(speech_recognition.Recognizer):
 
     # The minimum seconds of noise before a
     # phrase can be considered complete
-    MIN_LOUD_SEC_PER_PHRASE = 0.2
+    MIN_LOUD_SEC_PER_PHRASE = 0.1
 
     # The maximum length a phrase can be recorded,
     # provided there is noise the entire time
     RECORDING_TIMEOUT = 30.0
 
+    # The maximum time it will continue to record silence
+    # when not enough noise has been detected
+    RECORDING_TIMEOUT_WITH_SILENCE = 3.0
+
     # Time between pocketsphinx checks for the wake word
     SEC_BETWEEN_WW_CHECKS = 0.2
 
@@ -167,17 +171,17 @@ def record_phrase(self, source, sec_per_buffer):
         num_loud_chunks = 0
         noise = 0
 
-        max_noise = 20
+        max_noise = 25
         min_noise = 0
 
         def increase_noise(level):
             if level < max_noise:
-                return level + 2
+                return level + 200 * sec_per_buffer
             return level
 
         def decrease_noise(level):
             if level > min_noise:
-                return level - 1
+                return level - 100 * sec_per_buffer
             return level
 
         # Smallest number of loud chunks required to return
@@ -187,6 +191,10 @@ def decrease_noise(level):
         max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)
         num_chunks = 0
 
+        # Will return if exceeded this even if there's not enough loud chunks
+        max_chunks_of_silence = int(self.RECORDING_TIMEOUT_WITH_SILENCE /
+                                    sec_per_buffer)
+
         # bytearray to store audio in
         byte_data = '\0' * source.SAMPLE_WIDTH
 
@@ -205,7 +213,10 @@ def decrease_noise(level):
                 noise = decrease_noise(noise)
                 self.adjust_threshold(energy, sec_per_buffer)
 
-            if noise <= min_noise and num_loud_chunks > min_loud_chunks:
+            was_loud_enough = num_loud_chunks > min_loud_chunks
+            quiet_enough = noise <= min_noise
+            recorded_too_much_silence = num_chunks > max_chunks_of_silence
+            if quiet_enough and (was_loud_enough or recorded_too_much_silence):
                 phrase_complete = True
 
         return byte_data


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
"Whats" is not parsed out when searching WolframAlpha
`what is a dog` results in `I am searching for a dog` whereas `Whats a dog` results in `I am searching for whats a dog`.



Discussion:
This has to do with the basic EnglishQuestionParser that @clusterfudge made in the WA skill. It currently only removes certain words that it parses as question words. This doesn't actually affect what it sends to WA, though. Even though when you ask `what is a dog`, Mycroft responds `I am searching for a dog`, he still sends the query `what is a dog` to Wolfram. The removal of question words only affects responses to the user.

I think that just adding `whats` to the list of question words in the parser would work to solve this, but I was running into minor issues when I tried that out. 

@ethanaward What minor issues were you running into?

From what I remember, it was only working some of time, so `whats cats` would give `I'm searching for cats`, but `whats a cat` would give `I'm searching for whats a cat`.


Resolving patch:
diff --git a/mycroft/skills/wolfram_alpha/__init__.py b/mycroft/skills/wolfram_alpha/__init__.py
--- a/mycroft/skills/wolfram_alpha/__init__.py
+++ b/mycroft/skills/wolfram_alpha/__init__.py
@@ -46,6 +46,9 @@ def __init__(self):
                 ".*(?P<QuestionWord>who|what|when|where|why|which) "
                 "(?P<Query1>.*) (?P<QuestionVerb>is|are|was|were) "
                 "(?P<Query2>.*)"),
+            re.compile(
+                ".*(?P<QuestionWord>what)(?P<QuestionVerb>\'s|s) "
+                "(?P<Query>.*)"),
             re.compile(
                 ".*(?P<QuestionWord>who|what|when|where|why|which) "
                 "(?P<QuestionVerb>\w+) (?P<Query>.*)")


Test patch:
diff --git a/test/skills/wolfram_alpha/english_question_parser_test.py b/test/skills/wolfram_alpha/english_question_parser_test.py
new file mode 100644
--- /dev/null
+++ b/test/skills/wolfram_alpha/english_question_parser_test.py
@@ -0,0 +1,40 @@
+import unittest
+
+from mycroft.skills.wolfram_alpha import EnglishQuestionParser
+
+__author__ = 'wolfgange3311999'
+
+
+class EnglishQuestionParserTest(unittest.TestCase):
+    parser = EnglishQuestionParser()
+    test_jsons = [
+        {
+            'utterance': 'who is abraham lincoln',
+            'parsed_question': {
+                'QuestionWord': 'who',
+                'QuestionVerb': 'is',
+                'Query': 'abraham lincoln'
+            }
+        },
+        {
+            'utterance': 'what\'s a dog',
+            'parsed_question': {
+                'QuestionWord': 'what',
+                'QuestionVerb': '\'s',
+                'Query': 'a dog'
+            }
+        },
+        {
+            'utterance': 'who did this',
+            'parsed_question': {
+                'QuestionWord': 'who',
+                'QuestionVerb': 'did',
+                'Query': 'this'
+            }
+        }
+    ]
+
+    def test_question_parsing(self):
+        for test_json in self.test_jsons:
+            parsed_question = self.parser.parse(test_json['utterance'])
+            self.assertEquals(parsed_question, test_json['parsed_question'])
Repository: MycroftAI/mycroft-core

Issue:
Base media skill is loaded as a normal skill
At the moment, the load_skills function tries to load the media skill as if it is a normal skill. 



Discussion:

Resolving patch:
diff --git a/mycroft/skills/core.py b/mycroft/skills/core.py
--- a/mycroft/skills/core.py
+++ b/mycroft/skills/core.py
@@ -35,7 +35,7 @@
 __author__ = 'seanfitz'
 
 PRIMARY_SKILLS = ['intent', 'wake']
-BLACKLISTED_SKILLS = ["send_sms"]
+BLACKLISTED_SKILLS = ["send_sms", "media"]
 SKILLS_BASEDIR = dirname(__file__)
 THIRD_PARTY_SKILLS_DIR = "/opt/mycroft/third_party"
 


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
Mycroft is silent if enclosure/platform isn't configured
The platform check in `handle_speak` will fail if the `platform` or `enclosure` is missing from the config. For me it seems like the platform value isn't set.


Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/main.py b/mycroft/client/speech/main.py
--- a/mycroft/client/speech/main.py
+++ b/mycroft/client/speech/main.py
@@ -89,7 +89,7 @@ def handle_speak(event):
     #    
     # TODO: Remove or make an option?  This is really a hack, anyway,
     # so we likely will want to get rid of this when not running on Mimic
-    if not config.get('enclosure')['platform'] == "picroft":
+    if not config.get('enclosure', {}).get('platform') == "picroft":
         chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s',
                           utterance)
         for chunk in chunks:


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
Internet connection check fails when tls is blocked by network
Just as the title says. I am behind a weird firewall on a university network. Every command fails with the response "This device is not connected to the internet"  This is an issue with the connection check. When I edit "client/speech/listener.py", and just remove the check, Mycroft, can process voice commands just fine. I'm not sure if there is a better way to check network connections, but if there is, let me know, and I would be happy to implement it.



Discussion:
Interesting, thanks for creating an issue! We will keep it in mind, and feel free to make changes and a PR if you wish.

One possible fix that comes to mind is have it not fail when connected to the Internet, just speak. That would still provide the feedback while getting around this issue.

Thanks, I will review your PR

Due to network changes, I can no longer test this issue.

Resolving patch:
diff --git a/mycroft/client/speech/listener.py b/mycroft/client/speech/listener.py
--- a/mycroft/client/speech/listener.py
+++ b/mycroft/client/speech/listener.py
@@ -23,6 +23,7 @@
 import speech_recognition as sr
 from pyee import EventEmitter
 from requests import HTTPError
+from requests.exceptions import ConnectionError
 
 from mycroft.client.speech.local_recognizer import LocalRecognizer
 from mycroft.client.speech.mic import MutableMicrophone, ResponsiveRecognizer
@@ -127,11 +128,8 @@ def process(self, audio):
 
         if self._audio_length(audio) < self.MIN_AUDIO_SIZE:
             LOG.warn("Audio too short to be processed")
-        elif connected():
-            self.transcribe(audio)
         else:
-            # TODO: Localization
-            self.__speak("Mycroft seems not to be connected to the Internet")
+            self.transcribe(audio)
 
     def transcribe(self, audio):
         text = None
@@ -141,6 +139,9 @@ def transcribe(self, audio):
             LOG.debug("STT: " + text)
         except sr.RequestError as e:
             LOG.error("Could not request Speech Recognition {0}".format(e))
+        except ConnectionError as e:
+            LOG.error("Connection Error: {0}".format(e))
+            self.__speak("Mycroft seems not to be connected to the Internet")
         except HTTPError as e:
             if e.response.status_code == 401:
                 text = "pair my device"
diff --git a/mycroft/util/__init__.py b/mycroft/util/__init__.py
--- a/mycroft/util/__init__.py
+++ b/mycroft/util/__init__.py
@@ -19,6 +19,7 @@
 import socket
 import subprocess
 import tempfile
+import time
 
 import os
 import os.path
@@ -159,6 +160,11 @@ def connected(host="8.8.8.8", port=53, timeout=3):
     Host: 8.8.8.8 (google-public-dns-a.google.com)
     OpenPort: 53/tcp
     Service: domain (DNS/TCP)
+
+    NOTE:
+    This is no longer in use by this version
+    New method checks for a connection using ConnectionError only when
+    a question is asked
     """
     try:
         socket.setdefaulttimeout(timeout)


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
mimic tts fails silently when utterance contains unicode
It seems like hashing the unicode string for caching purposes causes an exception when unicode characters are parsed.


Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/main.py b/mycroft/client/speech/main.py
--- a/mycroft/client/speech/main.py
+++ b/mycroft/client/speech/main.py
@@ -103,7 +103,10 @@ def handle_speak(event):
         chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s',
                           utterance)
         for chunk in chunks:
-            mute_and_speak(chunk)
+            try:
+                mute_and_speak(chunk)
+            except:
+                logger.error('Error in mute_and_speak', exc_info=True)
     else:
         mute_and_speak(utterance)
 
diff --git a/mycroft/tts/mimic_tts.py b/mycroft/tts/mimic_tts.py
--- a/mycroft/tts/mimic_tts.py
+++ b/mycroft/tts/mimic_tts.py
@@ -20,6 +20,7 @@
 import os
 import os.path
 from time import time, sleep
+import unicodedata
 
 from mycroft import MYCROFT_ROOT_PATH
 from mycroft.configuration import ConfigurationManager
@@ -48,7 +49,7 @@ def init_args(self):
             self.args += ['--setf', 'duration_stretch=' + stretch]
 
     def get_tts(self, sentence):
-        key = str(hashlib.md5(sentence).hexdigest())
+        key = str(hashlib.md5(sentence.encode('utf-8', 'ignore')).hexdigest())
         wav_file = os.path.join(mycroft.util.get_cache_directory("tts"),
                                 key + ".wav")
 


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
Multi-sentence speak commands can't easily be stopped
If `self.speak()` is called from a skill with multiple sentences the stop functionality doesn't quite work. Only the current sentence is stopped and the following sentence will immediately be started in it's place.

Example:
```python
self.speak('First sentence that is quite long. This is the second sentence that is also of some length. Finally a third sentence.
```




Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/main.py b/mycroft/client/speech/main.py
--- a/mycroft/client/speech/main.py
+++ b/mycroft/client/speech/main.py
@@ -19,6 +19,7 @@
 import re
 import sys
 from threading import Thread, Lock
+import time
 
 from mycroft.client.enclosure.api import EnclosureAPI
 from mycroft.client.speech.listener import RecognizerLoop
@@ -36,6 +37,7 @@
 tts = TTSFactory.create()
 lock = Lock()
 loop = None
+_last_stop_signal = 0
 
 config = ConfigurationManager.get()
 
@@ -80,6 +82,8 @@ def handle_multi_utterance_intent_failure(event):
 
 
 def handle_speak(event):
+    global _last_stop_signal
+
     utterance = event.data['utterance']
     expect_response = event.data.get('expect_response', False)
 
@@ -95,10 +99,13 @@ def handle_speak(event):
         chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s',
                           utterance)
         for chunk in chunks:
+            now = time.time()
             try:
                 mute_and_speak(chunk)
             except:
                 logger.error('Error in mute_and_speak', exc_info=True)
+            if _last_stop_signal > now:
+                break
     else:
         mute_and_speak(utterance)
 
@@ -115,6 +122,8 @@ def handle_wake_up(event):
 
 
 def handle_stop(event):
+    global _last_stop_signal
+    _last_stop_signal = time.time()
     kill([config.get('tts').get('module')])
     kill(["aplay"])
 


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
skill container is broken
When the intent skill became the intent class the skill container wasn't updated to match the new structure and is currently not working.


Discussion:

Resolving patch:
diff --git a/mycroft/skills/container.py b/mycroft/skills/container.py
--- a/mycroft/skills/container.py
+++ b/mycroft/skills/container.py
@@ -23,7 +23,7 @@
 from mycroft.configuration import ConfigurationManager
 from mycroft.messagebus.client.ws import WebsocketClient
 from mycroft.skills.core import create_skill_descriptor, load_skill
-from mycroft.skills.intent import create_skill as create_intent_skill
+from mycroft.skills.intent import Intent
 from mycroft.util.log import getLogger
 
 __author__ = 'seanfitz'
@@ -44,7 +44,7 @@ def __init__(self, args):
         sys.path.append(params.dir)
         self.dir = params.dir
 
-        self.enable_intent_skill = params.enable_intent_skill
+        self.enable_intent = params.enable_intent
 
         self.__init_client(params)
 
@@ -57,7 +57,7 @@ def __build_params(args):
         parser.add_argument("--host", default=None)
         parser.add_argument("--port", default=None)
         parser.add_argument("--use-ssl", action='store_true', default=False)
-        parser.add_argument("--enable-intent-skill", action='store_true',
+        parser.add_argument("--enable-intent", action='store_true',
                             default=False)
         return parser.parse_args(args)
 
@@ -74,10 +74,9 @@ def __init_client(self, params):
                                   ssl=params.use_ssl)
 
     def load_skill(self):
-        if self.enable_intent_skill:
-            intent_skill = create_intent_skill()
-            intent_skill.bind(self.ws)
-            intent_skill.initialize()
+        if self.enable_intent:
+            Intent(self.ws)
+
         skill_descriptor = create_skill_descriptor(self.dir)
         self.skill = load_skill(skill_descriptor, self.ws)
 


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
ipc signals fails
interprocess communication signals may fail if the `$TMP/mycroft/ipc/signal` direcory is missing. The creation needs to make sure the directory exists before creating the signal file.


Discussion:

Resolving patch:
diff --git a/mycroft/util/__init__.py b/mycroft/util/__init__.py
--- a/mycroft/util/__init__.py
+++ b/mycroft/util/__init__.py
@@ -136,6 +136,11 @@ def read_dict(filename, div='='):
 
 
 def create_file(filename):
+    """ Create the file filename and create any directories needed
+
+        Args:
+            filename: Path to the file to be created
+    """
     try:
         os.makedirs(dirname(filename))
     except OSError:
@@ -301,9 +306,9 @@ def create_signal(signal_name):
             valid in filenames.
     """
     try:
-        with open(os.path.join(get_ipc_directory(), "signal", signal_name),
-                  'w'):
-            return True
+        path = os.path.join(get_ipc_directory(), "signal", signal_name)
+        create_file(path)
+        return os.path.isfile(path)
     except IOError:
         return False
 
@@ -321,7 +326,6 @@ def check_for_signal(signal_name, sec_lifetime=0):
         bool: True if the signal is defined, False otherwise
     """
     path = os.path.join(get_ipc_directory(), "signal", signal_name)
-
     if os.path.isfile(path):
         if sec_lifetime == 0:
             # consume this single-use signal


Test patch:
diff --git a/test/util/__init__.py b/test/util/__init__.py
new file mode 100644
diff --git a/test/util/test_signal.py b/test/util/test_signal.py
new file mode 100644
--- /dev/null
+++ b/test/util/test_signal.py
@@ -0,0 +1,30 @@
+from os.path import dirname, join, exists, isfile
+import unittest
+from shutil import rmtree
+from mycroft.util import create_signal, check_for_signal
+
+
+class TestSignals(unittest.TestCase):
+    def setUp(self):
+        if exists('/tmp/mycroft'):
+            rmtree('/tmp/mycroft')
+
+    def test_create_signal(self):
+        create_signal('test_signal')
+        self.assertTrue(isfile('/tmp/mycroft/ipc/signal/test_signal'))
+
+    def test_check_signal(self):
+        if exists('/tmp/mycroft'):
+            rmtree('/tmp/mycroft')
+        # check that signal is not found if file does not exist
+        self.assertFalse(check_for_signal('test_signal'))
+
+        # Check that the signal is found when created
+        create_signal('test_signal')
+        self.assertTrue(check_for_signal('test_signal'))
+        # Check that the signal is removed after use
+        self.assertFalse(isfile('/tmp/mycroft/ipc/signal/test_signal'))
+
+
+if __name__ == "__main__":
+    unittest.main()
Repository: MycroftAI/mycroft-core

Issue:
Typing error in recognize_google() methode
In mycroft/stt/\_\_init\_\_.py line 74 :
Replacing mistyped 's' parameter by self.lang fixed the problem.


Discussion:
Thanks for reporting (and providing a solution), I'll take a look at it.

Resolving patch:
diff --git a/mycroft/stt/__init__.py b/mycroft/stt/__init__.py
--- a/mycroft/stt/__init__.py
+++ b/mycroft/stt/__init__.py
@@ -71,7 +71,7 @@ def __init__(self):
 
     def execute(self, audio, language=None):
         self.lang = language or self.lang
-        return self.recognizer.recognize_google(audio, self.token, s)
+        return self.recognizer.recognize_google(audio, self.token, self.lang)
 
 
 class WITSTT(TokenSTT):


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
Report errors while installing default skills
Installing default skills may fail quietly in some conditions, ideally some feedback to the user should be given.


Discussion:

Resolving patch:
diff --git a/mycroft/skills/main.py b/mycroft/skills/main.py
--- a/mycroft/skills/main.py
+++ b/mycroft/skills/main.py
@@ -57,16 +57,25 @@ def connect():
 
 
 def install_default_skills(speak=True):
+    """
+        Install default skill set using msm.
+
+        Args:
+            speak (optional): Enable response for success. Default True
+    """
     if exists(MSM_BIN):
-        p = subprocess.Popen(MSM_BIN + " default", stderr=subprocess.STDOUT,
-                             stdout=subprocess.PIPE, shell=True)
-        t = p.communicate()[0]
-        if t.splitlines()[-1] == "Installed!" and speak:
+        res = subprocess.call(MSM_BIN + " default", stderr=subprocess.STDOUT,
+                              stdout=subprocess.PIPE, shell=True)
+        if res == 0 and speak:
             ws.emit(Message("speak", {
                 'utterance': mycroft.dialog.get("skills updated")}))
         elif not connected():
             ws.emit(Message("speak", {
                 'utterance': mycroft.dialog.get("no network connection")}))
+        elif res != 0:
+            ws.emit(Message("speak", {
+                'utterance': mycroft.dialog.get(
+                             "sorry I couldn't install default skills")}))
 
     else:
         logger.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)


Test patch:
Repository: MycroftAI/mycroft-core

Issue:
the WuW is not detected in slow speech or long WuW case
The hard coded duration of the wake up word, set to 1 sc,  is not suitable for slow speech or when the configured WuW is long. To handle such cases, the duration may be estimated from the phonological representation of the WuW.

As the phoneme duration highly depends on the speaking rate, the category of the phoneme and its context, a precise estimation will be hard, furthermore it is not required for the given purpose. So an overall estimation can be accepted.

From a fast review of some phonetical measures, the average duration of a vowel/consonant in different speaking rates is :
- fast speech :  vowel=60ms, consonant=30ms; syllabes=90ms
- normal speech : vowel=100ms, consonant=50ms; syllabes=150ms
- slow speech : vowel=250ms, consonant=75ms; syllabes=340ms

I think 100ms per phoneme will be enough, may be +10-20% to handle so slow speech.

possible solution :
- in mycroft.client.speech.mic, ResponsiveRecognizer::__init__() :
self.SAVED_WW_SEC = (wake_word_recognizer.phonemes.count( ' ' ) + 1 ) * 0.12






Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py
--- a/mycroft/client/speech/mic.py
+++ b/mycroft/client/speech/mic.py
@@ -130,10 +130,6 @@ def unmute(self):
 
 
 class ResponsiveRecognizer(speech_recognition.Recognizer):
-    # The maximum audio in seconds to keep for transcribing a phrase
-    # The wake word must fit in this time
-    SAVED_WW_SEC = 1.0
-
     # Padding of silence when feeding to pocketsphinx
     SILENCE_SEC = 0.01
 
@@ -157,6 +153,12 @@ class ResponsiveRecognizer(speech_recognition.Recognizer):
     SEC_BETWEEN_WW_CHECKS = 0.2
 
     def __init__(self, wake_word_recognizer):
+        # The maximum audio in seconds to keep for transcribing a phrase
+        # The wake word must fit in this time
+        num_phonemes = len(listener_config.get('phonemes').split())
+        len_phoneme = listener_config.get('phoneme_duration', 120) / 1000.0
+        self.SAVED_WW_SEC = num_phonemes * len_phoneme
+
         speech_recognition.Recognizer.__init__(self)
         self.wake_word_recognizer = wake_word_recognizer
         self.audio = pyaudio.PyAudio()


Test patch: