Coder Social home page Coder Social logo

snips-app-template-py's Introduction

snips-app-template-py

MIT License

This template is made for python >= 3.7

This is a template helping you build the first Snips Voice App quickly.

This template is modified from an origin python template but using a riche action code structure. The origin template is made for connecting to snippets, you can use it to build action for a single intent easily. However, if you already know how snips action code works with bundles, feel free to choice the one you you like best!

Template Organisation

Files listed below are required as a minimum construction, which ensures that this action code can be managed by snips-skill-server. But it does not mean you should only have these files. With a simple action, it can be written in the action-app_example.py file. However with some more complicated action code, it's better to have a specific class file for it.

└── snips-app-template-py
    ├── action-app_template.py          # main handler for intents
    ├── snipsTools.py                   # some useful tools
    ├── config.ini.default              # default app configuration
    ├── requirements.txt                # required dependencies
    └── setup.sh                        # setup script

Files Explanation in Detail

action-app_template.py

This is the file used to bind your action codes with MQTT bus. It helps to read the configuration file, setup MQTT connection, subscribe to Specific topics and setup callback functions.

A simplified code is shown below:

#!/usr/bin/env python3.7

from snipsTools import SnipsConfigParser
from hermes_python.hermes import Hermes

# imported to get type check and IDE completion
from hermes_python.ontology.dialogue.intent import IntentMessage

CONFIG_INI = "config.ini"

# if this skill is supposed to run on the satellite,
# please get this mqtt connection info from <config.ini>
#
# hint: MQTT server is always running on the master device
MQTT_IP_ADDR: str = "localhost"
MQTT_PORT: int = 1883
MQTT_ADDR: str = "{}:{}".format(MQTT_IP_ADDR, str(MQTT_PORT))


class Template:
    """class used to wrap action code with mqtt connection
       please change the name referring to your application
    """

    def __init__(self):
        # get the configuration if needed
        try:
            self.config = SnipsConfigParser.read_configuration_file(CONFIG_INI)
        except Exception:
            self.config = None

        # start listening to MQTT
        self.start_blocking()

    @staticmethod
    def intent_1_callback(hermes: Hermes,
                          intent_message: IntentMessage):

        # terminate the session first if not continue
        hermes.publish_end_session(intent_message.session_id, "")

        # action code goes here...
        print('[Received] intent: {}'.format(
            intent_message.intent.intent_name))

        # if need to speak the execution result by tts
        hermes.publish_start_session_notification(
            intent_message.site_id,
            "Action 1", "")

    @staticmethod
    def intent_2_callback(hermes: Hermes,
                          intent_message: IntentMessage):

        # terminate the session first if not continue
        hermes.publish_end_session(intent_message.session_id, "")

        # action code goes here...
        print('[Received] intent: {}'.format(
            intent_message.intent.intent_name))

        # if need to speak the execution result by tts
        hermes.publish_start_session_notification(
            intent_message.site_id,
            "Action 2", "")

    # register callback function to its intent and start listen to MQTT bus
    def start_blocking(self):
        with Hermes(MQTT_ADDR) as h:
            h.subscribe_intent('intent_1', self.intent_1_callback)\
            .subscribe_intent('intent_2', self.intent_2_callback)\
            .loop_forever()


if __name__ == "__main__":
    Template()

Note: because we can now use type check, and IDE can use that to give better completion, we import necessary definition and add types in methods.

The beginning is similar to most Python codes, it imports all the necessary dependencies / modules. It also defines the config file name (Usually set to config.ini and put this file as the same directory with this code file) and MQTT connection info. If the App you are making is supposed to run on a satellite or some other devices, we recommend that the MQTT connection info should be loaded from the external config.ini file instead of fixing it in the code.

The main part of this code is composed of one class - Template, which is used to bind App related action code with MQTT bus. This class should be named corresponding to the App.

The code is mainly composed by different intent callback functions such as intent_1_callback, inent_2_callback. Inside each callback function is the place to write the intent related action code.

For the intent callback function, it's better to terminate the session first if there is no need to continue. This can prevent other snips components (Like dialog-manager, hotword..) from being blocked by the action code.

start_blocking() is used to register callback functions with its associated intents then starts to listen on MQTT bus.

At the beginning of __init__(), SnipsConfigParser is called to provide a configuration dictionary. This part is not mandatory and can be removed if not needed.

snipsTools.py

This file provides some common useful class but is not part of the action code. For the moment, it only has the SnipsConfigParser.

read_configuration_file (configuration_file)

Read configuration file and return a dictionary.
​
:param configuration_file: configuration file. E.g. "config.ini".
:return: the dictionary representation of the config file.

