I’m running into a problem with custom actions in the final slot of a form. The bot doesn’t run the final action, even when directed to with rasa interactive, and instead invokes a ‘hello world action’. I can’t figure out why.
In the domain and action pasted below, the asana_form
is the one I’m having trouble with. The last two slots should trigger custom actions, since they have the prefix ‘action_ask’. The second-to-last slot is triggered correctly. But, when the bot asks to log information for the last slot, that’s when I run into a problem.
I’ll type something in for the prompt like ‘this is a note’, and in Rasa interactive, i force it to interpret it as an “inform” intent. But, then it just doesn’t work and instead invokes hello world, and it does that even if i also select “asana_form” from the rasa interactive menu.
thanks for any feedback and let me know if I can clarify this question
DOMAIN
version: '2.0'
session_config:
session_expiration_time: 60
carry_over_slots_to_new_session: false
intents:
- sleep_log
- affirm
- inform
- greet
- goodbye
- deny
- mood_great
- mood_unhappy
- bot_challenge
- question_test
- trigger_hello_world
- flush_slots
- check_asana
entities:
- exercise
- sleep
- stress
- task_name
slots:
confirm_log:
type: text
influence_conversation: true
sleep_confirm:
type: text
influence_conversation: true
sleep:
type: text
influence_conversation: true
sleep_description:
type: text
influence_conversation: true
goal:
type: text
influence_conversation: true
asana_task_name:
type: text
influence_conversation: true
asana_number_select:
type: text
influence_conversation: true
asana_list_tasks:
type: text
influence_conversation: true
notes_from_asana_task_selected:
type: text
influence_conversation: true
asana_select_options_slot:
type: text
influence_conversation: false
asana_after_note_logged:
type: text
influence_conversation: false
responses:
utter_confirm_sleep:
- text: Do you want to talk about how you slept?
utter_greet:
- text: Hi! It's time for your daily sleep check-in. I'm excited to learn about your experience. Shall we get started?
utter_goodbye:
- text: Thanks for chatting. Bye!
utter_iamabot:
- text: I am a bot, powered by Rasa.
utter_ask_confirm_log:
- text: Did you exercise yesterday? Don't sweat it if you didn't run a marathon - walks count!
utter_ask_exercise:
- text: What kind of exercise did you do 💪 ?
utter_ask_sleep:
- text: How much sleep did you get last night?
utter_ask_sleep_description:
- text: How would you describe your sleep?
utter_ask_diet:
- text: Did you stick to a healthy diet 🥦 yesterday?
utter_ask_stress:
- text: What is your stress level right now 🧘 ?
buttons:
- title: low
payload: '/inform{"stress": "low"}'
- title: medium
payload: '/inform{"stress": "medium"}'
- title: high
payload: '/inform{"stress": "high"}'
utter_ask_goal:
- text: Setting goals - even small ones - is a great way to focus your day. What do you want to accomplish today 🥇 ?
utter_slots_values:
- text: |-
You've submitted the following answers:
- Exercised?: {confirm_log}
- Sleep: {sleep}
- Goal: {goal}
utter_no_worries:
- text: No problem :)
utter_ask_continue:
- text: Sorry, I don't quite understand. Do you want to continue?
utter_cheer_up:
- text: 'Here is something to cheer you up:'
image: https://i.imgur.com/nGF1K8f.jpg
utter_did_that_help:
- text: Did that help you?
utter_start_over:
- text: Ok, let's start over.
utter_happy:
- text: Great, carry on!
utter_question_test:
- text: What's your question?
utter_question_color_test:
- text: my favorite color is blue
utter_ask_asana_task_name:
- text: What's the task you'd like to check?
actions:
- action_flush_slots
- action_hello_world
- action_submit_results
- confirm_log
- utter_confirm_sleep
- utter_exercise_info
- validate_health_form
- validate_sleep_form
- validate_sleep_log
- check_asana_action
- select_asana_action
- action_ask_asana_list_tasks
- action_ask_notes_from_asana_task_selected
- action_ask_asana_after_note_logged
forms:
asana_form:
asana_task_name:
- type: from_intent
intent: inform
value: true
asana_list_tasks:
- type: from_intent
intent: inform
value: true
notes_from_asana_task_selected:
- type: from_text
intent: None
not_intent: inform
asana_after_note_logged:
- type: from_text
intent: None
not_intent: inform
sleep_form:
sleep_confirm:
- type: from_intent
intent: affirm
value: true
- type: from_intent
intent: deny
value: false
- type: from_intent
intent: inform
value: true
sleep_description:
- type: from_text
intent: None
not_intent: inform
health_form:
confirm_log:
- type: from_intent
intent: affirm
value: true
- type: from_intent
intent: deny
value: false
- type: from_intent
intent: inform
value: true
sleep:
- type: from_entity
entity: sleep
- type: from_intent
intent: deny
value: None
sleep_description:
- type: from_text
intent: None
not_intent: inform
goal:
- type: from_intent
intent: affirm
value: true
- type: from_intent
intent: deny
value: false
experience_log:
verify_desire_log:
- type: from_intent
intent: affirm
value: true
substance:
- type: from_intent
intent: inform
value: true
dose:
- type: from_text
intent: None
not_intent: inform
note:
- type: from_text
intent: None
not_intent: inform
timing:
- type: from_text
intent: None
not_intent: inform
key_takeaway:
- type: from_text
intent: None
not_intent: inform
explanation_of_mechanism:
- type: from_text
intent: None
not_intent: inform
behavior_change:
- type: from_text
intent: None
not_intent: inform
feeling:
- type: from_text
intent: None
not_intent: inform
ACTION FILE
# This files contains your custom actions which can be used to run
# custom Python code.
#
# See this guide on how to implement these action:
# https://rasa.com/docs/rasa/custom-actions
# This is a simple example for a custom action which utters "Hello World!"
from typing import Any, Text, Dict, List, Optional
from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import FormValidationAction
#from rasa_core_sdk import Action
from rasa_sdk.forms import FormAction
from datetime import datetime
from rasa_sdk.events import SlotSet
from rasa_sdk.types import DomainDict
from rasa_sdk import Tracker, FormValidationAction
import re
now = datetime.now()
print("now =", now)
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
print("date and time =", dt_string)
##asana creds
import pandas as pd
import asana
import json
import re
from Levenshtein import distance
from dialogasanalink import list_tasks_all, get_task_details, list_tasks_numbered_names, update_task_note
# pip3 install python-Levenshtein
# Construct an Asana client
client = asana.Client.access_token(personal_access_token)
# Set things up to send the name of this script to us to show that you succeeded! This is optional.
client.options['client_name'] = "hello_world_python"
# Get your user info
me = client.users.me()
client.options['page_size'] = 100
print ('this is testing whether asana can be called', me)
class ActionHelloWorld(Action):
def name(self) -> Text:
return "action_hello_world"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
print ('action hello triggered')
#try:
# sheet.append_row(
# ["from test hello action", dt_string],
# value_input_option='RAW',
# insert_data_option=None,
# table_range=None)
#except:
# pass
dispatcher.utter_message("Hello World!")
return [SlotSet('asana_select_options_slot', "raw text")]
class ValidateHealthForm(FormValidationAction):
print ('validation triggered')
def name(self) -> Text:
print ('validation run health')
return "validate_health_form"
async def validate_confirm_log(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
if value:
print ('health log validated true')
return {"confirm_log": True}
else:
return {"exercise": "None", "confirm_log": False }
async def required_slots(
self,
slots_mapped_in_domain: List[Text],
dispatcher: "CollectingDispatcher",
tracker: "Tracker",
domain: "DomainDict",
) -> Optional[List[Text]]:
required_slots = slots_mapped_in_domain + ["sleep_description"]
return required_slots
async def extract_sleep_description(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
) -> Dict[Text, Any]:
text_of_last_user_message = tracker.latest_message.get("text")
sit_outside = "slept" in text_of_last_user_message
dispatcher.utter_message(text = "sleep description noted")
return {"sleep_description": sit_outside}
class ActionSubmitResults(Action):
print ('submit triggered')
def name(self) -> Text:
return "action_submit_results"
def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict]:
confirm_log = tracker.get_slot("confirm_log")
exercise = tracker.get_slot("exercise")
sleep = tracker.get_slot("sleep")
stress = tracker.get_slot("stress")
diet = tracker.get_slot("diet")
goal = tracker.get_slot("goal")
sleep_description = tracker.get_slot("sleep_description")
response = "this is the response"
#create_health_log(
# confirm_exercise=confirm_exercise,
# exercise=exercise,
# sleep=sleep,
# stress=stress,
# diet=diet,
# goal=goal
# )
x = []
print ('x before', x)
x.append(goal)
print ('x after', x)
print ('sleep variable', sleep)
print ("sleep des variable type", type(sleep_description))
sheet.append_row(
["from test doc", dt_string, type(sleep_description)],
value_input_option='RAW',
insert_data_option=None,
table_range=None)
dispatcher.utter_message("Thanks, your answers have been recorded!")
slots_to_reset = ["confirm_log", "sleep", "sleep_description", "goal", "requested_slot"]
return [SlotSet(slot, None) for slot in slots_to_reset]
# http://forum.rasa.com/t/form-deactivation-inside-validate-function/14435/16
class ValidateSleep(FormValidationAction):
print ("sleep form triggered")
def name(self) -> Text:
print ('validation run sleep')
return "validate_sleep_form"
async def validate_sleep_confirm(
self,
value: Text,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> Dict[Text, Any]:
if value:
print ('true value of sleep confirmed')
return {"sleep_confirm": True}
else:
print ('false value sleep confirmed')
return {"sleep_confirm": False }
async def required_slots(
self,
slots_mapped_in_domain: List[Text],
dispatcher: "CollectingDispatcher",
tracker: "Tracker",
domain: "DomainDict",
) -> Optional[List[Text]]:
required_slots = slots_mapped_in_domain + ["sleep_description"]
print ('required slot triggered')
return required_slots
async def extract_sleep_description(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
) -> Dict[Text, Any]:
text_of_last_user_message = tracker.latest_message.get("text")
sleep_description = text_of_last_user_message
print ('sleep extraction triggered')
dispatcher.utter_message(template="utter_ask_sleep_description")
print ('this is the sleep description from tracker- ', text_of_last_user_message)
for key in tracker.slots:
print ('these are the slots', key, '->', tracker.slots[key])
try:
sheet.append_row(
[text_of_last_user_message, dt_string],
value_input_option='RAW',
insert_data_option=None,
table_range=None)
except:
pass
return {"sleep_description": sleep_description}
class ActionFlushSlots(Action):
def name(self) -> Text:
return "action_flush_slots"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
slots = []
for key, value in tracker.current_slot_values().items():
if value is not None:
slots.append(SlotSet(key=key, value=None))
return slots
class AskForAsanaTasks(Action):
def name(self) -> Text:
return "action_ask_asana_list_tasks"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
text_of_last_user_message = tracker.latest_message.get("text")
tasklist = list_tasks_numbered_names(text_of_last_user_message)
tasklist = '"' + tasklist + '"'
print ('DEBUG: this is the task list', tasklist)
dispatcher.utter_message('here is a list of tasks', tasklist)
return [SlotSet('asana_select_options_slot', tasklist)]
class AsansSelect(Action):
def name(self) -> Text:
return "action_ask_notes_from_asana_task_selected"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
text_of_last_user_message = tracker.latest_message.get("text")
listed_tasks_from_slot = tracker.get_slot("asana_select_options_slot")
my_regex = re.escape(text_of_last_user_message) + r"(.*)(?:(id:) (\d*)(?:;))"
capture = re.search(my_regex, listed_tasks_from_slot)
print ('this is captured', capture)
task_name_selected = capture.group(3)
print ('DEBUG: this is the selected task', task_name_selected)
dispatcher.utter_message('What would you like to log about' + task_name_selected + '?')
#print ('DEBUG: captured notes', notes)
print ('DEBUG STATUS: user response before return', tracker.latest_message.get("text"))
return [SlotSet('asana_select_options_slot', task_name_selected)]
class AsanaNoteLogged(Action):
def name(self) -> Text:
print ('check asana invoked')
return "action_ask_asana_after_note_logged"
def run(self, dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
asana_notes_from_last_user_message = tracker.latest_message.get("text")
extracted_gid = tracker.get_slot("asana_select_options_slot")
print ('DEBUG EXTRACTED GID', extracted_gid)
print ('DEBUG user note', extracted_gid)
update_task_note(extracted_gid, asana_notes_from_last_user_message)
print ('DEBUG: this is the task notes', asana_notes_from_last_user_message)
try:
sheet.append_row(
[asana_notes_from_last_user_message, dt_string, extracted_gid],
value_input_option='RAW',
insert_data_option=None,
table_range=None)
except:
pass
dispatcher.utter_message('you updated the task')
return