Slot mapping didnt work for me :(

Hello everyone !

In my start-up we are developing a tool to retrieve information about drug treatments. In particular the dose of medication taken by the patient.

To do this, I use FormActions. This is the one I have a problem with today:

class TreatmentDosing(FormAction):
	def name(self):
		return "form_treatment_dosing"

	@staticmethod
	def required_slots(tracker):
		return ["treatment_dosing"]

	def slot_mappings(self):
		return {"treatment_dosing": [self.from_entity(entity="dosing"), self.from_entity(entity="QUANTITY"), self.from_entity(entity="CARDINAL"), self.from_entity(entity="number")]}

	def validate(self, dispatcher, tracker, domain):
		debug(dispatcher, tracker)
		slot_values = self.extract_other_slots(dispatcher, tracker, domain)
		for slot, value in slot_values.items():
			if slot == 'treatment_dosing':
				if tracker.get_slot('dosing') is not None:
					slot_values["treatment_dosing"] = tracker.get_slot('dosing')
				elif tracker.get_slot('QUANTITY') is not None:
					slot_values["treatment_dosing"] = tracker.get_slot('QUANTITY')
				elif tracker.get_slot('CARDINAL') is not None:
					slot_values["treatment_dosing"] = tracker.get_slot('CARDINAL')
		slot_to_fill = tracker.get_slot(REQUESTED_SLOT)
		if slot_to_fill:
			slot_values.update(self.extract_requested_slot(dispatcher, tracker, domain))
			if not slot_values:
				intent =  tracker.latest_message['intent'].get('name')
				if intent == "stop" or intent == "deny" or intent == "affirm" or intent == "reset1":
					raise ActionExecutionRejection(self.name(), "Failed to validate slot {0}" "with action {1}" "".format(slot_to_fill, self.name()))
				else:
					return []
		return [SlotSet(slot, value) for slot, value in slot_values.items()]

	def submit(self, dispatcher, tracker, domain):
		dispatcher.utter_message("I got it, it's "+str(tracker.get_slot("treatment_dosing"))+" of "+str(tracker.get_slot("drug"))+".")
		return [SlotSet("drug", None), SlotSet("treatment_dosing", None)]

The problem is that when I say a sentence like “I take 20mg of xanax”. The form asks me how much medication I am taking when I am already answering the question in the previous sentence. I have many unfeaturized slots as in the documentation.

I don’t know how to do… I already tried the slot_mapping method, force the values in the validation, etc. Any ideas ?

Can you share the snapshot of your nlu.md for intent “dosing” ?

A snapshot of my nlu.md ? How can I do that ?

The dosing entity is provided by a custom component that recognize and process it before it comes to the core. If this component cannot find the correct information by itself, SpacyEntityExtractor find a QUANTITY or a CARDINAL (depending on the format).

So if dosing is not found, the slot mapping function normally return the value of QUANTITY and CARDINAL if QUANTITY is not present.

[ 
     { "confidence": null, "entity": "QUANTITY", "extractor": "SpacyEntityExtractor", "value": "20 mg" }, 
     { "confidence": 1.0, "entity": "drug", "extractor": "regex_extractor", "value": "xanax" } 
]

You might have provided training data to the model while training (training data is stored in nlu.md in “data” folder of your project directory)

I’m sharing a snapshot my nul.md file for your reference, where I’ve mentioned various intents and entities. Keep the name of your slot values as same to entity with which you are trying to fill that slot, this will automatically fill the slot value for you

It is also mentioned on rasa’s docs: Training Data Format

Training is not used in my case.

The dosing entity is provided by a custom component that extract regular expression that recognize and process it before it comes to the core.

The regex we uses is this one :

(?P<dosing>(one|two|three|four|[\d,\.-]+)[ ]*(mg|unit|tab|mg tab|cig|pill|smoke|pack|bottle|tablet|pack|pk|l|ml|L)[es]*)($| )

If, in the user message, a value is detected but not extracted by other NER (spacy, duckling, etc.). The regex extractor component extract the entity and add it to the existing entities.

For example : I take 1 pill of xanax will return :

{
"confidence": null,
"entity": "CARDINAL",
"extractor": "SpacyEntityExtractor",
"value": "1"
},
{
"confidence": 1.0,
"entity": "number",
"extractor": "DucklingHTTPExtractor",
"text": "1",
"value": 1
},
{
"confidence": 1.0,
"entity": "dosing",
"extractor": "regex_extractor",
"value": "1 pill"
},
{
"confidence": 1.0,
"entity": "drug",
"extractor": "regex_extractor",
"value": "xanax"
}

The system detect entities correctly with NER and regex extractor for 1 pill.

Same here for I take 20mg of xanax :

{
"confidence": null,
"entity": "QUANTITY",
"extractor": "SpacyEntityExtractor",
"value": "20mg"
},
{
"confidence": 1.0,
"entity": "drug",
"extractor": "regex_extractor",
"value": "xanax"
}

In this case, the SpacyEntityExtractor extract correctly the value (the information is present so the regex extrator didnt activate on this one).

All the informations are correctly extracted and correctly set in the tracker. Here is the tracker of the previous exemple :

{
  "active_form": {
    "name": "form_treatment_dosing", 
    "rejected": false, 
    "trigger_message": {
      "entities": [
        {
          "confidence": null, 
          "end": 11, 
          "entity": "QUANTITY", 
          "extractor": "SpacyEntityExtractor", 
          "start": 7, 
          "value": "20mg"
        },
        {
          "confidence": 1.0, 
          "entity": "drug", 
          "extractor": "regex_extractor", 
          "value": "xanax"
        }
      ], 
      "intent": {
        "confidence": 0.9904214643, 
        "name": "treatment"
      }, 
      "intent_ranking": [
        {
          "confidence": 0.9904214643, 
          "name": "treatment"
        }
      ],
      "text": "I take 20mg of xanax"
    }, 
    "validate": true
  }, 
  "events": null, 
  "followup_action": null, 
  "latest_action_name": "action_listen", 
  "latest_event_time": 1571234636.124133, 
  "latest_input_channel": "rest", 
  "latest_message": {
    "entities": [
      {
        "confidence": null, 
        "end": 11, 
        "entity": "QUANTITY", 
        "extractor": "SpacyEntityExtractor", 
        "start": 7, 
        "value": "20mg"
      },
      {
        "confidence": 1.0, 
        "entity": "drug", 
        "extractor": "regex_extractor", 
        "value": "xanax"
      }
    ], 
    "intent": {
      "confidence": 0.9904214643, 
      "name": "treatment"
    }, 
    "intent_ranking": [
      {
        "confidence": 0.9904214643, 
        "name": "treatment"
      }
    ],
    "text": "I take 20mg of xanax"
  }, 
  "paused": false, 
  "sender_id": "3", 
  "slots": {
    "dosing": "20mg", 
    "drug": "xanax",  
    "treatment_dosing": null
  }
}

I remove all datas that are not required in order to simplify it. As you can see, entities are extracted and populate corresponding slots.

The system works correctly. When a treatment intent is detected by the NLU, the treatment form action is triggered and activate. Despite the fact that entities are detectes and slot populated, the form re-ask the question of the treatment_dosing. I need to repeat the information (here 20mg) to validate the form.

In my form I have this slot mapping function that is supposed to do the job of fill the entity with the first populated entity existing in the given list. We do that because dosing, CARDINAL, etc are used in other forms. We can call that a general entity. This “general” entity is used to populate a “particular” entity. Here dosing (or QUANTITY or CARDINAL or number) is used to populate treatment_dosing (with the slot mapping function. Here it’s a first present first used) :

def slot_mappings(self):
		return {"treatment_dosing": [self.from_entity(entity="dosing"), self.from_entity(entity="QUANTITY"), self.from_entity(entity="CARDINAL"), self.from_entity(entity="number")]}

Am I doing it wrong ? Is there a particular case for the first activation that it doesnt go in the mapping function ?

I find out what the problem is.

First : My form actions weren’t call right after an action_listen so the validation wasn’t triggered. I had to override the _validate_if_required method of my form.

Second : The slot mapping only work entirely for the current slot we are requested. For the others, the system check (with extract_other_slots) if there is an entity with the same name in the NLU results but didn’t trigger the slot mapping loop completely so the slot filling with other entity defined in slot mapping method is not made for other slots. It’s only made for the REQUESTED_SLOT.

Thanks for your time !

2 Likes