Check a slot in a database #893

Rasa Core version: rasa-core==0.9.7 Python version: 3.6 Operating system (windows, osx, …): linux Issue: I have an action to send sms-s, and I want to check if the “to” (receiver) slot is in a database, and ask the number if it is not. Do anyone know how can I do it? I have tried this but it’s not working:

class ActionSendSms(FormAction):
    RANDOMIZE = False

    @staticmethod
    def required_fields():
        return [
            EntityFormField("to", "to"),
            EntityFormField("message", "message")
        ]

    def name(self):
        return 'action_send_sms'

    def submit(self, dispatcher, tracker, domain):
        to = tracker.get_slot("to")
        message = tracker.get_slot("message")
        results = to, message
        conn = sqlite3.connect('example.db')
        c = conn.cursor()
        contacts = []
        numbers = []
        for row in c.execute('SELECT * FROM agenda'):
            contacts.append(row[0])
            numbers.append(row[1])
        if to not in contacts:
            dispatcher.utter_message("I don't know the number of {}, could you tell me please?".format(to))

            to = tracker.get_slot("to")
        conn.close()
        dispatcher.utter_message("/sms sender {} {}".format(to, message))
        return [SlotSet('sms', results)]

thanks

It should be possible , however you will have to write your stories correctly with these variations. In your custom action , I dont see you setting the slot back to None and your story should have this variation. if you want to mimic what FormAction does , you’d also have to set the requested_slot value (see documentation on FormAction)

Note that questions of the form “its not working” arent very useful unless you specify what is not working and whats happening .

well, I’m trying different things. The latest is creating a custon FormField object to validate the slot. I think that it is supossed to not set the slot if validate() function returns None, but it’s setting it. The code is:


class customFormField(object):

    def validate(self, value):
        conn = sqlite3.connect('example.db')
        c = conn.cursor()
        contacts = []
        numbers = []
        for row in c.execute('SELECT * FROM agenda'):
            contacts.append(row[0])
            numbers.append(row[1])
        conn.close()
        if value not in contacts:
            print('no esta')
            validated = None
            return None
class customEntityFormField(customFormField):

    def __init__(self, entity_name, slot_name):
        self.entity_name = entity_name
        self.slot_name = slot_name

    def extract(self, tracker):
        value = next(tracker.get_latest_entity_values(self.entity_name), None)
        validated = self.validate(value)
        print('val',validated)
        if validated is not None:
            print('validated')
            return [SlotSet(self.slot_name, validated)]
        else:
            print('not validated')
            return []

class ActionSendSms(FormAction):
    RANDOMIZE = False

    @staticmethod
    def required_fields():
        return [
            customEntityFormField("to", "to"),
            customEntityFormField("message", "message")
        ]

    def name(self):
        return 'action_send_sms'

    def submit(self, dispatcher, tracker, domain): 
        to = tracker.get_slot("to")
        message = tracker.get_slot("message")
        results = to, message

        dispatcher.utter_message("/sms sender {} {}".format(to, message))
        return [SlotSet('sms', results)]

and when I run with debug mode this is the answer (the slot thies is not in agenda so it should not be set):

Bot loaded. Type a message and press enter: 
send sms

2018-08-27 10:19:16 DEBUG    rasa_core.tracker_store  - Creating a new tracker for id 'default'.
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Received user message 'send sms' with intent '{'name': 'intent_send_sms', 'confidence': 0.95756924}' and entities '[]'
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Logged UserUtterance - tracker now has 2 events
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Current slot values: 
	author: None
	date: None
	description: None
	email: None
	from: None
	genre: None
	hour: None
	interval: None
	lang: None
	loc: None
	message: None
	report: None
	requested_slot: None
	sms: None
	subject: None
	summary: None
	text: None
	title: None
	to: None
	useremail: None
	username: None
2018-08-27 10:19:17 DEBUG    rasa_core.policies.ensemble  - Predicted next action using policy_0_KerasPolicy
2018-08-27 10:19:17 DEBUG    rasa_core.policies.ensemble  - Predicted next action 'action_send_sms' with prob 1.00.
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Bot utterance 'BotUttered(text: Can you tell me who it is for?, data: null)'
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Action 'action_send_sms' ended with events '['SlotSet(key: requested_slot, value: to)']'
2018-08-27 10:19:17 DEBUG    rasa_core.policies.ensemble  - Predicted next action using policy_0_KerasPolicy
2018-08-27 10:19:17 DEBUG    rasa_core.policies.ensemble  - Predicted next action 'action_listen' with prob 1.00.
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Action 'action_listen' ended with events '[]'
2018-08-27 10:19:17 DEBUG    rasa_core.processor  - Current topic: None

Can you tell me who it is for?
thies

2018-08-27 10:19:20 DEBUG    rasa_core.tracker_store  - Recreating tracker for id 'default'
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Received user message 'Can you tell me who it is for? thies' with intent '{'name': 'inform', 'confidence': 0.9948431}' and entities '[{'entity': 'to', 'value': 'thies', 'start': 31, 'end': 36, 'confidence': None, 'extractor': 'ner_dl'}]'
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Logged UserUtterance - tracker now has 8 events
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Current slot values: 
	author: None
	date: None
	description: None
	email: None
	from: None
	genre: None
	hour: None
	interval: None
	lang: None
	loc: None
	message: None
	report: None
	requested_slot: to
	sms: None
	subject: None
	summary: None
	text: None
	title: None
	to: thies
	useremail: None
	username: None
2018-08-27 10:19:20 DEBUG    rasa_core.policies.ensemble  - Predicted next action using policy_0_KerasPolicy
2018-08-27 10:19:20 DEBUG    rasa_core.policies.ensemble  - Predicted next action 'action_send_sms' with prob 1.00.
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Bot utterance 'BotUttered(text: Can you enter the message please?, data: null)'
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Action 'action_send_sms' ended with events '['SlotSet(key: requested_slot, value: message)']'
2018-08-27 10:19:20 DEBUG    rasa_core.policies.ensemble  - Predicted next action using policy_0_KerasPolicy
2018-08-27 10:19:20 DEBUG    rasa_core.policies.ensemble  - Predicted next action 'action_listen' with prob 1.00.
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Action 'action_listen' ended with events '[]'
2018-08-27 10:19:20 DEBUG    rasa_core.processor  - Current topic: None

no esta
val None
not validated
Can you enter the message please?

I didn’t add any different story because I don’t know how to do it. What I have is:

## action send sms
* intent_send_sms
  - action_send_sms
  - slot{"requested_slot": "to"}
* inform{"to": ""}
  - action_send_sms
  - slot{"to":""}
  - slot{"requested_slot": "message"}
* inform{"message": ""}
  - action_send_sms
  > check_sms_sent
  - action_renew

Hey! Is this solved?

I have a similar problem to solve I believe. My goal is to validate a slot by checking if the slot value is matching an entry in an external database (using API call). First, I thought this could probably be done within the FormAction’s validation, but I am not so sure anymore… Any ideas or existing solutions?

Thanks!

I’ve solved a similar problem using FormAction. You can do fine control of conversation flow with FormAction. If user input value does not match with entries in DB, you can provide a helpful message to the user with dispatcher.utter_message(SOME_HELPFUL_MESSAGE) then return [SlotSet(slot_name, None)] which will tell Form that required_field is not filled so it will ask user’s input again.

1 Like