From 03ff1774320489d9cb7ba39f7f2928d2cac05e15 Mon Sep 17 00:00:00 2001 From: Juan Rodriguez Date: Thu, 28 Oct 2021 12:45:39 -0500 Subject: [PATCH] Simplified README (#47) * Simplified README * Added extras * Fixed typo --- CHANGELOG.md | 6 + README.md | 1150 +-------------------- docs/images/greeter_directory.png | Bin 16107 -> 0 bytes docs/images/smart_lights_dir_complete.png | Bin 27313 -> 0 bytes docs/images/smart_lights_directory.png | Bin 18710 -> 0 bytes docs/images/switch_directory.png | Bin 10953 -> 0 bytes 6 files changed, 38 insertions(+), 1118 deletions(-) delete mode 100644 docs/images/greeter_directory.png delete mode 100644 docs/images/smart_lights_dir_complete.png delete mode 100644 docs/images/smart_lights_directory.png delete mode 100644 docs/images/switch_directory.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 784daf4..ada77a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 2.0.8 - 2021-10-28 + +### Changed + +- Simplified README and pointed to official SDK resources. + ## 1.0.0 - 2021-09-28 ### Added diff --git a/README.md b/README.md index 29516ad..c61071e 100644 --- a/README.md +++ b/README.md @@ -1,1152 +1,66 @@ -# Webex Skills SDK +# Webex Assistant Skills SDK -The Webex Skills SDK is designed to simplify the process of creating a Webex Assistant Skill. -It provides some tools that help to easily set up a template skill, deal with encryption and -test the skill locally, among other things. +The Webex Skills SDK is designed to simplify the process of creating a Webex Assistant Skill. It provides some +tools that help to easily set up a template skill, deal with encryption and test the skill locally, among other +things. -In this document we'll go through some examples of how to use this SDK to create different types -of skills, and we'll also show how to use the different tools available. +This is a simplified version of the documentation, for more information visit the official +[Webex Assistant Skills SDK website](https://developer.webex.com/docs/api/guides/webex-assistant-skills-guide). -## Overview +## Installing the SDK -In this documentation we are going to look at the following topics: +This SDK supports `Python 3.7` and above. If you want to be able to build +[MindMeld Skills](https://developer.webex.com/docs/api/guides/webex-assistant-skills-guide#building-a-mindmeld-skill), +you will need to use `Python 3.7` for compatibility with the [MindMeld library](https://www.mindmeld.com/). -- [Requirements](#requirements) - - [Installing the SDK](#installing-the-sdk) -- [Simple Skills vs MindMeld Skills](#simple-skills-vs-mindmeld-skills) - - [Simple Skills](#simple-skills) - - [MindMeld Skills](#mindmeld-skills) -- [Building a Simple Skill](#building-a-simple-skill) - - [Create the Skill Template](#create-the-skill-template) - - [Running the Template](#running-the-template) - - [Checking the Skill](#checking-the-skill) - - [Invoking the Skill](#invoking-the-skill) - - [Updating the Skill](#updating-the-skill) - - [More About the Simple Skill Handler Signature](#more-about-the-simple-skill-handler-signature) -- [Building a MindMeld Skill](#building-a-mindmeld-skill) - - [Invoking the MindMeld Skill](#invoking-the-mindMeld-skill) - - [Building New Models](#building-new-models) - - [Testing the Models](#testing-the-models) - - [More About the MindMelmd Skill Handler Signature](#more-about-the-mindmeld-skill-handler-signature) -- [Converting a Simple Skill into a MindMeld Skill](#converting-a-simple-skill-into-a-mindmeld-skill) - - [Adding the Training Data](#adding-the-training-data) - - [Updating the Handlers](#updating-the-handlers) - - [Testing the Skill](#testing-the-skill) -- [Encryption](#encryption) - - [Generating Secrets](#generating-secrets) - - [Generating Keys](#generating-keys) -- [Remotes](#remotes) - - [Creating a Remote](#creating-a-remote) - - [Listing Remotes](#listing-remotes) -- [Further Development and Deployment of your Skill](#further-development-and-deployment-of-your-skill) +### Using pip -## Requirements - -In order to follow the examples in this guide, we'll need to install the SDK and its dependencies. Right now the SDK -works with Python 3.8 and above. Note that if you want to build a `MindMeld Skill` as shown later in the guide you will -have to use Python 3.8, since that is the only supported version for the `MindMeld Library`. - -### Installing the SDK - -For this guide, we assume you are familiar and have installed: -- [pyenv](https://github.com/pyenv/pyenv) -- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv) -- [pip](https://pypi.org/project/pip/) -- [Poetry](https://python-poetry.org/) - -We'll start by creating a virtual environment: - -```bash -pyenv install 3.8.6 -pyenv virtualenv 3.8.6 webex-skills -pyenv local webex-skills -``` - -We can now install the SDK using `pip`: - -```bash -pip install webex-skills -``` - -We should be all set, we'll use the SDK later in this guide. You will need to work inside the `webex-skills` virtual -environment we just created. - -## Simple Skills vs MindMeld Skills - -In a nutshell, a skill is a web service that takes a request containing some text and some context, -analyzes that information and responds accordingly. The level of analysis done on that information -will depend greatly on the tasks the skills has to accomplish. Some skills will simply need to look -for keywords in the text, while others will perform complex NLP in order to understand what the user -is requesting. - -This SDK has tooling for creating 2 types of skills: `Simple Skills` and `MindMed Skills`. These should -serve as templates for basic and complex skills. Let's now take a look at these templates in detail. - -### Simple Skills - -`Simple Skills` do not perform any type of ML or NLP analysis on the requests. These skills are a good -starting point for developers to start tinkering with, and they are usually good enough for performing -trivial non-complicated tasks. Most developers would start with a `Simple Skill` and then migrate to a -`MindMed Skill` if needed. - -Most of the time all you need is to recognize a few keywords in the text. Imagine a skill which only task -is to turn on and off the lights in the office. Some typical queries would be: - -- "Turn on the lights" -- "Turn off the lights" -- "Turn on the lights please" -- "Turn the lights off" - -In this particular case, it will probably be good enough to just look for the words `on` and `off` in the -text received. If `on` is present, the skill turns on the lights and responds accordingly and vice versa. - -As you can imagine, we don't really need any complex NLP for this skill. A simple regex would be more -than enough. `Simple Skills` do just that: they provide a template where you can specify the regexes you -care about and have them map to specific handlers (`turn_on_lights` and `turn_off_lights` in our example). - -We'll build a simple skill in [this section](#building-a-simple-skill) - -### MindMeld Skills - -`MindMeld Skills` perform NLP analysis on the requests. These skills are a good template for cases where the -queries will have a lot of variation and contain a lot of information. - -Let's take the case of a skill for ordering food. Queries for a skill like this might look like the following: - -- "Order a pepperoni pizza from Super Pizzas" -- "Order a pad thai from Thailand Cafe" -- "I want a hamburger with fries and soda from Hyper Burgers" - -As we can see, using regexes for these cases can get out of hand really fast. We would need to be able to -recognize every single dish from every single restaurant, which might account for hundreds or thousands of regexes. -As we add more dishes and restaurants, updating the codebase becomes a real problem. - -For cases like this, we leverage the open source [MindMeld Library](https://www.mindmeld.com/). This library makes -it really easy to perform NLP on any text query and identify entities like `dishes`, `restaurants` and `quantities`. -With that, performing the required actions becomes a much easier job. - -We'll build a MindMeld skill in [this section](#building-a-mindmeld-skill) - -## Building a Simple Skill - -Let's now use the SDK to build a `Simple Skill`. As in the example above, we'll build a skill to turn lights on and -off according to what the user is asking. We are going to call this skill `Switch`. - -### Create the Skill Template - -In the `pyenv` environment we created before, run the following command: - -```bash -webex-skills project init switch -``` - -This will create a template for a simple skill. You should see the following file structure: - -![File Structure](docs/images/switch_directory.png) - -As you can see, the `project` section `init` command creates a template of a skill. As usual, you can use the `--help -` option to see the documentation for this command: - -```bash -$ webex-skills project init --help -Usage: webex-skills project init [OPTIONS] SKILL_NAME - - Create a new skill project from a template - -Arguments: - SKILL_NAME The name of the skill you want to create [required] - -Options: - --skill-path DIRECTORY Directory in which to initialize a skill project - [default: .] - - --secret TEXT A secret for encryption. If not provided, one - will be generated automatically. - - --mindmeld / --no-mindmeld If flag set, a MindMeld app will be created, - otherwise it defaults to a simple app [default: - False] - - --help Show this message and exit. -``` - -### Running the Template - -We can now run our skill and start testing it. There are a couple ways you can run it. - -First this SDK has a `run` command, you can run it as follows: - -```bash -webex-skills skills run switch -``` - -You should see an output similar to: -```bash -INFO: Started server process [86661] -INFO: Waiting for application startup. -INFO: Application startup complete. -INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) -``` - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills skills run --help -Usage: webex-skills skills run [OPTIONS] SKILL_NAME - -Arguments: - SKILL_NAME The name of the skill to run. [required] - -Options: - --help Show this message and exit. -``` - -The second option to run a skill is to use `uvicorn`. After all, the skill created is an `asgi` application based on -[FastAPI](https://fastapi.tiangolo.com/): - -```bash -uvicorn switch.main:api --port 8080 --reload -``` - -You should see an output similar to the following: - -```bash -INFO: Will watch for changes in these directories: [''] -INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) -INFO: Started reloader process [86234] using statreload -INFO: Started server process [86253] -INFO: Waiting for application startup. -INFO: Application startup complete. -``` - -Now that we have the skill actually run it, we can test it. - -### Checking the Skill - -One quick thing we can do before sending actual requests to the skill is to make sure we have everything correctly -setup. The sdk provides a tool for that. We can call it as: - -```bash -webex-skills skills check switch -``` - -In your skill output, you should see something like this: -```bash -INFO: 127.0.0.1:58112 - "GET /check?signature=%3D HTTP/1.1" 200 OK -``` - -In the SDK output you should see: - -```bash -switch appears to be working correctly -``` - -That means that your skill is running and the `check` request was successfully processed. - -### Invoking the Skill - -The SDK `skills` section has an `invoke` command which is used for sending requests to the skill. With the skill -running, we can invoke it as follows: - -```bash -webex-skills skills invoke switch -``` - -We can now enter a command and see a response: -```bash -$ webex-skills skills invoke switch -Enter commands below (Ctl+C to exit) ->> hi -{ 'challenge': 'a129d633075c9c227cc4bdcd1653b063b6dfe613ca50355fa84e852dde4b198f', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Hello I am a super simple skill'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Hello I am a super simple skill'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881359}, - 'text': 'hi'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881359}} -``` - -We can see that we got all the directives back. The template skill will simply repeat or echo everything we send to it. - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills skills invoke --help -Usage: webex-skills skills invoke [OPTIONS] [NAME] - - Invoke a skill running locally or remotely - -Arguments: - [NAME] The name of the skill to invoke. If none specified, you would need - to at least provide the `public_key_path` and `secret`. If - specified, all following configuration (keys, secret, url, ect.) - will be extracted from the skill. - - -Options: - -s, --secret TEXT The secret for the skill. If none provided you - will be asked for it. - - -k, --key PATH The path of the public key for the skill. - -u TEXT The public url for the skill. - -v Set this flag to get a more verbose output. - --encrypt / --no-encrypt Flag to specify if the skill is using encryption. - [default: True] - - --help Show this message and exit. -``` - -### Updating the Skill - -Let's now modify our skill so it does what we want: remember we want this skill to turn on and off the office lights. - -Simply update the `main.py` file with the following 2 handlers: - -```python -@api.handle(pattern=r'.*\son\s?.*') -async def turn_on(current_state: DialogueState) -> DialogueState: - new_state = current_state.copy() - - text = 'Ok, turning lights on.' - - # Call lights API to turn on your light here. - - new_state.directives = [ - responses.Reply(text), - responses.Speak(text), - responses.Sleep(10), - ] - - return new_state - - -@api.handle(pattern=r'.*\soff\s?.*') -async def turn_off(current_state: DialogueState) -> DialogueState: - new_state = current_state.copy() - - text = 'Ok, turning lights off.' - - # Call lights API to turn off your light here. - - new_state.directives = [ - responses.Reply(text), - responses.Speak(text), - responses.Sleep(10), - ] - - return new_state -``` - -The SDK provides the `@api.handle` decorator, and as you can see it can take a `pattern` parameter which is then -applied to the query to determine if the handler applies to the query being processed. This way, we can add -a few handlers by simple creating regexes that match the type of queries we want to support. - -In the example above, we have added regexes to identify the `on` and `off` keywords. Which mostly tell what the user -wants to do. - -By using the `skill invoke` command we can run a few tests: - -```bash ->> turn on the lights -{ 'challenge': '56094568e18c66cb89eca8eb092cc3bbddcd64b4c0442300cfbe9af67183e260', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning lights on.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning lights on.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn on the lights'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}} ->> turn off the lights -{ 'challenge': '2587110a9c97ebf9ce435412c0ea6154eaef80f384ac829cbdc679db483e5beb', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning lights off.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning lights off.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn on the lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn off the lights'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}} ->> turn the lights on -{ 'challenge': 'ce24a510f6a7025ac5e4cc51b082483bdbcda31836e2c3567780c231e5674c59', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning lights on.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning lights on.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn on the lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn off the lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}, - 'text': 'turn the lights on'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634881502}} -``` - -In the examples above, we can see the skill responding with the correct message. In a real skill, we would also call an -API to actually perform the action the user wants. - -### More About the Simple Skill Handler Signature - -When we created our `Simple Skill`, our handler had the following siganture: - -```python -async def greet(current_state: DialogueState) -> DialogueState: -``` - -You can also update the handler to give you another parameter: - -```python -async def greet(current_state: DialogueState, query: str) -> DialogueState: -``` - -The `query` string parameter will give you the query that was sent to the skill, this can be used in cases where you -need to further analyze the text. - -## Building a MindMeld Skill - -When a skill is very complex and needs to handle many commands, usually the best approach is to create a MindMeld -based skill. This will allow us to use NLP to better classify the request and extract important information we need -from it. We are not going to go very deep into how a MindMeld application works, but there are a lot of resources in the -official [MindMeld library](https://www.mindmeld.com/) site. - -This SDK also has tooling in place for setting up a MindMeld based skill. For that, we can use the `project init` -command with the `--mindmeld` flag set. But first, we need to add the extra dependency `mindmeld`: - -```bash -pip install "webex-skills[mindmeld]" -``` - -Let's create a skill called `greeter`: - -```bash -webex-skills project init greeter --mindmeld -``` - -The folder structure should look like this: - -![File Structure](docs/images/greeter_directory.png) - - -### Invoking the MindMeld Skill - -With the `greeter` skill running, let's try invoking it using the SDK `skills invoke` command: - -```bash -$ poetry run webex-skills skills invoke greeter - -Enter commands below (Ctl+C to exit) ->> hi -{ 'challenge': 'a31ced06481293abd8cbbcffe72d712e996cf0ddfb56d981cd1ff9c1d9a46bfd', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Hello I am a super simple skill using NLP'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Hello I am a super simple skill using NLP'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634880182}, - 'text': 'hi'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634880182}} -``` - -As you can see, the response of a `MindMeld Skill` has the same shape as a `Simple Skill`, it's really just the internals -of the skill that change. - -### Building New Models - -Since `MindMeld Skills` use NLP, we need to retrain the ML models each time we modify the training data. The SDK -provides a the 'nlp build` command for this purpose: - -```bash -webex-skills nlp build greeter -``` - -After running this, the models will be refreshed with the latest training data. - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills nlp build --help -Usage: webex-skills nlp build [OPTIONS] [NAME] - - Build nlp models associated with this skill - -Arguments: - [NAME] The name of the skill to build. - -Options: - --help Show this message and exit. -``` - -### Testing the Models - -Anothoer useful command in this SDK is the `nlp process` command. It's similar to the `skill invoke` command, in the -sense that it will send a query to the running skill. However, the query will only be run through the NLP pipeline so -we can see how it was categorized. Let's look at an example: - -```bash -$ webex-skills nlp process greeter - -Enter a query below (Ctl+C to exit) ->> hi -{'domain': 'greeting', 'entities': [], 'intent': 'greet', 'text': 'hi'} ->> -``` - -You can see that now the response only contains the extracted ANLP pieces. This command is very useful for testing -your models as you work on improving them. - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills nlp process --help -Usage: webex-skills nlp process [OPTIONS] [NAME] - - Run a query through NLP processing - -Arguments: - [NAME] The name of the skill to send the query to. - -Options: - --help Show this message and exit. -``` - -### More About the MindMeld Skill Handler Signature - -When we created our `Simple Skill`, our handler had the following siganture: +Create a virtual environment with `Python 3.7`: ```python -async def greet(current_state: DialogueState) -> DialogueState: +pyenv install 3.7.5 +pyenv virtualenv 3.7.5 webex-skills +pyenv local webex-skills ``` -You can also update the handler to give you another parameter: +Install using `pip`: ```python -async def greet(current_state: DialogueState, , processed_query: ProcessedQuery) -> DialogueState: +pip install webex-skills ``` -The `processed_query` parameter will give you the `text` that was sent to the skill, the `domain` and `intent` identified -as well as the `entities` extracted from the query. This can be useful in cases where you want to use the entities as -part of the skill logic. We'll show an example of this in the -[Converting a Simple Skill into a MindMeld Skill](#converting-a-simple-skill-into-a-mindMeld-skill) section. - -## Converting a Simple Skill into a MindMeld Skill - -In many cases, when you start creating a new skill, you would probably start with a `Simple Skill`. As your skill grows -in complexity, you might need to convert it into a `Mindmeld Skill`. This SDK makes that conversion very easy, we are -going to take a look into that next. - -Consider the [Switch Skill](#building-a-simple-skill) we built above. It really just recognizes if we want to turn -something on or off. But what if we have multiple lights? We could in principle look at the query and try to extract -the light we want to switch with another regex, but that can be very brittle. Instead, let's try turning it into a -`MindMeld Skill`. - -### Adding the Training Data +In order to build `MindMeld Skills` you need the `mindmeld` extra: -Let's start by creating our domains, intents and entities. We still want to just turn on and off lights, but we want to -be able to identify which light to switch. On the `switch` app, create the following folder structure: - -![File Structure](docs/images/smart_lights_directory.png) - -As you can see, we have created a `greeting` and `smart_lights` domains, the intents `greet`, `turn_lights_on` -and `turn_lights_off`, and the entities `all` and `location`. We now need to add training data to make this setup work. - -Normally, you would need to collect training data manually to create your domain, intents and entities. But, for this -guide, we are going to take a shortcut. If you are familiar with the [MindMeld library](https://www.mindmeld.com/), you -have probably seen that it comes with `Blueprint` applications, so we are going to borrow some data from one of them. - -Go to this [repo](https://github.com/CiscoDevNet/mindmeld-blueprints/tree/develop/blueprints/home_assistant/domains) -and copy the `train.txt` files from the corresponding intents into our folders. Do the same for entities, from -[here](https://github.com/CiscoDevNet/mindmeld-blueprints/tree/develop/blueprints/home_assistant/entities) copy the -corresponding `gazetteer.txt` and `mapping.json` files into our folders. Our directory should now look like this: - -![File Structure](docs/images/smart_lights_dir_complete.png) - -### Updating the Handlers - -The next thing we'll do is to convert our logic to turn it into a `MindMeld Skill`. The steps are very simple, let's -start. We'll make all the following changes in `main.py`: - -Instead of making the variable `app` a `SimpleApi`, make it a `MindMeldAPI`: ```python -api = MindmeldAPI() +pip install 'webex-skills[mindmeld]' ``` -In the `@api.handle` decorators, add the intent you want to handle instead of the pattern: +### Install from Source -```python -@api.handle(intent='turn_lights_on') -async def turn_on(current_state: DialogueState, processed_query: ProcessedQuery) -> DialogueState: -... - -@api.handle(intent='turn_lights_off') -async def turn_off(current_state: DialogueState, processed_query: ProcessedQuery) -> DialogueState: -``` - -Finally, add some logic to complement the response with the location entity if available. In the `turn_on` handler, -replace the line: +You can install from source using `Poetry`. Set up python 3.7.5 locally: ```python - text = 'Ok, turning lights on.' +pyenv install 3.7.5 +pyenv local 3.7.5 ``` -With the following logic: +Now you can run `Poetry`'s `install` command: ```python - if len(processed_query.entities) > 0: - entity = processed_query.entities[0] - if entity['type'] == 'location': - text = f'Ok, turning the {entity["text"]} lights on.' - else: - text = 'Ok, turning all lights on.' - else: - text = 'Ok, turning all lights on.' +poetry install ``` -Do the corresponding change to the `turn_off` handler. - -You will also need to import the new classes you are using: `MindmeldAPI` and `ProcessedQuery`. - -That's it! We now have NLP support in our skill. - -All in all your `main.py` should look like this: +In order to build `MindMeld Skills` you need the `mindmeld` extra: ```python -from webex_skills.api import MindmeldAPI -from webex_skills.dialogue import responses -from webex_skills.models.mindmeld import DialogueState, ProcessedQuery - -api = MindmeldAPI() - - -@api.handle(default=True) -async def greet(current_state: DialogueState) -> DialogueState: - text = 'Hello I am a super simple skill' - new_state = current_state.copy() - - new_state.directives = [ - responses.Reply(text), - responses.Speak(text), - responses.Sleep(10), - ] - - return new_state - - -@api.handle(intent='turn_lights_on') -async def turn_on(current_state: DialogueState, processed_query: ProcessedQuery) -> DialogueState: - new_state = current_state.copy() - - if len(processed_query.entities) > 0: - entity = processed_query.entities[0] - if entity['type'] == 'location': - text = f'Ok, turning the {entity["text"]} lights on.' - else: - text = 'Ok, turning all lights on.' - else: - text = 'Ok, turning all lights on.' - - # Call lights API to turn on your light here. - - new_state.directives = [ - responses.Reply(text), - responses.Speak(text), - responses.Sleep(10), - ] - - return new_state - - -@api.handle(intent='turn_lights_off') -async def turn_off(current_state: DialogueState, processed_query: ProcessedQuery) -> DialogueState: - new_state = current_state.copy() - - if len(processed_query.entities) > 0: - entity = processed_query.entities[0] - if entity['type'] == 'location': - text = f'Ok, turning the {entity["text"]} lights off.' - else: - text = 'Ok, turning all lights off.' - else: - text = 'Ok, turning all lights off.' - - # Call lights API to turn off your light here. - - new_state.directives = [ - responses.Reply(text), - responses.Speak(text), - responses.Sleep(10), - ] - - return new_state -``` - -### Testing the Skill - -We can now test the skill to make sure it works as intended. Since we just added our training data, we need to build -the models first. Since we have entities defined, we will need to have Elasticsearch running for the `nlp build` -command to work properly. You can refer to the -[MindMeld Getting Started Documentation](https://www.mindmeld.com/docs/userguide/getting_started.html) for a guide on -how to install and run Elasticsearch. - -Remember that in order to build `MindMeld` skills we need the extra `mindmeld` dependency: - -```bash -pip install "webex-skills[mindmeld]" -``` - -With that out of the way, you can build the models: - -```bash -webex-skills nlp build switch -``` - -We can now run our new skill: - -```bash -webex-skills skills run switch -``` - -Finally, we can use the invoke method to send a couple commands: - -```bash -$ webex-skills skills invoke switch -Enter commands below (Ctl+C to exit) ->> hi -{ 'challenge': 'bd57973f82227c37fdaed9404f86be521ecdbefc684e15319f0d51bbecbb456e', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Hello I am a super simple skill'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Hello I am a super simple skill'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'hi'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}} ->> turn on the lights -{ 'challenge': 'ff8e57bcb94b90c736e11dd79ae5fe3b269dcc450d7bb07b083de73d9a22d5e8', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning all lights on.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning all lights on.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'hi'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn on the lights'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}} ->> turn off the kitchen lights -{ 'challenge': '300e7adfe2f199998f152793b944bc597c5145e991dda621e1495e2e06cebb6e', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning the kitchen lights off.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning the kitchen lights off.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'hi'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn on the lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn off the kitchen lights'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}} ->> turn off all the lights -{ 'challenge': 'e92a90c304c9ef96a3edf31c6ffb10606739cdf98ad34cfd57314b20138ad59b', - 'directives': [ {'name': 'reply', 'payload': {'text': 'Ok, turning all lights off.'}, 'type': 'action'}, - {'name': 'speak', 'payload': {'text': 'Ok, turning all lights off.'}, 'type': 'action'}, - {'name': 'sleep', 'payload': {'delay': 10}, 'type': 'action'}], - 'frame': {}, - 'history': [ { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'hi'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn on the lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn off the kitchen lights'}, - { 'context': {}, - 'directives': [], - 'frame': {}, - 'history': [], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}, - 'text': 'turn off all the lights'}], - 'params': { 'allowed_intents': [], - 'dynamic_resource': {}, - 'language': 'en', - 'locale': None, - 'target_dialogue_state': None, - 'time_zone': 'UTC', - 'timestamp': 1634934720}} ->> -``` - -We have now converted a `Simple Skill` into a `MindMeld Skill`. - -## Encryption - -Skills require encryption in order to safely send and receive requests. For the encryption to work properly, we need -to provide a key pair and a secret for our skills. As we saw in the [Simple Skill](#building-a-simple-skill) and -[MindMeld Skill](#building-a-mindMeld-skill) examples above, the keys and secret will be automatically created for us -when we use the SDK to create a template. However, the SDK also has tools to create these manually if we need to. - -These tools are under the `crypto` section which we'll try next. - -### Generating Secrets - -Generating a secret is very simple, simply use the `generate-secret` command: - -```bash -webex-skills crypto generate-secret -``` - -A secret will be logged to the terminal, which then you can add to your app. - -### Generating Keys - -Generating a key pair is very simple, simply use the `generate-keys` command: - -```bash -webex-skills crypto generate-keys -``` - -A key pair will be created. - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills crypto generate-keys --help -Usage: webex-skills crypto generate-keys [OPTIONS] [FILEPATH] - - Generate an RSA keypair - -Arguments: - [FILEPATH] The path where to save the keys created. By default, they get - created in the current directory. - - -Options: - --name TEXT The name to use for the keys created. [default: id_rsa] - --help Show this message and exit. -``` - -## Remotes - -This SDK also has the notion of `remotes`. That is, skills that are already running and even deployed somewhere, but -we still want to be able to test them using the SDK. - -The process for using remotes is very simple, we're going to look into that now. We'll use the `remote` section of the -SDK. - -Remotes are automatically added for skills created with this SDK. - -### Creating a Remote - -You can create a remote by using the `create` command. Let's recreate a remote for a skill called `echo`: - -```bash -webex-skills remote create echo -``` - -Follow the prompts to create a new remote: - -```bash -$ webex-skills remote create echo - -Secret: -Public key path [id_rsa.pub]: -URL to invoke the skill [http://localhost:8080/parse]: -``` - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ webex-skills remote create --help - -Usage: webex-skills remote create [OPTIONS] NAME - - Add configuration for a new remote skill to the cli config file - -Arguments: - NAME The name to give to the remote. [required] - -Options: - -u TEXT URL of the remote. If not provided it will be requested. - -s, --secret TEXT The skill secret. If not provided it will be requested. - -k, --key PATH The path to the public key. If not provided it will be - requested. - - --help Show this message and exit. -``` - -### Listing Remotes - -You can also list the remotes you currently have set up. For that you can use the `list` command: - -```bash -webex-skills remote list -``` - -You will get something like: -```bash -{'echo': {'name': 'echo', - 'public_key_path': '', - 'secret': '', - 'url': 'http://localhost:8080/parse'}, - 'greeter': {'app_dir': '>', - 'name': 'greeter', - 'private_key_path': '', - 'project_path': '', - 'public_key_path': '', - 'secret': '', - 'url': 'http://localhost:8080/parse'}, - 'switch': {'app_dir': '>', - 'name': 'switch', - 'private_key_path': '', - 'project_path': '', - 'public_key_path': '', - 'secret': '', - 'url': 'http://localhost:8080/parse'}} -``` - -As usual, you can use the `--help` option to see the documentation for this command: - -```bash -$ run webex-skills remote list --help - -Usage: webex-skills remote list [OPTIONS] - - List configured remote skills - -Options: - --name TEXT The name of a particular skill to display. - --help Show this message and exit. +poetry install --extras "mindmeld" ``` -## Further Development and Deployment of your Skill -You might have noticed that when you create a new skill, there is a `pyproject.toml` file that gets added to the -project. This file already contains the dependencies needed to run the skill independently (without using the SDK's -`skills run` command.) +## Building Skills -In order to run the skill independently, you can use [Poetry](https://python-poetry.org/) to manage your dependencies, -or you can also replace the `pyproject.toml` with a `requirements.txt` file if you want to use -[pip](https://pypi.org/project/pip/) instead. +You can follow the next guides for building your first skills: -For deployment, the SDK builds the skill based on [FastAPI](https://fastapi.tiangolo.com/), which offers multiple -options for running an app in production. You can find more information in their -[Deployment Documentation](https://fastapi.tiangolo.com/deployment/). +- [Simple Skills vs MindMeld Skills](https://developer.webex.com/docs/api/guides/webex-assistant-skills-guide#simple-skills-vs-mindmeld-skills) +- [Building a Simple Skill](https://developer.webex.com/docs/api/guides/webex-assistant-skills-guide#building-a-simple-skill) +- [Building a MindMeld Skill](https://developer.webex.com/docs/api/guides/webex-assistant-skills-guide#building-a-mindmeld-skill) diff --git a/docs/images/greeter_directory.png b/docs/images/greeter_directory.png deleted file mode 100644 index 05d9bf02f2e5dbd9fa9d0534b27051ce9ee3ea15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16107 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

ND}GR_WXoMFKw<@oY#Jc_m&ZXyU`3u5SxP$q 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 diff --git a/docs/images/smart_lights_dir_complete.png b/docs/images/smart_lights_dir_complete.png deleted file mode 100644 index 7923b9c130dc2cd09488b504176cc9953a10abf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27313 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

