# snips-skill
Helpers to keep [Snips](https://snips.ai) skills in Python3 free of boilerplate code.
## Contents
- `MqttClient`: A thin wrapper around [paho-mqtt](https://www.eclipse.org/paho/clients/python/docs/)
- `CommandLineClient` skeleton MQTT command line client with connection settings.
- `SnipsClient`: Reads connection parameters from `/etc/snips/toml`
- Snips-specific decorators for callbacks, see below.
- `MultiRoomConfig`: Utilities for multi-room setups.
- `Skill`: Base class for Snips actions.
- `@intent` decorator, see below.
- `StateAwareMixin` with `@when` and `@conditional` decorators for stateful MQTT clients.
## Plain MQTT clients
Plain MQTT is supported via the `MqttClient` and `CommandLineClient` classes
and the `@topic` decorator.
A `CommandLineClient` provides argument parsing for connection parameters and includes
standard logging. For message handling, define a function or method as
above, and decorate it with `@topic`. This registers the method (or function)
as a callback for the given MQTT topic.
### Usage example
```python
from snips_skill import CommandLineClient, topic
class Logger(CommandLineClient):
'Log all incoming MQTT messages'
@topic('#')
def print_msg(self, userdata, msg):
self.log.info("%s: %s", msg.topic, msg.payload[:64])
if __name__ == '__main__':
Logger().run()
```
## Snips session event decorators
The `Skill` class provides automatic connection configuration via `/etc/snips/toml`.
Also, the following Snips-specific decorators for session events are provided:
* `on_intent`: Handle intents,
* `on_intent_not_recognized`: Handle unknown intents,
* `on_start_session`: Called before session start,
* `on_continue_session`: Called for subsequent session prompts,
* `on_session_started`: Called at session start,
* `on_end_session`: Called before session end,
* `on_session_ended`: Called at session end.
All decorators can be used either on standalone callback functions,
or on methods of the various client classes (including `Skill`).
Methods should expect the parameters `self, userdata, msg`, and
standalone functions should expect `client, userdata, msg`.
Multiple decorators on the same method are possible,
but if they have inconsistent `qos` values, the results will be unpredictable.
Also note that multiple decorators will produce repetitive log lines
with `DEBUG` level. Set `log_level=None` on all but one decorator to fix it.
## The `@intent` decorator
`@intent`-decorated callbacks receive `msg.paylod`
as an `IntentPayload` object, a parsed version of the JSON intent data.
Slot values are converted to appropriate Python types.
The next step in the Snips session depends on the outcome of the decorated function or method:
* If the function returns a string or raises a `SnipsError`, the session ends with a message,
* If it returns en empty string, the session is ended silently.
* If it raises a `SnipsClarificationError`, the session is continued with a question. This can be used to narrow down parameters or to implement question-and-answer sequences.
To require a minimum level of confidence for an intent,
put `@min_confidence` below `@intent`.
To ensure that certain slots are present in the intent,
put `@require_slot` with a slot name below `@intent`.
The `@intent` decorator should not be used in combination
with any `on_*` decorators.
### Usage example
```python
from snips_skill import intent, Skill
class HelloSkill(Skill):
'Snips skill to say hello'
@intent('example:hello')
def say_hello(self, userdata, msg):
return 'Hello, there'
if __name__ == '__main__':
HelloSkill().run()
```
## `StateAwareMixin`, `@when` and `@conditional` decorators
These define actions triggered by state changes on MQTT.
Example: _Sensor registers motion -> switch the light on_
Clients can use `StateAwareMixin` to track the last known state
of relevant topics. For that, a `status_topic` needs to be configured
in the global section of `config.ini`.
Topics and payloads are kept in `self.current_state`.
Change handlers should be decorated with either `@when` or `@conditional`.
The former triggers the handler whenever a boolean condition on the current
state is fulfilled, the latter whenever a MQTT topic relevant for the given boolean condition changes.
### Usage example
```python
@when('topic/a > 0')
def topic_a_handler(self):
... # do something
@conditional('topic/a != 0 or topic/b != 0')
def topic_a_or_b_handler(self, on):
if on:
... # switch something on
else:
... # switch it off
```
Boolean expressions, numeric comparisons, string (in)equality
and string matching with regular expressions are supported.
As usual, parentheses can be used to control the evaluation order.
See `test_expr.py` for the exact grammar.
Raw data
{
"_id": null,
"home_page": "https://github.com/dnknth/snips-skill",
"name": "snips-skill",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "dnknth",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/81/fa/6ebd2742a0193a40e0fd8691d50614706a73a950f703211f7a4997219fb9/snips-skill-0.1.27.tar.gz",
"platform": null,
"description": "# snips-skill\n\nHelpers to keep [Snips](https://snips.ai) skills in Python3 free of boilerplate code.\n\n## Contents\n\n - `MqttClient`: A thin wrapper around [paho-mqtt](https://www.eclipse.org/paho/clients/python/docs/)\n - `CommandLineClient` skeleton MQTT command line client with connection settings.\n - `SnipsClient`: Reads connection parameters from `/etc/snips/toml`\n - Snips-specific decorators for callbacks, see below.\n - `MultiRoomConfig`: Utilities for multi-room setups.\n - `Skill`: Base class for Snips actions.\n - `@intent` decorator, see below.\n - `StateAwareMixin` with `@when` and `@conditional` decorators for stateful MQTT clients.\n\n## Plain MQTT clients\n\nPlain MQTT is supported via the `MqttClient` and `CommandLineClient` classes\nand the `@topic` decorator. \n\nA `CommandLineClient` provides argument parsing for connection parameters and includes \nstandard logging. For message handling, define a function or method as\nabove, and decorate it with `@topic`. This registers the method (or function) \nas a callback for the given MQTT topic.\n\n### Usage example\n\n```python\nfrom snips_skill import CommandLineClient, topic\n\nclass Logger(CommandLineClient):\n 'Log all incoming MQTT messages'\n \n @topic('#')\n def print_msg(self, userdata, msg):\n self.log.info(\"%s: %s\", msg.topic, msg.payload[:64])\n\nif __name__ == '__main__':\n Logger().run()\n```\n\n## Snips session event decorators\n\nThe `Skill` class provides automatic connection configuration via `/etc/snips/toml`.\nAlso, the following Snips-specific decorators for session events are provided:\n\n* `on_intent`: Handle intents,\n* `on_intent_not_recognized`: Handle unknown intents,\n* `on_start_session`: Called before session start,\n* `on_continue_session`: Called for subsequent session prompts,\n* `on_session_started`: Called at session start,\n* `on_end_session`: Called before session end,\n* `on_session_ended`: Called at session end.\n\nAll decorators can be used either on standalone callback functions,\nor on methods of the various client classes (including `Skill`).\n\nMethods should expect the parameters `self, userdata, msg`, and \nstandalone functions should expect `client, userdata, msg`.\n\nMultiple decorators on the same method are possible,\nbut if they have inconsistent `qos` values, the results will be unpredictable.\nAlso note that multiple decorators will produce repetitive log lines\nwith `DEBUG` level. Set `log_level=None` on all but one decorator to fix it.\n\n## The `@intent` decorator\n\n`@intent`-decorated callbacks receive `msg.paylod`\nas an `IntentPayload` object, a parsed version of the JSON intent data. \nSlot values are converted to appropriate Python types.\n\nThe next step in the Snips session depends on the outcome of the decorated function or method:\n\n* If the function returns a string or raises a `SnipsError`, the session ends with a message,\n* If it returns en empty string, the session is ended silently.\n* If it raises a `SnipsClarificationError`, the session is continued with a question. This can be used to narrow down parameters or to implement question-and-answer sequences.\n\nTo require a minimum level of confidence for an intent,\nput `@min_confidence` below `@intent`.\n\nTo ensure that certain slots are present in the intent,\nput `@require_slot` with a slot name below `@intent`.\n\nThe `@intent` decorator should not be used in combination\nwith any `on_*` decorators. \n\n### Usage example\n\n```python\nfrom snips_skill import intent, Skill\n\nclass HelloSkill(Skill):\n 'Snips skill to say hello'\n \n @intent('example:hello')\n def say_hello(self, userdata, msg):\n return 'Hello, there'\n \nif __name__ == '__main__':\n HelloSkill().run()\n```\n\n## `StateAwareMixin`, `@when` and `@conditional` decorators\n\nThese define actions triggered by state changes on MQTT.\nExample: _Sensor registers motion -> switch the light on_\n\nClients can use `StateAwareMixin` to track the last known state\nof relevant topics. For that, a `status_topic` needs to be configured\nin the global section of `config.ini`.\nTopics and payloads are kept in `self.current_state`.\n\nChange handlers should be decorated with either `@when` or `@conditional`.\nThe former triggers the handler whenever a boolean condition on the current\nstate is fulfilled, the latter whenever a MQTT topic relevant for the given boolean condition changes.\n\n### Usage example\n\n```python\n\n @when('topic/a > 0')\n def topic_a_handler(self):\n ... # do something\n \n @conditional('topic/a != 0 or topic/b != 0')\n def topic_a_or_b_handler(self, on):\n if on:\n ... # switch something on\n else:\n ... # switch it off\n```\n\nBoolean expressions, numeric comparisons, string (in)equality\nand string matching with regular expressions are supported.\nAs usual, parentheses can be used to control the evaluation order.\n\nSee `test_expr.py` for the exact grammar.\n\n\n",
"bugtrack_url": null,
"license": "",
"summary": "Boilerplate for Snips skills in Python3",
"version": "0.1.27",
"project_urls": {
"Homepage": "https://github.com/dnknth/snips-skill"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d48181edb243728861b33537f6dc7f2895bf8e0de7038c73dc12a1584df5f837",
"md5": "641552f6fe235f8a1ac9d0497262beef",
"sha256": "69c1bc1edd58d1fc0dd3fed1e42e05b8258a5c42f91b1717c7a80595ca8c8df2"
},
"downloads": -1,
"filename": "snips_skill-0.1.27-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "641552f6fe235f8a1ac9d0497262beef",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 30759,
"upload_time": "2023-12-16T17:55:08",
"upload_time_iso_8601": "2023-12-16T17:55:08.636260Z",
"url": "https://files.pythonhosted.org/packages/d4/81/81edb243728861b33537f6dc7f2895bf8e0de7038c73dc12a1584df5f837/snips_skill-0.1.27-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "81fa6ebd2742a0193a40e0fd8691d50614706a73a950f703211f7a4997219fb9",
"md5": "b8b6ee85dbcc34d7aebec6f65b99164a",
"sha256": "7e1d2145e5973e6bec570fb5a725ed12a3b2663d3a877d2e087608b5e60ca0de"
},
"downloads": -1,
"filename": "snips-skill-0.1.27.tar.gz",
"has_sig": false,
"md5_digest": "b8b6ee85dbcc34d7aebec6f65b99164a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 26964,
"upload_time": "2023-12-16T17:55:10",
"upload_time_iso_8601": "2023-12-16T17:55:10.624970Z",
"url": "https://files.pythonhosted.org/packages/81/fa/6ebd2742a0193a40e0fd8691d50614706a73a950f703211f7a4997219fb9/snips-skill-0.1.27.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-16 17:55:10",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "dnknth",
"github_project": "snips-skill",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "snips-skill"
}