Skip to content

Creating a Custom DFF Skill

Kseniya Petukhova edited this page Dec 13, 2022 · 2 revisions

1. Create a folder

Go into skills and copy paste the dff_template_skill folder. Remember that correct naming is very important, so you should give your folder a clear name so that others could see the name and understand the main idea of your skill. An example of a clear name is dff_get_book_information_skill. In this folder replace all mentions of dff_template_skill with the name of your skill.

2. Find a docker-compose.override.yml

You should then go to assistant_dists/distribution_name/docker-compose.override.yml, find WAIT_HOSTS, and add your skill and a port which is not taken. Thus, if you are working with the main Dream distribution, you go to assistant_dists/dream/docker-compose.override.yml, and add dff-your-name-skill:port to WAIT_HOSTS. Make sure you add your skill right before dff-template-skill:8120.

Notice that here we use dash instead of underscore (and in the future you should always pay attention to whether it is needed to use dash or underscore, such extra attention will definitely save you from unexpected bugs). The thing is, underscores are used in skills’ names which in turn are used in Python code to refer to the Dialog State. Docker containers, meanwhile, are named using dashes.

3. Add the skill to docker-compose.override.yml

At the end of the same file find configuration of dff-template-skill:

  dff-template-skill:
    env_file: [.env]
    build:
      args:
        SERVICE_PORT: 8120
        SERVICE_NAME: dff_template_skill
      context: .
      dockerfile: ./skills/dff_template_skill/Dockerfile
    command: gunicorn --workers=1 server:app -b 0.0.0.0:8120 --reload
    deploy:
      resources:
        limits:
          memory: 128M
        reservations:
          memory: 128M

Copy it and paste. Then:

  • change dff-template-skill to dff-your-name-skill,
  • change port in SERVICE_PORT field,
  • change name in SERVICE_NAME and dockerfile fields,
  • change port in command.

If you are going to use some big models in your skill, you can also change memory: memory in limits is the maximum memory that can be used by your skill before it’s killed, memory in reservations is the amount of memory that needs to be reserved for your skill.

4. Add the skill to dev.yml

Go to assistant_dists/distribution_name/dev.yml, find dff-template-skill, and copy paste it (remember that we always paste it right before dff-template-skill):

  dff-template-skill:
    volumes:
      - "./skills/dff_template_skill:/src"
      - "./common:/src/common"
    ports:
      - 8120:8120

Change both dff-template-skill and dff_template_skill and don’t forget about ports.

5. Add the skill to pipeline_conf.json

Now go to assistant_dists/distribution_name/pipeline_conf.json, find dff_template_skill, copy paste.

            "dff_template_skill": {
                "connector": {
                    "protocol": "http",
                    "timeout": 2,
                    "url": "http://dff-template-skill:8120/respond"
                },
                "dialog_formatter": "state_formatters.dp_formatters:dff_template_skill_formatter",
                "response_formatter": "state_formatters.dp_formatters:skill_with_attributes_formatter_service",
                "previous_services": [
                    "skill_selectors"
                ],
                "state_manager_method": "add_hypothesis"
            }

Then change the name url (both name and port), dff_template_skill in dialog_formatter.

6. Create a formatter

Go to state_formatters/dp_formatters.py, copy dff_template_skill_formatter, paste it, rename according to your skill (like in the previous step), and change the skill name in return.

def dff_template_skill_formatter(dialog: Dict) -> List[Dict]:
    return utils.dff_formatter(dialog, "dff_template_skill")

7. Specify when to turn on the skill

Skill-Selector needs to know when to include your skill in the list of skills that can provide the next response of the bot. There are three options:

  • You want your skill to be included every time: then just go to skill_selectors/rule_based_selector/connector.py and add your skill name into skills_for_uttr.

  • You want your skill to be triggered by some templates/regexes/entities/detected topics: Go to skill_selectors/rule_based_selector/connector.py, add the name of your skill to the list of available skills. To add patterns that will trigger your skill you have to go to common folder, and add a python file with compile expressions in it, for example, common/movies.py contains:

