Rasa 1.0 Mapping Policy

Hi, I had been figuring out the Mapping Policy for a while, at first with rasa 0.14.4 but now I have updated to rasa 1.0 hoping it will work there.

Right now, I get an error:

...Anaconda3\envs\lewis\lib\site-packages\rasa_sdk\interfaces.py", line 175, in name
    raise NotImplementedError("An action must implement a name")
NotImplementedError: An action must implement a name

The steps I followed for the Mapping Policy were:

Add MappingPolicy() to the training:

async def train_core():
    """Trains the core"""
    agent = Agent(
        DOMAIN,
        policies=[
            MemoizationPolicy(max_history=10),
            MappingPolicy()],
    )

    training_data = await agent.load_data(STORIES)
    agent.train(training_data)

    # Attention: agent.persist stores the model and all meta data into a folder.
    # The folder itself is not zipped.
    agent.persist(os.path.join(MODEL_PATH, MODEL_NAME, "core"))

Add a trigger to the intent in the domain.yml

intents:
  - faq_enrollment:
      triggers: action_faq_enrollment

actions:
  - utter_faq_enrollment
  - action_faq_enrollment

Create a new file called actions.py and put this in there:

from rasa_sdk import Action
from rasa_sdk.events import UserUtteranceReverted


class FaqEnrollment(Action):
    """Revertible mapped action for utter_faq_enrollment"""


  def name(self):
      return "action_faq_enrollment"


  def run(self, dispatcher, tracker, domain):
    
 
 dispatcher.utter_template("utter_faq_enrollment", tracker)
    return [UserUtteranceReverted()] 

And then I ran python -m rasa_sdk --actions actions, as stated in the docs. That’s when I got the error.

And when I just train and test the bot, it stops whenever the FAQ is asked.

Can anybody help me setting up the Mappig Policy? Or does anybody have another idea for handling FAQ’s randomly throughout the conversation without disturbing the story?

I think your format in domain.yml might be wrong try this:

add your intents

  • stop: {triggers: action_stop}
  • wait: {triggers: action_waiting}

hi @Nikki, how did you import the MappingPolicy? I can’t find it.

Hi @lgrinberg!

I think it changed with rasa 1.0 to what I did, but I tried your solution and unfortunately it did not work

Hi @XufengXufengXufeng!

I imported it in my training file. Just to be sure I did nothing weird there, it looks like this:

# pylint: disable=E0611, E0001, R0801
"""From the Rasa Restaurantbot example
https://github.com/RasaHQ/rasa/blob/master/examples/restaurantbot/run.py"""
import os
import asyncio
from rasa.core.agent import Agent
from rasa.core.policies.memoization import MemoizationPolicy
from rasa.core.policies.mapping_policy import MappingPolicy
from rasa.nlu.training_data import load_data
from rasa.nlu import config
from rasa.nlu.model import Trainer

DOMAIN = "nlu_db/domain.yml"
MODEL_PATH = "nlu_db/models"
MODEL_NAME = "current"
STORIES = "nlu_db/data/stories.md"
CONFIG = "nlu_db/config.yml"
NLU = "nlu_db/data/nlu.md"


async def train_core():
    """Trains the core"""
    agent = Agent(
        DOMAIN,
        policies=[
            MemoizationPolicy(max_history=10),
            MappingPolicy()],
    )

    training_data = await agent.load_data(STORIES)
    agent.train(training_data)

    # Attention: agent.persist stores the model and all meta data into a folder.
    # The folder itself is not zipped.
    agent.persist(os.path.join(MODEL_PATH, MODEL_NAME, "core"))


def train_nlu():
    """Trains the NLU"""
    training_data = load_data(NLU)
    trainer = Trainer(config.load(CONFIG))
    trainer.train(training_data)

    # Attention: trainer.persist stores the model and all meta data into a folder.
    # The folder itself is not zipped.
    model_directory = trainer.persist(os.path.join(MODEL_PATH, MODEL_NAME), fixed_model_name="nlu")
    return model_directory


