From a418f309cf2c2b2ffe22fc7bb626571f261b15cb Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 18 Jan 2017 11:24:18 +0100 Subject: [PATCH 01/54] [Test] update test_check_supported_version --- Tests/test_resources_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/test_resources_manager.py b/Tests/test_resources_manager.py index 0ec03fa2..9af6f84f 100644 --- a/Tests/test_resources_manager.py +++ b/Tests/test_resources_manager.py @@ -147,8 +147,9 @@ def test_check_supported_version(self): supported_versions=supported_version)) # version non ok, user does not config + # Testing with integer values instead of string current_version = '0.4.0' - supported_version = ['0.3', '0.2'] + supported_version = [0.3, 0.2] with mock.patch('kalliope.Utils.query_yes_no', return_value=True): self.assertTrue(ResourcesManager._check_supported_version(current_version=current_version, From 34a0ce71f0d7502d9fe66452d074add0b93f1e30 Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 18 Jan 2017 13:19:00 +0100 Subject: [PATCH 02/54] [Test] add order_listener --- Tests/test_order_listener.py | 53 ++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 Tests/test_order_listener.py diff --git a/Tests/test_order_listener.py b/Tests/test_order_listener.py new file mode 100644 index 00000000..2de3c20f --- /dev/null +++ b/Tests/test_order_listener.py @@ -0,0 +1,53 @@ +import unittest + +from mock import mock + +from kalliope.core import OrderListener +from kalliope.core.Models import Resources +from kalliope.core.Models.Stt import Stt + + +class TestOrderListener(unittest.TestCase): + + """Test case for the OrderListener Class""" + + def setUp(self): + pass + + def test_load_stt_plugin(self): + + # Test getting default stt + ol = OrderListener() + + stt1 = Stt(name="default-stt", + parameters=dict()) + + stt2 = Stt(name="second-stt", + parameters=dict()) + + stt3 = Stt(name="third-stt", + parameters=dict()) + + resources = Resources(stt_folder="/tmp") + ol.settings = mock.MagicMock(default_stt_name="default-stt", + stts=[stt1,stt2,stt3], + resources=resources) + + callback = mock.MagicMock() + + ol.callback = callback + + with mock.patch("kalliope.core.Utils.get_dynamic_class_instantiation") as mock_get_dynamic_class_instantiation: + mock_get_dynamic_class_instantiation.return_value = 'class_instance' + self.assertEquals(ol.load_stt_plugin(), + "class_instance", + "Fail getting the proper value") + + mock_get_dynamic_class_instantiation.assert_called_once_with(package_name= "stt", + module_name= "Default-stt", + parameters={'callback' : callback}, + resources_dir= "/tmp") + + +if __name__ == '__main__': + unittest.main() From 8bcd75926e65275005557711149e94f5587489dd Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 18 Jan 2017 22:21:16 +0100 Subject: [PATCH 03/54] add HUE neuron into the community list --- Docs/neuron_list.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 4d120b32..a293dca6 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -19,19 +19,16 @@ A neuron is a module that will perform some actions attached to an order. You ca ## Community neuron | Name | Description | -|--------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | -| [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | -| [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | -| [openweathermap](https://github.com/kalliope-project/kalliope_neuron_openweathermap) | Get the weather of a location | -| [pi camera](https://github.com/bacardi55/kalliope-picamera) | Take picture with your picamera | +|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| +| [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | +| [hue](https://github.com/kalliope-project/kalliope_neuron_hue) | Control the Philips Hue lighting system | +| [openweathermap](https://github.com/kalliope-project/kalliope_neuron_openweathermap) | Get the weather of a location | | [pushetta](https://github.com/kalliope-project/kalliope_neuron_pushetta) | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser | -| [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | get rss feed from website | -| [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | -| [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | -| [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | -| [web scraper](https://github.com/bacardi55/kalliope-web-scraper) | Read web pages that don't provide RSS feed or APIs (by scraping html) | -| [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | +| [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | get rss feed from website | +| [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | +| [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | +| [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | +| [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | Wanna add your neuron in the list? Open [an issue](../../issues) with the link of your neuron or send a pull request to update the list directly. From 9f1ee4b88ccf32fcae8432155b3b77c3ca66271d Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 25 Jan 2017 17:01:32 +0100 Subject: [PATCH 04/54] [Refactor] Remove unused template directory in kalliope Core --- kalliope/templates/en_rss.j2 | 7 --- .../en_systemdate_template_example.j2 | 50 ------------------- kalliope/templates/fr_gmail.j2 | 12 ----- kalliope/templates/fr_gmail_count_unread.j2 | 5 -- kalliope/templates/fr_rss.j2 | 7 --- .../fr_systemdate_template_example.j2 | 5 -- kalliope/templates/remove_file.j2 | 5 -- .../templates/wikipedia_returned_value.j2 | 12 ----- 8 files changed, 103 deletions(-) delete mode 100644 kalliope/templates/en_rss.j2 delete mode 100644 kalliope/templates/en_systemdate_template_example.j2 delete mode 100644 kalliope/templates/fr_gmail.j2 delete mode 100644 kalliope/templates/fr_gmail_count_unread.j2 delete mode 100644 kalliope/templates/fr_rss.j2 delete mode 100644 kalliope/templates/fr_systemdate_template_example.j2 delete mode 100644 kalliope/templates/remove_file.j2 delete mode 100644 kalliope/templates/wikipedia_returned_value.j2 diff --git a/kalliope/templates/en_rss.j2 b/kalliope/templates/en_rss.j2 deleted file mode 100644 index 80ccf975..00000000 --- a/kalliope/templates/en_rss.j2 +++ /dev/null @@ -1,7 +0,0 @@ -Here's the news from {{ feed }} - -{% set count = 1 %} -{% for item in items %} -News {{ count }}. {{ item.title }}. -{% set count = count + 1 %} -{% endfor %} \ No newline at end of file diff --git a/kalliope/templates/en_systemdate_template_example.j2 b/kalliope/templates/en_systemdate_template_example.j2 deleted file mode 100644 index a7313d90..00000000 --- a/kalliope/templates/en_systemdate_template_example.j2 +++ /dev/null @@ -1,50 +0,0 @@ -{% set day_of_week = { - "0": "sunday", - "1": "monday", - "2": "tuesday", - "3": "wednesday", - "4": "thursday", - "5": "friday", - "6": "saturday" - }[weekday] | default("") --%} - -{% set month_word = {"1": "january", "2": "february", "3": "march", "4": "april", "5": "may", "6": "june", "7": "july", "8": "august", "9": "september", "10": "october", "11": "november", "12": "december"}[month] | default("") -%} - -{% set day_month_formated = { - "1": "first", - "2": "second", - "3": "third", - "4": "fourth", - "5": "fifth", - "6": "sixth", - "7": "seventh", - "8": "eighth", - "9": "ninth", - "10": "tenth", - "11": "eleventh", - "12": "twelfth", - "13": "thirteenth", - "14": "fourteenth", - "15": "fifteenth", - "16": "sixteenth", - "17": "seventeenth", - "18": "eighteenth", - "19": "nineteenth", - "20": "twentieth", - "21": "twenty-first", - "22": "twenty-second", - "23": "twenty-third", - "24": "twenty-fourth", - "25": "twenty-fifth", - "26": "twenty-sixth", - "27": "twenty-seventh", - "28": "twenty-eighth", - "29": "twenty-ninth", - "30": "thirtieth", - "31": "thirty-first", - -}[day_month] | default("") -%} - -It' {{ hours }} hours and {{ minutes }} minutes. -We are the {{ day_of_week }} {{ month_word }} the {{ day_month_formated }} {{ year }} diff --git a/kalliope/templates/fr_gmail.j2 b/kalliope/templates/fr_gmail.j2 deleted file mode 100644 index e447dbaf..00000000 --- a/kalliope/templates/fr_gmail.j2 +++ /dev/null @@ -1,12 +0,0 @@ -{% if unread == 0 %} - Vous n'avez aucun email -{% else %} - Vous avez {{ unread }} email. - {% set count = 1 %} - {% if unread > 0 %} - {% for subject in subjects %} - i-maile {{ count }}. {{ subject }}. - {% set count = count + 1 %} - {% endfor %} - {% endif %} -{% endif %} diff --git a/kalliope/templates/fr_gmail_count_unread.j2 b/kalliope/templates/fr_gmail_count_unread.j2 deleted file mode 100644 index dc3046b6..00000000 --- a/kalliope/templates/fr_gmail_count_unread.j2 +++ /dev/null @@ -1,5 +0,0 @@ -{% if unread == 0 %} - Vous n'avez aucun email. -{% else %} - Vous avez {{ unread }} email. -{% endif %} \ No newline at end of file diff --git a/kalliope/templates/fr_rss.j2 b/kalliope/templates/fr_rss.j2 deleted file mode 100644 index 529bd9c0..00000000 --- a/kalliope/templates/fr_rss.j2 +++ /dev/null @@ -1,7 +0,0 @@ -Voici les nouvelles de {{ feed }} - -{% set count = 1 %} -{% for item in items %} -Nouvelle {{ count }}. {{ item.title }}. -{% set count = count + 1 %} -{% endfor %} diff --git a/kalliope/templates/fr_systemdate_template_example.j2 b/kalliope/templates/fr_systemdate_template_example.j2 deleted file mode 100644 index 13ef14b2..00000000 --- a/kalliope/templates/fr_systemdate_template_example.j2 +++ /dev/null @@ -1,5 +0,0 @@ -{% set day_of_week = {"0": "dimanche", "1": "lundi", "2": "mardi", "3": "mercredi", "4": "jeudi", "5": "vendredi", "6": "samedi"}[weekday] | default("") -%} -{% set month_word = {"1": "janvier", "2": "février", "3": "mars", "4": "avril", "5": "mai", "6": "juin", "7": "juillet", "8": "août", "9": "septembre", "10": "octobre", "11": "novembre", "12": "décembre"}[month] | default("") -%} - -Il est {{ hours }} heures et {{ minutes }} minutes. -Nous sommes le {{ day_of_week }} {{ day_month }} {{ month_word }} {{ year }} \ No newline at end of file diff --git a/kalliope/templates/remove_file.j2 b/kalliope/templates/remove_file.j2 deleted file mode 100644 index c0cda7bb..00000000 --- a/kalliope/templates/remove_file.j2 +++ /dev/null @@ -1,5 +0,0 @@ -{% if returncode == 0 %} - The command has succeeded -{% else %} - The command has failed -{% endif %} \ No newline at end of file diff --git a/kalliope/templates/wikipedia_returned_value.j2 b/kalliope/templates/wikipedia_returned_value.j2 deleted file mode 100644 index b8cdeffa..00000000 --- a/kalliope/templates/wikipedia_returned_value.j2 +++ /dev/null @@ -1,12 +0,0 @@ -{% if returncode == "DisambiguationError" %} - Veuillez etre plus précis. La recherche que vous venez d'éffectuez peut correspondre au page Wikipédia suivante: - {% if may_refer is not none %} - {% for el in may_refer %} - {{ el }} - {% endfor %} - {% endif %} -{% elif returncode == "PageError" %} - Je n'ai rien trouvé la dessus -{% else %} - {{ summary }} -{% endif %} From 4bb3deae25e9ac82942345c986c9c70b87810e51 Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 1 Feb 2017 22:01:15 +0100 Subject: [PATCH 05/54] [Doc] Add the Slack Neuron --- Docs/neuron_list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index a293dca6..6f792cb7 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -29,6 +29,7 @@ A neuron is a module that will perform some actions attached to an order. You ca | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | | [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | +| [slack](https://github.com/kalliope-project/kalliope_neuron_slack) | Post and Read message on Slack | Wanna add your neuron in the list? Open [an issue](../../issues) with the link of your neuron or send a pull request to update the list directly. From 7a9d909a7cf00272c68361019aad4732a309a819 Mon Sep 17 00:00:00 2001 From: Andreas Weber Date: Sun, 5 Feb 2017 14:22:30 +0100 Subject: [PATCH 06/54] fix position of python_requirements.txt in installation.md --- Docs/installation.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Docs/installation.md b/Docs/installation.md index 6b9864b3..c5199453 100644 --- a/Docs/installation.md +++ b/Docs/installation.md @@ -53,6 +53,11 @@ Install the project using the local environment: venv/bin/pip install --editable . ``` +Activate the local environment: +```bash +source venv/bin/activate +``` + ### Method 4 - Developer, dependencies install only Clone the project: @@ -63,7 +68,7 @@ cd kalliope Install the python dependencies directly: ```bash -sudo pip install -r install/python_requirements.txt +sudo pip install -r install/files/python_requirements.txt ``` ## Test your env From a19dceb17800c937be60ea9b3be12d3ec772a5b7 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 15 Feb 2017 20:25:37 +0100 Subject: [PATCH 07/54] fix maximum recursion depth exceeded Close #200 --- kalliope/core/MainController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalliope/core/MainController.py b/kalliope/core/MainController.py index 0af0be4d..211f2598 100644 --- a/kalliope/core/MainController.py +++ b/kalliope/core/MainController.py @@ -55,7 +55,7 @@ def __init__(self, brain=None): self.on_ready_notification_played_once = False # Initialize the state machine - self.machine = Machine(model=self, states=MainController.states, initial='init') + self.machine = Machine(model=self, states=MainController.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', 'init', 'starting_trigger') From 1a177685e59777337721176dbbfeb15931864d79 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 15 Feb 2017 20:58:47 +0100 Subject: [PATCH 08/54] disable Rest API by default. --- kalliope/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalliope/settings.yml b/kalliope/settings.yml index 72cf07a1..fa9fca6c 100644 --- a/kalliope/settings.yml +++ b/kalliope/settings.yml @@ -126,7 +126,7 @@ on_ready_sounds: # Rest API # --------------------------- rest_api: - active: True + active: False port: 5000 password_protected: True login: admin From c33bfe7e13e5e92539ee37fcdf5cfd45ac72e18a Mon Sep 17 00:00:00 2001 From: bacardi55 Date: Wed, 15 Feb 2017 21:07:24 +0100 Subject: [PATCH 09/54] Add new community neurons --- Docs/neuron_list.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 4d120b32..a7886f95 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -23,10 +23,12 @@ A neuron is a module that will perform some actions attached to an order. You ca | [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | | [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | | [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | +| [MPD](https://github.com/bacardi55/kalliope-mpd) | Play music via an MPD server | | [openweathermap](https://github.com/kalliope-project/kalliope_neuron_openweathermap) | Get the weather of a location | | [pi camera](https://github.com/bacardi55/kalliope-picamera) | Take picture with your picamera | | [pushetta](https://github.com/kalliope-project/kalliope_neuron_pushetta) | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser | -| [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | get rss feed from website | +| [repeat](https://github.com/bacardi55/kalliope-repeat) | Make kalliope say whatever you want | +| [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | Get rss feed from website | | [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | From 93292162258d63fb82ca94b93e04c3469fb352cc Mon Sep 17 00:00:00 2001 From: bacardi55 Date: Thu, 16 Feb 2017 18:08:28 +0100 Subject: [PATCH 10/54] Add system_status neuron --- Docs/neuron_list.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 1a11ed52..eb996d61 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -22,6 +22,7 @@ A neuron is a module that will perform some actions attached to an order. You ca |--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| | [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | | [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | +| [hue](https://github.com/kalliope-project/kalliope_neuron_hue) | Control the Philips Hue lighting system | | [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | | [MPD](https://github.com/bacardi55/kalliope-mpd) | Play music via an MPD server | | [openweathermap](https://github.com/kalliope-project/kalliope_neuron_openweathermap) | Get the weather of a location | @@ -29,6 +30,7 @@ A neuron is a module that will perform some actions attached to an order. You ca | [pushetta](https://github.com/kalliope-project/kalliope_neuron_pushetta) | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser | | [repeat](https://github.com/bacardi55/kalliope-repeat) | Make kalliope say whatever you want | | [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | Get rss feed from website | +| [system_status](https://github.com/bacardi55/kalliope-system-status) | Get info about the system (cpu, memory, … | | [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | From 1c32a0e81e8546321f281118d71f91ed3288f5d4 Mon Sep 17 00:00:00 2001 From: Monf Date: Fri, 17 Feb 2017 16:02:11 +0100 Subject: [PATCH 11/54] [Doc] Add facebook ref --- Docs/neuron_list.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index eb996d61..093e968e 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -20,7 +20,8 @@ A neuron is a module that will perform some actions attached to an order. You ca | Name | Description | |--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| -| [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | +| [facebook](https://github.com/kalliope-project/kalliope_neuron_facebook) | Post and Read message on Facebook | +| [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | | [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | | [hue](https://github.com/kalliope-project/kalliope_neuron_hue) | Control the Philips Hue lighting system | | [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | @@ -30,13 +31,13 @@ A neuron is a module that will perform some actions attached to an order. You ca | [pushetta](https://github.com/kalliope-project/kalliope_neuron_pushetta) | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser | | [repeat](https://github.com/bacardi55/kalliope-repeat) | Make kalliope say whatever you want | | [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | Get rss feed from website | +| [slack](https://github.com/kalliope-project/kalliope_neuron_slack) | Post and Read message on Slack | | [system_status](https://github.com/bacardi55/kalliope-system-status) | Get info about the system (cpu, memory, … | | [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | | [web scraper](https://github.com/bacardi55/kalliope-web-scraper) | Read web pages that don't provide RSS feed or APIs (by scraping html) | | | [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | -| [slack](https://github.com/kalliope-project/kalliope_neuron_slack) | Post and Read message on Slack | Wanna add your neuron in the list? Open [an issue](../../issues) with the link of your neuron or send a pull request to update the list directly. From 6beb43680af0d266dbdaca6d72f1f92854fc9cb5 Mon Sep 17 00:00:00 2001 From: Andreas Weber Date: Fri, 17 Feb 2017 17:24:09 +0100 Subject: [PATCH 12/54] changed to os independend tmpfile location, changed os.rename to shutil.move --- kalliope/core/ResourcesManager.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kalliope/core/ResourcesManager.py b/kalliope/core/ResourcesManager.py index 296a9c03..6942cfcb 100644 --- a/kalliope/core/ResourcesManager.py +++ b/kalliope/core/ResourcesManager.py @@ -3,6 +3,7 @@ import os import shutil import re +import tempfile from git import Repo from packaging import version @@ -17,7 +18,7 @@ logger = logging.getLogger("kalliope") # Global values for processing: -LOCAL_TMP_FOLDER = "/tmp/kalliope/resources/" +# LOCAL_TMP_FOLDER = "/tmp/kalliope/resources/" TMP_GIT_FOLDER = "kalliope_new_module_temp_name" DNA_FILE_NAME = "dna.yml" INSTALL_FILE_NAME = "install.yml" @@ -53,7 +54,8 @@ def __init__(self, **kwargs): self.git_url = kwargs.get('git_url', None) # temp path where we install the new module - self.tmp_path = LOCAL_TMP_FOLDER + TMP_GIT_FOLDER + self.tmp_path = tempfile.gettempdir() + "/kalliope/resources/" +\ + TMP_GIT_FOLDER self.dna_file_path = self.tmp_path + os.sep + DNA_FILE_NAME self.install_file_path = self.tmp_path + os.sep + INSTALL_FILE_NAME self.dna = None @@ -214,7 +216,7 @@ def _rename_temp_folder(name, target_folder, tmp_path): logger.debug("[ResourcesManager] Rename temp folder") new_absolute_neuron_path = target_folder + os.sep + name try: - os.rename(tmp_path, new_absolute_neuron_path) + shutil.move(tmp_path, new_absolute_neuron_path) return new_absolute_neuron_path except OSError: # the folder already exist From fdaa22010488a9c82be7bab2a3c46ff04df7f033 Mon Sep 17 00:00:00 2001 From: Andreas Weber Date: Fri, 17 Feb 2017 17:47:54 +0100 Subject: [PATCH 13/54] added --run-order cmd-line-option --- Docs/kalliope_cli.md | 9 +++++++++ kalliope/__init__.py | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/Docs/kalliope_cli.md b/Docs/kalliope_cli.md index 0586171d..5eeb0b3a 100644 --- a/Docs/kalliope_cli.md +++ b/Docs/kalliope_cli.md @@ -72,6 +72,15 @@ Example of use kalliope start --run-synapse "say-hello" ``` +### --run-order "Your Order" + +Run a specific order from command line. + +Example of use +```bash +kalliope start --run-order "hello" +``` + ### --brain-file BRAIN_FILE Replace the default brain file from the root of the project folder by a custom one. diff --git a/kalliope/__init__.py b/kalliope/__init__.py index f6ce0639..c1aeb296 100644 --- a/kalliope/__init__.py +++ b/kalliope/__init__.py @@ -15,6 +15,7 @@ from kalliope.core.ResourcesManager import ResourcesManager from kalliope.core.SynapseLauncher import SynapseLauncher +from kalliope.core.OrderAnalyser import OrderAnalyser logging.basicConfig() logger = logging.getLogger("kalliope") @@ -42,6 +43,7 @@ def main(): parser = argparse.ArgumentParser(description='Kalliope') parser.add_argument("action", help="[start|gui|install]") parser.add_argument("--run-synapse", help="Name of a synapse to load surrounded by quote") + parser.add_argument("--run-order", help="order surrounded by a quote") parser.add_argument("--brain-file", help="Full path of a brain file") parser.add_argument("--debug", action='store_true', help="Show debug output") parser.add_argument("--git-url", help="Git URL of the neuron to install") @@ -62,24 +64,42 @@ def main(): # by default, no brain file is set. Use the default one: brain.yml in the root path brain_file = None + # check if user set a brain.yml file if args.brain_file: brain_file = args.brain_file - # load the brain once - brain_loader = BrainLoader(file_path=brain_file) - brain = brain_loader.brain - + # check the user provide a valid action if args.action not in ACTION_LIST: Utils.print_warning("%s is not a recognised action\n" % args.action) parser.print_help() + # install modules + if args.action == "install": + if not args.git_url: + Utils.print_danger("You must specify the git url") + else: + parameters = { + "git_url": args.git_url + } + res_manager = ResourcesManager(**parameters) + res_manager.install() + + # load the brain once + brain_loader = BrainLoader(file_path=brain_file) + brain = brain_loader.brain + if args.action == "start": + # user set a synapse to start if args.run_synapse is not None: SynapseLauncher.start_synapse(args.run_synapse, brain=brain) + + if args.run_order is not None: + order_analyser = OrderAnalyser(args.run_order, brain=brain) + order_analyser.start() - if args.run_synapse is None: + if (args.run_synapse is None) and (args.run_order is None): # first, load events in event manager EventManager(brain.synapses) Utils.print_success("Events loaded") @@ -94,15 +114,7 @@ def main(): if args.action == "gui": ShellGui(brain=brain) - if args.action == "install": - if not args.git_url: - Utils.print_danger("You must specify the git url") - else: - parameters = { - "git_url": args.git_url - } - res_manager = ResourcesManager(**parameters) - res_manager.install() + def configure_logging(debug=None): From 61d2e03892db0b290893c59cc639d9b5322faa42 Mon Sep 17 00:00:00 2001 From: Andreas Weber Date: Fri, 17 Feb 2017 17:58:31 +0100 Subject: [PATCH 14/54] fixed code style, fixed missing return --- kalliope/__init__.py | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/kalliope/__init__.py b/kalliope/__init__.py index c1aeb296..48d7215b 100644 --- a/kalliope/__init__.py +++ b/kalliope/__init__.py @@ -23,9 +23,11 @@ def signal_handler(signal, frame): """ - Used to catch a keyboard signal like Ctrl+C in order to kill the kalliope program + Used to catch a keyboard signal like Ctrl+C in order to kill the kalliope program. + :param signal: signal handler :param frame: execution frame + """ print "\n" Utils.print_info("Ctrl+C pressed. Killing Kalliope") @@ -36,18 +38,20 @@ def signal_handler(signal, frame): def main(): - """ - Entry point of Kalliope program - """ + """Entry point of Kalliope program.""" + # create arguments parser = argparse.ArgumentParser(description='Kalliope') parser.add_argument("action", help="[start|gui|install]") - parser.add_argument("--run-synapse", help="Name of a synapse to load surrounded by quote") - parser.add_argument("--run-order", help="order surrounded by a quote") + parser.add_argument("--run-synapse", + help="Name of a synapse to load surrounded by quote") + parser.add_argument("--run-order", help="order surrounded by a quote") parser.add_argument("--brain-file", help="Full path of a brain file") - parser.add_argument("--debug", action='store_true', help="Show debug output") + parser.add_argument("--debug", action='store_true', + help="Show debug output") parser.add_argument("--git-url", help="Git URL of the neuron to install") - parser.add_argument('-v', '--version', action='version', version='Kalliope ' + version_str) + parser.add_argument('-v', '--version', action='version', + version='Kalliope ' + version_str) # parse arguments from script parameters args = parser.parse_args() @@ -62,13 +66,14 @@ def main(): logger.debug("kalliope args: %s" % args) - # by default, no brain file is set. Use the default one: brain.yml in the root path + # by default, no brain file is set. + # Use the default one: brain.yml in the root path brain_file = None - + # check if user set a brain.yml file if args.brain_file: brain_file = args.brain_file - + # check the user provide a valid action if args.action not in ACTION_LIST: Utils.print_warning("%s is not a recognised action\n" % args.action) @@ -84,17 +89,18 @@ def main(): } res_manager = ResourcesManager(**parameters) res_manager.install() + return # load the brain once brain_loader = BrainLoader(file_path=brain_file) brain = brain_loader.brain if args.action == "start": - + # user set a synapse to start if args.run_synapse is not None: SynapseLauncher.start_synapse(args.run_synapse, brain=brain) - + if args.run_order is not None: order_analyser = OrderAnalyser(args.run_order, brain=brain) order_analyser.start() @@ -115,12 +121,12 @@ def main(): ShellGui(brain=brain) - - def configure_logging(debug=None): """ - Prepare log folder in current home directory + Prepare log folder in current home directory. + :param debug: If true, set the lof level to debug + """ logger = logging.getLogger("kalliope") logger.propagate = False From 7a310c720b3632547ebed4eb3747d82c6def4105 Mon Sep 17 00:00:00 2001 From: monf Date: Fri, 17 Feb 2017 19:27:05 +0100 Subject: [PATCH 15/54] [Fix] Missing return in sleep neuron when checking parameters --- kalliope/neurons/sleep/sleep.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kalliope/neurons/sleep/sleep.py b/kalliope/neurons/sleep/sleep.py index 12964df9..b745ee08 100644 --- a/kalliope/neurons/sleep/sleep.py +++ b/kalliope/neurons/sleep/sleep.py @@ -21,3 +21,4 @@ def _is_parameters_ok(self): """ if self.seconds is None: raise MissingParameterException("You must set a number of seconds as parameter") + return True From fb74a46945dab2a845b9f22111efa1e714574ff5 Mon Sep 17 00:00:00 2001 From: nico Date: Sat, 18 Feb 2017 14:30:39 +0100 Subject: [PATCH 16/54] run default synapse if STT engine do not return an order + add default synapse in the default brain (still in french) --- kalliope/brain.yml | 12 ++++++++++++ kalliope/core/MainController.py | 5 ++++- kalliope/settings.yml | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/kalliope/brain.yml b/kalliope/brain.yml index 0320fe43..953b74b5 100755 --- a/kalliope/brain.yml +++ b/kalliope/brain.yml @@ -14,3 +14,15 @@ - say: message: - "Hello sir" + + - name: "default-synapse" + signals: + - order: "default-synapse-order" + neurons: + - say: + message: + - "Je n'ai pas compris vôtre ordre" + - "Je ne connais pas cet ordre" + - "Veuillez renouveller votre ordre" + - "Veuillez reformuller s'il vous plait" + - "Je n'ai pas saisi cet ordre" diff --git a/kalliope/core/MainController.py b/kalliope/core/MainController.py index 211f2598..b5654788 100644 --- a/kalliope/core/MainController.py +++ b/kalliope/core/MainController.py @@ -3,6 +3,7 @@ from time import sleep from flask import Flask +from kalliope.core.SynapseLauncher import SynapseLauncher from transitions import Machine from kalliope.core import Utils @@ -189,12 +190,14 @@ def order_listener_callback(self, order): def analysing_order_thread(self): """ Start the order analyser with the caught order to process - :param order: the text order to analyse """ logger.debug("order in analysing_order_thread %s" % self.order_to_process) if self.order_to_process is not None: # maybe we have received a null audio from STT engine order_analyser = OrderAnalyser(self.order_to_process, brain=self.brain) order_analyser.start() + else: + if self.settings.default_synapse is not None: + SynapseLauncher.start_synapse(name=self.settings.default_synapse, brain=self.brain) # return to the state "unpausing_trigger" self.unpause_trigger() diff --git a/kalliope/settings.yml b/kalliope/settings.yml index fa9fca6c..875fbbd6 100644 --- a/kalliope/settings.yml +++ b/kalliope/settings.yml @@ -137,7 +137,7 @@ rest_api: # Default Synapse # --------------------------- # Specify an optional default synapse response in case your order is not found. -default_synapse: "Default-synapse" +default_synapse: "default-synapse" # --------------------------- # Resource directory path From b843fd0e07dad1ca4eeaf3d4991b88cdd01b1f64 Mon Sep 17 00:00:00 2001 From: Andreas Weber Date: Sat, 18 Feb 2017 18:39:47 +0100 Subject: [PATCH 17/54] added references to german starterkit --- Docs/installation.md | 2 +- Docs/installation/quickstart.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Docs/installation.md b/Docs/installation.md index c5199453..a94cd6ee 100644 --- a/Docs/installation.md +++ b/Docs/installation.md @@ -93,7 +93,7 @@ Those repositories provide you a basic structure to start playing with kalliope. - [French starter config](https://github.com/kalliope-project/kalliope_starter_fr) - [English starter config](https://github.com/kalliope-project/kalliope_starter_en) - +- [German starter config](https://github.com/kalliope-project/kalliope_starter_de) ## Next: If everything is ok, you can start playing with Kalliope. First, take a look to the [default settings](settings.md). diff --git a/Docs/installation/quickstart.md b/Docs/installation/quickstart.md index 109ae87d..501fd84d 100644 --- a/Docs/installation/quickstart.md +++ b/Docs/installation/quickstart.md @@ -8,6 +8,7 @@ If you are using kalliope from a Rpi, the idea would be to configure your assist We made starter kits that only needs to be cloned, placed into the Rpi and launched. - [French starter kit](https://github.com/kalliope-project/kalliope_starter_fr) - [English starter kit](https://github.com/kalliope-project/kalliope_starter_en) +- [German starter kit](https://github.com/kalliope-project/kalliope_starter_de) Those repositories provide you a structure to start playing and learning basics of Kalliope. Download the starter kit of your choice and open the folder with your IDE. @@ -17,7 +18,7 @@ When you start kalliope using the CLI (`kalliope start`), the program will try t - From `/etc/kalliope/settings.yml` - From the default `settings.yml`. You can take a look into the default [`settings.yml`](../kalliope/settings.yml) file which is located in the root of the project tree. -This a common tree of a Kalliope configuration folder: +This is a common tree of a Kalliope configuration folder: ``` kalliope_config/ ├── brains From e8a2df336945a1fe028a482c9a2860120bf9e37c Mon Sep 17 00:00:00 2001 From: nico Date: Sun, 19 Feb 2017 17:53:51 +0100 Subject: [PATCH 18/54] update doc about starting the default synapse --- Docs/settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docs/settings.md b/Docs/settings.md index 9e09edf6..b1456308 100644 --- a/Docs/settings.md +++ b/Docs/settings.md @@ -259,7 +259,7 @@ Remember that an origin is composed of the scheme (http(s)), the port (eg: 80, 4 ## Default synapse -Run a default [synapse](brain.md) when Kalliope can't find the order in any synapse. +Run a default [synapse](brain.md) when Kalliope can't find the order in any synapse or if the SST engine haven't understood the order. ```yml default_synapse: "synapse-name" From 359d5efa6ca789746c6983d70e4a411eff5b2b01 Mon Sep 17 00:00:00 2001 From: nico Date: Sun, 19 Feb 2017 18:30:19 +0100 Subject: [PATCH 19/54] allow STT mother class to read an audo file if provided by the child STT engine class --- Docs/contributing/contribute_stt.md | 11 +++++----- kalliope/stt/Utils.py | 33 +++++++++++++++++++---------- kalliope/stt/apiai/apiai.py | 6 ++++-- kalliope/stt/bing/bing.py | 6 ++++-- kalliope/stt/cmusphinx/cmusphinx.py | 6 ++++-- kalliope/stt/google/google.py | 8 ++++--- kalliope/stt/houndify/houndify.py | 6 ++++-- kalliope/stt/wit/wit.py | 6 ++++-- 8 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Docs/contributing/contribute_stt.md b/Docs/contributing/contribute_stt.md index d4f32f58..80d090b5 100644 --- a/Docs/contributing/contribute_stt.md +++ b/Docs/contributing/contribute_stt.md @@ -37,14 +37,15 @@ The constructor has a __**kwargs argument__ which is corresponding to the Dict o 1. Attach the incoming callback to the self.main_controller_callback attribute. This callback come from the main controller and will receive the text at the end of the process 1. Obtain audio from the microphone in the constructor. (Note : we mostly use the [speech_recognition library](https://pypi.python.org/pypi/SpeechRecognition/)) 1. Set your callback method into the mother class with `self.set_callback(self.google_callback)`. This callback is the one which will process the audio into a text. -1. Use self.start_listening() from the mother class to get an audio. Once caught, the mother class will give the audio stream to the callback you've set before. -1. The callback method must implement two arguments: recognizer and audio. The audio argument contains the stream caught by the microphone +1. Use self.start_processing() from the mother class to get an audio from the microphone or read the audio file path if provided. The mother class will give the audio stream to the callback you've set before. +1. The callback method must implement two arguments: recognizer and audio. The audio argument contains the stream caught by the microphone or read from an audio file path 1. Do magic stuff with the audio in order to get a string that contains the translated text 1. Once you get the text, let give it to the main_controller_callback method received in the constructor by calling it with the text string as argument `self.main_controller_callback(audio_to_text)` ```python def __init__(self, callback=None, **kwargs): - OrderListener.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # here is the main controller callback. We will return the text at the end of the process self.main_controller_callback = callback @@ -52,8 +53,8 @@ The constructor has a __**kwargs argument__ which is corresponding to the Dict o # give our callback self.set_callback(self.my_callback) - # start the microphone to capture an audio - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def my_callback((self, recognizer, audio): # --------------------------------------------- diff --git a/kalliope/stt/Utils.py b/kalliope/stt/Utils.py index e1ad8096..a5cdaf3f 100644 --- a/kalliope/stt/Utils.py +++ b/kalliope/stt/Utils.py @@ -12,7 +12,7 @@ class SpeechRecognition(Thread): - def __init__(self): + def __init__(self, audio_file=None): """ Thread used to caught n audio from the microphone and pass it to a callback method """ @@ -22,22 +22,33 @@ def __init__(self): self.callback = None self.stop_thread = None self.kill_yourself = False - with self.microphone as source: - # we only need to calibrate once, before we start listening - self.recognizer.adjust_for_ambient_noise(source) + self.audio_stream = None + + if audio_file is None: + # audio file not set, we need to capture a sample from the microphone + with self.microphone as source: + # we only need to calibrate once, before we start listening + self.recognizer.adjust_for_ambient_noise(source) + else: + # audio file provided + with sr.AudioFile(audio_file) as source: + self.audio_stream = self.recognizer.record(source) # read the entire audio file def run(self): """ Start the thread that listen the microphone and then give the audio to the callback method """ - Utils.print_info("Say something!") - self.stop_thread = self.recognizer.listen_in_background(self.microphone, self.callback) - while not self.kill_yourself: - sleep(0.1) - logger.debug("kill the speech recognition process") - self.stop_thread() + if self.audio_stream is None: + Utils.print_info("Say something!") + self.stop_thread = self.recognizer.listen_in_background(self.microphone, self.callback) + while not self.kill_yourself: + sleep(0.1) + logger.debug("kill the speech recognition process") + self.stop_thread() + else: + self.callback(self.recognizer, self.audio_stream) - def start_listening(self): + def start_processing(self): """ A method to start the thread """ diff --git a/kalliope/stt/apiai/apiai.py b/kalliope/stt/apiai/apiai.py index 72ddd6ab..533987c4 100644 --- a/kalliope/stt/apiai/apiai.py +++ b/kalliope/stt/apiai/apiai.py @@ -12,7 +12,8 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback @@ -23,7 +24,8 @@ def __init__(self, callback=None, **kwargs): # start listening in the background self.set_callback(self.apiai_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def apiai_callback(self, recognizer, audio): """ diff --git a/kalliope/stt/bing/bing.py b/kalliope/stt/bing/bing.py index 38955c6f..17950380 100644 --- a/kalliope/stt/bing/bing.py +++ b/kalliope/stt/bing/bing.py @@ -12,7 +12,8 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback @@ -22,7 +23,8 @@ def __init__(self, callback=None, **kwargs): # start listening in the background self.set_callback(self.bing_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def bing_callback(self, recognizer, audio): """ diff --git a/kalliope/stt/cmusphinx/cmusphinx.py b/kalliope/stt/cmusphinx/cmusphinx.py index 83a0d2b7..0478f0da 100644 --- a/kalliope/stt/cmusphinx/cmusphinx.py +++ b/kalliope/stt/cmusphinx/cmusphinx.py @@ -12,14 +12,16 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback # start listening in the background self.set_callback(self.sphinx_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def sphinx_callback(self, recognizer, audio): """ diff --git a/kalliope/stt/google/google.py b/kalliope/stt/google/google.py index 80ebfc7e..c7485b3b 100644 --- a/kalliope/stt/google/google.py +++ b/kalliope/stt/google/google.py @@ -14,7 +14,8 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback @@ -22,9 +23,10 @@ def __init__(self, callback=None, **kwargs): self.language = kwargs.get('language', "en-US") self.show_all = kwargs.get('show_all', False) - # start listening in the background + # set the callback that will process the audio stream self.set_callback(self.google_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def google_callback(self, recognizer, audio): """ diff --git a/kalliope/stt/houndify/houndify.py b/kalliope/stt/houndify/houndify.py index 66403551..cb50dc8e 100644 --- a/kalliope/stt/houndify/houndify.py +++ b/kalliope/stt/houndify/houndify.py @@ -12,7 +12,8 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback @@ -24,7 +25,8 @@ def __init__(self, callback=None, **kwargs): # start listening in the background self.set_callback(self.houndify_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def houndify_callback(self, recognizer, audio): """ diff --git a/kalliope/stt/wit/wit.py b/kalliope/stt/wit/wit.py index 3606ba60..bb4faba6 100644 --- a/kalliope/stt/wit/wit.py +++ b/kalliope/stt/wit/wit.py @@ -12,7 +12,8 @@ def __init__(self, callback=None, **kwargs): :param callback: The callback function to call to send the text :param kwargs: """ - SpeechRecognition.__init__(self) + # give the audio file path to process directly to the mother class if exist + SpeechRecognition.__init__(self, kwargs.get('audio_file_path', None)) # callback function to call after the translation speech/tex self.main_controller_callback = callback @@ -21,7 +22,8 @@ def __init__(self, callback=None, **kwargs): # start listening in the background self.set_callback(self.wit_callback) - self.start_listening() + # start processing, record a sample from the microphone if no audio file path provided, else read the file + self.start_processing() def wit_callback(self, recognizer, audio): try: From 5668c3ccbb1764c4841e171922f03454b2f73ae9 Mon Sep 17 00:00:00 2001 From: nico Date: Sun, 19 Feb 2017 21:00:06 +0100 Subject: [PATCH 20/54] update REST API URLs --- Docs/rest_api.md | 20 ++++++++++---------- kalliope/core/RestAPI/FlaskAPI.py | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Docs/rest_api.md b/Docs/rest_api.md index 519fa020..53a0c92c 100644 --- a/Docs/rest_api.md +++ b/Docs/rest_api.md @@ -4,12 +4,12 @@ Kalliope provides the REST API to manage the synapses. For configuring the API r ## Synapse API -| Method | URL | Action | -|--------|--------------------------|-----------------------------| -| GET | /synapses | List synapses | -| GET | /synapses/ | Show synapse details | -| POST | /synapses/ | Run a synapse by its name | -| POST | /order | Run a synapse from an order | +| Method | URL | Action | +|--------|-----------------------------------|---------------------------------| +| GET | /synapses | List synapses | +| GET | /synapses/ | Get synapse details by name | +| POST | /synapses/start/id/ | Run a synapse by its name | +| POST | /synapses/start/order | Run a synapse from a text order | ## Curl examples @@ -21,7 +21,7 @@ Normal response codes: 200 Error response codes: unauthorized(401), itemNotFound(404) Curl command: ```bash -curl -i --user admin:secret -X GET http://localhost:5000/synapses/ +curl -i --user admin:secret -X GET http://localhost:5000/synapses ``` Output example: @@ -107,7 +107,7 @@ Normal response codes: 201 Error response codes: unauthorized(401), itemNotFound(404) Curl command: ```bash -curl -i --user admin:secret -X POST http://localhost:5000/synapses/say-hello +curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/id/say-hello ``` Output example: @@ -141,7 +141,7 @@ Error response codes: unauthorized(401), itemNotFound(404) Curl command: ```bash -curl -i --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"my order"}' http://localhost:5000/order/ +curl -i --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"my order"}' http://localhost:5000/synapses/start/order ``` If the order contains accent or quotes, use a file for testing with curl @@ -151,7 +151,7 @@ cat post.json ``` Then ```bash -curl -i --user admin:secret -H "Content-Type: application/json" -X POST --data @post.json http://localhost:5000/order/ +curl -i --user admin:secret -H "Content-Type: application/json" -X POST --data @post.json http://localhost:5000/synapses/start/order ``` Output example if the order have matched and so launched synapses: diff --git a/kalliope/core/RestAPI/FlaskAPI.py b/kalliope/core/RestAPI/FlaskAPI.py index 57ff52a0..24443146 100644 --- a/kalliope/core/RestAPI/FlaskAPI.py +++ b/kalliope/core/RestAPI/FlaskAPI.py @@ -13,6 +13,7 @@ logging.basicConfig() logger = logging.getLogger("kalliope") + class FlaskAPI(threading.Thread): def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): """ @@ -38,11 +39,10 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): # Add routing rules self.app.add_url_rule('/synapses', view_func=self.get_synapses, methods=['GET']) self.app.add_url_rule('/synapses/', view_func=self.get_synapse, methods=['GET']) - self.app.add_url_rule('/synapses/', view_func=self.run_synapse, methods=['POST']) - self.app.add_url_rule('/order/', view_func=self.run_order, methods=['POST']) + self.app.add_url_rule('/synapses/start/id/', view_func=self.run_synapse_by_name, methods=['POST']) + self.app.add_url_rule('/synapses/start/order', view_func=self.run_synapse_by_order, methods=['POST']) self.app.add_url_rule('/shutdown/', view_func=self.shutdown_server, methods=['POST']) - def run(self): self.app.run(host='0.0.0.0', port="%s" % int(self.port), debug=True, threaded=True, use_reloader=False) @@ -65,6 +65,8 @@ def _get_synapse_by_name(self, synapse_name): def get_synapses(self): """ get all synapses. + test with curl: + curl -i --user admin:secret -X GET http://127.0.0.1:5000/synapses """ data = jsonify(synapses=[e.serialize() for e in self.brain.synapses]) return data, 200 @@ -73,6 +75,8 @@ def get_synapses(self): def get_synapse(self, synapse_name): """ get a synapse by its name + test with curl: + curl --user admin:secret -i -X GET http://127.0.0.1:5000/synapses/say-hello-en """ synapse_target = self._get_synapse_by_name(synapse_name) if synapse_target is not None: @@ -85,11 +89,11 @@ def get_synapse(self, synapse_name): return jsonify(error=data), 404 @requires_auth - def run_synapse(self, synapse_name): + def run_synapse_by_name(self, synapse_name): """ Run a synapse by its name test with curl: - curl -i --user admin:secret -X POST http://localhost:5000/synapses/say-hello + curl -i --user admin:secret -X POST http://127.0.0.1:5000/synapses/start/id/say-hello-fr :param synapse_name: :return: """ @@ -103,15 +107,15 @@ def run_synapse(self, synapse_name): # run the synapse SynapseLauncher.start_synapse(synapse_name, brain=self.brain) - data = jsonify(synapses=synapse_target) + data = jsonify(synapses=synapse_target.serialize()) return data, 201 @requires_auth - def run_order(self): + def run_synapse_by_order(self): """ Give an order to Kalliope via API like it was from a spoken one Test with curl - curl -i --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"my order"}' http://localhost:5000/order + curl -i --user admin:secret -H "Content-Type: application/json" -X POST -d '{"order":"my order"}' http://localhost:5000/synapses/start/order In case of quotes in the order or accents, use a file cat post.json: {"order":"j'aime"} From ce2bfcb0a72ec4458866ee8d8a8d221be97c1c8a Mon Sep 17 00:00:00 2001 From: monf Date: Sun, 19 Feb 2017 22:35:22 +0100 Subject: [PATCH 21/54] [Feature] #203 Global variables --- Tests/settings/settings_test.yml | 4 ++ Tests/test_settings_loader.py | 3 + .../ConfigurationManager/SettingLoader.py | 24 +++++++ kalliope/core/Models/Settings.py | 2 + kalliope/core/OrderAnalyser.py | 64 +++++++++---------- kalliope/core/Utils/Utils.py | 58 ++++++++++++++++- kalliope/neurons/sleep/sleep.py | 2 +- kalliope/neurons/sleep/tests/test_sleep.py | 4 +- kalliope/settings.yml | 11 +++- 9 files changed, 133 insertions(+), 39 deletions(-) diff --git a/Tests/settings/settings_test.yml b/Tests/settings/settings_test.yml index 68389551..e609f2dd 100644 --- a/Tests/settings/settings_test.yml +++ b/Tests/settings/settings_test.yml @@ -110,3 +110,7 @@ resource_directory: stt: "/tmp/kalliope/tests/kalliope_resources_dir/stt" tts: "/tmp/kalliope/tests/kalliope_resources_dir/tts" trigger: "/tmp/kalliope/tests/kalliope_resources_dir/trigger" + +# --------------------------- +# Variables TODO +# --------------------------- diff --git a/Tests/test_settings_loader.py b/Tests/test_settings_loader.py index dd140b0f..c6f9b027 100644 --- a/Tests/test_settings_loader.py +++ b/Tests/test_settings_loader.py @@ -189,6 +189,9 @@ def test_get_resources(self): sl = SettingLoader(file_path=self.settings_file_to_test) self.assertEquals(expected_resource, sl._get_resources(self.settings_dict)) + def test_get_variables(self): + # TODO + pass if __name__ == '__main__': unittest.main() diff --git a/kalliope/core/ConfigurationManager/SettingLoader.py b/kalliope/core/ConfigurationManager/SettingLoader.py index 4d16ee2f..2205662f 100644 --- a/kalliope/core/ConfigurationManager/SettingLoader.py +++ b/kalliope/core/ConfigurationManager/SettingLoader.py @@ -112,6 +112,7 @@ def _get_settings(self): cache_path = self._get_cache_path(settings) default_synapse = self._get_default_synapse(settings) resources = self._get_resources(settings) + variables = self._get_variables(settings) # Load the setting singleton with the parameters setting_object.default_tts_name = default_tts_name @@ -129,6 +130,7 @@ def _get_settings(self): setting_object.cache_path = cache_path setting_object.default_synapse = default_synapse setting_object.resources = resources + setting_object.variables = variables return setting_object @@ -641,5 +643,27 @@ def _get_on_ready_sounds(settings): return on_ready_sounds + @staticmethod + def _get_variables(settings): + """ + Return the dict of variables from the settings. + :param settings: The YAML settings file + :return: dict + """ + + variables = dict() + try: + variables_files_name = settings["var_files"] + # In case files are declared in settings.yml, make sure kalliope can access them. + for files in variables_files_name: + var = Utils.get_real_file_path(files) + if var is None: + raise SettingInvalidException("Variables file %s not found" % files) + else: + variables.update(YAMLLoader.get_config(var)) + return variables + except KeyError: + # User does not provide this settings + return dict() diff --git a/kalliope/core/Models/Settings.py b/kalliope/core/Models/Settings.py index 4587eec4..449ec364 100644 --- a/kalliope/core/Models/Settings.py +++ b/kalliope/core/Models/Settings.py @@ -24,6 +24,7 @@ def __init__(self, cache_path=None, default_synapse=None, resources=None, + variables= None, # dict() machine=None, kalliope_version=None): @@ -42,6 +43,7 @@ def __init__(self, self.cache_path = cache_path self.default_synapse = default_synapse self.resources = resources + self.variables = variables self.machine = platform.machine() # can be x86_64 or armv7l self.kalliope_version = current_kalliope_version diff --git a/kalliope/core/OrderAnalyser.py b/kalliope/core/OrderAnalyser.py index 5a8c0662..107a182a 100644 --- a/kalliope/core/OrderAnalyser.py +++ b/kalliope/core/OrderAnalyser.py @@ -65,7 +65,8 @@ def start(self, synapses_to_run=None, external_order=None): # Start a neuron list with params self._start_list_neurons(list_neurons=tuple.synapse.neurons, - params=params) + params=params, + settings=self.settings) synapses_launched.append(tuple.synapse) # return the list of launched synapse @@ -139,17 +140,37 @@ def _get_params_from_order(cls, string_order, order_to_check): :return: the dict key/value """ params = dict() - if cls._is_containing_bracket(string_order): + if Utils.is_containing_bracket(string_order): params = cls._associate_order_params_to_values(order_to_check, string_order) logger.debug("Parameters for order: %s" % params) return params @classmethod - def _start_list_neurons(cls, list_neurons, params): + def _start_list_neurons(cls, list_neurons, params, settings): # start neurons for neuron in list_neurons: + cls._replace_global_variables(neuron, settings) cls._start_neuron(neuron, params) + @staticmethod + def _replace_global_variables(neuron, settings): + """ + Replace all the parameters with variables with the variable value. + :param neuron: the neuron + :param settings: the settings + """ + for param in neuron.parameters: + if Utils.is_containing_bracket(neuron.parameters[param]): + sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=neuron.parameters[param]) + list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) + for param_with_bracket in list_of_bracket_params: + param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") + if param_no_brackets in settings.variables: + logger.debug("Replacing variable %s with %s" % (param_with_bracket, + settings.variables[param_no_brackets])) + neuron.parameters[param] = sentence_no_spaces.replace(param_with_bracket, + str(settings.variables[param_no_brackets])) + @staticmethod def _start_neuron(neuron, params): """ @@ -190,8 +211,8 @@ def _start_neuron(neuron, params): else: Utils.print_danger("A problem has been found in the Synapse.") - @classmethod - def _associate_order_params_to_values(cls, order, order_to_check): + @staticmethod + def _associate_order_params_to_values(order, order_to_check): """ Associate the variables from the order to the incoming user order :param order_to_check: the order to check incoming from the brain @@ -203,9 +224,7 @@ def _associate_order_params_to_values(cls, order, order_to_check): logger.debug("[OrderAnalyser._associate_order_params_to_values] user order: %s, " "order to check: %s" % (order, order_to_check)) - pattern = '\s+(?=[^\{\{\}\}]*\}\})' - # Remove white spaces (if any) between the variable and the double brace then split - list_word_in_order = re.sub(pattern, '', order_to_check).split() + list_word_in_order = Utils.remove_spaces_in_brackets(order_to_check).split() # get the order, defined by the first words before {{ # /!\ Could be empty if order starts with double brace @@ -218,10 +237,10 @@ def _associate_order_params_to_values(cls, order, order_to_check): # make dict var:value dict_var = dict() for idx, ow in enumerate(list_word_in_order): - if cls._is_containing_bracket(ow): + if Utils.is_containing_bracket(ow): # remove bracket and grab the next value / stop value var_name = ow.replace("{{", "").replace("}}", "") - stop_value = cls._get_next_value_list(list_word_in_order[idx:]) + stop_value = Utils._get_next_value_list(list_word_in_order[idx:]) if stop_value is None: dict_var[var_name] = " ".join(truncate_list_word_said) break @@ -236,26 +255,6 @@ def _associate_order_params_to_values(cls, order, order_to_check): truncate_list_word_said = truncate_list_word_said[1:] return dict_var - @staticmethod - def _is_containing_bracket(sentence): - """ - Return True if the text in contains brackets - :param sentence: - :return: - """ - # print "sentence to test %s" % sentence - pattern = r"{{|}}" - # prog = re.compile(pattern) - check_bool = re.search(pattern, sentence) - if check_bool is not None: - return True - return False - - @staticmethod - def _get_next_value_list(list_to_check): - ite = list_to_check.__iter__() - next(ite, None) - return next(ite, None) @classmethod def spelt_order_match_brain_order_via_table(cls, order_to_analyse, user_said): @@ -305,9 +304,8 @@ def _get_split_order_without_bracket(order): :param order: sentence to split :return: list of string without bracket """ - pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))" - # find everything like {{ word }} - matches = re.findall(pattern, order) + + matches = Utils.find_all_matching_brackets(order) for match in matches: order = order.replace(match, "") # then split diff --git a/kalliope/core/Utils/Utils.py b/kalliope/core/Utils/Utils.py index 18a5dec8..8f6c4eef 100644 --- a/kalliope/core/Utils/Utils.py +++ b/kalliope/core/Utils/Utils.py @@ -2,8 +2,7 @@ import os import inspect import imp - -import sys +import re logging.basicConfig() logger = logging.getLogger("kalliope") @@ -217,3 +216,58 @@ def query_yes_no(question, default="yes"): return valid[choice] else: Utils.print_warning("Please respond with 'yes' or 'no' or 'y' or 'n').\n") + + ################## + # + # Brackets management + # + ######### + @staticmethod + def is_containing_bracket(sentence): + """ + Return True if the text in contains brackets + :param sentence: + :return: + """ + # print "sentence to test %s" % sentence + pattern = r"{{|}}" + # prog = re.compile(pattern) + check_bool = re.search(pattern, sentence) + if check_bool is not None: + return True + return False + + @staticmethod + def find_all_matching_brackets(sentence): + """ + Find all the bracket matches from a given sentence + :param sentence: the sentence to check + :return: the list with all the matches + """ + + pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))" + # find everything like {{ word }} + return re.findall(pattern, sentence) + + @staticmethod + def remove_spaces_in_brackets(sentence): + """ + If has brackets it removes spaces in brackets + :param sentence: the sentence to work on + :return: the sentence without any spaces in brackets + """ + + pattern = '\s+(?=[^\{\{\}\}]*\}\})' + # Remove white spaces (if any) between the variable and the double brace then split + return re.sub(pattern, '', sentence) + + ################## + # + # Lists management + # + ######### + @staticmethod + def _get_next_value_list(list_to_check): + ite = list_to_check.__iter__() + next(ite, None) + return next(ite, None) diff --git a/kalliope/neurons/sleep/sleep.py b/kalliope/neurons/sleep/sleep.py index b745ee08..954c02e8 100644 --- a/kalliope/neurons/sleep/sleep.py +++ b/kalliope/neurons/sleep/sleep.py @@ -6,7 +6,7 @@ class Sleep(NeuronModule): def __init__(self, **kwargs): super(Sleep, self).__init__(**kwargs) - self.seconds = kwargs.get('seconds', None) + self.seconds = float(kwargs.get('seconds', None)) # check parameters if self._is_parameters_ok(): diff --git a/kalliope/neurons/sleep/tests/test_sleep.py b/kalliope/neurons/sleep/tests/test_sleep.py index c78ec386..847cf4dd 100644 --- a/kalliope/neurons/sleep/tests/test_sleep.py +++ b/kalliope/neurons/sleep/tests/test_sleep.py @@ -7,7 +7,7 @@ class TestSleep(unittest.TestCase): def setUp(self): - self.second="second" + self.seconds = 10 self.random="random" def testParameters(self): @@ -19,7 +19,7 @@ def run_test(parameters_to_test): parameters = dict() run_test(parameters) - # missing second + # missing seconds parameters = { "random": self.random } diff --git a/kalliope/settings.yml b/kalliope/settings.yml index 875fbbd6..7bd5b54a 100644 --- a/kalliope/settings.yml +++ b/kalliope/settings.yml @@ -126,7 +126,7 @@ on_ready_sounds: # Rest API # --------------------------- rest_api: - active: False + active: True port: 5000 password_protected: True login: admin @@ -153,3 +153,12 @@ default_synapse: "default-synapse" # stt: "resources/stt" # tts: "resources/tts" # trigger: "resources/trigger" + + +# --------------------------- +# Global files variables +# /!\ If a variable is defined in different files, the last file defines the value. +# --------------------------- +var_files: + - variables.yml + - variables2.yml From 8170c384a9a13db12ca40e55e919b1089e156041 Mon Sep 17 00:00:00 2001 From: monf Date: Sun, 19 Feb 2017 23:28:52 +0100 Subject: [PATCH 22/54] [Tests] #203 Add tests for global variables --- Tests/settings/settings_test.yml | 5 ++- Tests/settings/variables.yml | 3 ++ Tests/test_order_analyser.py | 44 ------------------ Tests/test_settings_loader.py | 26 ++++++++--- Tests/test_utils.py | 77 ++++++++++++++++++++++++++++++++ kalliope/core/OrderAnalyser.py | 2 +- kalliope/core/Utils/Utils.py | 2 +- kalliope/settings.yml | 6 +-- 8 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 Tests/settings/variables.yml diff --git a/Tests/settings/settings_test.yml b/Tests/settings/settings_test.yml index e609f2dd..0d7d5477 100644 --- a/Tests/settings/settings_test.yml +++ b/Tests/settings/settings_test.yml @@ -112,5 +112,8 @@ resource_directory: trigger: "/tmp/kalliope/tests/kalliope_resources_dir/trigger" # --------------------------- -# Variables TODO +# Global files variables +# /!\ If a variable is defined in different files, the last file defines the value. # --------------------------- +var_files: + - "../Tests/settings/variables.yml" diff --git a/Tests/settings/variables.yml b/Tests/settings/variables.yml new file mode 100644 index 00000000..0f945772 --- /dev/null +++ b/Tests/settings/variables.yml @@ -0,0 +1,3 @@ +test: kalliope +test_number: 60 +author: Lamonf \ No newline at end of file diff --git a/Tests/test_order_analyser.py b/Tests/test_order_analyser.py index dee7a72a..44b190e3 100644 --- a/Tests/test_order_analyser.py +++ b/Tests/test_order_analyser.py @@ -161,50 +161,6 @@ def test_start_neuron(self): mock_start_neuron_method.reset_mock() - def test_is_containing_bracket(self): - # Success - order_to_test = "This test contains {{ bracket }}" - self.assertTrue(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning True when order contains spaced brackets") - - order_to_test = "This test contains {{bracket }}" - self.assertTrue(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning True when order contains right spaced bracket") - - order_to_test = "This test contains {{ bracket}}" - self.assertTrue(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning True when order contains left spaced bracket") - - order_to_test = "This test contains {{bracket}}" - self.assertTrue(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning True when order contains no spaced bracket") - - # Failure - order_to_test = "This test does not contain bracket" - self.assertFalse(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning False when order has no brackets") - - # Behaviour - order_to_test = "" - self.assertFalse(OrderAnalyser._is_containing_bracket(order_to_test), - "Fail returning False when no order") - - def test_get_next_value_list(self): - # Success - list_to_test = {1, 2, 3} - self.assertEqual(OrderAnalyser._get_next_value_list(list_to_test), 2, - "Fail to match the expected next value from the list") - - # Failure - list_to_test = {1} - self.assertEqual(OrderAnalyser._get_next_value_list(list_to_test), None, - "Fail to ensure there is no next value from the list") - - # Behaviour - list_to_test = {} - self.assertEqual(OrderAnalyser._get_next_value_list(list_to_test), None, - "Fail to ensure the empty list return None value") - def test_spelt_order_match_brain_order_via_table(self): order_to_test = "this is the order" sentence_to_test = "this is the order" diff --git a/Tests/test_settings_loader.py b/Tests/test_settings_loader.py index c6f9b027..933087ca 100644 --- a/Tests/test_settings_loader.py +++ b/Tests/test_settings_loader.py @@ -51,19 +51,24 @@ def setUp(self): 'text_to_speech': [ {'pico2wave': {'cache': True, 'language': 'fr-FR'}}, {'voxygen': {'voice': 'Agnes', 'cache': True}} - ] + ], + 'var_files': ["../Tests/settings/variables.yml"] } - # Init the folders, otherwise it raises an exceptions os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/neurons") os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/stt") os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/tts") os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/trigger") + os.makedirs("/tmp/kalliope/tests/variables/") + open("/tmp/kalliope/tests/variables/variables.yml", 'a').close() + open("/tmp/kalliope/tests/variables/variables2.yml", 'a').close() + def tearDown(self): # Cleanup shutil.rmtree('/tmp/kalliope/tests/kalliope_resources_dir') + shutil.rmtree('/tmp/kalliope/tests/variables/') Singleton._instances = {} @@ -105,8 +110,12 @@ def test_get_settings(self): stt_folder="/tmp/kalliope/tests/kalliope_resources_dir/stt", tts_folder="/tmp/kalliope/tests/kalliope_resources_dir/tts", trigger_folder="/tmp/kalliope/tests/kalliope_resources_dir/trigger") - settings_object.resources = resources + settings_object.variables = { + "author": "Lamonf", + "test_number": 60, + "test": "kalliope" + } settings_object.machine = platform.machine() sl = SettingLoader(file_path=self.settings_file_to_test) @@ -190,8 +199,15 @@ def test_get_resources(self): self.assertEquals(expected_resource, sl._get_resources(self.settings_dict)) def test_get_variables(self): - # TODO - pass + expected_result = { + "author": "Lamonf", + "test_number": 60, + "test": "kalliope" + } + sl = SettingLoader(file_path=self.settings_file_to_test) + self.assertEqual(expected_result, + sl._get_variables(self.settings_dict)) + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_utils.py b/Tests/test_utils.py index bfc5fda2..2f5725da 100644 --- a/Tests/test_utils.py +++ b/Tests/test_utils.py @@ -138,3 +138,80 @@ def test_get_dynamic_class_instantiation(self): Say), "Fail instantiate a class") + + def test_is_containing_bracket(self): + # Success + order_to_test = "This test contains {{ bracket }}" + self.assertTrue(Utils.is_containing_bracket(order_to_test), + "Fail returning True when order contains spaced brackets") + + order_to_test = "This test contains {{bracket }}" + self.assertTrue(Utils.is_containing_bracket(order_to_test), + "Fail returning True when order contains right spaced bracket") + + order_to_test = "This test contains {{ bracket}}" + self.assertTrue(Utils.is_containing_bracket(order_to_test), + "Fail returning True when order contains left spaced bracket") + + order_to_test = "This test contains {{bracket}}" + self.assertTrue(Utils.is_containing_bracket(order_to_test), + "Fail returning True when order contains no spaced bracket") + + # Failure + order_to_test = "This test does not contain bracket" + self.assertFalse(Utils.is_containing_bracket(order_to_test), + "Fail returning False when order has no brackets") + + # Behaviour + order_to_test = "" + self.assertFalse(Utils.is_containing_bracket(order_to_test), + "Fail returning False when no order") + + def test_get_next_value_list(self): + # Success + list_to_test = {1, 2, 3} + self.assertEqual(Utils.get_next_value_list(list_to_test), 2, + "Fail to match the expected next value from the list") + + # Failure + list_to_test = {1} + self.assertEqual(Utils.get_next_value_list(list_to_test), None, + "Fail to ensure there is no next value from the list") + + # Behaviour + list_to_test = {} + self.assertEqual(Utils.get_next_value_list(list_to_test), None, + "Fail to ensure the empty list return None value") + + def test_find_all_matching_brackets(self): + """ + Test the Utils find all matching brackets + """ + sentence = "This is the {{bracket}}" + expected_result = ["{{bracket}}"] + self.assertEqual(Utils.find_all_matching_brackets(sentence=sentence), + expected_result, + "Fail to match one bracket") + + sentence = "This is the {{bracket}} {{second}}" + expected_result = ["{{bracket}}", "{{second}}"] + self.assertEqual(Utils.find_all_matching_brackets(sentence=sentence), + expected_result, + "Fail to match two brackets") + + def test_remove_spaces_in_brackets(self): + """ + Test the Utils remove_spaces_in_brackets + """ + + sentence = "This is the {{ bracket }}" + expected_result = "This is the {{bracket}}" + self.assertEqual(Utils.remove_spaces_in_brackets(sentence=sentence), + expected_result, + "Fail to remove spaces in one bracket") + + sentence = "This is the {{ bracket }} {{ second }}" + expected_result = "This is the {{bracket}} {{second}}" + self.assertEqual(Utils.remove_spaces_in_brackets(sentence=sentence), + expected_result, + "Fail to remove spaces in two brackets") \ No newline at end of file diff --git a/kalliope/core/OrderAnalyser.py b/kalliope/core/OrderAnalyser.py index 107a182a..5e3ae56a 100644 --- a/kalliope/core/OrderAnalyser.py +++ b/kalliope/core/OrderAnalyser.py @@ -240,7 +240,7 @@ def _associate_order_params_to_values(order, order_to_check): if Utils.is_containing_bracket(ow): # remove bracket and grab the next value / stop value var_name = ow.replace("{{", "").replace("}}", "") - stop_value = Utils._get_next_value_list(list_word_in_order[idx:]) + stop_value = Utils.get_next_value_list(list_word_in_order[idx:]) if stop_value is None: dict_var[var_name] = " ".join(truncate_list_word_said) break diff --git a/kalliope/core/Utils/Utils.py b/kalliope/core/Utils/Utils.py index 8f6c4eef..e9b607d8 100644 --- a/kalliope/core/Utils/Utils.py +++ b/kalliope/core/Utils/Utils.py @@ -267,7 +267,7 @@ def remove_spaces_in_brackets(sentence): # ######### @staticmethod - def _get_next_value_list(list_to_check): + def get_next_value_list(list_to_check): ite = list_to_check.__iter__() next(ite, None) return next(ite, None) diff --git a/kalliope/settings.yml b/kalliope/settings.yml index 7bd5b54a..98d83853 100644 --- a/kalliope/settings.yml +++ b/kalliope/settings.yml @@ -159,6 +159,6 @@ default_synapse: "default-synapse" # Global files variables # /!\ If a variable is defined in different files, the last file defines the value. # --------------------------- -var_files: - - variables.yml - - variables2.yml +#var_files: +# - variables.yml +# - variables2.yml From 54428826058f6e5862e0bff8bf1a72c871947d9f Mon Sep 17 00:00:00 2001 From: monf Date: Sun, 19 Feb 2017 23:41:14 +0100 Subject: [PATCH 23/54] [Doc] #203 Global variables --- Docs/neurons.md | 11 +++++++++++ Docs/settings.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/Docs/neurons.md b/Docs/neurons.md index 87a5f2bd..6bd708c9 100644 --- a/Docs/neurons.md +++ b/Docs/neurons.md @@ -47,6 +47,7 @@ Full list of [available neuron here](neuron_list.md) Neurons require some **parameters** from the synapse declaration to work. Those parameters, also called arguments, can be passed to the neuron in two way: - from the neuron declaration +- from global variables - from the captured order From the neuron declaration: @@ -57,6 +58,16 @@ neurons: parameter2: "value2" ``` +From global variables: (cf: [settings.md](settings.md)) +```yml + - name: "run-simple-sleep" + signals: + - order: "Wait for me " + neurons: + - sleep: + seconds: {{variable}} +``` + From the captured order: ```yml - name: "run-neuron-with-parameter-in-order" diff --git a/Docs/settings.md b/Docs/settings.md index b1456308..817803ee 100644 --- a/Docs/settings.md +++ b/Docs/settings.md @@ -289,5 +289,34 @@ resource_directory: trigger: "/full/path/to/trigger" ``` + +## Global Variables + +The Global Variables paths list where to load the global variables. +Those variables can be reused in neuron parameters within double brackets. + +E.g +```yml +var_files: + - variables.yml + - variables2.yml +``` + +In the files the variables are defined by key/value: +```yml +variable: 60 +variable2: "http://" +``` + +And use variables in your neurons: +```yml + - name: "run-simple-sleep" + signals: + - order: "Wait for me " + neurons: + - sleep: + seconds: {{variable}} +``` + ## Next: configure the brain of Kalliope Now your settings are ok, you can start creating the [brain](brain.md) of your assistant. From f60cb38d33f85739e90785ed17b595cc8d73adab Mon Sep 17 00:00:00 2001 From: monf Date: Mon, 20 Feb 2017 00:10:47 +0100 Subject: [PATCH 24/54] [Fix] bug on the sleep neuron with float while getting the parameter --- kalliope/neurons/sleep/sleep.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kalliope/neurons/sleep/sleep.py b/kalliope/neurons/sleep/sleep.py index 954c02e8..b745ee08 100644 --- a/kalliope/neurons/sleep/sleep.py +++ b/kalliope/neurons/sleep/sleep.py @@ -6,7 +6,7 @@ class Sleep(NeuronModule): def __init__(self, **kwargs): super(Sleep, self).__init__(**kwargs) - self.seconds = float(kwargs.get('seconds', None)) + self.seconds = kwargs.get('seconds', None) # check parameters if self._is_parameters_ok(): From c89f88d6aa768d37f2d0e561d25a6fe1921414a9 Mon Sep 17 00:00:00 2001 From: nico Date: Mon, 20 Feb 2017 21:10:15 +0100 Subject: [PATCH 25/54] upload audio ok, processing it ok. TODO: fix context --- kalliope/core/OrderListener.py | 6 ++- kalliope/core/RestAPI/FlaskAPI.py | 63 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/kalliope/core/OrderListener.py b/kalliope/core/OrderListener.py index e965179b..fcc09743 100644 --- a/kalliope/core/OrderListener.py +++ b/kalliope/core/OrderListener.py @@ -19,7 +19,7 @@ class OrderListener(Thread): starting to listen the incoming order. Basically it avoids delays. """ - def __init__(self, callback=None, stt=None): + def __init__(self, callback=None, stt=None, audio_file_path=None): """ This class is called after we catch the hotword that has woken up Kalliope. We now wait for an order spoken out loud by the user, translate the order into a text and run the action @@ -42,6 +42,7 @@ def __init__(self, callback=None, stt=None): sl = SettingLoader() self.settings = sl.settings self.stt_instance = None + self.audio_file_path = audio_file_path def run(self): """ @@ -56,6 +57,9 @@ def load_stt_plugin(self): for stt_object in self.settings.stts: if stt_object.name == self.stt_module_name: stt_object.parameters["callback"] = self.callback + # add the audio file path to the list of parameter if set + if self.audio_file_path is not None: + stt_object.parameters["audio_file_path"] = self.audio_file_path stt_folder = None if self.settings.resources: diff --git a/kalliope/core/RestAPI/FlaskAPI.py b/kalliope/core/RestAPI/FlaskAPI.py index 24443146..bba4b04c 100644 --- a/kalliope/core/RestAPI/FlaskAPI.py +++ b/kalliope/core/RestAPI/FlaskAPI.py @@ -1,6 +1,11 @@ import logging +import os import threading +from kalliope.core.ConfigurationManager import SettingLoader +from kalliope.core.OrderListener import OrderListener +from werkzeug.utils import secure_filename + from flask import jsonify from flask import request from flask_restful import abort @@ -13,6 +18,9 @@ logging.basicConfig() logger = logging.getLogger("kalliope") +UPLOAD_FOLDER = '/tmp/kalliope/tmp_uploaded_audio' +ALLOWED_EXTENSIONS = {'mp3', 'wav'} + class FlaskAPI(threading.Thread): def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): @@ -29,6 +37,13 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): self.brain = brain self.allowed_cors_origin = allowed_cors_origin + # get current settings + sl = SettingLoader() + self.settings = sl.settings + + # configure the upload folder + app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER + # Flask configuration remove default Flask behaviour to encode to ASCII self.app.url_map.strict_slashes = False self.app.config['JSON_AS_ASCII'] = False @@ -41,11 +56,17 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): self.app.add_url_rule('/synapses/', view_func=self.get_synapse, methods=['GET']) self.app.add_url_rule('/synapses/start/id/', view_func=self.run_synapse_by_name, methods=['POST']) 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']) def run(self): self.app.run(host='0.0.0.0', port="%s" % int(self.port), debug=True, threaded=True, use_reloader=False) + @staticmethod + def allowed_file(filename): + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + def _get_synapse_by_name(self, synapse_name): """ Find a synapse in the brain by its name @@ -148,6 +169,34 @@ def run_synapse_by_order(self): } return jsonify(error=data), 400 + def run_synapse_by_audio(self): + # check if the post request has the file part + if 'file' not in request.files: + data = { + "error": "No file provided" + } + return jsonify(error=data), 400 + + file = request.files['file'] + # if user does not select file, browser also + # submit a empty part without filename + if file.filename == '': + data = { + "error": "No file provided" + } + return jsonify(error=data), 400 + if file and self.allowed_file(file.filename): + # save the file + filename = secure_filename(file.filename) + base_path = os.path.join(self.app.config['UPLOAD_FOLDER']) + file.save(os.path.join(base_path, filename)) + + # now start analyse the audio with STT engine + audio_path = base_path + os.sep + filename + ol = OrderListener(callback=self.audio_analyser_callback, audio_file_path=audio_path) + ol.start() + ol.join() + @requires_auth def shutdown_server(self): func = request.environ.get('werkzeug.server.shutdown') @@ -155,3 +204,17 @@ def shutdown_server(self): raise RuntimeError('Not running with the Werkzeug Server') func() return "Shutting down..." + + def audio_analyser_callback(self, order): + logger.debug("order to process %s" % order) + if order is not None: # maybe we have received a null audio from STT engine + order_analyser = OrderAnalyser(order, brain=self.brain) + synapses_launched = order_analyser.start() + # TODO fix this. RuntimeError: Working outside of request context. + with self.app.app_context(): + data = jsonify(synapses=[e.serialize() for e in synapses_launched]) + return data, 201 + + else: + if self.settings.default_synapse is not None: + SynapseLauncher.start_synapse(name=self.settings.default_synapse, brain=self.brain) From 78a76bbddb8091c1a391ab1e51c376ca9efc759f Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 21 Feb 2017 15:54:49 +0100 Subject: [PATCH 26/54] [Tests] #203 Add a missing test + quick requested fixes --- Docs/settings.md | 13 +++-- Tests/test_order_analyser.py | 99 ++++++++++++++++++++++++++++++---- Tests/test_settings_loader.py | 4 -- kalliope/core/OrderAnalyser.py | 5 +- kalliope/settings.yml | 2 +- 5 files changed, 101 insertions(+), 22 deletions(-) diff --git a/Docs/settings.md b/Docs/settings.md index 817803ee..830e8868 100644 --- a/Docs/settings.md +++ b/Docs/settings.md @@ -295,27 +295,32 @@ resource_directory: The Global Variables paths list where to load the global variables. Those variables can be reused in neuron parameters within double brackets. -E.g +E.g ```yml var_files: - variables.yml - variables2.yml ``` +/!\ If a variable is defined in different files, the last file defines the value. In the files the variables are defined by key/value: ```yml variable: 60 -variable2: "http://" +baseURL: "http://blabla.com/" +password: "secret" ``` And use variables in your neurons: +/!\ Because YAML format does no allow double braces not surrounded by quotes: you must use the variable between double quotes. ```yml - name: "run-simple-sleep" signals: - order: "Wait for me " neurons: - - sleep: - seconds: {{variable}} + - uri: + url: "{{baseURL}}get/1" + user: "admin" + password: "{{password}}" ``` ## Next: configure the brain of Kalliope diff --git a/Tests/test_order_analyser.py b/Tests/test_order_analyser.py index 44b190e3..9b51ed26 100644 --- a/Tests/test_order_analyser.py +++ b/Tests/test_order_analyser.py @@ -160,7 +160,6 @@ def test_start_neuron(self): mock_start_neuron_method.assert_not_called() mock_start_neuron_method.reset_mock() - def test_spelt_order_match_brain_order_via_table(self): order_to_test = "this is the order" sentence_to_test = "this is the order" @@ -180,7 +179,6 @@ def test_spelt_order_match_brain_order_via_table(self): "Fail matching Upper/lower cases") def test_format_sentences_to_analyse(self): - # First capital in sentence order_to_test = "this is the order" sentence_to_test = "This is the order" @@ -218,7 +216,6 @@ def test_format_sentences_to_analyse(self): "Fails formatting the sentences with random in both order and sentence") def test_get_split_order_without_bracket(self): - # Success order_to_test = "this is the order" expected_result = ["this", "is", "the", "order"] @@ -521,9 +518,9 @@ def test_find_synapse_to_run(self): """ Test to find the good synapse to run Scenarii: - - Find the synapse - - No synpase found, no default synapse - - No synapse found, run the default synapse + - 1/ Find the synapse + - 2/ No synpase found, no default synapse + - 3/ No synapse found, run the default synapse """ # Init neuron1 = Neuron(name='neurone1', parameters={'var1': 'val1'}) @@ -545,7 +542,7 @@ def test_find_synapse_to_run(self): br = Brain(synapses=all_synapse_list) st = Settings() - # Find synapse + # 1/ Find synapse order = "this is the sentence" expected_result = synapse1 oa_tuple_list = OrderAnalyser._find_synapse_to_run(brain=br,settings=st, order=order) @@ -555,16 +552,17 @@ def test_find_synapse_to_run(self): expected_result = signal1.sentence self.assertEquals(oa_tuple_list[0].order, - expected_result, - "Fail to run the proper synapse matching the order") - # No Default synapse + expected_result, + "Fail to run the proper synapse matching the order") + + # 2/ No Default synapse order = "No default synapse" expected_result = [] self.assertEquals(OrderAnalyser._find_synapse_to_run(brain=br,settings=st, order=order), expected_result, "Fail to run no synapse, when no default is defined") - # Default synapse + # 3/ Default synapse st = Settings(default_synapse="Synapse2") order = "default synapse" expected_result = synapse2 @@ -574,5 +572,84 @@ def test_find_synapse_to_run(self): "Fail to run the default synapse") + def test_replace_global_variables(self): + """ + Testing the _replace_global_variables function from the OrderAnalyser. + Scenarii: + - 1/ only one global variable + - 2/ global variable with string after + - 3/ global variable with int after + - 4/ multiple global variables + + """ + + # 1/ only one global variable + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}'}) + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test'}) + + # assign global variable to neuron1 + OrderAnalyser._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a single global variable to neuron") + + # 2/ global variable with string after + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} Sispheor'}) + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test Sispheor'}) + + # assign global variable to neuron1 + OrderAnalyser._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a global variable with string after to neuron") + + # 3/ global variable with int after + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}0'}) + variables = { + "hello": 60, + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '600'}) + + # assign global variable to neuron1 + OrderAnalyser._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign global variable with int after to neuron") + + # 4/ multiple global variables + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} {{me}}'}) + variables = { + "hello": "hello", + "me": "LaMonf" + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'hello LaMonf'}) + + # assign global variable to neuron1 + OrderAnalyser._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign multiple global variables to neuron") + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_settings_loader.py b/Tests/test_settings_loader.py index 933087ca..c8cc1d99 100644 --- a/Tests/test_settings_loader.py +++ b/Tests/test_settings_loader.py @@ -61,10 +61,6 @@ def setUp(self): os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/tts") os.makedirs("/tmp/kalliope/tests/kalliope_resources_dir/trigger") - os.makedirs("/tmp/kalliope/tests/variables/") - open("/tmp/kalliope/tests/variables/variables.yml", 'a').close() - open("/tmp/kalliope/tests/variables/variables2.yml", 'a').close() - def tearDown(self): # Cleanup shutil.rmtree('/tmp/kalliope/tests/kalliope_resources_dir') diff --git a/kalliope/core/OrderAnalyser.py b/kalliope/core/OrderAnalyser.py index 5e3ae56a..25043a80 100644 --- a/kalliope/core/OrderAnalyser.py +++ b/kalliope/core/OrderAnalyser.py @@ -168,8 +168,9 @@ def _replace_global_variables(neuron, settings): if param_no_brackets in settings.variables: logger.debug("Replacing variable %s with %s" % (param_with_bracket, settings.variables[param_no_brackets])) - neuron.parameters[param] = sentence_no_spaces.replace(param_with_bracket, - str(settings.variables[param_no_brackets])) + sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, + str(settings.variables[param_no_brackets])) + neuron.parameters[param] = sentence_no_spaces @staticmethod def _start_neuron(neuron, params): diff --git a/kalliope/settings.yml b/kalliope/settings.yml index 98d83853..5ca220e6 100644 --- a/kalliope/settings.yml +++ b/kalliope/settings.yml @@ -126,7 +126,7 @@ on_ready_sounds: # Rest API # --------------------------- rest_api: - active: True + active: False port: 5000 password_protected: True login: admin From 4095b06954eb6db54a89776d426bf1b7d730ac76 Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 21 Feb 2017 16:05:43 +0100 Subject: [PATCH 27/54] [Tests] Fix failing tests --- Tests/test_settings_loader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/test_settings_loader.py b/Tests/test_settings_loader.py index c8cc1d99..3cba76b6 100644 --- a/Tests/test_settings_loader.py +++ b/Tests/test_settings_loader.py @@ -64,7 +64,6 @@ def setUp(self): def tearDown(self): # Cleanup shutil.rmtree('/tmp/kalliope/tests/kalliope_resources_dir') - shutil.rmtree('/tmp/kalliope/tests/variables/') Singleton._instances = {} From 012bd60aec7842c35855303e380fec941fbd40a4 Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 21 Feb 2017 20:49:46 +0100 Subject: [PATCH 28/54] [Feature] #203 Update the code and tests to manage list as parameter --- Tests/test_order_analyser.py | 38 ++++++++++++++++++++++++++- kalliope/core/OrderAnalyser.py | 46 +++++++++++++++++++++++---------- kalliope/neurons/sleep/sleep.py | 4 +++ 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/Tests/test_order_analyser.py b/Tests/test_order_analyser.py index 9b51ed26..270f394c 100644 --- a/Tests/test_order_analyser.py +++ b/Tests/test_order_analyser.py @@ -571,7 +571,6 @@ def test_find_synapse_to_run(self): expected_result, "Fail to run the default synapse") - def test_replace_global_variables(self): """ Testing the _replace_global_variables function from the OrderAnalyser. @@ -580,6 +579,7 @@ def test_replace_global_variables(self): - 2/ global variable with string after - 3/ global variable with int after - 4/ multiple global variables + - 5/ parameter value is a list """ @@ -651,5 +651,41 @@ def test_replace_global_variables(self): expected_neuron_result, "Fail to assign multiple global variables to neuron") + # 5/ parameter value is a list + neuron1 = Neuron(name='neuron1', parameters={'var1': '[hello {{name}}, bonjour {{name}}]'}) + variables = { + "name": "LaMonf", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '[hello LaMonf, bonjour LaMonf]'}) + + # assign global variable to neuron1 + OrderAnalyser._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a single global when parameter value is a list to neuron") + + def test_get_global_variable(self): + """ + Test the get_global_variable of the OrderAnalyser Class + """ + sentence = "i am {{name2}}" + variables = { + "name": "LaMonf", + "name2": "kalliope", + } + st = Settings(variables=variables) + + expected_result = "i am kalliope" + + self.assertEquals(OrderAnalyser._get_global_variable(sentence=sentence, + settings=st), + expected_result, + "Fail to get the global variable from the sentence") + + if __name__ == '__main__': unittest.main() diff --git a/kalliope/core/OrderAnalyser.py b/kalliope/core/OrderAnalyser.py index 25043a80..0f2c9d65 100644 --- a/kalliope/core/OrderAnalyser.py +++ b/kalliope/core/OrderAnalyser.py @@ -152,25 +152,45 @@ def _start_list_neurons(cls, list_neurons, params, settings): cls._replace_global_variables(neuron, settings) cls._start_neuron(neuron, params) - @staticmethod - def _replace_global_variables(neuron, settings): + @classmethod + def _replace_global_variables(cls, neuron, settings): """ Replace all the parameters with variables with the variable value. :param neuron: the neuron :param settings: the settings """ for param in neuron.parameters: - if Utils.is_containing_bracket(neuron.parameters[param]): - sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=neuron.parameters[param]) - list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) - for param_with_bracket in list_of_bracket_params: - param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") - if param_no_brackets in settings.variables: - logger.debug("Replacing variable %s with %s" % (param_with_bracket, - settings.variables[param_no_brackets])) - sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, - str(settings.variables[param_no_brackets])) - neuron.parameters[param] = sentence_no_spaces + if isinstance(neuron.parameters[param], list): + list_param_value = list() + for sentence in neuron.parameters[param]: + sentence_with_global_variables = cls._get_global_variable(sentence=sentence, + settings=settings) + list_param_value.append(sentence_with_global_variables) + neuron.parameters[param] = list_param_value + + else: + if Utils.is_containing_bracket(neuron.parameters[param]): + sentence_with_global_variables = cls._get_global_variable(sentence=neuron.parameters[param], + settings=settings) + neuron.parameters[param] = sentence_with_global_variables + + @staticmethod + def _get_global_variable(sentence, settings): + """ + Get the global variable from the sentence with brackets + :param sentence: the sentence to check + :return: the global variable + """ + sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=sentence) + list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) + for param_with_bracket in list_of_bracket_params: + param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") + if param_no_brackets in settings.variables: + logger.debug("Replacing variable %s with %s" % (param_with_bracket, + settings.variables[param_no_brackets])) + sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, + str(settings.variables[param_no_brackets])) + return sentence_no_spaces @staticmethod def _start_neuron(neuron, params): diff --git a/kalliope/neurons/sleep/sleep.py b/kalliope/neurons/sleep/sleep.py index b745ee08..4cf8a7a9 100644 --- a/kalliope/neurons/sleep/sleep.py +++ b/kalliope/neurons/sleep/sleep.py @@ -10,6 +10,10 @@ def __init__(self, **kwargs): # check parameters if self._is_parameters_ok(): + + if isinstance(self.seconds, str): + self.seconds = float(self.seconds) + time.sleep(self.seconds) def _is_parameters_ok(self): From b3efbd0366487da8c2f2b1295bff1777e9fa948b Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 21 Feb 2017 22:34:08 +0100 Subject: [PATCH 29/54] [Fix] Fix bug when parameter are int --- kalliope/core/Utils/Utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kalliope/core/Utils/Utils.py b/kalliope/core/Utils/Utils.py index e9b607d8..e98dfaa4 100644 --- a/kalliope/core/Utils/Utils.py +++ b/kalliope/core/Utils/Utils.py @@ -232,7 +232,7 @@ def is_containing_bracket(sentence): # print "sentence to test %s" % sentence pattern = r"{{|}}" # prog = re.compile(pattern) - check_bool = re.search(pattern, sentence) + check_bool = re.search(pattern, str(sentence)) if check_bool is not None: return True return False @@ -247,7 +247,7 @@ def find_all_matching_brackets(sentence): pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))" # find everything like {{ word }} - return re.findall(pattern, sentence) + return re.findall(pattern, str(sentence)) @staticmethod def remove_spaces_in_brackets(sentence): @@ -259,7 +259,7 @@ def remove_spaces_in_brackets(sentence): pattern = '\s+(?=[^\{\{\}\}]*\}\})' # Remove white spaces (if any) between the variable and the double brace then split - return re.sub(pattern, '', sentence) + return re.sub(pattern, '', str(sentence)) ################## # From 7a8afc79c17614aa1a7386a503466b2cf176140a Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 21 Feb 2017 23:00:29 +0100 Subject: [PATCH 30/54] audio upload + analyse + return synapse list ok. TODO: tests --- Docs/rest_api.md | 58 +++++++++++++++++++++++++++---- kalliope/core/RestAPI/FlaskAPI.py | 50 +++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Docs/rest_api.md b/Docs/rest_api.md index 53a0c92c..dd11c298 100644 --- a/Docs/rest_api.md +++ b/Docs/rest_api.md @@ -4,12 +4,13 @@ Kalliope provides the REST API to manage the synapses. For configuring the API r ## Synapse API -| Method | URL | Action | -|--------|-----------------------------------|---------------------------------| -| GET | /synapses | List synapses | -| GET | /synapses/ | Get synapse details by name | -| POST | /synapses/start/id/ | Run a synapse by its name | -| POST | /synapses/start/order | Run a synapse from a text order | +| Method | URL | Action | +|--------|-----------------------------------|------------------------------------| +| GET | /synapses | List synapses | +| GET | /synapses/ | Get synapse details by name | +| POST | /synapses/start/id/ | 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 | ## Curl examples @@ -176,7 +177,50 @@ Output example if the order have matched and so launched synapses: } ``` -If the order haven't match ny synapses: +If the order haven't match any synapses: +```JSON +{ + "error": { + "error": "The given order doesn't match any synapses" + } +} +``` + +### Run a synapse from an audio file + +Normal response codes: 201 +Error response codes: unauthorized(401), itemNotFound(404) + +The audio file must use WAV or MP3 extension. + +Curl command: +```bash +curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/audio -F "file=@/home/nico/Desktop/input.wav" +``` + +Output example if the order inside the audio have matched and so launched synapses: +```JSON +{ + "synapses": [ + { + "name": "Say-hello", + "neurons": [ + { + "name": "say", + "parameters": "{'message': ['Hello sir']}" + } + ], + "signals": [ + { + "order": "hello" + } + ] + } + ] +} +``` + +If the order haven't match any synapses: ```JSON { "error": { diff --git a/kalliope/core/RestAPI/FlaskAPI.py b/kalliope/core/RestAPI/FlaskAPI.py index bba4b04c..f8b3a0ae 100644 --- a/kalliope/core/RestAPI/FlaskAPI.py +++ b/kalliope/core/RestAPI/FlaskAPI.py @@ -2,6 +2,10 @@ import os import threading +import time + +from kalliope.core.Utils.FileManager import FileManager + from kalliope.core.ConfigurationManager import SettingLoader from kalliope.core.OrderListener import OrderListener from werkzeug.utils import secure_filename @@ -41,8 +45,15 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): sl = SettingLoader() self.settings = sl.settings + # list of launched synapse by the Order Analyser when using the /synapses/start/audio URL + self.launched_synapses = None + # boolean used to notify the main process that we get the list of returned synapse + self.order_analyser_return = False + # configure the upload folder app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER + # create the temp folder + FileManager.create_directory(UPLOAD_FOLDER) # Flask configuration remove default Flask behaviour to encode to ASCII self.app.url_map.strict_slashes = False @@ -170,6 +181,12 @@ def run_synapse_by_order(self): return jsonify(error=data), 400 def run_synapse_by_audio(self): + """ + Give an order to Kalliope with an audio file + Test with curl + curl -i --user admin:secret -X POST http://localhost:5000/synapses/start/audio -F "file=@/path/to/input.wav" + :return: + """ # check if the post request has the file part if 'file' not in request.files: data = { @@ -196,6 +213,19 @@ def run_synapse_by_audio(self): ol = OrderListener(callback=self.audio_analyser_callback, audio_file_path=audio_path) ol.start() ol.join() + # wait the Order Analyser processing. We need to wait in this thread to keep the context + while not self.order_analyser_return: + time.sleep(0.1) + self.order_analyser_return = False + if self.launched_synapses is not None and self.launched_synapses: + data = jsonify(synapses=[e.serialize() for e in self.launched_synapses]) + self.launched_synapses = None + return data, 201 + else: + data = { + "error": "The given order doesn't match any synapses" + } + return jsonify(error=data), 400 @requires_auth def shutdown_server(self): @@ -206,15 +236,25 @@ def shutdown_server(self): return "Shutting down..." def audio_analyser_callback(self, order): + """ + Callback of the OrderListener. Called after the processing of the audio file + This method will + - call the Order Analyser to analyse the order and launch corresponding synapse as usual. + - get a list of launched synapse. + - give the list to the main process via self.launched_synapses + - notify that the processing is over via order_analyser_return + :param order: string order to analyse + :return: + """ logger.debug("order to process %s" % order) if order is not None: # maybe we have received a null audio from STT engine order_analyser = OrderAnalyser(order, brain=self.brain) synapses_launched = order_analyser.start() - # TODO fix this. RuntimeError: Working outside of request context. - with self.app.app_context(): - data = jsonify(synapses=[e.serialize() for e in synapses_launched]) - return data, 201 - + self.launched_synapses = synapses_launched else: if self.settings.default_synapse is not None: SynapseLauncher.start_synapse(name=self.settings.default_synapse, brain=self.brain) + self.launched_synapses = self.brain.get_synapse_by_name(synapse_name=self.settings.default_synapse) + + # this boolean will notify the main process that the order have been processed + self.order_analyser_return = True From 64b7ca30e3d99688bf4679f98e7396660992f0df Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 21 Feb 2017 23:25:31 +0100 Subject: [PATCH 31/54] [Fix] fix to manage unicodes and add tests --- Tests/test_utils.py | 22 +++++++++++++++------- kalliope/core/Utils/Utils.py | 12 +++++++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Tests/test_utils.py b/Tests/test_utils.py index 2f5725da..fb279d46 100644 --- a/Tests/test_utils.py +++ b/Tests/test_utils.py @@ -1,15 +1,14 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + import unittest import os -import mock from kalliope.core.Models.Neuron import Neuron -from kalliope.core.Models.Order import Order -from kalliope.core.Models.Synapse import Synapse from kalliope.neurons.say.say import Say from kalliope.core.Utils.Utils import Utils from kalliope.core.ConfigurationManager import SettingLoader -from kalliope.core.ConfigurationManager import BrainLoader class TestUtils(unittest.TestCase): @@ -138,7 +137,6 @@ def test_get_dynamic_class_instantiation(self): Say), "Fail instantiate a class") - def test_is_containing_bracket(self): # Success order_to_test = "This test contains {{ bracket }}" @@ -157,16 +155,26 @@ def test_is_containing_bracket(self): self.assertTrue(Utils.is_containing_bracket(order_to_test), "Fail returning True when order contains no spaced bracket") - # Failure + # Failure order_to_test = "This test does not contain bracket" self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when order has no brackets") - # Behaviour + # Behaviour order_to_test = "" self.assertFalse(Utils.is_containing_bracket(order_to_test), "Fail returning False when no order") + # Behaviour int + order_to_test = 6 + self.assertFalse(Utils.is_containing_bracket(order_to_test), + "Fail returning False when an int") + + # Behaviour unicode + order_to_test = "j'aime les goûters l'été" + self.assertFalse(Utils.is_containing_bracket(order_to_test), + "Fail returning False when an int") + def test_get_next_value_list(self): # Success list_to_test = {1, 2, 3} diff --git a/kalliope/core/Utils/Utils.py b/kalliope/core/Utils/Utils.py index e98dfaa4..1161da43 100644 --- a/kalliope/core/Utils/Utils.py +++ b/kalliope/core/Utils/Utils.py @@ -232,7 +232,9 @@ def is_containing_bracket(sentence): # print "sentence to test %s" % sentence pattern = r"{{|}}" # prog = re.compile(pattern) - check_bool = re.search(pattern, str(sentence)) + if not isinstance(sentence, unicode): + sentence = str(sentence) + check_bool = re.search(pattern, sentence) if check_bool is not None: return True return False @@ -247,7 +249,9 @@ def find_all_matching_brackets(sentence): pattern = r"((?:{{\s*)[\w\.]+(?:\s*}}))" # find everything like {{ word }} - return re.findall(pattern, str(sentence)) + if not isinstance(sentence, unicode): + sentence = str(sentence) + return re.findall(pattern, sentence) @staticmethod def remove_spaces_in_brackets(sentence): @@ -259,7 +263,9 @@ def remove_spaces_in_brackets(sentence): pattern = '\s+(?=[^\{\{\}\}]*\}\})' # Remove white spaces (if any) between the variable and the double brace then split - return re.sub(pattern, '', str(sentence)) + if not isinstance(sentence, unicode): + sentence = str(sentence) + return re.sub(pattern, '', sentence) ################## # From ae9bbfcc65f3a2b01476ca0f0894c6649291ef72 Mon Sep 17 00:00:00 2001 From: bacardi55 Date: Tue, 21 Feb 2017 23:25:39 +0100 Subject: [PATCH 32/54] Add Google Maps neuron --- Docs/neuron_list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 093e968e..020018f8 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -23,6 +23,7 @@ A neuron is a module that will perform some actions attached to an order. You ca | [facebook](https://github.com/kalliope-project/kalliope_neuron_facebook) | Post and Read message on Facebook | | [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | | [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | +| [google maps](https://github.com/bacardi55/kalliope-gmaps) | Get address / distance / time / directions from Google maps | | [hue](https://github.com/kalliope-project/kalliope_neuron_hue) | Control the Philips Hue lighting system | | [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | | [MPD](https://github.com/bacardi55/kalliope-mpd) | Play music via an MPD server | From 2bc973f470af39a0354b02252d3b4f032c003b93 Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 22 Feb 2017 11:09:49 +0100 Subject: [PATCH 33/54] [Feature] Refactoring of the Global Variables in the neuron launcher --- Tests/test_launchers.py | 115 ++++++++++++++++++++++++++++++++ Tests/test_order_analyser.py | 115 -------------------------------- kalliope/core/NeuronLauncher.py | 43 ++++++++++++ kalliope/core/OrderAnalyser.py | 41 ------------ 4 files changed, 158 insertions(+), 156 deletions(-) diff --git a/Tests/test_launchers.py b/Tests/test_launchers.py index a682bbd7..ff2e019a 100644 --- a/Tests/test_launchers.py +++ b/Tests/test_launchers.py @@ -6,6 +6,7 @@ from kalliope.core.SynapseLauncher import SynapseLauncher, SynapseNameNotFound from kalliope.core.TriggerLauncher import TriggerLauncher from kalliope.core.ConfigurationManager import SettingLoader +from kalliope.core.Models.Settings import Settings from kalliope.core.Models.Trigger import Trigger from kalliope.core.Models.Neuron import Neuron @@ -136,3 +137,117 @@ def test_start_neuron(self): resources_dir=sl.settings.resources.neuron_folder) mock_get_class_instantiation.reset_mock() + def test_replace_global_variables(self): + """ + Testing the _replace_global_variables function from the NeuronLauncher. + Scenarii: + - 1/ only one global variable + - 2/ global variable with string after + - 3/ global variable with int after + - 4/ multiple global variables + - 5/ parameter value is a list + + """ + + # 1/ only one global variable + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}'}) + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test'}) + + # assign global variable to neuron1 + NeuronLauncher._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a single global variable to neuron") + + # 2/ global variable with string after + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} Sispheor'}) + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test Sispheor'}) + + # assign global variable to neuron1 + NeuronLauncher._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a global variable with string after to neuron") + + # 3/ global variable with int after + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}0'}) + variables = { + "hello": 60, + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '600'}) + + # assign global variable to neuron1 + NeuronLauncher._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign global variable with int after to neuron") + + # 4/ multiple global variables + neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} {{me}}'}) + variables = { + "hello": "hello", + "me": "LaMonf" + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'hello LaMonf'}) + + # assign global variable to neuron1 + NeuronLauncher._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign multiple global variables to neuron") + + # 5/ parameter value is a list + neuron1 = Neuron(name='neuron1', parameters={'var1': '[hello {{name}}, bonjour {{name}}]'}) + variables = { + "name": "LaMonf", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '[hello LaMonf, bonjour LaMonf]'}) + + # assign global variable to neuron1 + NeuronLauncher._replace_global_variables(neuron=neuron1, + settings=st) + self.assertEquals(neuron1, + expected_neuron_result, + "Fail to assign a single global when parameter value is a list to neuron") + + def test_get_global_variable(self): + """ + Test the get_global_variable of the OrderAnalyser Class + """ + sentence = "i am {{name2}}" + variables = { + "name": "LaMonf", + "name2": "kalliope", + } + st = Settings(variables=variables) + + expected_result = "i am kalliope" + + self.assertEquals(NeuronLauncher._get_global_variable(sentence=sentence, + settings=st), + expected_result, + "Fail to get the global variable from the sentence") diff --git a/Tests/test_order_analyser.py b/Tests/test_order_analyser.py index 270f394c..8156f2df 100644 --- a/Tests/test_order_analyser.py +++ b/Tests/test_order_analyser.py @@ -571,121 +571,6 @@ def test_find_synapse_to_run(self): expected_result, "Fail to run the default synapse") - def test_replace_global_variables(self): - """ - Testing the _replace_global_variables function from the OrderAnalyser. - Scenarii: - - 1/ only one global variable - - 2/ global variable with string after - - 3/ global variable with int after - - 4/ multiple global variables - - 5/ parameter value is a list - - """ - - # 1/ only one global variable - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}'}) - variables = { - "hello": "test", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test'}) - - # assign global variable to neuron1 - OrderAnalyser._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a single global variable to neuron") - - # 2/ global variable with string after - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} Sispheor'}) - variables = { - "hello": "test", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test Sispheor'}) - - # assign global variable to neuron1 - OrderAnalyser._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a global variable with string after to neuron") - - # 3/ global variable with int after - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}0'}) - variables = { - "hello": 60, - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '600'}) - - # assign global variable to neuron1 - OrderAnalyser._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign global variable with int after to neuron") - - # 4/ multiple global variables - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} {{me}}'}) - variables = { - "hello": "hello", - "me": "LaMonf" - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'hello LaMonf'}) - - # assign global variable to neuron1 - OrderAnalyser._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign multiple global variables to neuron") - - # 5/ parameter value is a list - neuron1 = Neuron(name='neuron1', parameters={'var1': '[hello {{name}}, bonjour {{name}}]'}) - variables = { - "name": "LaMonf", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '[hello LaMonf, bonjour LaMonf]'}) - - # assign global variable to neuron1 - OrderAnalyser._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a single global when parameter value is a list to neuron") - - def test_get_global_variable(self): - """ - Test the get_global_variable of the OrderAnalyser Class - """ - sentence = "i am {{name2}}" - variables = { - "name": "LaMonf", - "name2": "kalliope", - } - st = Settings(variables=variables) - - expected_result = "i am kalliope" - - self.assertEquals(OrderAnalyser._get_global_variable(sentence=sentence, - settings=st), - expected_result, - "Fail to get the global variable from the sentence") - if __name__ == '__main__': unittest.main() diff --git a/kalliope/core/NeuronLauncher.py b/kalliope/core/NeuronLauncher.py index 6c72725a..cf72f9f4 100644 --- a/kalliope/core/NeuronLauncher.py +++ b/kalliope/core/NeuronLauncher.py @@ -26,7 +26,50 @@ def start_neuron(cls, neuron): neuron_folder = None if settings.resources: neuron_folder = settings.resources.neuron_folder + + cls._replace_global_variables(neuron, settings) + return Utils.get_dynamic_class_instantiation(package_name="neurons", module_name=neuron.name, parameters=neuron.parameters, resources_dir=neuron_folder) + + @classmethod + def _replace_global_variables(cls, neuron, settings): + """ + Replace all the parameters with variables with the variable value. + :param neuron: the neuron + :param settings: the settings + """ + for param in neuron.parameters: + if isinstance(neuron.parameters[param], list): + list_param_value = list() + for sentence in neuron.parameters[param]: + sentence_with_global_variables = cls._get_global_variable(sentence=sentence, + settings=settings) + list_param_value.append(sentence_with_global_variables) + neuron.parameters[param] = list_param_value + + else: + if Utils.is_containing_bracket(neuron.parameters[param]): + sentence_with_global_variables = cls._get_global_variable(sentence=neuron.parameters[param], + settings=settings) + neuron.parameters[param] = sentence_with_global_variables + + @staticmethod + def _get_global_variable(sentence, settings): + """ + Get the global variable from the sentence with brackets + :param sentence: the sentence to check + :return: the global variable + """ + sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=sentence) + list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) + for param_with_bracket in list_of_bracket_params: + param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") + if param_no_brackets in settings.variables: + logger.debug("Replacing variable %s with %s" % (param_with_bracket, + settings.variables[param_no_brackets])) + sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, + str(settings.variables[param_no_brackets])) + return sentence_no_spaces diff --git a/kalliope/core/OrderAnalyser.py b/kalliope/core/OrderAnalyser.py index 0f2c9d65..1e3784fd 100644 --- a/kalliope/core/OrderAnalyser.py +++ b/kalliope/core/OrderAnalyser.py @@ -149,49 +149,8 @@ def _get_params_from_order(cls, string_order, order_to_check): def _start_list_neurons(cls, list_neurons, params, settings): # start neurons for neuron in list_neurons: - cls._replace_global_variables(neuron, settings) cls._start_neuron(neuron, params) - @classmethod - def _replace_global_variables(cls, neuron, settings): - """ - Replace all the parameters with variables with the variable value. - :param neuron: the neuron - :param settings: the settings - """ - for param in neuron.parameters: - if isinstance(neuron.parameters[param], list): - list_param_value = list() - for sentence in neuron.parameters[param]: - sentence_with_global_variables = cls._get_global_variable(sentence=sentence, - settings=settings) - list_param_value.append(sentence_with_global_variables) - neuron.parameters[param] = list_param_value - - else: - if Utils.is_containing_bracket(neuron.parameters[param]): - sentence_with_global_variables = cls._get_global_variable(sentence=neuron.parameters[param], - settings=settings) - neuron.parameters[param] = sentence_with_global_variables - - @staticmethod - def _get_global_variable(sentence, settings): - """ - Get the global variable from the sentence with brackets - :param sentence: the sentence to check - :return: the global variable - """ - sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=sentence) - list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) - for param_with_bracket in list_of_bracket_params: - param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") - if param_no_brackets in settings.variables: - logger.debug("Replacing variable %s with %s" % (param_with_bracket, - settings.variables[param_no_brackets])) - sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, - str(settings.variables[param_no_brackets])) - return sentence_no_spaces - @staticmethod def _start_neuron(neuron, params): """ From 4a3e68e8131242ae5128bd6999c84ec50abbdaf7 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 22 Feb 2017 22:38:47 +0100 Subject: [PATCH 34/54] Rest API review --- Docs/rest_api.md | 16 + Tests/brains/brain_test_api.yml | 19 ++ Tests/files/bonjour.wav | Bin 0 -> 540716 bytes Tests/test_rest_api.py | 427 +++++++++++++++----------- install/files/python_requirements.txt | 2 +- kalliope/core/RestAPI/FlaskAPI.py | 8 + setup.py | 4 +- 7 files changed, 290 insertions(+), 186 deletions(-) create mode 100644 Tests/brains/brain_test_api.yml create mode 100644 Tests/files/bonjour.wav diff --git a/Docs/rest_api.md b/Docs/rest_api.md index dd11c298..7fe27f71 100644 --- a/Docs/rest_api.md +++ b/Docs/rest_api.md @@ -6,6 +6,7 @@ Kalliope provides the REST API to manage the synapses. For configuring the API r | Method | URL | Action | |--------|-----------------------------------|------------------------------------| +| GET | / | Get kaliope version | | GET | /synapses | List synapses | | GET | /synapses/ | Get synapse details by name | | POST | /synapses/start/id/ | Run a synapse by its name | @@ -16,6 +17,21 @@ Kalliope provides the REST API to manage the synapses. For configuring the API r >**Note:** --user is only needed if `password_protected` is True +### Get Kalliope's version + +Normal response codes: 200 +Error response codes: unauthorized(401) +Curl command: +```bash +curl -i --user admin:secret -X GET http://localhost:5000/ +``` +Output example: +```JSON +{ + "Kalliope version": "0.4.2" +} +``` + ### List synapses Normal response codes: 200 diff --git a/Tests/brains/brain_test_api.yml b/Tests/brains/brain_test_api.yml new file mode 100644 index 00000000..6a98b10a --- /dev/null +++ b/Tests/brains/brain_test_api.yml @@ -0,0 +1,19 @@ +--- + - name: "test" + signals: + - order: "test_order" + neurons: + - say: + message: + - "test message" + + - name: "test2" + signals: + - order: "bonjour" + neurons: + - say: + message: + - "test message" + + - includes: + - included_brain_test.yml \ No newline at end of file diff --git a/Tests/files/bonjour.wav b/Tests/files/bonjour.wav new file mode 100644 index 0000000000000000000000000000000000000000..be0d4c4d25f62d7e0f90c22a8008f23bfb4bc64d GIT binary patch literal 540716 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
QA{V0-w5sGU^AP$qgglb%|-X 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 z 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

$UdQDXy?(Yv&^_R>DEo*Rnfh8^>0xda=gE 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 Dd>LcI literal 0 HcmV?d00001 diff --git a/Tests/test_rest_api.py b/Tests/test_rest_api.py index c57037be..7a9cd2f9 100644 --- a/Tests/test_rest_api.py +++ b/Tests/test_rest_api.py @@ -1,11 +1,14 @@ +import json import os import unittest +from werkzeug.datastructures import FileStorage + from flask import Flask from flask_testing import LiveServerTestCase from kalliope.core.Models import Singleton - +from kalliope._version import version_str from kalliope.core.ConfigurationManager import BrainLoader from kalliope.core.ConfigurationManager import SettingLoader from kalliope.core.RestAPI.FlaskAPI import FlaskAPI @@ -20,8 +23,12 @@ def create_app(self): # be sure that the singleton haven't been loaded before Singleton._instances = {} current_path = os.getcwd() - full_path_brain_to_test = current_path + os.sep + "Tests/brains/brain_test.yml" - print full_path_brain_to_test + if "/Tests" in os.getcwd(): + full_path_brain_to_test = current_path + os.sep + "brains/brain_test_api.yml" + self.audio_file = "files/bonjour.wav" + else: + full_path_brain_to_test = current_path + os.sep + "Tests/brains/brain_test_api.yml" + self.audio_file = "Tests/files/bonjour.wav" # rest api config sl = SettingLoader() @@ -36,196 +43,250 @@ def create_app(self): brain = brain_loader.brain self.app = Flask(__name__) + self.app.config['TESTING'] = True self.flask_api = FlaskAPI(self.app, port=5000, brain=brain) - self.flask_api.app.config['TESTING'] = True + self.client = self.app.test_client() return self.flask_api.app - # TODO all following test passes with 'python -m unittest Tests.TestRestAPI' but not with discover - # def test_get_all_synapses(self): - # url = "http://127.0.0.1:5000/synapses" - # - # result = requests.get(url=url) - # expected_content = { - # "synapses": [ - # { - # "name": "test", - # "neurons": [ - # { - # "say": { - # "message": [ - # "test message" - # ] - # } - # } - # ], - # "signals": [ - # { - # "order": "test_order" - # } - # ] - # }, - # { - # "name": "test2", - # "neurons": [ - # { - # "say": { - # "message": [ - # "test message" - # ] - # } - # } - # ], - # "signals": [ - # { - # "order": "test_order_2" - # } - # ] - # }, - # { - # "includes": [ - # "included_brain_test.yml" - # ] - # }, - # { - # "name": "test3", - # "neurons": [ - # { - # "say": { - # "message": [ - # "test message" - # ] - # } - # } - # ], - # "signals": [ - # { - # "order": "test_order_3" - # } - # ] - # } - # ] - # } - # - # self.assertEqual(result.status_code, 200) - # self.assertEqual(expected_content, json.loads(result.content)) - # - # def test_get_one_synapse(self): - # url = "http://127.0.0.1:5000/synapses/test" - # result = requests.get(url=url) - # - # expected_content = { - # "synapses": { - # "name": "test", - # "neurons": [ - # { - # "say": { - # "message": [ - # "test message" - # ] - # } - # } - # ], - # "signals": [ - # { - # "order": "test_order" - # } - # ] - # } - # } - # - # self.assertEqual(expected_content, json.loads(result.content)) - # - # def test_get_synapse_not_found(self): - # url = "http://127.0.0.1:5000/synapses/test-none" - # result = requests.get(url=url) - # - # expected_content = { - # "error": { - # "synapse name not found": "test-none" + def test_server_is_up_and_running(self): + # response = urllib2.urlopen(self.get_server_url()) + response = self.client.get(self.get_server_url()) + self.assertEqual(response.status_code, 200) + + def test_get_main_page(self): + url = self.get_server_url() + "/" + response = self.client.get(url) + expected_content = { + "Kalliope version": "%s" % version_str + } + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(response.get_data()))) + + def test_get_all_synapses(self): + url = self.get_server_url()+"/synapses" + + response = self.client.get(url) + expected_content = { + "synapses": [ + { + "name": "test", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "test_order" + } + ] + }, + { + "name": "test2", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "bonjour" + } + ] + }, + { + "name": "test3", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "test_order_3" + } + ] + } + ] + } + # a lot of char ti process + self.maxDiff = None + self.assertEqual(response.status_code, 200) + # print response.get_data() + # print json.dumps(expected_content) + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(response.get_data()))) + + def test_get_one_synapse(self): + url = self.get_server_url() + "/synapses/test" + response = self.client.get(url) + + expected_content = { + "synapses": { + "name": "test", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "test_order" + } + ] + } + } + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(response.get_data()))) + + def test_get_synapse_not_found(self): + url = self.get_server_url() + "/synapses/test-none" + result = self.client.get(url) + + expected_content = { + "error": { + "synapse name not found": "test-none" + } + } + + self.assertEqual(expected_content, json.loads(result.get_data())) + self.assertEqual(result.status_code, 404) + + def test_run_synapse_by_name(self): + url = self.get_server_url() + "/synapses/start/id/test" + result = self.client.post(url) + + expected_content = { + "synapses": { + "name": "test", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "test_order" + } + ] + } + } + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data()))) + self.assertEqual(result.status_code, 201) + + def test_post_synapse_not_found(self): + url = self.get_server_url() + "/synapses/start/id/test-none" + result = self.client.post(url) + + expected_content = { + "error": { + "synapse name not found": "test-none" + } + } + + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data()))) + self.assertEqual(result.status_code, 404) + + def test_run_synapse_with_order(self): + url = self.get_server_url() + "/synapses/start/order" + headers = {"Content-Type": "application/json"} + data = {"order": "test_order"} + result = self.client.post(url, headers=headers, data=json.dumps(data)) + + expected_content = { + "synapses": [ + { + "name": "test", + "neurons": [ + { + "name": "say", + "parameters": { + "message": [ + "test message" + ] + } + } + ], + "signals": [ + { + "order": "test_order" + } + ] + } + ] + } + print result.get_data() + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data()))) + self.assertEqual(result.status_code, 201) + + def test_post_synapse_by_order_not_found(self): + url = self.get_server_url() + "/synapses/start/order" + data = {"order": "non existing order"} + headers = {"Content-Type": "application/json"} + result = self.client.post(url, headers=headers, data=json.dumps(data)) + + expected_content = {'error': {'error': "The given order doesn't match any synapses"}} + + self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data()))) + self.assertEqual(result.status_code, 400) + + # TODO this doesn't work on travis but works locally with python -m unittest discover + # def test_post_synapse_by_audio(self): + # url = self.get_server_url() + "/synapses/start/audio" + # with open(os.path.join(self.audio_file), 'rb') as fp: + # file = FileStorage(fp) + # data = { + # 'file': file # } - # } + # result = self.client.post(url, data=data, content_type='multipart/form-data') # - # self.assertEqual(expected_content, json.loads(result.content)) - # self.assertEqual(result.status_code, 404) - # - # def test_run_synapse_by_name(self): - # url = "http://127.0.0.1:5000/synapses/test" - # result = requests.post(url=url) - # - # expected_content = { - # "synapses": { - # "name": "test", - # "neurons": [ - # { - # "say": { - # "message": [ - # "test message" - # ] - # } - # } - # ], - # "signals": [ + # expected_content = { + # "synapses": [ # { - # "order": "test_order" + # "name": "test2", + # "neurons": [ + # { + # "name": "say", + # "parameters": { + # "message": [ + # "test message" + # ] + # } + # } + # ], + # "signals": [ + # { + # "order": "bonjour" + # } + # ] # } # ] # } - # } - # - # self.assertEqual(expected_content, json.loads(result.content)) - # self.assertEqual(result.status_code, 201) - # - # def test_post_synapse_not_found(self): - # url = "http://127.0.0.1:5000/synapses/test-none" - # result = requests.post(url=url) - # - # expected_content = { - # "error": { - # "synapse name not found": "test-none" - # } - # } - # - # self.assertEqual(expected_content, json.loads(result.content)) - # self.assertEqual(result.status_code, 404) - # - # def test_run_synapse_with_order(self): - # url = "http://127.0.0.1:5000/order/" - # headers = {"Content-Type": "application/json"} - # data = {"order": "test_order"} - # result = requests.post(url=url, headers=headers, json=data) - # - # expected_content = { - # "synapses": [ - # { - # "name": "test", - # "neurons": [ - # { - # "name": "say", - # "parameters": "{'message': ['test message']}" - # } - # ], - # "signals": [ - # { - # "order": "test_order" - # } - # ] - # } - # ] - # } - # - # self.assertEqual(expected_content, json.loads(result.content)) - # self.assertEqual(result.status_code, 201) - # - # def test_post_synapse_by_order_not_found(self): - # url = "http://127.0.0.1:5000/order/" - # data = {"order": "non existing order"} - # headers = {"Content-Type": "application/json"} - # result = requests.post(url=url, headers=headers, json=data) - # - # expected_content = {'error': {'error': "The given order doesn't match any synapses"}} # - # self.assertEqual(expected_content, json.loads(result.content)) - # self.assertEqual(result.status_code, 400) + # self.assertEqual(json.dumps(expected_content), json.dumps(json.loads(result.get_data()))) + # self.assertEqual(result.status_code, 201) if __name__ == '__main__': unittest.main() diff --git a/install/files/python_requirements.txt b/install/files/python_requirements.txt index 526fad6c..0371af03 100644 --- a/install/files/python_requirements.txt +++ b/install/files/python_requirements.txt @@ -14,7 +14,7 @@ flask_cors==3.0.2 requests==2.12.4 httpretty==0.8.14 mock==2.0.0 -Flask-Testing==0.6.1 +Flask-Testing>=0.6.1 apscheduler==3.3.0 GitPython==2.1.1 packaging>=16.8 diff --git a/kalliope/core/RestAPI/FlaskAPI.py b/kalliope/core/RestAPI/FlaskAPI.py index f8b3a0ae..6016fff5 100644 --- a/kalliope/core/RestAPI/FlaskAPI.py +++ b/kalliope/core/RestAPI/FlaskAPI.py @@ -18,6 +18,7 @@ from kalliope.core import OrderAnalyser from kalliope.core.RestAPI.utils import requires_auth from kalliope.core.SynapseLauncher import SynapseLauncher +from kalliope._version import version_str logging.basicConfig() logger = logging.getLogger("kalliope") @@ -63,6 +64,7 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): cors = CORS(app, resources={r"/*": {"origins": allowed_cors_origin}}, supports_credentials=True) # 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']) self.app.add_url_rule('/synapses/', view_func=self.get_synapse, methods=['GET']) self.app.add_url_rule('/synapses/start/id/', view_func=self.run_synapse_by_name, methods=['POST']) @@ -73,6 +75,12 @@ def __init__(self, app, port=5000, brain=None, allowed_cors_origin=False): def run(self): self.app.run(host='0.0.0.0', port="%s" % int(self.port), debug=True, threaded=True, use_reloader=False) + def get_main_page(self): + data = { + "Kalliope version": "%s" % version_str + } + return jsonify(data), 200 + @staticmethod def allowed_file(filename): return '.' in filename and \ diff --git a/setup.py b/setup.py index 34dbab03..c99f1843 100644 --- a/setup.py +++ b/setup.py @@ -73,11 +73,11 @@ def read_version_py(file_name): 'requests==2.12.4', 'httpretty==0.8.14', 'mock==2.0.0', - 'Flask-Testing==0.6.1', + 'Flask-Testing>=0.6.1', 'apscheduler==3.3.0', 'GitPython==2.1.1', 'packaging>=16.8', - 'transitions>=0.4.3' + 'transitions>=0.4.3', ], From 71da0931b76d442b2dfc5a955c9151fb140fb70e Mon Sep 17 00:00:00 2001 From: nico Date: Sun, 26 Feb 2017 14:27:06 +0100 Subject: [PATCH 35/54] remove password from log output + fix crash when sudo password is empty --- Tests/test_neuron_model.py | 42 +++++++++++++++++++++++++++++++ kalliope/core/Models/Neuron.py | 16 +++++++++++- kalliope/core/NeuronLauncher.py | 2 +- kalliope/core/NeuronModule.py | 1 - kalliope/core/ResourcesManager.py | 29 +++++++++++++-------- kalliope/core/Utils/Utils.py | 1 - 6 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 Tests/test_neuron_model.py diff --git a/Tests/test_neuron_model.py b/Tests/test_neuron_model.py new file mode 100644 index 00000000..4d63289e --- /dev/null +++ b/Tests/test_neuron_model.py @@ -0,0 +1,42 @@ +import os +import unittest + +from kalliope.core.Models import Neuron + + +class TestNeuronModule(unittest.TestCase): + + def test_password_parameter(self): + neuron_name = "test" + neuron_parameters = { + "password": "my secret", + "parameter": "test" + } + + neuron = Neuron() + neuron.name = neuron_name + neuron.parameters = neuron_parameters + + print neuron.__str__() + expected_result = "Neuron: name: test, parameters: {'password': '*****', 'parameter': 'test'}" + + self.assertEqual(neuron.__str__(), expected_result) + + def test_password_in_parameter(self): + neuron_name = "test" + neuron_parameters = { + "password_parameter": "my secret", + "parameter": "test" + } + + neuron = Neuron() + neuron.name = neuron_name + neuron.parameters = neuron_parameters + + print neuron.__str__() + expected_result = "Neuron: name: test, parameters: {'parameter': 'test', 'password_parameter': '*****'}" + + self.assertEqual(neuron.__str__(), expected_result) + +if __name__ == '__main__': + unittest.main() diff --git a/kalliope/core/Models/Neuron.py b/kalliope/core/Models/Neuron.py index 2e282ef0..76c81a87 100644 --- a/kalliope/core/Models/Neuron.py +++ b/kalliope/core/Models/Neuron.py @@ -22,7 +22,21 @@ def serialize(self): } def __str__(self): - return "Neuron: name: %s, parameters: %s" % (self.name, self.parameters) + """ + Return a string that describe the neuron. If a parameter contains the word "password", + the output of this parameter will be masked in order to not appears in clean in the console + :return: string description of the neuron + """ + returned_string = str() + returned_string += "Neuron: name: %s" % self.name + cleaned_parameters = dict() + for key, value in self.parameters.iteritems(): + if "password" in key: + cleaned_parameters[key] = "*****" + else: + cleaned_parameters[key] = value + returned_string += ", parameters: %s" % cleaned_parameters + return returned_string def __eq__(self, other): """ diff --git a/kalliope/core/NeuronLauncher.py b/kalliope/core/NeuronLauncher.py index cf72f9f4..2e9152da 100644 --- a/kalliope/core/NeuronLauncher.py +++ b/kalliope/core/NeuronLauncher.py @@ -20,7 +20,7 @@ def start_neuron(cls, neuron): :type neuron: Neuron :return: """ - logger.debug("Run plugin \"%s\" with parameters %s" % (neuron.name, neuron.parameters)) + logger.debug("Run neuron: \"%s\"" % (neuron.__str__())) sl = SettingLoader() settings = sl.settings neuron_folder = None diff --git a/kalliope/core/NeuronModule.py b/kalliope/core/NeuronModule.py index 18008a5e..737c6042 100644 --- a/kalliope/core/NeuronModule.py +++ b/kalliope/core/NeuronModule.py @@ -64,7 +64,6 @@ def __init__(self, **kwargs): # get the child who called the class child_name = self.__class__.__name__ self.neuron_name = child_name - logger.debug("NeuronModule called from class %s with parameters: %s" % (child_name, str(kwargs))) sl = SettingLoader() self.settings = sl.settings diff --git a/kalliope/core/ResourcesManager.py b/kalliope/core/ResourcesManager.py index 6942cfcb..bedab71c 100644 --- a/kalliope/core/ResourcesManager.py +++ b/kalliope/core/ResourcesManager.py @@ -95,8 +95,10 @@ def install(self): # if the target_path exists, then run the install file within the new repository if target_path is not None: self.install_file_path = target_path + os.sep + INSTALL_FILE_NAME - self.run_ansible_playbook_module(install_file_path=self.install_file_path) - Utils.print_success("Module: %s installed" % module_name) + if self.run_ansible_playbook_module(install_file_path=self.install_file_path): + Utils.print_success("Module: %s installed" % module_name) + else: + Utils.print_danger("Module: %s not installed" % module_name) else: logger.debug("[ResourcesManager] installation cancelled, deleting temp repo %s" % str(self.tmp_path)) @@ -218,7 +220,7 @@ def _rename_temp_folder(name, target_folder, tmp_path): try: shutil.move(tmp_path, new_absolute_neuron_path) return new_absolute_neuron_path - except OSError: + except shutil.Error: # the folder already exist Utils.print_warning("The module %s already exist in the path %s" % (name, target_folder)) # remove the cloned repo @@ -237,14 +239,19 @@ def run_ansible_playbook_module(install_file_path): Utils.print_info("Starting neuron installation") # ask the sudo password pswd = getpass.getpass('Sudo password:') - ansible_neuron_parameters = { - "task_file": install_file_path, - "sudo": True, - "sudo_user": "root", - "sudo_password": pswd - } - neuron = Neuron(name="ansible_playbook", parameters=ansible_neuron_parameters) - NeuronLauncher.start_neuron(neuron) + if not pswd or pswd == "": + Utils.print_warning("You must enter a sudo password") + return False + else: + ansible_neuron_parameters = { + "task_file": install_file_path, + "sudo": True, + "sudo_user": "root", + "sudo_password": pswd + } + neuron = Neuron(name="ansible_playbook", parameters=ansible_neuron_parameters) + NeuronLauncher.start_neuron(neuron) + return True @staticmethod def _check_supported_version(current_version, supported_versions): diff --git a/kalliope/core/Utils/Utils.py b/kalliope/core/Utils/Utils.py index 1161da43..86f7043f 100644 --- a/kalliope/core/Utils/Utils.py +++ b/kalliope/core/Utils/Utils.py @@ -101,7 +101,6 @@ def get_dynamic_class_instantiation(cls, package_name, module_name, parameters=N :param resources_dir: the resource directory to check for external resources :return: """ - logger.debug("Run plugin %s with parameter %s" % (module_name, parameters)) package_path = "kalliope." + package_name + "." + module_name.lower() + "." + module_name.lower() if resources_dir is not None: neuron_resource_path = resources_dir + os.sep + module_name.lower() \ From 6478a1d61999f8ed0cec3d41461a1fd6c637b152 Mon Sep 17 00:00:00 2001 From: nico Date: Sun, 26 Feb 2017 15:54:43 +0100 Subject: [PATCH 36/54] add feature uninstall resources --- Docs/neuron_list.md | 82 +++++++++++++++++++++++++++++++ Docs/neurons.md | 17 +------ kalliope/__init__.py | 19 ++++++- kalliope/core/ResourcesManager.py | 57 +++++++++++++++++---- 4 files changed, 147 insertions(+), 28 deletions(-) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 020018f8..d6e29748 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -44,3 +44,85 @@ A neuron is a module that will perform some actions attached to an order. You ca Wanna add your neuron in the list? Open [an issue](../../issues) with the link of your neuron or send a pull request to update the list directly. To know how to install a community neuron, read the "Installation" section of the [neuron documentation](neurons.md). + +## Installation + +Core neurons are already packaged with the installation of kalliope an can be used out of the box. Community neuron need to be installed manually. +>**Note:** To install a neuron, you must declare your `resource_directory` in your [settings](settings.md). + +### Via the kalliope's CLI + +CLI syntax +```bash +kalliope install --git-url +``` + +E.g: +```bash +kalliope install --git-url https://github.com/kalliope-project/kalliope_neuron_wikipedia.git +``` +You may be prompted to type your `sudo` password during the process. + +### Manually + +You can also install a neuron manually. +Fist, clone the repo in the right resource folder. +```bash +cd /path/to/resource_folder +git clone +``` + +Then install it manually via Ansible (Ansible has been installed with kalliope) +```bash +cd +ansible-playbook install.yml -K +``` + +Full example +```bash +cd /home/me/my_kalliope_config/resources/neurons +git clone https://github.com/kalliope-project/kalliope_neuron_hue.git +cd hue +ansible-playbook install.yml -K +``` + +## Uninstall a resource +### Via the kalliope's CLI +>**Note:** To uninstall a resource, you must declare the `resource_directory` in your [settings](settings.md). + +CLI syntax +```bash +kalliope uninstall --neuron-name +kalliope uninstall --stt-name +kalliope uninstall --tts-name +kalliope uninstall --trigger-name +``` + +E.g: +```bash +kalliope uninstall --neuron-name hue +``` + +### Manually + +To remove a resource, you only need to delete the folder from the corresponding `resource_directory`. +```bash +cd /path/to/resource_folder +rm -rf +``` + +E.g +```bash +cd /home/me/my_kalliope_config/resources/neurons +rm -rf hue +``` + +>**Note:** When deleting a resource folder, libraries that have been installed by the resource are not removed from the system. If you want a complete cleanup, you'll have to open the install.yml file of the resource to see what have been installed and rollback manually each task. +For example, when installing the neuron hue, the python lib called phue has been installed. To perform a complete cleanup, you need then to run "sudo pip uninstall phue". + + +## Update a resource + +To update a resource, you can either: +- uninstall the resource and then reinstall it back +- go into the resource directory and run a `git pull` diff --git a/Docs/neurons.md b/Docs/neurons.md index 6bd708c9..276dfc6f 100644 --- a/Docs/neurons.md +++ b/Docs/neurons.md @@ -2,22 +2,7 @@ A neuron is a plugin that performs a specific action. You use it to create a synapse. You can add as many neurons as you want to a synapse. The neurons are executed one by one when the input order is triggered. - -## Installation - -Core neurons are already packaged with the installation of kalliope an can be used out of the box. Community neuron need to be installed manually. - -Use the CLI -```bash -kalliope install --git-url -``` - -E.g: -```bash -kalliope install --git-url https://github.com/kalliope-project/kalliope_neuron_wikipedia.git -``` - -You may be prompted to type your `sudo` password during the process. You can see the list of [available neuron here](neuron_list.md) +If you want to install a community neuron, see the [neuron list documentation](neuron_list.md). ## Usage Neurons are declared in the `neurons` section of a synapse in your brain file. diff --git a/kalliope/__init__.py b/kalliope/__init__.py index 48d7215b..291d697c 100644 --- a/kalliope/__init__.py +++ b/kalliope/__init__.py @@ -34,7 +34,7 @@ def signal_handler(signal, frame): sys.exit(0) # actions available -ACTION_LIST = ["start", "gui", "install"] +ACTION_LIST = ["start", "gui", "install", "uninstall"] def main(): @@ -42,7 +42,7 @@ def main(): # create arguments parser = argparse.ArgumentParser(description='Kalliope') - parser.add_argument("action", help="[start|gui|install]") + parser.add_argument("action", help="[start|gui|install|uninstall]") parser.add_argument("--run-synapse", help="Name of a synapse to load surrounded by quote") parser.add_argument("--run-order", help="order surrounded by a quote") @@ -50,6 +50,10 @@ def main(): parser.add_argument("--debug", action='store_true', help="Show debug output") parser.add_argument("--git-url", help="Git URL of the neuron to install") + parser.add_argument("--neuron-name", help="Neuron name to uninstall") + parser.add_argument("--stt-name", help="STT name to uninstall") + parser.add_argument("--tts-name", help="TTS name to uninstall") + parser.add_argument("--trigger-name", help="Trigger name to uninstall") parser.add_argument('-v', '--version', action='version', version='Kalliope ' + version_str) @@ -91,6 +95,17 @@ def main(): res_manager.install() return + # uninstall modules + if args.action == "uninstall": + if not args.neuron_name and not args.stt_name and not args.tts_name and not args.trigger_name: + Utils.print_danger("You must specify a module name with --neuron-name or --stt-name or --tts-name " + "or --trigger-name") + else: + res_manager = ResourcesManager() + res_manager.uninstall(neuron_name=args.neuron_name, stt_name=args.stt_name, + tts_name=args.tts_name, trigger_name=args.trigger_name) + return + # load the brain once brain_loader = BrainLoader(file_path=brain_file) brain = brain_loader.brain diff --git a/kalliope/core/ResourcesManager.py b/kalliope/core/ResourcesManager.py index bedab71c..2115dacb 100644 --- a/kalliope/core/ResourcesManager.py +++ b/kalliope/core/ResourcesManager.py @@ -54,8 +54,7 @@ def __init__(self, **kwargs): self.git_url = kwargs.get('git_url', None) # temp path where we install the new module - self.tmp_path = tempfile.gettempdir() + "/kalliope/resources/" +\ - TMP_GIT_FOLDER + self.tmp_path = tempfile.gettempdir() + "/kalliope/resources/" + TMP_GIT_FOLDER self.dna_file_path = self.tmp_path + os.sep + DNA_FILE_NAME self.install_file_path = self.tmp_path + os.sep + INSTALL_FILE_NAME self.dna = None @@ -104,6 +103,39 @@ def install(self): % str(self.tmp_path)) shutil.rmtree(self.tmp_path) + def uninstall(self, neuron_name=None, tts_name=None, stt_name=None, trigger_name=None): + """ + Uninstall a community resource + """ + target_path_to_delete = None + module_name = "" + if neuron_name is not None: + target_path_to_delete = self._get_target_folder(resources=self.settings.resources, + module_type="neuron") + module_name = neuron_name + if tts_name is not None: + target_path_to_delete = self._get_target_folder(resources=self.settings.resources, + module_type="neuron") + module_name = tts_name + if stt_name is not None: + target_path_to_delete = self._get_target_folder(resources=self.settings.resources, + module_type="neuron") + module_name = stt_name + if trigger_name is not None: + target_path_to_delete = self._get_target_folder(resources=self.settings.resources, + module_type="neuron") + module_name = trigger_name + + if target_path_to_delete is not None: + try: + shutil.rmtree(target_path_to_delete + os.sep + module_name) + Utils.print_success("Module %s deleted" % module_name) + except shutil.Error: + Utils.print_warning("The module %s doest not exist in the path %s" % (module_name, target_path_to_delete)) + except OSError: + Utils.print_warning( + "The module %s doest not exist in the path %s" % (module_name, target_path_to_delete)) + @staticmethod def is_settings_ok(resources, dna): """ @@ -169,23 +201,28 @@ def _get_target_folder(resources, module_type): Return the folder from the resources and given a module type :param resources: Resource object :type resources: Resources - :param module_type: type of the module + :param module_type: type of the module (TYPE_NEURON, TYPE_STT, TYPE_TTS, TYPE_TRIGGER) :return: path of the folder """ + module_type_converter = dict() # dict to get the path behind a type of resource - module_type_converter = { - TYPE_NEURON: resources.neuron_folder, - TYPE_STT: resources.stt_folder, - TYPE_TTS: resources.tts_folder, - TYPE_TRIGGER: resources.trigger_folder - } + try: + module_type_converter = { + TYPE_NEURON: resources.neuron_folder, + TYPE_STT: resources.stt_folder, + TYPE_TTS: resources.tts_folder, + TYPE_TRIGGER: resources.trigger_folder + } + except AttributeError: + # will be raised if the resource folder is not set in settings + pass # Let's find the right path depending of the type try: folder_path = module_type_converter[module_type] except KeyError: folder_path = None # No folder_path has been found - message = "No %s folder set in settings, cannot install." % module_type + message = "No %s folder set in settings." % module_type if folder_path is None: logger.debug(message) Utils.print_danger(message) From d89478d6015165e9505907cefaa578403c4bad77 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Mon, 27 Feb 2017 12:40:34 +0100 Subject: [PATCH 37/54] Unpin some dependencies These are outdated and it makes no sense to pin them for rolling releases. I hope this does not break anything, but these seem common and mature modules that are less likely to introduce regressions. --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 34dbab03..b8bf6f6d 100644 --- a/setup.py +++ b/setup.py @@ -62,15 +62,15 @@ def read_version_py(file_name): 'markupsafe==0.23', 'pyaudio==0.2.9', 'pyasn1>=0.1.8', - 'ansible==2.2.0.0', + 'ansible>=2.2', 'python2-pythondialog==3.4.0', - 'jinja2==2.8', + 'jinja2>=2.8', 'cffi==1.9.1', - 'ipaddress==1.0.17', - 'flask==0.11.1', + 'ipaddress>=1.0.17', + 'flask>=0.11.1', 'Flask-Restful==0.3.5', 'flask_cors==3.0.2', - 'requests==2.12.4', + 'requests>=2.12.4', 'httpretty==0.8.14', 'mock==2.0.0', 'Flask-Testing==0.6.1', From 16f4fa24d0d3fd56ba102213672558c13a96b63a Mon Sep 17 00:00:00 2001 From: Monf Date: Mon, 27 Feb 2017 21:43:12 +0100 Subject: [PATCH 38/54] [fix] remove useless included brain --- Tests/brains/brain_test_api.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/brains/brain_test_api.yml b/Tests/brains/brain_test_api.yml index 6a98b10a..bb717497 100644 --- a/Tests/brains/brain_test_api.yml +++ b/Tests/brains/brain_test_api.yml @@ -14,6 +14,3 @@ - say: message: - "test message" - - - includes: - - included_brain_test.yml \ No newline at end of file From f6474a8a10b8d8d786e59fe73f4932456ec8cb23 Mon Sep 17 00:00:00 2001 From: Monf Date: Mon, 27 Feb 2017 21:43:38 +0100 Subject: [PATCH 39/54] [Fix] remove useless print --- Tests/test_neuron_model.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/test_neuron_model.py b/Tests/test_neuron_model.py index 4d63289e..ad382a9f 100644 --- a/Tests/test_neuron_model.py +++ b/Tests/test_neuron_model.py @@ -17,7 +17,6 @@ def test_password_parameter(self): neuron.name = neuron_name neuron.parameters = neuron_parameters - print neuron.__str__() expected_result = "Neuron: name: test, parameters: {'password': '*****', 'parameter': 'test'}" self.assertEqual(neuron.__str__(), expected_result) @@ -33,7 +32,6 @@ def test_password_in_parameter(self): neuron.name = neuron_name neuron.parameters = neuron_parameters - print neuron.__str__() expected_result = "Neuron: name: test, parameters: {'parameter': 'test', 'password_parameter': '*****'}" self.assertEqual(neuron.__str__(), expected_result) From 22962adba83c23a7ed7de733bf1a68c4472a73f1 Mon Sep 17 00:00:00 2001 From: Monf Date: Mon, 27 Feb 2017 21:54:07 +0100 Subject: [PATCH 40/54] [fix] add not so useless brain test --- Tests/brains/brain_test_api.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/brains/brain_test_api.yml b/Tests/brains/brain_test_api.yml index bb717497..83eca48d 100644 --- a/Tests/brains/brain_test_api.yml +++ b/Tests/brains/brain_test_api.yml @@ -14,3 +14,6 @@ - say: message: - "test message" + + - includes: + - included_brain_test.yml From 693d5329e2432030a6247ad684507614119d5d07 Mon Sep 17 00:00:00 2001 From: Monf Date: Mon, 27 Feb 2017 21:59:56 +0100 Subject: [PATCH 41/54] [fix] remove useless print --- Tests/test_neuron_model.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/test_neuron_model.py b/Tests/test_neuron_model.py index 4d63289e..ad382a9f 100644 --- a/Tests/test_neuron_model.py +++ b/Tests/test_neuron_model.py @@ -17,7 +17,6 @@ def test_password_parameter(self): neuron.name = neuron_name neuron.parameters = neuron_parameters - print neuron.__str__() expected_result = "Neuron: name: test, parameters: {'password': '*****', 'parameter': 'test'}" self.assertEqual(neuron.__str__(), expected_result) @@ -33,7 +32,6 @@ def test_password_in_parameter(self): neuron.name = neuron_name neuron.parameters = neuron_parameters - print neuron.__str__() expected_result = "Neuron: name: test, parameters: {'parameter': 'test', 'password_parameter': '*****'}" self.assertEqual(neuron.__str__(), expected_result) From aac87817f35e71562d8ce8d9ec1ac3c7f14de6ed Mon Sep 17 00:00:00 2001 From: monf Date: Mon, 27 Feb 2017 22:05:24 +0100 Subject: [PATCH 42/54] [Fix] manage uppercaser and lowercase on the uninstalled module --- kalliope/core/ResourcesManager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kalliope/core/ResourcesManager.py b/kalliope/core/ResourcesManager.py index 2115dacb..c72d0c59 100644 --- a/kalliope/core/ResourcesManager.py +++ b/kalliope/core/ResourcesManager.py @@ -128,13 +128,13 @@ def uninstall(self, neuron_name=None, tts_name=None, stt_name=None, trigger_name if target_path_to_delete is not None: try: - shutil.rmtree(target_path_to_delete + os.sep + module_name) - Utils.print_success("Module %s deleted" % module_name) + shutil.rmtree(target_path_to_delete + os.sep + module_name.lower()) + Utils.print_success("Module %s deleted" % module_name.lower()) except shutil.Error: - Utils.print_warning("The module %s doest not exist in the path %s" % (module_name, target_path_to_delete)) + Utils.print_warning("The module %s doest not exist in the path %s" % (module_name.lower(), target_path_to_delete)) except OSError: Utils.print_warning( - "The module %s doest not exist in the path %s" % (module_name, target_path_to_delete)) + "The module %s doest not exist in the path %s" % (module_name.lower(), target_path_to_delete)) @staticmethod def is_settings_ok(resources, dna): From bd71d160f610376604f8fd6f293aabe633a7d68d Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 28 Feb 2017 08:34:38 +0100 Subject: [PATCH 43/54] fix acapela TTS --> #221 --- kalliope/tts/acapela/acapela.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kalliope/tts/acapela/acapela.py b/kalliope/tts/acapela/acapela.py index f498dae1..aa7d4a17 100644 --- a/kalliope/tts/acapela/acapela.py +++ b/kalliope/tts/acapela/acapela.py @@ -7,7 +7,7 @@ logging.basicConfig() logger = logging.getLogger("kalliope") -TTS_URL = "http://www.acapela-group.com/demo-tts/DemoHTML5Form_V2_fr.php" +TTS_URL = "http://dmbx.acapela-group.com/DemoHTML5Form_V2_fr.php" TTS_CONTENT_TYPE = "audio/mpeg" TTS_TIMEOUT_SEC = 30 @@ -80,6 +80,7 @@ def get_payload(self): "MySelectedVoice": self.voice, "MyTextForTTS": self.words, "t": "1", + "agreeterms": "on", "SendToVaaS": "" } From 239b0c1433d5506e6320f17149d2e5a3cf11e331 Mon Sep 17 00:00:00 2001 From: monf Date: Tue, 28 Feb 2017 23:44:23 +0100 Subject: [PATCH 44/54] [Feature] #203 Global parameters loaded in the BrainLoader --- .../core/ConfigurationManager/BrainLoader.py | 61 +++++++++++++++++-- .../core/ConfigurationManager/YAMLLoader.py | 9 +++ kalliope/core/NeuronLauncher.py | 41 ------------- 3 files changed, 65 insertions(+), 46 deletions(-) diff --git a/kalliope/core/ConfigurationManager/BrainLoader.py b/kalliope/core/ConfigurationManager/BrainLoader.py index 634b3d65..c5ba3c16 100644 --- a/kalliope/core/ConfigurationManager/BrainLoader.py +++ b/kalliope/core/ConfigurationManager/BrainLoader.py @@ -4,6 +4,7 @@ from YAMLLoader import YAMLLoader from kalliope.core.Utils import Utils +from kalliope.core.ConfigurationManager import SettingLoader from kalliope.core.ConfigurationManager.ConfigurationChecker import ConfigurationChecker from kalliope.core.Models import Singleton from kalliope.core.Models.Brain import Brain @@ -29,6 +30,9 @@ class BrainLoader(object): __metaclass__ = Singleton def __init__(self, file_path=None): + sl = SettingLoader() + self.settings = sl.settings + self.file_path = file_path if self.file_path is None: # we don't provide a file path, so search for the default one self.file_path = Utils.get_real_file_path(FILE_NAME) @@ -85,7 +89,7 @@ def get_brain(self): if ConfigurationChecker().check_synape_dict(synapses_dict): # print "synapses_dict ok" name = synapses_dict["name"] - neurons = self._get_neurons(synapses_dict["neurons"]) + neurons = self._get_neurons(synapses_dict["neurons"], self.settings) signals = self._get_signals(synapses_dict["signals"]) new_synapse = Synapse(name=name, neurons=neurons, signals=signals) synapses.append(new_synapse) @@ -100,13 +104,14 @@ def get_brain(self): return brain - @staticmethod - def _get_neurons(neurons_dict): + @classmethod + def _get_neurons(cls, neurons_dict, settings): """ Get a list of Neuron object from a neuron dict :param neurons_dict: Neuron name or dictionary of Neuron_name/Neuron_parameters :type neurons_dict: String or dict + :param settings: The Settings with the global variables :return: A list of Neurons :rtype: List @@ -127,7 +132,11 @@ def _get_neurons(neurons_dict): name = neuron_name parameters = neuron_dict[name] - # print parameters + + # Update brackets + parameters = cls._replace_global_variables(parameters=parameters, + settings=settings) + new_neuron = Neuron(name=name, parameters=parameters) neurons.append(new_neuron) else: @@ -234,4 +243,46 @@ def get_key(key_name): second = get_key("second") return Event(year=year, month=month, day=day, week=week, - day_of_week=day_of_week, hour=hour, minute=minute, second=second) \ No newline at end of file + day_of_week=day_of_week, hour=hour, minute=minute, second=second) + + @classmethod + def _replace_global_variables(cls, parameters, settings): + """ + Replace all the parameters with variables with the variable value. + :param parameters: the parameters dict with brackets + :param settings: the settings + :return: the parameter dict + """ + for param in parameters: + if isinstance(parameters[param], list): + list_param_value = list() + for sentence in parameters[param]: + sentence_with_global_variables = cls._get_global_variable(sentence=sentence, + settings=settings) + list_param_value.append(sentence_with_global_variables) + parameters[param] = list_param_value + + else: + if Utils.is_containing_bracket(parameters[param]): + sentence_with_global_variables = cls._get_global_variable(sentence=parameters[param], + settings=settings) + parameters[param] = sentence_with_global_variables + return parameters + + @staticmethod + def _get_global_variable(sentence, settings): + """ + Get the global variable from the sentence with brackets + :param sentence: the sentence to check + :return: the global variable + """ + sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=sentence) + list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) + for param_with_bracket in list_of_bracket_params: + param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") + if param_no_brackets in settings.variables: + logger.debug("Replacing variable %s with %s" % (param_with_bracket, + settings.variables[param_no_brackets])) + sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, + str(settings.variables[param_no_brackets])) + return sentence_no_spaces \ No newline at end of file diff --git a/kalliope/core/ConfigurationManager/YAMLLoader.py b/kalliope/core/ConfigurationManager/YAMLLoader.py index 120892ce..5052ad08 100644 --- a/kalliope/core/ConfigurationManager/YAMLLoader.py +++ b/kalliope/core/ConfigurationManager/YAMLLoader.py @@ -14,6 +14,13 @@ class YAMLFileNotFound(Exception): pass +class YAMLFileEmpty(Exception): + """ + YAML file empty + """ + pass + + class YAMLLoader: """ Simple Class to Verify / Load a YAML file. @@ -67,6 +74,8 @@ def __init__(self, file_path): # load the yaml file self.data = yaml.load(open(file_path, 'r')) + if self.data is None: + raise YAMLFileEmpty("File %s is empty" % file_path) # add included brain if isinstance(self.data, list): for el in self.data: diff --git a/kalliope/core/NeuronLauncher.py b/kalliope/core/NeuronLauncher.py index 2e9152da..94f70017 100644 --- a/kalliope/core/NeuronLauncher.py +++ b/kalliope/core/NeuronLauncher.py @@ -27,49 +27,8 @@ def start_neuron(cls, neuron): if settings.resources: neuron_folder = settings.resources.neuron_folder - cls._replace_global_variables(neuron, settings) - return Utils.get_dynamic_class_instantiation(package_name="neurons", module_name=neuron.name, parameters=neuron.parameters, resources_dir=neuron_folder) - @classmethod - def _replace_global_variables(cls, neuron, settings): - """ - Replace all the parameters with variables with the variable value. - :param neuron: the neuron - :param settings: the settings - """ - for param in neuron.parameters: - if isinstance(neuron.parameters[param], list): - list_param_value = list() - for sentence in neuron.parameters[param]: - sentence_with_global_variables = cls._get_global_variable(sentence=sentence, - settings=settings) - list_param_value.append(sentence_with_global_variables) - neuron.parameters[param] = list_param_value - - else: - if Utils.is_containing_bracket(neuron.parameters[param]): - sentence_with_global_variables = cls._get_global_variable(sentence=neuron.parameters[param], - settings=settings) - neuron.parameters[param] = sentence_with_global_variables - - @staticmethod - def _get_global_variable(sentence, settings): - """ - Get the global variable from the sentence with brackets - :param sentence: the sentence to check - :return: the global variable - """ - sentence_no_spaces = Utils.remove_spaces_in_brackets(sentence=sentence) - list_of_bracket_params = Utils.find_all_matching_brackets(sentence=sentence_no_spaces) - for param_with_bracket in list_of_bracket_params: - param_no_brackets = param_with_bracket.replace("{{", "").replace("}}", "") - if param_no_brackets in settings.variables: - logger.debug("Replacing variable %s with %s" % (param_with_bracket, - settings.variables[param_no_brackets])) - sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, - str(settings.variables[param_no_brackets])) - return sentence_no_spaces From d166703cb5611bf3aea06da3d6e3cbb391c0d69c Mon Sep 17 00:00:00 2001 From: bacardi55 Date: Thu, 2 Mar 2017 23:39:35 +0100 Subject: [PATCH 45/54] Add todotxt neuron to community list --- Docs/neuron_list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index d6e29748..ec74362f 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -35,6 +35,7 @@ A neuron is a module that will perform some actions attached to an order. You ca | [slack](https://github.com/kalliope-project/kalliope_neuron_slack) | Post and Read message on Slack | | [system_status](https://github.com/bacardi55/kalliope-system-status) | Get info about the system (cpu, memory, … | | [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | +| [todotxt](https://github.com/bacardi55/kalliope-todotxt) | Manage a todolist via Kalliope | | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | | [web scraper](https://github.com/bacardi55/kalliope-web-scraper) | Read web pages that don't provide RSS feed or APIs (by scraping html) | | From d32b0ec374d8f74c2bdafdda8ab1fb4068ae7f10 Mon Sep 17 00:00:00 2001 From: monf Date: Fri, 3 Mar 2017 00:01:22 +0100 Subject: [PATCH 46/54] [Tests] Add tests for global variables now loading from the brainloader --- Tests/test_brain_loader.py | 154 ++++++++++++++++++++++++++++++++++++- Tests/test_launchers.py | 113 --------------------------- 2 files changed, 153 insertions(+), 114 deletions(-) diff --git a/Tests/test_brain_loader.py b/Tests/test_brain_loader.py index 6b6e60d5..0ed67d54 100644 --- a/Tests/test_brain_loader.py +++ b/Tests/test_brain_loader.py @@ -9,6 +9,7 @@ from kalliope.core.Models import Synapse from kalliope.core.Models import Order from kalliope.core.Models.Brain import Brain +from kalliope.core.Models.Settings import Settings class TestBrainLoader(unittest.TestCase): @@ -63,12 +64,37 @@ def test_get_brain(self): self.assertEqual(brain, brain_loader.brain) def test_get_neurons(self): + """ + Test to get neurons from the brainLoader + scenarii: + - 1/ get a simple neuron from the brainloader + - 2/ get a neuron with global variables as parameters + """ + # 1/ get a simple neuron from the brainloader + st = Settings() neuron_list = [{'say': {'message': ['test message']}}] neuron = Neuron(name='say', parameters={'message': ['test message']}) bl = BrainLoader(file_path=self.brain_to_test) - neurons_from_brain_loader = bl._get_neurons(neuron_list) + neurons_from_brain_loader = bl._get_neurons(neuron_list, + settings=st) + + self.assertEqual([neuron], neurons_from_brain_loader) + + # 2/ get a neuron with global variables as parameters + neuron_list = [{'say': {'message': ['bonjour {{name}}']}}] + variables = { + "author": "Lamonf", + "test_number": 60, + "name": "kalliope" + } + st = Settings(variables=variables) + bl = BrainLoader(file_path=self.brain_to_test) + neurons_from_brain_loader = bl._get_neurons(neuron_list, + settings=st) + + neuron = Neuron(name='say', parameters={'message': ['bonjour kalliope']}) self.assertEqual([neuron], neurons_from_brain_loader) @@ -103,5 +129,131 @@ def test_singleton(self): self.assertTrue(bl1.brain is bl2.brain) + def test_replace_global_variables(self): + """ + Testing the _replace_global_variables function from the NeuronLauncher. + Scenarii: + - 1/ only one global variable + - 2/ global variable with string after + - 3/ global variable with int after + - 4/ multiple global variables + - 5/ parameter value is a list + + """ + + # 1/ only one global variable + parameters={ + 'var1': '{{hello}}' + } + + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_parameters={ + 'var1': 'test' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + settings=st), + expected_parameters, + "Fail to assign a single global variable to parameters") + + # 2/ global variable with string after + parameters={ + 'var1': '{{hello}} Sispheor' + } + variables = { + "hello": "test", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_parameters = { + 'var1': 'test Sispheor' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + settings=st), + expected_parameters, + "Fail to assign a global variable with string after to parameters") + + # 3/ global variable with int after + parameters={ + 'var1': '{{hello}}0' + } + variables = { + "hello": 60, + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_parameters={ + 'var1': '600' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + settings=st), + expected_parameters, + "Fail to assign global variable with int after to parameters") + + # 4/ multiple global variables + parameters={ + 'var1': '{{hello}} {{me}}' + } + variables = { + "hello": "hello", + "me": "LaMonf" + } + st = Settings(variables=variables) + + expected_parameters={ + 'var1': 'hello LaMonf' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + settings=st), + expected_parameters, + "Fail to assign multiple global variables to parameters") + + # 5/ parameter value is a list + parameters={ + 'var1': '[hello {{name}}, bonjour {{name}}]' + } + variables = { + "name": "LaMonf", + "hello2": "test2", + } + st = Settings(variables=variables) + + expected_parameters={ + 'var1': '[hello LaMonf, bonjour LaMonf]' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + settings=st), + expected_parameters, + "Fail to assign a single global when parameter value is a list to neuron") + + def test_get_global_variable(self): + """ + Test the get_global_variable of the OrderAnalyser Class + """ + sentence = "i am {{name2}}" + variables = { + "name": "LaMonf", + "name2": "kalliope", + } + st = Settings(variables=variables) + + expected_result = "i am kalliope" + + self.assertEquals(BrainLoader._get_global_variable(sentence=sentence, + settings=st), + expected_result, + "Fail to get the global variable from the sentence") + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_launchers.py b/Tests/test_launchers.py index ff2e019a..ae56be7b 100644 --- a/Tests/test_launchers.py +++ b/Tests/test_launchers.py @@ -137,117 +137,4 @@ def test_start_neuron(self): resources_dir=sl.settings.resources.neuron_folder) mock_get_class_instantiation.reset_mock() - def test_replace_global_variables(self): - """ - Testing the _replace_global_variables function from the NeuronLauncher. - Scenarii: - - 1/ only one global variable - - 2/ global variable with string after - - 3/ global variable with int after - - 4/ multiple global variables - - 5/ parameter value is a list - - """ - # 1/ only one global variable - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}'}) - variables = { - "hello": "test", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test'}) - - # assign global variable to neuron1 - NeuronLauncher._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a single global variable to neuron") - - # 2/ global variable with string after - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} Sispheor'}) - variables = { - "hello": "test", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'test Sispheor'}) - - # assign global variable to neuron1 - NeuronLauncher._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a global variable with string after to neuron") - - # 3/ global variable with int after - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}}0'}) - variables = { - "hello": 60, - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '600'}) - - # assign global variable to neuron1 - NeuronLauncher._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign global variable with int after to neuron") - - # 4/ multiple global variables - neuron1 = Neuron(name='neuron1', parameters={'var1': '{{hello}} {{me}}'}) - variables = { - "hello": "hello", - "me": "LaMonf" - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': 'hello LaMonf'}) - - # assign global variable to neuron1 - NeuronLauncher._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign multiple global variables to neuron") - - # 5/ parameter value is a list - neuron1 = Neuron(name='neuron1', parameters={'var1': '[hello {{name}}, bonjour {{name}}]'}) - variables = { - "name": "LaMonf", - "hello2": "test2", - } - st = Settings(variables=variables) - - expected_neuron_result = Neuron(name='neuron1', parameters={'var1': '[hello LaMonf, bonjour LaMonf]'}) - - # assign global variable to neuron1 - NeuronLauncher._replace_global_variables(neuron=neuron1, - settings=st) - self.assertEquals(neuron1, - expected_neuron_result, - "Fail to assign a single global when parameter value is a list to neuron") - - def test_get_global_variable(self): - """ - Test the get_global_variable of the OrderAnalyser Class - """ - sentence = "i am {{name2}}" - variables = { - "name": "LaMonf", - "name2": "kalliope", - } - st = Settings(variables=variables) - - expected_result = "i am kalliope" - - self.assertEquals(NeuronLauncher._get_global_variable(sentence=sentence, - settings=st), - expected_result, - "Fail to get the global variable from the sentence") From b5b0f64457c6fb668742406a667fa636e4b79959 Mon Sep 17 00:00:00 2001 From: nico Date: Sat, 4 Mar 2017 13:59:54 +0100 Subject: [PATCH 47/54] fix neurotransmitter --- Tests/test_brain_loader.py | 55 ++++++++++++++----- Tests/test_neuron_module.py | 3 +- .../core/ConfigurationManager/BrainLoader.py | 44 ++++++++------- kalliope/core/NeuronModule.py | 6 +- 4 files changed, 71 insertions(+), 37 deletions(-) diff --git a/Tests/test_brain_loader.py b/Tests/test_brain_loader.py index 0ed67d54..a6bc714d 100644 --- a/Tests/test_brain_loader.py +++ b/Tests/test_brain_loader.py @@ -15,7 +15,11 @@ class TestBrainLoader(unittest.TestCase): def setUp(self): - self.brain_to_test = os.getcwd() + os.sep + "Tests/brains/brain_test.yml" + if "/Tests" in os.getcwd(): + self.brain_to_test = os.getcwd() + os.sep + "brains/brain_test.yml" + else: + self.brain_to_test = os.getcwd() + os.sep + "Tests/brains/brain_test.yml" + self.expected_result = [ {'signals': [{'order': 'test_order'}], 'neurons': [{'say': {'message': ['test message']}}], @@ -138,11 +142,12 @@ def test_replace_global_variables(self): - 3/ global variable with int after - 4/ multiple global variables - 5/ parameter value is a list + - 6/ parameter is a dict """ # 1/ only one global variable - parameters={ + parameters = { 'var1': '{{hello}}' } @@ -152,17 +157,17 @@ def test_replace_global_variables(self): } st = Settings(variables=variables) - expected_parameters={ + expected_parameters = { 'var1': 'test' } - self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, settings=st), expected_parameters, "Fail to assign a single global variable to parameters") # 2/ global variable with string after - parameters={ + parameters = { 'var1': '{{hello}} Sispheor' } variables = { @@ -175,13 +180,13 @@ def test_replace_global_variables(self): 'var1': 'test Sispheor' } - self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, settings=st), expected_parameters, "Fail to assign a global variable with string after to parameters") # 3/ global variable with int after - parameters={ + parameters = { 'var1': '{{hello}}0' } variables = { @@ -190,17 +195,17 @@ def test_replace_global_variables(self): } st = Settings(variables=variables) - expected_parameters={ + expected_parameters = { 'var1': '600' } - self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, settings=st), expected_parameters, "Fail to assign global variable with int after to parameters") # 4/ multiple global variables - parameters={ + parameters = { 'var1': '{{hello}} {{me}}' } variables = { @@ -209,17 +214,17 @@ def test_replace_global_variables(self): } st = Settings(variables=variables) - expected_parameters={ + expected_parameters = { 'var1': 'hello LaMonf' } - self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, settings=st), expected_parameters, "Fail to assign multiple global variables to parameters") # 5/ parameter value is a list - parameters={ + parameters = { 'var1': '[hello {{name}}, bonjour {{name}}]' } variables = { @@ -228,11 +233,31 @@ def test_replace_global_variables(self): } st = Settings(variables=variables) - expected_parameters={ + expected_parameters = { 'var1': '[hello LaMonf, bonjour LaMonf]' } - self.assertEquals(BrainLoader._replace_global_variables(parameters=parameters, + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, + settings=st), + expected_parameters, + "Fail to assign a single global when parameter value is a list to neuron") + + # 6/ parameter is a dict + parameters = {'from_answer_link': [{'synapse': 'synapse2', 'answers': ['absolument', '{{ name }}']}, + {'synapse': 'synapse3', 'answers': ['{{ name }}']}], 'default': 'synapse4'} + + variables = { + "name": "nico" + } + st = Settings(variables=variables) + + expected_parameters = { + 'from_answer_link': [ + {'synapse': 'synapse2', 'answers': ['absolument', 'nico']}, + {'synapse': 'synapse3', 'answers': ['nico']}], 'default': 'synapse4' + } + + self.assertEquals(BrainLoader._replace_global_variables(parameter=parameters, settings=st), expected_parameters, "Fail to assign a single global when parameter value is a list to neuron") diff --git a/Tests/test_neuron_module.py b/Tests/test_neuron_module.py index 3b4e9736..514bb9f3 100644 --- a/Tests/test_neuron_module.py +++ b/Tests/test_neuron_module.py @@ -36,7 +36,8 @@ def test_get_audio_from_stt(self): with mock.patch("kalliope.core.OrderListener.join") as mock_orderListener_join: def callback(): pass - NeuronModule.get_audio_from_stt(callback=callback()) + + self.neuron_module_test.get_audio_from_stt(callback=callback()) mock_orderListener_start.assert_called_once_with() mock_orderListener_start.reset_mock() diff --git a/kalliope/core/ConfigurationManager/BrainLoader.py b/kalliope/core/ConfigurationManager/BrainLoader.py index c5ba3c16..8eedd77b 100644 --- a/kalliope/core/ConfigurationManager/BrainLoader.py +++ b/kalliope/core/ConfigurationManager/BrainLoader.py @@ -133,8 +133,8 @@ def _get_neurons(cls, neurons_dict, settings): name = neuron_name parameters = neuron_dict[name] - # Update brackets - parameters = cls._replace_global_variables(parameters=parameters, + # Update brackets with the global parameter if exist + parameters = cls._replace_global_variables(parameter=parameters, settings=settings) new_neuron = Neuron(name=name, parameters=parameters) @@ -246,28 +246,32 @@ def get_key(key_name): day_of_week=day_of_week, hour=hour, minute=minute, second=second) @classmethod - def _replace_global_variables(cls, parameters, settings): + def _replace_global_variables(cls, parameter, settings): """ - Replace all the parameters with variables with the variable value. - :param parameters: the parameters dict with brackets + replace a parameter that contains bracket by the instantiated parameter from the var file + This function will call itself multiple time to handle different level of parameter in a neuron + + :param parameter: the parameter to update. can be a dict, a list or a string :param settings: the settings :return: the parameter dict """ - for param in parameters: - if isinstance(parameters[param], list): - list_param_value = list() - for sentence in parameters[param]: - sentence_with_global_variables = cls._get_global_variable(sentence=sentence, - settings=settings) - list_param_value.append(sentence_with_global_variables) - parameters[param] = list_param_value - else: - if Utils.is_containing_bracket(parameters[param]): - sentence_with_global_variables = cls._get_global_variable(sentence=parameters[param], - settings=settings) - parameters[param] = sentence_with_global_variables - return parameters + if isinstance(parameter, dict): + # print "parameter is dict %s" % str(parameter) + for key, value in parameter.iteritems(): + parameter[key] = cls._replace_global_variables(value, settings=settings) + return parameter + if isinstance(parameter, list): + # print "parameter is list %s" % str(parameter) + new_parameter_list = list() + for el in parameter: + new_parameter_list.append(cls._replace_global_variables(el, settings=settings)) + return new_parameter_list + if isinstance(parameter, str) or isinstance(parameter, unicode): + # print "parameter is string %s" % parameter + if Utils.is_containing_bracket(parameter): + return cls._get_global_variable(sentence=parameter, settings=settings) + return parameter @staticmethod def _get_global_variable(sentence, settings): @@ -285,4 +289,4 @@ def _get_global_variable(sentence, settings): settings.variables[param_no_brackets])) sentence_no_spaces = sentence_no_spaces.replace(param_with_bracket, str(settings.variables[param_no_brackets])) - return sentence_no_spaces \ No newline at end of file + return sentence_no_spaces diff --git a/kalliope/core/NeuronModule.py b/kalliope/core/NeuronModule.py index 737c6042..71dd0ac7 100644 --- a/kalliope/core/NeuronModule.py +++ b/kalliope/core/NeuronModule.py @@ -209,7 +209,8 @@ def run_synapse_by_name_with_order(self, order, synapse_name, order_template): oa = OrderAnalyser(order=order, brain=self.brain) oa.start(synapses_to_run=list_to_run, external_order=order_template) else: - logger.debug("[NeuronModule]-> run_synapse_by_name_with_order, the synapse has not been found : %s" % synapse_name) + logger.debug("[NeuronModule]-> run_synapse_by_name_with_order, the synapse has not been found : %s" + % synapse_name) return synapse_to_run is not None @staticmethod @@ -245,6 +246,9 @@ def get_audio_from_stt(callback): ol = OrderListener(callback=callback) ol.start() ol.join() + # wait that the STT engine has finish his job (or the neurotransmitter neuron will be killed) + if ol.stt_instance is not None: + ol.stt_instance.join() def get_neuron_name(self): """ From 4ecbe41a52c86d7b094df5ea862f833cd18c44fb Mon Sep 17 00:00:00 2001 From: bacardi55 Date: Wed, 8 Mar 2017 10:21:28 -0500 Subject: [PATCH 48/54] Add uber neuron --- Docs/neuron_list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index ec74362f..0078975f 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -37,6 +37,7 @@ A neuron is a module that will perform some actions attached to an order. You ca | [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | | [todotxt](https://github.com/bacardi55/kalliope-todotxt) | Manage a todolist via Kalliope | | [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | +| [Uber](https://github.com/bacardi55/kalliope-uber) | Get time and price estimation for a uber ride | | [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | | [web scraper](https://github.com/bacardi55/kalliope-web-scraper) | Read web pages that don't provide RSS feed or APIs (by scraping html) | | | [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | From 50aa961d62cdac0940ba8694a1d5f9566749c9c7 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 8 Mar 2017 22:23:38 +0100 Subject: [PATCH 49/54] add a link to the main install doc in each distro install doc --- Docs/installation/debian_jessie.md | 2 ++ Docs/installation/raspbian_jessie.md | 2 ++ Docs/installation/ubuntu_14.04.md | 2 ++ Docs/installation/ubuntu_16.04.md | 2 ++ Docs/neuron_list.md | 50 +++------------------------- README.md | 4 +-- 6 files changed, 14 insertions(+), 48 deletions(-) diff --git a/Docs/installation/debian_jessie.md b/Docs/installation/debian_jessie.md index 325c9c73..19a7a890 100644 --- a/Docs/installation/debian_jessie.md +++ b/Docs/installation/debian_jessie.md @@ -26,3 +26,5 @@ Then, with pip, the last release of setuptools sudo pip install -U setuptools ``` +Then, follow the [main installation documentation](../installation.md). + diff --git a/Docs/installation/raspbian_jessie.md b/Docs/installation/raspbian_jessie.md index 774f9eab..edaf5542 100644 --- a/Docs/installation/raspbian_jessie.md +++ b/Docs/installation/raspbian_jessie.md @@ -153,3 +153,5 @@ Check the [official documentation](https://www.raspberrypi.org/documentation/con ```bash sudo raspi-config ``` + +Then, follow the [main installation documentation](../installation.md). diff --git a/Docs/installation/ubuntu_14.04.md b/Docs/installation/ubuntu_14.04.md index 38b8a382..54653ec0 100644 --- a/Docs/installation/ubuntu_14.04.md +++ b/Docs/installation/ubuntu_14.04.md @@ -14,3 +14,5 @@ Let's install the last release of python-pip wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py ``` + +Then, follow the [main installation documentation](../installation.md). diff --git a/Docs/installation/ubuntu_16.04.md b/Docs/installation/ubuntu_16.04.md index b791660a..9185132a 100644 --- a/Docs/installation/ubuntu_16.04.md +++ b/Docs/installation/ubuntu_16.04.md @@ -13,3 +13,5 @@ Let's install the last release of python-pip wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py ``` + +Then, follow the [main installation documentation](../installation.md). diff --git a/Docs/neuron_list.md b/Docs/neuron_list.md index 0078975f..3cd78f16 100644 --- a/Docs/neuron_list.md +++ b/Docs/neuron_list.md @@ -1,51 +1,9 @@ -# List of available neuron - +# Neuron installation A neuron is a module that will perform some actions attached to an order. You can use it in your synapses. See the [complete neuron documentation](neurons.md) for more information. -## Core neuron - -| Name | Description | -|-----------------------------------------------------------|---------------------------------------------------| -| [ansible_playbook](../kalliope/neurons/ansible_playbook/) | Run an ansible playbook | -| [kill_switch](../kalliope/neurons/kill_switch/) | Stop Kalliope process | -| [neurotransmitter](../kalliope/neurons/neurotransmitter/) | Link synapse together | -| [say](../kalliope/neurons/say/) | Make Kalliope talk by using TTS | -| [script](../kalliope/neurons/script/) | Run an executable script | -| [shell](../kalliope/neurons/shell/) | Run a shell command | -| [sleep](../kalliope/neurons/sleep/) | Make Kalliope sleep for a while before continuing | -| [systemdate](../kalliope/neurons/systemdate/) | Give the local system date and time | -| [uri](../kalliope/neurons/uri/) | Interacts with HTTP and HTTPS web services. | - -## Community neuron - -| Name | Description | -|--------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| -| [facebook](https://github.com/kalliope-project/kalliope_neuron_facebook) | Post and Read message on Facebook | -| [gmail_checker](https://github.com/kalliope-project/kalliope_neuron_gmail) | Get the number of unread email and their subjects from a gmail account | -| [google agenda](https://github.com/bacardi55/kalliope-google-calendar) | Get your next meetings on google calendar | -| [google maps](https://github.com/bacardi55/kalliope-gmaps) | Get address / distance / time / directions from Google maps | -| [hue](https://github.com/kalliope-project/kalliope_neuron_hue) | Control the Philips Hue lighting system | -| [list available orders](https://github.com/bacardi55/kalliope-list-available-orders) | Let kalliope tell you what she how she can help | -| [MPD](https://github.com/bacardi55/kalliope-mpd) | Play music via an MPD server | -| [openweathermap](https://github.com/kalliope-project/kalliope_neuron_openweathermap) | Get the weather of a location | -| [pi camera](https://github.com/bacardi55/kalliope-picamera) | Take picture with your picamera | -| [pushetta](https://github.com/kalliope-project/kalliope_neuron_pushetta) | Send a push message to a remote device like Android/iOS/Windows Phone or Chrome browser | -| [repeat](https://github.com/bacardi55/kalliope-repeat) | Make kalliope say whatever you want | -| [rss_reader](https://github.com/kalliope-project/kalliope_neuron_rss_reader) | Get rss feed from website | -| [slack](https://github.com/kalliope-project/kalliope_neuron_slack) | Post and Read message on Slack | -| [system_status](https://github.com/bacardi55/kalliope-system-status) | Get info about the system (cpu, memory, … | -| [tasker](https://github.com/kalliope-project/kalliope_neuron_tasker) | Send a message to Android tasker app | -| [todotxt](https://github.com/bacardi55/kalliope-todotxt) | Manage a todolist via Kalliope | -| [twitter](https://github.com/kalliope-project/kalliope_neuron_twitter) | Send a Twit from kalliope | -| [Uber](https://github.com/bacardi55/kalliope-uber) | Get time and price estimation for a uber ride | -| [wake_on_lan](https://github.com/kalliope-project/kalliope_neuron_wake_on_lan) | Wake on lan a computer | -| [web scraper](https://github.com/bacardi55/kalliope-web-scraper) | Read web pages that don't provide RSS feed or APIs (by scraping html) | | -| [wikipedia](https://github.com/kalliope-project/kalliope_neuron_wikipedia) | Search for a page on Wikipedia | - - -Wanna add your neuron in the list? Open [an issue](../../issues) with the link of your neuron or send a pull request to update the list directly. - -To know how to install a community neuron, read the "Installation" section of the [neuron documentation](neurons.md). +## Neuron list + +Get the full neuron list available on [the project web site](https://kalliope-project.github.io/). ## Installation diff --git a/README.md b/README.md index bde7c220..7cad77b4 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,12 @@ Once installed, you can start learning basics of Kalliope from a [quick start co | [Settings](Docs/settings.md) | The main Kalliope configuration | | [Brain](Docs/brain.md) | What is the brain and how to create your own bot | | [neuron](Docs/neurons.md) | What is a neuron and how to use it | -| [neuron list](Docs/neuron_list.md) | List of availlable neurons | +| [neuron list](Docs/neuron_list.md) | List of available neurons | | [CLI](Docs/kalliope_cli.md) | How to use Kalliope from the command line interface | | [Signals](Docs/signals.md) | Signals are input event that can wake up kalliope (spoken order, scheduled event, REST API) | | [STT](Docs/stt.md) | Speech to text configuration | | [TTS](Docs/tts.md) | Text to speech configuration | -| [Triggers](Docs/trigger.md) | Magic hotword engine used to make Kalliope listtening for an order | +| [Triggers](Docs/trigger.md) | Magic hotword engine used to make Kalliope listening for an order | | [REST API](Docs/rest_api.md) | Integrated REST API. Can be used to send an order | ## Contributing From 60a9a4489fb37384375f68b08c45d78f5e7366df Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 8 Mar 2017 22:30:30 +0100 Subject: [PATCH 50/54] [Release] Update version + changelog --- CHANGELOG.md | 15 +++++++++++++++ kalliope/_version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f08f24e..d8ab010b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +v0.4.3 / 2017-03-11 +=================== +- Update Documentation +- Improve API + manage incoming audio +- Fix bug maximum recursion +- Disable REST API by default +- Add command line run-order to start a synapse +- Run default synapse if STT engine do not return an order +- Manage global variables +- Remove password from log +- cli command to delete a neuron +- Fix neurotransmitter +- Fix Acapela TTS +- Remove Voxygen TTS (not working anymore) + v0.4.2 / 2017-01-18 =================== - fix community neuron installation diff --git a/kalliope/_version.py b/kalliope/_version.py index eab3cce9..f7954917 100644 --- a/kalliope/_version.py +++ b/kalliope/_version.py @@ -1,2 +1,2 @@ # https://www.python.org/dev/peps/pep-0440/ -version_str = "0.4.2" +version_str = "0.4.3" From bac902e046ec2eabb7ddcd9af36dd58f1b5c7fc0 Mon Sep 17 00:00:00 2001 From: nico Date: Wed, 8 Mar 2017 22:38:07 +0100 Subject: [PATCH 51/54] update setup.py --- setup.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 5bf4b702..a9a64973 100644 --- a/setup.py +++ b/setup.py @@ -58,24 +58,24 @@ def read_version_py(file_name): # required libs install_requires=[ 'six==1.10.0', - 'SpeechRecognition>=3.5.0', - 'markupsafe==0.23', - 'pyaudio==0.2.9', - 'pyasn1>=0.1.8', + 'SpeechRecognition>=3.6.0', + 'markupsafe>=1.0', + 'pyaudio>=0.2.10', + 'pyasn1>=0.2.3', 'ansible>=2.2', - 'python2-pythondialog==3.4.0', - 'jinja2>=2.8', + 'python2-pythondialog>=3.4.0', + 'jinja2>=2.9.5', 'cffi==1.9.1', 'ipaddress>=1.0.17', - 'flask>=0.11.1', - 'Flask-Restful==0.3.5', + 'flask>=0.12', + 'Flask-Restful>=0.3.5', 'flask_cors==3.0.2', - 'requests>=2.12.4', - 'httpretty==0.8.14', - 'mock==2.0.0', - 'Flask-Testing>=0.6.1', - 'apscheduler==3.3.0', - 'GitPython==2.1.1', + 'requests>=2.13', + 'httpretty>=0.8.14', + 'mock>=2.0.0', + 'Flask-Testing>=0.6.2', + 'apscheduler>=3.3.1', + 'GitPython>=2.1.3', 'packaging>=16.8', 'transitions>=0.4.3', ], From c32681d772a112f4c89a359ba22a4f41995f66bf Mon Sep 17 00:00:00 2001 From: monf Date: Wed, 8 Mar 2017 22:52:33 +0100 Subject: [PATCH 52/54] [Remove] Voxygen not supported anymore --- Docs/neurons.md | 4 +- Docs/settings.md | 4 +- Docs/tts.md | 3 -- Docs/tts_list.md | 2 +- brain_examples/systemdate.yml | 2 +- kalliope/core/TTS/TTSModule.py | 2 +- kalliope/settings.yml | 8 ++-- kalliope/tts/voxygen/README.md | 11 ----- kalliope/tts/voxygen/__init__.py | 1 - kalliope/tts/voxygen/voxygen.py | 69 -------------------------------- 10 files changed, 11 insertions(+), 95 deletions(-) delete mode 100644 kalliope/tts/voxygen/README.md delete mode 100644 kalliope/tts/voxygen/__init__.py delete mode 100644 kalliope/tts/voxygen/voxygen.py diff --git a/Docs/neurons.md b/Docs/neurons.md index 276dfc6f..21dad35a 100644 --- a/Docs/neurons.md +++ b/Docs/neurons.md @@ -156,10 +156,10 @@ neurons: - say: message: - "My name is Kalliope" - tts: "voxygen" + tts: "acapela" ``` -Here, the first neuron will use the default tts as set in the settings.yml file. The second neuron will use the tts "voxygen". +Here, the first neuron will use the default tts as set in the settings.yml file. The second neuron will use the tts "acapela". >**Note:** The TTS must has been configured with its required parameters in the settings.yml file. See [TTS documentation](tts.md). diff --git a/Docs/settings.md b/Docs/settings.md index 830e8868..2adad698 100644 --- a/Docs/settings.md +++ b/Docs/settings.md @@ -104,8 +104,8 @@ E.g text_to_speech: - pico2wave: language: "fr-FR" - - voxygen: - voice: "michel" + - googletts: + language: "fr" ``` Some arguments are required, some other optional, please refer to the [TTS documentation](tts.md) to know available parameters for each supported TTS. diff --git a/Docs/tts.md b/Docs/tts.md index f3ae45a7..4fd40fbe 100644 --- a/Docs/tts.md +++ b/Docs/tts.md @@ -75,9 +75,6 @@ text_to_speech: - pico2wave: language: "fr-FR" cache: True - - voxygen: - voice: "Agnes" - cache: True - acapela: language: "sonid15" voice: "Manon" diff --git a/Docs/tts_list.md b/Docs/tts_list.md index bf73410a..46416637 100644 --- a/Docs/tts_list.md +++ b/Docs/tts_list.md @@ -12,7 +12,7 @@ Core TTSs are already packaged with the installation of Kalliope an can be used | GoogleTTS | [GoogleTTS](../kalliope/tts/googletts/README.md) | Cloud based | | VoiceRSS | [VoiceRSS](../kalliope/tts/voicerss/README.md) | Cloud based | | Pico2wave | [Pico2wave](../kalliope/tts/pico2wave/README.md) | Self hosted | -| Voxygen | [Voxygen](../kalliope/tts/voxygen/README.md) | Cloud based | +| ~~Voxygen~~ | ~~[Voxygen](../kalliope/tts/voxygen/README.md)~~ |~~Cloud based~~| ## Community TTS Community TTSs need to be installed manually. diff --git a/brain_examples/systemdate.yml b/brain_examples/systemdate.yml index 63ed1fad..d7e2d89e 100644 --- a/brain_examples/systemdate.yml +++ b/brain_examples/systemdate.yml @@ -5,7 +5,7 @@ - order: "quelle heure est-il" neurons: - systemdate: - tts: "voxygen" + tts: "acapela" say_template: - "il est {{ hours }} heure et {{ minutes }} minute" diff --git a/kalliope/core/TTS/TTSModule.py b/kalliope/core/TTS/TTSModule.py index 6cf94eb2..cbce6223 100644 --- a/kalliope/core/TTS/TTSModule.py +++ b/kalliope/core/TTS/TTSModule.py @@ -114,7 +114,7 @@ def _get_path_to_store_audio(self): //tts.parameter["language"]/tts.parameter["voice"]/ Date: Wed, 8 Mar 2017 23:09:24 +0100 Subject: [PATCH 53/54] fix setup.py. ansible require jinja < 2.9 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a9a64973..bddff0e3 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ def read_version_py(file_name): 'pyasn1>=0.2.3', 'ansible>=2.2', 'python2-pythondialog>=3.4.0', - 'jinja2>=2.9.5', + 'jinja2>=2.8', 'cffi==1.9.1', 'ipaddress>=1.0.17', 'flask>=0.12', From 29e3c68636240deccc8d9ec7f2fa676448ee6c59 Mon Sep 17 00:00:00 2001 From: nico Date: Sat, 11 Mar 2017 14:49:31 +0100 Subject: [PATCH 54/54] fix install on last raspbian --- Docs/installation/raspbian_jessie.md | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Docs/installation/raspbian_jessie.md b/Docs/installation/raspbian_jessie.md index edaf5542..18d1b306 100644 --- a/Docs/installation/raspbian_jessie.md +++ b/Docs/installation/raspbian_jessie.md @@ -28,7 +28,7 @@ Install some required system libraries and software: ```bash sudo apt-get update -sudo apt-get install git python-dev libsmpeg0 libttspico-utils libsmpeg0 flac dialog libffi-dev libffi-dev libssl-dev portaudio19-dev build-essential libssl-dev libffi-dev sox libatlas3-base mplayer +sudo apt-get install git python-dev libsmpeg0 libttspico-utils libsmpeg0 flac dialog libffi-dev libffi-dev libssl-dev portaudio19-dev build-essential libssl-dev libffi-dev sox libatlas3-base mplayer libyaml-dev libpython2.7-dev ``` Let's install the last release of python-pip diff --git a/setup.py b/setup.py index bddff0e3..3e87953f 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,7 @@ def read_version_py(file_name): 'pyasn1>=0.2.3', 'ansible>=2.2', 'python2-pythondialog>=3.4.0', - 'jinja2>=2.8', + 'jinja2>=2.8,<2.9', 'cffi==1.9.1', 'ipaddress>=1.0.17', 'flask>=0.12',