write_configuration_file (configuration_file, data)

Write configuration dictionary to config file.
​
:param configuration_file: configuration file. E.g. "config.ini".
:data: the dictionary contains the data to save.
:return: False if failed to write.

config.ini.default

This is the file used to save action code configurations. An example is shown below:

# no section for preset values
actionName=example
​
[secret]
#empty value for secret values
passExample=

You may notice that the config file required by action-app_template.py is named config.ini but config.ini.default. This is because if we make config.ini file tracked by git, then the user setting will be rewritten to default during each update pull. The solution here is using setup.py, it will copy config.ini.default to config.ini only if the later one does not exist.

Initially, there are several configuration lines shown as the example, this should be changed. This file is not mandatory for a template. If the action code never uses configuration, this file can be removed.

Beware! Do not use any space to separate key, value and the "=" sign.

requirements.txt

This file is holding the project dependencies.

# Bindings for the hermes protocol
hermes-python>=0.8

If there are some libraries that needs to be installed in your code, append it here.

setup.sh

This file is used to set up the running environment for the action code. Most of the time, you don't need to modify it.

#!/usr/bin/env bash
set -e

if [ ! -e "./config.ini" ]; then
    cp config.ini.default config.ini
fi

VENV=venv

if [ ! -d $VENV ]; then
    PYTHON=`which python3.7`

    if [ -f $PYTHON ]; then
        virtualenv -p $PYTHON $VENV
    else
        echo "could not find python3.7"
    fi
fi

. $VENV/bin/activate

pip3 install -r requirements.txt

An Example APP

A Joke App based on this template is documented here.

Contributing

Please see the Contribution Guidelines.

Copyright

This library is provided by Snips as Open Source software. See LICENSE for more information.

snips-app-template-py's People

Contributors

coorfun avatar maxbachmann avatar metal3d avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

snips-app-template-py's Issues

Test for python binary in setup.sh is inappropriate

setup.sh contains code to make sure that the python binary exists as a regular file, using "which python2". This doesn't really make sense. If which returns any data at all, it will return a file that is executable, and that file could be a symbolic link. If that happens, then the test will fail (because it's a symbolic link, not a regular file), indicating that python2 cannot be found, when it fact it does exist. There is no condition whereby "which python2" will return a string for a file that doesn't exist or cannot be executed.

Instead, the check should be a simple existence of the string. If which doesn't find a program, it'll return an empty string. A check such as:

PYTHON=which python2
if [ -z "$PYTHON" ]

would be adequate, and won't prevent the script from working if python2 happens to be a symbolic link.

Still uses start()

According to the documentation using .start() is deprecated. Yet this script still uses it.

TypeError: cannot be converted to pointer

(Snips does not crash and everything continues working)

Triggered by all callbacks, even one as simple as :

@staticmethod
def PickRandomBoardgameCallback(hermes: Hermes, intent_message: IntentMessage):
    return hermes.publish_end_session(intent_message.session_id, "Ok")

snips-skills-server -vvv
bug_snips

[setup.sh] `/usr/bin/env: 'bash -e': No such file or directory`

I got a lot of Problems while installing my assistant's skills.

When i try to run the setup.sh shell-scripts i get the error:

/usr/bin/env: 'bash -e': No such file or directory

This seems to be a shellscript portability issue with the shebang and the specified -e parameter.

We could replace

#!/usr/bin/env bash -e

with

#!/usr/bin/env bash
set -e

Migrate app template to Python 3

Python 2.7 will not be maintained after January 1, 2020. Snips users are already getting errors for every app they install:

Error setting up virtualenv, one or more actions might not be able to run. Reason :
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.

When pip drops support for Python 2.7, Snips apps won’t work anymore with this new version.

Just for fun, I changed setup.sh for one of my apps based on this app template to make use of Python 3, and it seems to work, although I have to test it more thoroughly.

This app template should be updated so app developers will write their apps for Python 3.

SnipsConfigParser.write_configuration_file should return True when it succeeds

The helper function SnipsConfigParser.write_configuration_file returns False when it fails, but doesn't return anything when writing the configuration succeeds. It would be more logical if it returns True then.

That would make it cleaner to test if writing succeeded in an app:

if SnipsConfigParser.write_configuration_file(CONFIG_INI, self.config):
  # Do something
else:
  # Give an error message or do something else

Moreover, the helper function SnipsConfigParser.read_configuration_file always returns a value: the dictionary with configuration values if reading succeeds and an empty dictionary when it fails. So it would be more consistent if SnipsConfigParser.write_configuration_file does the same.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.