if __name__ == "__main__":
    LOOP = asyncio.get_event_loop()
    print("Training Lewis' NLU..")
    train_nlu()
    print("Training Lewis' core..")
    LOOP.run_until_complete(train_core())
    print("Training bot for Rasa X..")
    os.chdir("nlu_db/")
    os.system("rasa train")

But I made an actions.py file for custom actions, which is in the root folder. However, I am not sure how to include this file in my training… How does Rasa know it should use actions.py?

EDIT:

When I run python -m rasa_sdk --actions actions it now gives no error (I’dput actions.py in the wrong folder at first), but this:

2019-06-05 10:20:03 INFO     rasa_sdk.endpoint  - Starting action endpoint server...
2019-06-05 10:20:03 INFO     rasa_sdk.executor  - Registered function for 'action_faq_enrollment'.
2019-06-05 10:20:03 INFO     rasa_sdk.endpoint  - Action endpoint is up and running. on ('0.0.0.0', 5055)

And it keeps running. What is the point there?

EDIT #2:

I’m thinking it uses some server? But we use our own local server. I just want to include the actions.py file when training to use Mapping Policy…

OK, in case anyone is still struggling with the Mapping Policy of Rasa 1.0, this is what I did to make it work:

Put this in endpoints.yml

action_endpoint:
  url: "http://localhost:5055/webhook"

Create an actions.py in your working folder with your custom action. For me, this was:

from rasa_sdk import Action
from rasa_sdk.events import UserUtteranceReverted


class FaqEnrollment(Action):
    """Revertible mapped action for utter_faq_enrollment"""

    def name(self):
        return "action_faq_enrollment"

    def run(self, dispatcher, tracker, domain):
        dispatcher.utter_template("utter_faq_enrollment", tracker)
        return [UserUtteranceReverted()]

Wherever you load your bot, put an argument action_endpoint along with it. You should do import the endpoint config (from rasa.utils.endpoints import EndpointConfig) and set action_endpoint = EndpointConfig(url="http://localhost:5055/webhook"). I had to do this in my training file and my file to run the chat. Just in case:

ENDPOINT = EndpointConfig(url="http://localhost:5055/webhook")

async def train_core():
    """Trains the core"""
    agent = Agent(
        DOMAIN,
        policies=[
            MemoizationPolicy(max_history=10),
            MappingPolicy()],
        action_endpoint=ENDPOINT
    )

Now put the trigger in your domain.yml. Example:

intents:
  - faq_enrollment:
      triggers: action_faq_enrollment

And don’t include any of these in your stories.md

Now, to run it you need to open your command prompt. Type: rasa run actions --actions actions (assuming your file is called actions.py, otherwise change the last “actions” in the command).

In another command prompt, train your bot and run the chat.

It should work now!

Hi, all:

In my domain file, it always a domain syntax error:

 - request_music
      triggers: action_ask_weather

rasa.core.domain.InvalidDomain: The provided domain file is invalid. You can use http://www.yamllint.com/ to validate the yaml syntax of your domain file.

The problem occurs only after I added the ‘trigger:…’ part. Otherwise, it works well.

Something wrong here?

Don’t you miss a “:”?

- request_music:
      triggers: action_ask_weather

Hi, Nikki: That’s a great observation, and it doesn’t report the syntax error anymore. But now I am encountering another issue. Although the custom action is already listed in domain, but it reports this error: rasa.core.domain.InvalidDomain: Intent 'request_music' is set to trigger action 'action_ask_weather', which is not defined in the domain.

My actions listed in domain.yml:

actions:
  - action_request_music
  - utter_change_music
  - utter_inform_robot

Any further idea?

@lingvisa, well in your trigger you have

 - request_music
      triggers: action_ask_weather

Did you mean to trigger action_request_music?

 - request_music
      triggers: action_request_music

@erohmensing Good catch. My silly question.

No worries! It happens sometimes :grinning_face_with_smiling_eyes:

As your solution, I didn’t do anything except giving “dispatcher.utter_template” method a parameter as “tracker=tracker”, it works, Why :sob::sob::sob: