Преглед изворни кода

Merge pull request #436 from kalliope-project/feature/introduce_mute_settings

Feature/introduce mute settings
Nicolas Marcq пре 7 година
родитељ
комит
a7697d9723

+ 4 - 4
Docs/kalliope_cli.md

@@ -96,18 +96,18 @@ You can combine the options together like, for example:
 kalliope start --run-synapse "say-hello" --brain-file /home/me/my_other_brain.yml
 ```
 
-### --muted
+### --deaf
 
-Starts Kalliope in a muted state.
+Starts Kalliope in a deaf state, the trigger is paused.
 
 Example of use
 ```bash
-kalliope start --muted
+kalliope start --deaf
 ```
 
 You can combine the options together like, for example:
 ```bash
-kalliope start --muted --brain-file /home/me/my_other_brain.yml
+kalliope start --deaf --brain-file /home/me/my_other_brain.yml
 ```
 
 ### --debug

+ 55 - 15
Docs/rest_api.md

@@ -12,6 +12,8 @@ Kalliope provides the REST API to manage the synapses. For configuring the API r
 | POST   | /synapses/start/id/<synapse_name> | Run a synapse by its name          |
 | POST   | /synapses/start/order             | Run a synapse from a text order    |
 | POST   | /synapses/start/audio             | Run a synapse from an audio sample |
+| GET    | /deaf                             | Get the current deaf status        |
+| POST   | /deaf                             | Switch the deaf status             |
 | GET    | /mute                             | Get the current mute status        |
 | POST   | /mute                             | Switch the mute status             |
 
@@ -149,11 +151,11 @@ Output example:
 }
 ```
 