2$@d)lC|+1*0lGVv8fzV6o4 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 diff --git a/docs/images/smart_lights_directory.png b/docs/images/smart_lights_directory.png deleted file mode 100644 index 187351bd885f6a7e15a2bbd538055efff9ce9ed0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18710 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 l`w$`^WC%cHcTOrrqlt^x0>i*S;~B~du3fb&Ux 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�t(LPl@DxoJ5hZN5Ufrn$eBW~&PB{%Ub zG!7gcAAK;`Zc^i77oiIP41RY*@GCF;)0vbW2>@1^0VO{Ck+I3Gf>e$zjY#1seRA4UJ@8V*-XL>plL(E2 zwmqwNRln;Nv9%fDs&B`LkPK8x+o=&HqFng5X4sRY>+6b*(c&liesVGvQ-uheQ>}ot zeT~b3`-RKRHXfdiU-A5AR8INWNAf+`QL1@7_37s~>WE!)oHONARShOG znm)9(q`l?HD$PAAEBuTNaxch}+aG^zy7YTG%G9KFX1@>R0QJn%$$(lBZ+n}|eu`~( ze*dvO!+?xV6Z~)se@%w)CP(FrlMoo=WX@|4CaBswSRY5s`$;vv=_GcB+k7u`0-lKW%DOq~?ndh#H`G|D$8 zd@iszt{NlN8agRU3@HB9!N(BnM!W48A>R=vk=F;)dt`wHFbvUnQ|cHem3S;N4u>S0rz*pn? zoOpX{RI_@ou2tIl&;~lH?e_3{yyZ)qR6;s~YV#1jZ^}m_>qa&+y3s#B9iq!3^4T1l u^Xt$Pf45VO8i_$g>Un<^)3m?5V)4I>NTL0T6#Qq$TtP-fx=PX{