MOVIE_COMPILED_PATTERN = re.compile(
    r"(movie|film|picture|series|tv[ -]?show|reality[ -]?show|netflix|\btv\b|"
    r"comedy|comedies|thriller|animation|anime|talk[ -]?show|cartoon|drama|"
    r"fantasy|watch\b|watching\b|watched\b|youtube|\byou tube\b)",
    re.IGNORECASE,
)

In the future if you need to add any custom functions connected to your skill, it is a good idea to code them in the same file. Now in the same folder (common) you can find skills_turn_on_topics_and_patterns.py, and here you can import the templates that you’ve added and add your skill name and its triggers into SKILL_TRIGGERS, for example:

    "dff_movie_skill": {
        "compiled_patterns": [MOVIE_COMPILED_PATTERN],
        "previous_bot_patterns": [MOVIE_COMPILED_PATTERN],
        "detected_topics": [
            "Entertainment_Movies",
            "Entertainment_General",
            "Movies_TV",
            "Celebrities",
            "Art_Event",
            "Entertainment",
            "Fashion",
        ],
        "intents": [],
    },
  • You want your skill to be included by some custom conditions: in skill_selectors/rule_based_selector/connector.py add conditions for including your skill to the skills_for_uttr list.

8. Code the skill

Now it’s time to code your skill. Go to you skill folder, open scenario, and here you can see:

  • main.py – here you can code your skill using Dialog Flow Framework (DFF). In DFF a dialog is represented as a graph with nodes corresponding to bot responses, where we can specify the text of bot response, the processing functions needed (e.g., slot-filling), and the conditions for transitioning to other nodes.
  • condition.py – for your custom conditions that you want to use to move between nodes.
  • processing.py – for your custom functions for processing of utterances.
  • response.py – for you custom functions you want to use when providing a response.

We will not discuss in detail how to code your skill since a lot of examples can be found here. But when you add global transitions, don’t forget about the templates from the previous step, they can be helpful.

9. Create test configs for the skill

When the scenario of your skill is ready, go to server.py in your skill folder. In order to create test configs, uncomment three lines in respond function, and make sure that the line that activates test is commented.

Now you need to talk with your skill, so you have to build the bot with needed distribution:

docker-compose -f docker-compose.yml -f assistant_dists/dream/docker-compose.override.yml -f assistant_dists/dream/dev.yml -f assistant_dists/dream/proxy.yml  up --build

This command will NOT build all Dream services locally, because they can be accessed via proxy, so the only service that will be built locally is your skill. Remember to change dream to another distribution if needed. When the bot is up, you can talk to it. In a separate terminal tab run:

docker-compose exec agent python -m deeppavlov_agent.run agent.channel=cmd agent.pipeline_config=assistant_dists/dream/pipeline_conf.json

Now chat with your skill. Each turn information that bot receives is saved into tests folder in *_in.json file, and the information about the bot’s answer is saved in *_out.json. These files are overwritten after each turn. It's better to think of several cases you want to test, just name files differently (test_1_in, test_2_in, etc.) If your skill works fine, you can stop chatting and comment those three lines. If something is wrong, you can fix it and then try chatting again.

Let’s suppose everything is fine and now you have both *_in.json file with user’s requests and *_out.json with expected bot’s answers. Now you can uncomment this line to activate tests. Tests are run each time you build skill, even when you build it without the rest of the bot. Don’t forget to comment the line that activates the skill when you change the skill, and remember to rewrite tests when the changes are done.

Some useful commands:

  • if you want to build only your skill, you can run this one:
docker-compose -f docker-compose.yml -f assistant_dists/dream/docker-compose.override.yml -f assistant_dists/dream/dev.yml up --build dff-your-skill
  • if you want to see logs:
docker-compose -f docker-compose.yml -f assistant_dists/dream/docker-compose.override.yml -f assistant_dists/dream/dev.yml logs -f dff-your-skill
  • if you don’t want to rebuild a service, but you do want to restart it:
docker-compose -f docker-compose.yml -f assistant_dists/dream/docker-compose.override.yml -f assistant_dists/dream/dev.yml restart dff-your-skill
Clone this wiki locally