-The [no_voice flag](#no-voice-flag) can be added to this call.
+The [mute flag](#mute-flag) can be added to this call.
 Curl command:
 ```bash
 curl -i -H "Content-Type: application/json" --user admin:secret -X POST \
--d '{"no_voice":"true"}' http://127.0.0.1:5000/synapses/start/id/say-hello-fr
+-d '{"mute":"true"}' http://127.0.0.1:5000/synapses/start/id/say-hello-fr
 ```
 
 Some neuron inside a synapse will wait for parameters that comes from the order. 
@@ -234,11 +236,11 @@ Or return an empty list of matched synapse
 }
 ```
 
-The [no_voice flag](#no-voice-flag) can be added to this call.
+The [mute flag](#mute-flag) can be added to this call.
 Curl command:
 ```bash
 curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
--d '{"order":"my order", "no_voice":"true"}' http://localhost:5000/synapses/start/order
+-d '{"order":"my order", "mute":"true"}' http://localhost:5000/synapses/start/order
 ```
 
 ### Run a synapse from an audio file
@@ -302,10 +304,10 @@ Or return an empty list of matched synapse
 }
 ```
 
-The [no_voice flag](#no-voice-flag) can be added to this call with a form.
+The [mute flag](#mute-flag) can be added to this call with a form.
 Curl command:
 ```bash
-curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/audio -F "file=@path/to/file.wav" -F no_voice="true"
+curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/audio -F "file=@path/to/file.wav" -F mute="true"
 ```
 
 #### The neurotransmitter case
@@ -351,7 +353,7 @@ The response should be as follow:
 The ```"status": "waiting_for_answer"``` indicates that it waits for a response, so let's send it:
 
 ```bash
- --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"not at all"}' http://localhost:5000/synapses/start/order
+curl -i --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"not at all"}' http://localhost:5000/synapses/start/order
 ```
 
 ```JSON
@@ -390,42 +392,80 @@ The ```"status": "waiting_for_answer"``` indicates that it waits for a response,
 
 And now the status is complete. This works also when you have nested neurotransmitter neurons, you just need to keep monitoring the status from the API answer.
 
-### Get mute status
+### Get deaf status
 
 Normal response codes: 200
 Error response codes: unauthorized(401), Bad request(400)
 
 Curl command:
 ```bash
-curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/mute
+curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/deaf
 ```
 
 Output example:
 ```JSON
 {
-  "mute": true
+  "deaf": true
 }
 ```
 
-### Switch mute status
+### Switch deaf status
+Kalliope can switch to 'deaf' mode, so she can not ear you anymore, the trigger/hotword is desactivated.
+However Kalliope continues to process synapses.
 
 Normal response codes: 200
 Error response codes: unauthorized(401), Bad request(400)
 
 Curl command:
 ```bash
-curl -i -H "Content-Type: application/json" --user admin:secret  -X POST -d '{"mute": "True"}' http://127.0.0.1:5000/mute
+curl -i -H "Content-Type: application/json" --user admin:secret  -X POST -d '{"deaf": "True"}' http://127.0.0.1:5000/deaf
 ```
 
 Output example:
 ```JSON
 {
-  "mute": true
+  "deaf": true
 }
 ```
 
-## No voice flag
+## Mute flag
 
 When you use the API, by default Kalliope will generate a text and process it into the TTS engine.
 Some calls to the API can be done with a flag that will tell Kalliope to only return the generated text without processing it into the audio player.
-When `no_voice` is switched to true, Kalliope will not speak out loud on the server side.
+When `mute` is switched to true, Kalliope will not speak out loud on the server side.
+
+### Get mute status
+
+Normal response codes: 200
+Error response codes : unauthorized(401), Bad request(400)
+
+
+Curl command:
+```bash
+curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/mute
+```
+
+Output example:
+```JSON
+{
+  "mute": true
+}
+```
+
+### Set mute status
+
+Normal response codes: 200
+Error response codes : unauthorized(401), Bad request(400)
+
+
+Curl command:
+```bash
+curl -i -H "Content-Type: application/json" --user admin:secret  -X POST -d '{"mute": "True"}' http://127.0.0.1:5000/mute
+```
+
+Output example:
+```JSON
+{
+  "mute": true
+}
+```

+ 5 - 3
Docs/settings.md

@@ -246,8 +246,10 @@ List of available hook
 | on_order_found         | When the pronounced order has been found in the brain           |
 | on_order_not_found     | When the pronounced order has not been found in the brain       |
 | on_processed_synapses  | When all neurons in synapses have been processed                |
-| on_mute                | When Kalliope switches from non muted to muted                  |
-| on_unmute              | When Kalliope switches from muted to non muted                  |
+| on_deaf                | When Kalliope switches from non deaf to deaf                    |
+| on_undeaf              | When Kalliope switches from deaf to non deaf                    |
+| on_mute                | When Kalliope switches from non mute to mute                    |
+| on_unmute              | When Kalliope switches from mute to non mute                    |
 | on_start_speaking      | When Kalliope starts speaking via the text to speech engine     |
 | on_stop_speaking       | When Kalliope stops speaking                                    |
 
@@ -461,7 +463,7 @@ Options that can be defined when kalliope starts.
 
 Example config
 ```yaml
-start_options:
+options:
   muted: True
 ```
 

+ 5 - 2
Tests/settings/settings_test.yml

@@ -92,6 +92,8 @@ hooks:
   on_order_not_found:
     - "order-not-found-synapse"
   on_processed_synapses:
+  on_deaf: []
+  on_undeaf: []
   on_mute: []
   on_unmute: []
   on_start_speaking:
@@ -113,5 +115,6 @@ resource_directory:
 var_files:
   - "../Tests/settings/variables.yml"
 
-start_options:
-  muted: True
+options:
+  deaf: True
+  mute: False

+ 2 - 2
Tests/test_hook_manager.py

@@ -77,11 +77,11 @@ class TestInit(unittest.TestCase):
     def test_on_processed_synapses(self):
         self.assertIsNone(HookManager.on_processed_synapses())
 
-    def test_on_mute(self):
+    def test_on_deaf(self):
         """
         test that empty list of synapse return none
         """
-        self.assertIsNone(HookManager.on_mute())
+        self.assertIsNone(HookManager.on_deaf())
 
 
 if __name__ == '__main__':

+ 4 - 4
Tests/test_models.py

@@ -259,7 +259,7 @@ class TestModels(unittest.TestCase):
                                 resources=None,
                                 variables={"key1": "val1"},
                                 recognition_options=recognition_options,
-                                start_options={'muted': False})
+                                options={'deaf': False, 'mute': False})
             setting1.kalliope_version = "0.4.5"
 
             setting2 = Settings(default_tts_name="accapela",
@@ -274,7 +274,7 @@ class TestModels(unittest.TestCase):
                                 resources=None,
                                 variables={"key1": "val1"},
                                 recognition_options=recognition_options,
-                                start_options={'muted': False})
+                                options={'deaf': False, 'mute': False})
             setting2.kalliope_version = "0.4.5"
 
             setting3 = Settings(default_tts_name="pico2wav",
@@ -290,7 +290,7 @@ class TestModels(unittest.TestCase):
                                 resources=None,
                                 variables={"key1": "val1"},
                                 recognition_options=recognition_options,
-                                start_options={'muted': False})
+                                options={'deaf': False, 'mute': False})
             setting3.kalliope_version = "0.4.5"
 
             expected_result_serialize = {
@@ -318,7 +318,7 @@ class TestModels(unittest.TestCase):
                 'triggers': ['snowboy'],
                 'players': ['mplayer'],
                 'recognition_options': {'energy_threshold': 4000, 'adjust_for_ambient_noise_second': 0},
-                'start_options': {'muted': False}
+                'options': {'deaf': False, 'mute': False}
             }
 
             self.maxDiff = None

+ 18 - 8
Tests/test_settings_loader.py

@@ -51,15 +51,17 @@ class TestSettingLoader(unittest.TestCase):
                 {'voxygen': {'voice': 'Agnes', 'cache': True}}
                 ],
             'var_files': ["../Tests/settings/variables.yml"],
-            'start_options': {'muted': True},
+            'options': {'deaf': True, 'mute': False},
             'hooks': {'on_waiting_for_trigger': 'test',
                       'on_stop_listening': None,
                       'on_start_listening': None,
                       'on_order_found': None,
                       'on_start': ['on-start-synapse', 'bring-led-on'],
-                      'on_unmute': [],
+                      'on_undeaf': [],
                       'on_triggered': ['on-triggered-synapse'],
+                      'on_deaf': [],
                       'on_mute': [],
+                      'on_unmute': [],
                       'on_order_not_found': [
                           'order-not-found-synapse'],
                       'on_processed_synapses': None,
@@ -123,8 +125,9 @@ class TestSettingLoader(unittest.TestCase):
             "test_number": 60,
             "test": "kalliope"
         }
-        settings_object.start_options = {
-            "muted": True
+        settings_object.options = {
+            "deaf": True,
+            "mute": False
         }
         settings_object.machine = platform.machine()
         settings_object.recognition_options = RecognitionOptions()
@@ -133,9 +136,11 @@ class TestSettingLoader(unittest.TestCase):
                                  'on_start_listening': None,
                                  'on_order_found': None,
                                  'on_start': ['on-start-synapse', 'bring-led-on'],
-                                 'on_unmute': [],
+                                 'on_undeaf': [],
                                  'on_triggered': ['on-triggered-synapse'],
+                                 'on_deaf': [],
                                  'on_mute': [],
+                                 'on_unmute': [],
                                  'on_order_not_found': [
                                      'order-not-found-synapse'],
                                  'on_processed_synapses': None,
@@ -221,13 +226,14 @@ class TestSettingLoader(unittest.TestCase):
         self.assertEqual(expected_result,
                          sl._get_variables(self.settings_dict))
 
-    def test_get_start_options(self):
+    def test_get_options(self):
         expected_result = {
-            "muted": True
+            "deaf": True,
+            "mute": False
         }
         sl = SettingLoader(file_path=self.settings_file_to_test)
         self.assertEqual(expected_result,
-                         sl._get_start_options(self.settings_dict))
+                         sl._get_options(self.settings_dict))
 
     def test_get_hooks(self):
 
@@ -245,6 +251,8 @@ class TestSettingLoader(unittest.TestCase):
             "on_stop_listening": None,
             "on_order_found": None,
             "on_order_not_found": None,
+            "on_deaf": None,
+            "on_undeaf": None,
             "on_mute": None,
             "on_unmute": None,
             "on_start_speaking": None,
@@ -266,6 +274,8 @@ class TestSettingLoader(unittest.TestCase):
             "on_stop_listening": None,
             "on_order_found": None,
             "on_order_not_found": None,
+            "on_deaf": None,
+            "on_undeaf": None,
             "on_mute": None,
             "on_unmute": None,
             "on_start_speaking": None,

+ 2 - 2
brain_examples/mute.yml

@@ -1,10 +1,10 @@
 
-- name: "mute-synapse"
+- name: "deaf-synapse"
   signals:
     - order: "stop listening"
   neurons:
     - say:
         message:
           - "I stop hearing you, sir"
-    - mute:
+    - deaf:
         status: True

+ 4 - 4
kalliope/__init__.py

@@ -63,7 +63,7 @@ def parse_args(args):
     parser.add_argument("--tts-name", help="TTS name to uninstall")
     parser.add_argument("--trigger-name", help="Trigger name to uninstall")
     parser.add_argument("--signal-name", help="Signal name to uninstall")
-    parser.add_argument("--muted", action='store_true', help="Starts Kalliope muted")
+    parser.add_argument("--deaf", action='store_true', help="Starts Kalliope deaf")
     parser.add_argument('-v', '--version', action='version',
                         version='Kalliope ' + version_str)
 
@@ -155,9 +155,9 @@ def main():
                                                             is_api_call=False)
 
         if (parser.run_synapse is None) and (parser.run_order is None):
-            # if --muted
-            if parser.muted:
-                settings.start_options['muted'] = True
+            # if --deaf
+            if parser.deaf:
+                settings.options['deaf'] = True
 
             # start rest api
             start_rest_api(settings, brain)

+ 47 - 0
kalliope/core/ConfigurationManager/SettingEditor.py

@@ -0,0 +1,47 @@
+import logging
+
+from kalliope.core.Utils import Utils
+from kalliope.core.HookManager import HookManager
+from kalliope.core.ConfigurationManager import SettingLoader
+
+logging.basicConfig()
+logger = logging.getLogger("kalliope")
+
+
+class SettingEditor(object):
+    """This class provides methods/functions to update properties from the Settings"""
+
+    @staticmethod
+    def set_mute_status(mute=False):
+        """
+        Define is the mute status
+        :param mute: Boolean. If false, Kalliope is voice is stopped
+        """
+        logger.debug("[SettingEditor] mute. Switch trigger process to mute : %s" % mute)
+        settings = SettingLoader().settings
+        if mute:
+            Utils.print_info("Kalliope now muted, voice has been stopped.")
+            HookManager.on_mute()
+        else:
+            Utils.print_info("Kalliope now speaking.")
+            HookManager.on_unmute()
+        settings.options["mute"] = mute
+
+    @staticmethod
+    def set_deaf_status(trigger_instance, deaf=False):
+        """
+        Define is the trigger is listening or not.
+        :param trigger_instance: the trigger instance coming from the order. It will be paused or unpaused.
+        :param deaf: Boolean. If true, kalliope is trigger is paused
+        """
+        logger.debug("[MainController] deaf . Switch trigger process to deaf : %s" % deaf)
+        settings = SettingLoader().settings
+        if deaf:
+            trigger_instance.pause()
+            Utils.print_info("Kalliope now deaf, trigger has been paused")
+            HookManager.on_deaf()
+        else:
+            trigger_instance.unpause()
+            Utils.print_info("Kalliope now listening for trigger detection")
+            HookManager.on_undeaf()
+        settings.options["deaf"] = deaf

+ 17 - 13
kalliope/core/ConfigurationManager/SettingLoader.py

@@ -112,7 +112,7 @@ class SettingLoader(with_metaclass(Singleton, object)):
         resources = self._get_resources(settings)
         variables = self._get_variables(settings)
         recognition_options = self._get_recognition_options(settings)
-        start_options = self._get_start_options(settings)
+        options = self._get_options(settings)
         hooks = self._get_hooks(settings)
 
         # Load the setting singleton with the parameters
@@ -129,7 +129,7 @@ class SettingLoader(with_metaclass(Singleton, object)):
         setting_object.resources = resources
         setting_object.variables = variables
         setting_object.recognition_options = recognition_options
-        setting_object.start_options = start_options
+        setting_object.options = options
         setting_object.hooks = hooks
 
         return setting_object
@@ -632,7 +632,7 @@ class SettingLoader(with_metaclass(Singleton, object)):
         return recognition_options
 
     @staticmethod
-    def _get_start_options(settings):
+    def _get_options(settings):
         """
         Return the start options settings
 
@@ -641,21 +641,23 @@ class SettingLoader(with_metaclass(Singleton, object)):
         :return: A dict containing the start options
         :rtype: dict
         """
-        options = dict()
-        muted = False
+
+        deaf = False
+        mute = False
 
         try:
-            start_options = settings["start_options"]
+            options = settings["options"]
         except KeyError:
-            start_options = None
+            options = dict()
 
-        if start_options is not None:
-            try:
-                muted = start_options['muted']
-            except KeyError:
-                muted = False
+        if options is not None:
+            if options['deaf']:
+                deaf = options['deaf']
+            if options['mute']:
+                mute = options['mute']
 
-        options['muted'] = muted
+        options['deaf'] = deaf
+        options['mute'] = mute
 
         logger.debug("Start options: %s" % options)
         return options
@@ -684,6 +686,8 @@ class SettingLoader(with_metaclass(Singleton, object)):
             "on_stop_listening",
             "on_order_found",
             "on_order_not_found",
+            "on_deaf",
+            "on_undeaf",
             "on_mute",
             "on_unmute",
             "on_start_speaking",

+ 1 - 0
kalliope/core/ConfigurationManager/__init__.py

@@ -1,3 +1,4 @@
 from .YAMLLoader import YAMLLoader
 from .SettingLoader import SettingLoader
 from .BrainLoader import BrainLoader
+from .SettingEditor import SettingEditor

+ 8 - 0
kalliope/core/HookManager.py

@@ -39,6 +39,14 @@ class HookManager(object):
     def on_processed_synapses(cls):
         return cls.execute_synapses_in_hook_name("on_processed_synapses")
 
+    @classmethod
+    def on_deaf(cls):
+        return cls.execute_synapses_in_hook_name("on_deaf")
+
+    @classmethod
+    def on_undeaf(cls):
+        return cls.execute_synapses_in_hook_name("on_undeaf")
+
     @classmethod
     def on_mute(cls):
         return cls.execute_synapses_in_hook_name("on_mute")

+ 2 - 7
kalliope/core/Lifo/LIFOBuffer.py

@@ -39,7 +39,6 @@ class LIFOBuffer(object):
         self.lifo_list = list()
         self.answer = None
         self.is_api_call = False
-        self.no_voice = False
         self.is_running = False
         self.reset_lifo = False
 
@@ -79,7 +78,7 @@ class LIFOBuffer(object):
         self.api_response = APIResponse()
         return returned_api_response
 
-    def execute(self, answer=None, is_api_call=False, no_voice=False):
+    def execute(self, answer=None, is_api_call=False):
         """
         Process the LIFO list.
 
@@ -91,13 +90,11 @@ class LIFOBuffer(object):
 
         :param answer: String answer to give the the last neuron which was waiting for an answer
         :param is_api_call: Boolean passed to all neuron in order to let them know if the current call comes from API
-        :param no_voice: If true, the generated text will not be processed by the TTS engine
         :return: serialized APIResponse object
         """
         # store the answer if present
         self.answer = answer
         self.is_api_call = is_api_call
-        self.no_voice = no_voice
 
         try:
             if not self.is_running:
@@ -170,9 +167,7 @@ class LIFOBuffer(object):
                 self.answer = None
             # todo fix this when we have a full client/server call. The client would be the voice or api call
             neuron.parameters["is_api_call"] = self.is_api_call
-            neuron.parameters["no_voice"] = self.no_voice
-            logger.debug("[LIFOBuffer] process_neuron_list: is_api_call: %s, no_voice: %s" % (self.is_api_call,
-                                                                                              self.no_voice))
+            logger.debug("[LIFOBuffer] process_neuron_list: is_api_call: %s" % (self.is_api_call))
             # execute the neuron
             instantiated_neuron = NeuronLauncher.start_neuron(neuron=neuron,
                                                               parameters_dict=matched_synapse.parameters)

+ 3 - 3
kalliope/core/Models/Settings.py

@@ -22,7 +22,7 @@ class Settings(object):
                  resources=None,
                  variables=None,
                  recognition_options=None,
-                 start_options=None,
+                 options=None,
                  hooks=None):
 
         self.default_tts_name = default_tts_name
@@ -40,7 +40,7 @@ class Settings(object):
         self.machine = platform.machine()   # can be x86_64 or armv7l
         self.kalliope_version = current_kalliope_version
         self.recognition_options = recognition_options
-        self.start_options = start_options
+        self.options = options
         self.hooks = hooks
 
     def serialize(self):
@@ -67,7 +67,7 @@ class Settings(object):
             'machine': self.machine,
             'kalliope_version': self.kalliope_version,
             'recognition_options': self.recognition_options.serialize() if self.recognition_options is not None else None,
-            'start_options': self.start_options,
+            'options': self.options,
             'hooks': self.hooks
         }
 

+ 6 - 8
kalliope/core/NeuronModule.py

@@ -105,8 +105,6 @@ class NeuronModule(object):
         self.tts_message = None
         # if the current call is api one
         self.is_api_call = kwargs.get('is_api_call', False)
-        # if the current call want to mute kalliope
-        self.no_voice = kwargs.get('no_voice', False)
         # boolean to know id the synapse is waiting for an answer
         self.is_waiting_for_answer = False
         # the synapse name to add the the buffer
@@ -171,11 +169,11 @@ class NeuronModule(object):
             # save in kalliope memory the last tts message
             Cortex.save("kalliope_last_tts_message", tts_message)
 
-            # process the audio only if the no_voice flag is false
-            if self.no_voice:
-                logger.debug("[NeuronModule] no_voice is True, Kalliope is muted")
+            # process the audio only if the mute flag is false
+            if self.settings.options["mute"]:
+                logger.debug("[NeuronModule] mute is True, Kalliope is muted")
             else:
-                logger.debug("[NeuronModule] no_voice is False, make Kalliope speaking")
+                logger.debug("[NeuronModule] mute is False, make Kalliope speaking")
                 HookManager.on_start_speaking()
                 # get the instance of the TTS module
                 tts_folder = None
@@ -237,7 +235,7 @@ class NeuronModule(object):
 
     @staticmethod
     def run_synapse_by_name(synapse_name, user_order=None, synapse_order=None, high_priority=False,
-                            is_api_call=False, overriding_parameter_dict=None, no_voice=False):
+                            is_api_call=False, overriding_parameter_dict=None):
         """
         call the lifo for adding a synapse to execute in the list of synapse list to process
         :param synapse_name: The name of the synapse to run
@@ -258,7 +256,7 @@ class NeuronModule(object):
         # get the singleton
         lifo_buffer = LifoManager.get_singleton_lifo()
         lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process, high_priority=high_priority)
-        lifo_buffer.execute(is_api_call=is_api_call, no_voice=no_voice)
+        lifo_buffer.execute(is_api_call=is_api_call)
 
     @staticmethod
     def is_order_matching(order_said, order_match):

+ 105 - 43
kalliope/core/RestAPI/FlaskAPI.py

@@ -9,9 +9,9 @@ from flask_cors import CORS
 from flask_restful import abort
 from werkzeug.utils import secure_filename
 
-from kalliope import SignalLauncher
+from kalliope.core.SignalLauncher import SignalLauncher
 from kalliope._version import version_str
-from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader
+from kalliope.core.ConfigurationManager import SettingLoader, BrainLoader, SettingEditor
 from kalliope.core.Lifo.LifoManager import LifoManager
 from kalliope.core.Models.MatchedSynapse import MatchedSynapse
 from kalliope.core.OrderListener import OrderListener
@@ -62,9 +62,6 @@ class FlaskAPI(threading.Thread):
         if self.allowed_cors_origin is not False:
             CORS(app, resources={r"/*": {"origins": allowed_cors_origin}}, supports_credentials=True)
 
-        # no voice flag
-        self.no_voice = False
-
         # Add routing rules
         self.app.add_url_rule('/', view_func=self.get_main_page, methods=['GET'])
         self.app.add_url_rule('/synapses', view_func=self.get_synapses, methods=['GET'])
@@ -73,6 +70,8 @@ class FlaskAPI(threading.Thread):
         self.app.add_url_rule('/synapses/start/order', view_func=self.run_synapse_by_order, methods=['POST'])
         self.app.add_url_rule('/synapses/start/audio', view_func=self.run_synapse_by_audio, methods=['POST'])
         self.app.add_url_rule('/shutdown/', view_func=self.shutdown_server, methods=['POST'])
+        self.app.add_url_rule('/deaf/', view_func=self.get_deaf, methods=['GET'])
+        self.app.add_url_rule('/deaf/', view_func=self.set_deaf, methods=['POST'])
         self.app.add_url_rule('/mute/', view_func=self.get_mute, methods=['GET'])
         self.app.add_url_rule('/mute/', view_func=self.set_mute, methods=['POST'])
 
@@ -145,11 +144,11 @@ class FlaskAPI(threading.Thread):
 
         run a synapse without making kalliope speaking
         curl -i -H "Content-Type: application/json" --user admin:secret -X POST  \
-        -d '{"no_voice":"true"}' http://127.0.0.1:5000/synapses/start/id/say-hello-fr
+        -d '{"mute":"true"}' http://127.0.0.1:5000/synapses/start/id/say-hello-fr
 
         Run a synapse by its name and pass order's parameters
         curl -i -H "Content-Type: application/json" --user admin:secret -X POST  \
-        -d '{"no_voice":"true", "parameters": {"parameter1": "value1" }}' \
+        -d '{"mute":"true", "parameters": {"parameter1": "value1" }}' \
         http://127.0.0.1:5000/synapses/start/id/say-hello-fr
 
         :param synapse_name: name(id) of the synapse to execute
@@ -159,8 +158,11 @@ class FlaskAPI(threading.Thread):
         logger.debug("[FlaskAPI] run_synapse_by_name: synapse name -> %s" % synapse_name)
         synapse_target = BrainLoader().brain.get_synapse_by_name(synapse_name=synapse_name)
 
-        # get no_voice_flag if present
-        no_voice = self.get_boolean_flag_from_request(request, boolean_flag_to_find="no_voice")
+        # Store the mute value, then apply depending of the request parameters
+        old_mute_value = self.settings.options["mute"]
+        mute = self.get_boolean_flag_from_request(request, boolean_flag_to_find="mute")
+        if mute is not None:
+            SettingEditor.set_mute_status(mute=mute)
 
         # get parameters
         parameters = self.get_parameters_from_request(request)
@@ -169,6 +171,8 @@ class FlaskAPI(threading.Thread):
             data = {
                 "synapse name not found": "%s" % synapse_name
             }
+            if mute is not None:
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return jsonify(error=data), 404
         else:
             # generate a MatchedSynapse from the synapse
@@ -176,8 +180,10 @@ class FlaskAPI(threading.Thread):
             # get the current LIFO buffer from the singleton
             lifo_buffer = LifoManager.get_singleton_lifo()
             lifo_buffer.add_synapse_list_to_lifo([matched_synapse])
-            response = lifo_buffer.execute(is_api_call=True, no_voice=no_voice)
+            response = lifo_buffer.execute(is_api_call=True)
             data = jsonify(response)
+            if mute is not None:
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return data, 201
 
     @requires_auth
@@ -194,9 +200,9 @@ class FlaskAPI(threading.Thread):
         curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
         --data @post.json http://localhost:5000/order/
 
-        Can be used with no_voice flag
+        Can be used with mute flag
         curl -i --user admin:secret -H "Content-Type: application/json" -X POST \
-        -d '{"order":"my order", "no_voice":"true"}' http://localhost:5000/synapses/start/order
+        -d '{"order":"my order", "mute":"true"}' http://localhost:5000/synapses/start/order
 
         :return:
         """
@@ -204,8 +210,13 @@ class FlaskAPI(threading.Thread):
             abort(400)
 
         order = request.get_json('order')
-        # get no_voice_flag if present
-        no_voice = self.get_boolean_flag_from_request(request, boolean_flag_to_find="no_voice")
+
+        # Store the mute value, then apply depending of the request parameters
+        old_mute_value = self.settings.options["mute"]
+        mute = self.get_boolean_flag_from_request(request, boolean_flag_to_find="mute")
+        if mute is not None:
+            SettingEditor.set_mute_status(mute=mute)
+
         if order is not None:
             # get the order
             order_to_run = order["order"]
@@ -213,15 +224,18 @@ class FlaskAPI(threading.Thread):
             api_response = SynapseLauncher.run_matching_synapse_from_order(order_to_run,
                                                                            self.brain,
                                                                            self.settings,
-                                                                           is_api_call=True,
-                                                                           no_voice=no_voice)
+                                                                           is_api_call=True)
 
             data = jsonify(api_response)
+            if mute is not None:
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return data, 201
         else:
             data = {
                 "error": "order cannot be null"
             }
+            if mute is not None:
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return jsonify(error=data), 400
 
     @requires_auth
@@ -231,13 +245,10 @@ class FlaskAPI(threading.Thread):
         Test with curl
         curl -i --user admin:secret -X POST  http://localhost:5000/synapses/start/audio -F "file=@/path/to/input.wav"
 
-        With no_voice flag
-        curl -i -H "Content-Type: application/json" --user admin:secret -X POST \
-        http://localhost:5000/synapses/start/audio -F "file=@path/to/file.wav" -F no_voice="true"
+        With mute flag
+        curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/audio -F "file=@path/to/file.wav" -F mute="true"
         :return:
         """
-        # get no_voice_flag if present
-        self.no_voice = self.str_to_bool(request.form.get("no_voice"))
 
         # check if the post request has the file part
         if 'file' not in request.files:
@@ -254,6 +265,12 @@ class FlaskAPI(threading.Thread):
                 "error": "No file provided"
             }
             return jsonify(error=data), 400
+
+        # Store the mute value, then apply depending of the request parameters
+        old_mute_value = self.settings.options["mute"]
+        if request.form.get("mute"):
+            SettingEditor.set_mute_status(mute=self.str_to_bool(request.form.get("mute")))
+
         # save the file
         filename = secure_filename(uploaded_file.filename)
         base_path = os.path.join(self.app.config['UPLOAD_FOLDER'])
@@ -275,11 +292,15 @@ class FlaskAPI(threading.Thread):
             data = jsonify(self.api_response)
             self.api_response = None
             logger.debug("[FlaskAPI] run_synapse_by_audio: data %s" % data)
+            if request.form.get("mute"):
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return data, 201
         else:
             data = {
                 "error": "The given order doesn't match any synapses"
             }
+            if request.form.get("mute"):
+                SettingEditor.set_mute_status(mute=old_mute_value)
             return jsonify(error=data), 400
 
     @staticmethod
@@ -309,58 +330,100 @@ class FlaskAPI(threading.Thread):
         return "Shutting down..."
 
     @requires_auth
-    def get_mute(self):
+    def get_deaf(self):
         """
         Return the current trigger status
 
         Curl test
-        curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/mute
+        curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/deaf
         """
 
-        # find the order signal and call the mute method
-        signal_order = SignalLauncher.get_order_instance()
-        if signal_order is not None:
+        # find the order signal and call the deaf settings
+        if self.settings.options["deaf"] is not None:
             data = {
-                "mute": signal_order.get_mute_status()
+                "deaf": self.settings.options["deaf"]
             }
             return jsonify(data), 200
 
         # if no Order instance
         data = {
-            "error": "Mute status unknow"
+            "error": "deaf status unknow"
         }
         return jsonify(error=data), 400
 
     @requires_auth
-    def set_mute(self):
+    def set_deaf(self):
         """
-        Set the trigger status (muted or not)
+        Set the trigger status (deaf or not)
 
         Curl test:
         curl -i -H "Content-Type: application/json" --user admin:secret  -X POST \
-        -d '{"mute": "True"}' http://127.0.0.1:5000/mute
+        -d '{"deaf": "True"}' http://127.0.0.1:5000/deaf
         """
 
-        if not request.get_json() or 'mute' not in request.get_json():
+        if not request.get_json() or 'deaf' not in request.get_json():
             abort(400)
 
-        # get mute if present
-        mute = self.get_boolean_flag_from_request(request, boolean_flag_to_find="mute")
+        # get deaf if present
+        deaf = self.get_boolean_flag_from_request(request, boolean_flag_to_find="deaf")
 
-        # find the order signal and call the mute method
         signal_order = SignalLauncher.get_order_instance()
-        if signal_order is not None:
-            signal_order.set_mute_status(mute)
+        if signal_order is not None and deaf is not None and self.settings.options["deaf"] is not None:
+            SettingEditor.set_deaf_status(signal_order.trigger_instance, deaf)
             data = {
-                "mute": signal_order.get_mute_status()
+                "deaf": self.settings.options["deaf"]
             }
             return jsonify(data), 200
 
         data = {
-            "error": "Cannot switch mute status"
+            "error": "Cannot switch deaf status"
         }
         return jsonify(error=data), 400
 
+    @requires_auth
+    def get_mute(self):
+        """
+        Return the current mute status
+
+        Curl test
+        curl -i --user admin:secret  -X GET  http://127.0.0.1:5000/mute
+        """
+
+        # find the order signal and call the mute settings
+        if self.settings.options["mute"] is not None:
+            data = {
+                "mute": self.settings.options["mute"]
+            }
+            return jsonify(data), 200
+
+        # if no Order instance
+        data = {
+            "error": "mute status unknow"
+        }
+        return jsonify(error=data), 400
+
+    @requires_auth
+    def set_mute(self):
+        """
+        Set the Kalliope Core mute status (mute or not)
+
+        Curl test:
+        curl -i -H "Content-Type: application/json" --user admin:secret  -X POST \
+        -d '{"mute": "True"}' http://127.0.0.1:5000/mute
+        """
+
+        if not request.get_json() or 'mute' not in request.get_json():
+            abort(400)
+
+        # get mute if present
+        mute = self.get_boolean_flag_from_request(request, boolean_flag_to_find="mute")
+        SettingEditor.set_mute_status(mute=mute)
+
+        data = {
+            "mute": mute
+        }
+        return jsonify(data), 200
+
     def audio_analyser_callback(self, order):
         """
         Callback of the OrderListener. Called after the processing of the audio file
@@ -376,8 +439,7 @@ class FlaskAPI(threading.Thread):
         api_response = SynapseLauncher.run_matching_synapse_from_order(order,
                                                                        self.brain,
                                                                        self.settings,
-                                                                       is_api_call=True,
-                                                                       no_voice=self.no_voice)
+                                                                       is_api_call=True)
         self.api_response = api_response
 
         # this boolean will notify the main process that the order have been processed
@@ -385,12 +447,12 @@ class FlaskAPI(threading.Thread):
 
     def get_boolean_flag_from_request(self, http_request, boolean_flag_to_find):
         """
-        Get the boolean flag from the request if exist
+        Get the boolean flag from the request if exist, None otherwise !
         :param http_request:
         :param boolean_flag_to_find: json flag to find in the http_request
         :return: True or False if the boolean flag has been found in the request
         """
-        boolean_flag = False
+        boolean_flag = None
         try:
             received_json = http_request.get_json(force=True, silent=True, cache=True)
             if boolean_flag_to_find in received_json:

+ 3 - 4
kalliope/core/SynapseLauncher.py

@@ -64,14 +64,13 @@ class SynapseLauncher(object):
         return None
 
     @classmethod
-    def run_matching_synapse_from_order(cls, order_to_process, brain, settings, is_api_call=False, no_voice=False):
+    def run_matching_synapse_from_order(cls, order_to_process, brain, settings, is_api_call=False):
         """
         
         :param order_to_process: the spoken order sent by the user
         :param brain: Brain object
         :param settings: Settings object
         :param is_api_call: if True, the current call come from the API. This info must be known by launched Neuron
-        :param no_voice: If true, the generated text will not be processed by the TTS engine
         :return: list of matched synapse
         """
 
@@ -81,7 +80,7 @@ class SynapseLauncher(object):
         # if the LIFO is not empty, so, the current order is passed to the current processing synapse as an answer
         if len(lifo_buffer.lifo_list) > 0:
             # the LIFO is not empty, this is an answer to a previous call
-            return lifo_buffer.execute(answer=order_to_process, is_api_call=is_api_call, no_voice=no_voice)
+            return lifo_buffer.execute(answer=order_to_process, is_api_call=is_api_call)
 
         else:  # the LIFO is empty, this is a new call
             # get a list of matched synapse from the order
@@ -95,6 +94,6 @@ class SynapseLauncher(object):
             lifo_buffer.add_synapse_list_to_lifo(list_synapse_to_process)
             lifo_buffer.api_response.user_order = order_to_process
 
-            execdata = lifo_buffer.execute(is_api_call=is_api_call, no_voice=no_voice)
+            execdata = lifo_buffer.execute(is_api_call=is_api_call)
             HookManager.on_processed_synapses()
             return execdata

+ 11 - 11
kalliope/neurons/mute/README.md → kalliope/neurons/deaf/README.md

@@ -1,12 +1,12 @@
-# Mute
+# Deaf
 
 ## Synopsis
 
-Mute control of kalliope. If set to True the trigger process will be stopped.
+Deaf control of kalliope. If set to True the trigger process will be stopped.
 
-Once this neuron is used, and Kalliope muted, the hotword is deactivated. Only ways to unmute are:
-- by calling the API (see [mute section](../../../Docs/rest_api.md#switch-mute-status))
-- If running on Raspberry, by using the unmute button. (See the section [Raspberry LED and mute button](../../../Docs/settings.md#raspberry-led-and-mute-button))
+Once this neuron is used, and Kalliope deaf, the hotword is deactivated. Only ways to undeaf are:
+- by calling the API (see [deaf section](../../../Docs/rest_api.md#switch-deaf-status))
+- If running on Raspberry, by using the undeaf button. (See the section [Raspberry LED and deaf button](../../../Docs/settings.md#raspberry-led-and-deaf-button))
 - by using another signals than a "vocal order" that call back this neuron with a status set to "False"
 - Restarting Kalliope
 
@@ -23,28 +23,28 @@ Not returned values
 
 ## Synapses example
 
-Mute Kalliope from a vocal order
+Deaf Kalliope from a vocal order
 ```yml
-- name: "mute-synapse"
+- name: "deaf-synapse"
   signals:
     - order: "stop listening"
   neurons:
     - say:
         message:
           - "I stop hearing you, sir"
-    - mute:
+    - deaf:
         status: True
 ```
 
-Unmute Kalliope from another signals. In the following example, a MQTT message is received
+Undeaf Kalliope from another signals. In the following example, a MQTT message is received
 ```yml
-- name: "unmute-synapse"
+- name: "undeaf-synapse"
   signals:
     - mqtt_subscriber:
         broker_ip: "127.0.0.1"
         topic: "/my/sensor"
   neurons:
-    - mute:
+    - deaf:
         status: False
     - say:
         message:

+ 0 - 0
kalliope/neurons/mute/__init__.py → kalliope/neurons/deaf/__init__.py


+ 5 - 4
kalliope/neurons/mute/mute.py → kalliope/neurons/deaf/deaf.py

@@ -2,15 +2,16 @@ import logging
 
 from kalliope import SignalLauncher
 from kalliope.core.NeuronModule import NeuronModule
+from kalliope.core.ConfigurationManager.SettingEditor import SettingEditor
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
 
-class Mute(NeuronModule):
+class Deaf(NeuronModule):
 
     def __init__(self, **kwargs):
-        super(Mute, self).__init__(**kwargs)
+        super(Deaf, self).__init__(**kwargs)
 
         self.status = kwargs.get('status', None)
 
@@ -18,7 +19,7 @@ class Mute(NeuronModule):
         if self._is_parameters_ok():
             signal_order = SignalLauncher.get_order_instance()
             if signal_order is not None:
-                signal_order.set_mute_status(self.status)
+                SettingEditor.set_deaf_status(signal_order.trigger_instance, self.status)
 
     def _is_parameters_ok(self):
         """
@@ -28,6 +29,6 @@ class Mute(NeuronModule):
         .. raises:: MissingParameterException
         """
         if self.status is None:
-            logger.debug("[Mute] You must specify a status with a boolean")
+            logger.debug("[Deaf] You must specify a status with a boolean")
             return False
         return True

+ 1 - 2
kalliope/neurons/neurotransmitter/neurotransmitter.py

@@ -53,8 +53,7 @@ class Neurotransmitter(NeuronModule):
                                                  user_order=audio,
                                                  synapse_order=answer,
                                                  high_priority=True,
-                                                 is_api_call=self.is_api_call,
-                                                 no_voice=self.no_voice)
+                                                 is_api_call=self.is_api_call)
                         found = True
                         break
             if not found:  # the answer do not correspond to any answer. We run the default synapse

+ 1 - 2
kalliope/neurons/neurotransmitter/tests/test_neurotransmitter.py

@@ -124,8 +124,7 @@ class TestNeurotransmitter(unittest.TestCase):
                                                                  user_order=audio_text,
                                                                  synapse_order="answer one",
                                                                  high_priority=True,
-                                                                 is_api_call=False,
-                                                                 no_voice=False)
+                                                                 is_api_call=False)
 
     def testInit(self):
         """

+ 6 - 5
kalliope/settings.yml

@@ -119,8 +119,8 @@ hooks:
   on_order_found:
   on_order_not_found: "order-not-found-synapse"
   on_processed_synapses:
-  on_mute:
-  on_unmute:
+  on_deaf:
+  on_undeaf:
   on_start_speaking:
   on_stop_speaking:
 
@@ -162,7 +162,8 @@ rest_api:
 #  - variables2.yml
 
 # -------------
-# Start options
+# Options
 # -------------
-#start_options:
-#  muted: False
+options:
+  deaf: False
+  mute: False

+ 2 - 31
kalliope/signals/order/order.py

@@ -48,11 +48,6 @@ class Order(Thread):
         # save an instance of the trigger
         self.trigger_instance = None
         self.trigger_callback_called = False
-        self.is_trigger_muted = False
-
-        # If kalliope is asked to start muted
-        if self.settings.start_options['muted'] is True:
-            self.is_trigger_muted = True
 
         # save the current order listener
         self.order_listener = None
@@ -101,8 +96,8 @@ class Order(Thread):
         Method to print in debug that the main process is waiting for a trigger detection
         """
         logger.debug("[MainController] Entering state: %s" % self.state)
