Is it possible to provide context about the conversation/user without them having to say it in an utterance? For example, if a user is logged in to our system, we will have certain metadata about their location/preferences already so can we pass that metadata to rasa and fill those slots in as soon as they start the conversation? For example, if we know from the user’s login metadata that they are in NYC and their first message to Rasa is “What is the weather?” Then Rasa should already have their location slot filled and look up the weather for NYC without asking the user for their location…
Yes, metadata can be accessed from your actions. The action_session_start
event can be used to capture this information from the metadata and load it into a slot when the user session begins.
Something like this:
class ActionSessionStart(Action):
def name(self) -> Text:
return "action_session_start"
@staticmethod
def _slot_set_events_from_tracker(
tracker: "DialogueStateTracker",
) -> List["SlotSet"]:
"""Fetch SlotSet events from tracker and carry over key, value and metadata."""
from rasa.core.events import SlotSet
return [
SlotSet(key=event.key, value=event.value, metadata=event.metadata)
for event in tracker.applied_events()
if isinstance(event, SlotSet)
]
async def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[EventType]:
events = [SessionStarted()]
# any slots that should be carried over should come after the
# `session_started` event`
events.extend(self._slot_set_events_from_tracker(tracker))
# Grab slots from metadata
message_metadata = []
for e in tracker.events[::-1]:
# Does this tracker event have metadata?
if "metadata" in e and e["metadata"] != None:
message_metadata = e["metadata"]
# Does this metadata have slots?
if message_metadata and "slots" in message_metadata:
for key, value in message_metadata["slots"].items():
logger.info(f"{key} | {value}")
if value is not None:
events.append(SlotSet(key=key, value=value))
break
if len(message_metadata) == 0:
logger.warn(f"session_start but no metadata, tracker.events: {tracker.events}")
# an `action_listen` should be added at the end as a user message follows
events.append(ActionExecuted("action_listen"))
return events
Hi @stephens,
Can you also give an example for filling a slot with a value that is not in metadata by using “action_session_start”? For example, I want to use a slot for “username” and I need to fill this slot when the session started because some of the answers require to know the username. Thank you.
Huseyin,
Here’s an example from our financial bot. In this case it looks back in the tracker store to find a value and sets the slot.
If username is available via an API call, then you would make the call there.
Greg
Hello @stephens - I was using the trigger_intent end point defined here to pass a default intent with the metadata in the entities object. I’m using 1.10.14 currently.
Questions -
- Is trigger_intent not the recommended method to pass metadata anymore?
- Is trigger_intent deprecated? Trouble is I’m getting a 404 that the
trigger_intent
is not found.
{"version":"1.10.14","status":"failure","message":"The intent ([Route(handler=<function create_app.<locals>.trigger_intent at 0x7f6e71b28320>, methods=frozenset({'POST'}), pattern=re.compile('^\/conversations\/([^\/]+)\/trigger_intent$'), parameters=[Parameter(name='conversation_id', cast=<class 'str'>)], name='trigger_intent', uri='\/conversations\/<conversation_id>\/trigger_intent'), Route(handler=<function create_app.<locals>.trigger_intent at 0x7f6e71b28320>, methods=frozenset({'POST'}), pattern=re.compile('^\/conversations\/([^\/]+)\/trigger_intent\/$'), parameters=[Parameter(name='conversation_id', cast=<class 'str'>)], name='trigger_intent', uri='\/conversations\/<conversation_id>\/trigger_intent\/')], <function create_app.<locals>.trigger_intent at 0x7f6e71b28320>) does not exist in the domain.","reason":"NotFound","details":{},"help":null,"code":404}[]```
The trigger intent is still supported and passing your metadata as an entity should be no problem. Do you also get a 404 when you hit /
?
@stephens Thanks for confirming! I tried a fresh copy of the bot and I got the trigger_intent API working, but there’s something that I’m not quite following.
In the payload for the trigger_intent, it says we pass the name of the intent and the entities to be passed as metadata. However, in the response, under tracker.latest_message
, there’s a text
key that has the value of an utterance (in the docs and screenshot below it has "text": "Hello!"
). We did not pass this in the payload, so how did this appear here? Is there a value that appears by default if we did not pass a message in the payload?
@stephens Looks like the trigger_intent endpoint is failing again for me. Not sure why it worked in the middle and not sure why it’s failing again.
Update - I figured out what you meant by hitting /
, and I got a healthy response -
Command
curl -d '{"name":"affirm", "entities":[]}' -H "Content-Type: application/json" -X GET http://localhost:5005/
Output
Hello from Rasa: 1.10.14
But the /trigger_intent
endpoint is still failing.
Command -
curl -d '{"name":"affirm", "entities":[]}' -H "Content-Type: application/json" -X POST http://localhost:5005/conversations/test1/trigger_intent
Output
{"version":"1.10.14","status":"failure","message":"The intent ([Route(handler=<function create_app.<locals>.trigger_intent at 0x7efe6c225320>, methods=frozenset({'POST'}), pattern=re.compile('^\/conversations\/([^\/]+)\/trigger_intent$'), parameters=[Parameter(name='conversation_id', cast=<class 'str'>)], name='trigger_intent', uri='\/conversations\/<conversation_id>\/trigger_intent'), Route(handler=<function create_app.<locals>.trigger_intent at 0x7efe6c225320>, methods=frozenset({'POST'}), pattern=re.compile('^\/conversations\/([^\/]+)\/trigger_intent\/$'), parameters=[Parameter(name='conversation_id', cast=<class 'str'>)], name='trigger_intent', uri='\/conversations\/<conversation_id>\/trigger_intent\/')], <function create_app.<locals>.trigger_intent at 0x7efe6c225320>) does not exist in the domain.","reason":"NotFound","details":{},"help":null,"code":404}
Okay, so I think I figured it out (this was probably due to my lack of nous with docker). I had my docker containers running rasa, and then I ran a rasa train
command to create a model. But the docker containers running rasa did not immediately load this model. So I had to recompose those containers after training the model and then the trigger_intent endpoint worked.