-        if self.is_trigger_muted:  # the user asked to mute inside the mute neuron
-            Utils.print_info("Kalliope is muted")
+        if self.settings.options["deaf"]:  # the user asked to deaf inside the deaf neuron
+            Utils.print_info("Kalliope is deaf")
             self.trigger_instance.pause()
         else:
             Utils.print_info("Waiting for trigger detection")
@@ -179,27 +174,3 @@ class Order(Thread):
 
         # return to the state "unpausing_trigger"
         self.start_trigger()
-
-    def set_mute_status(self, muted=False):
-        """
-        Define is the trigger is listening or not
-        :param muted: Boolean. If true, kalliope is muted
-        """
-        logger.debug("[MainController] Mute button pressed. Switch trigger process to muted: %s" % muted)
-        if muted:
-            self.trigger_instance.pause()
-            self.is_trigger_muted = True
-            Utils.print_info("Kalliope now muted")
-            HookManager.on_mute()
-        else:
-            self.trigger_instance.unpause()
-            self.is_trigger_muted = False
-            Utils.print_info("Kalliope now listening for trigger detection")
-            HookManager.on_unmute()
-
-    def get_mute_status(self):
-        """
-        return the current state of the trigger (muted or not)
-        :return: Boolean
-        """
-        return self.is_trigger_muted