Basic Question on Extracting Values from User Input Using FormAction

I’m trying to extract a person’s name using a form action. I am picking up all of the slots which are defined as entities in my slot_mappings function using “name”: self.from_entity(entity=“name”, not_intent=“chitchat”). However, I also want to be able to extract names that aren’t in the database. It’s easy to just capture the user input using “name”: self.from_text(not_intent=“chitchat”). However, if the user types in my name is bill I want the name portion extracted from this response. Right now, I get “my name is bill” as the text captured instead of “bill”

How can I get Rasa to recognize the portion of the user text which is an entity if it is not in my nlu.md file?

Hi @d7x,

extracting names is a difficult thing sometimes. I always like to point to this amusing post about the task which might be of interest for you.

In the meantime, I am not sure what you are using to extract names as entities, but if you haven’t used Spacy to extract them, I can recommend Stanford NER to be used in a custom action like this:

def custom_validate_fullname(self, tracker):
    latest_message = tracker.latest_message["text"]
    latest_message = str(latest_message.encode("utf-8"))
    for sent in nltk.sent_tokenize(latest_message):
        tokens = nltk.tokenize.word_tokenize(sent)
        tags = self.st.tag(tokens)
        tag_string = ""
        for tag in tags:
            if tag[1] == "PERSON":
                tag_string += str(tag[0]) + " "
        return tag_string if tag_string != "" else None

The advantage is that the CRF extractor was explicitly trained on either first- and lastnames (alongside fullnames) which sometimes can be very difficult.

In addition to e.g. Spacy and/or self-trained NLU.md name entities, this is pretty might to accomplish the task.

Did that help? Don’t hesitate to ask, if you need help.

Kind regards
Julian

Julian,

That link was great! It’s certainly not a trivial task.

Thanks so much for the code for the Stanford NER. I decided to start with Spacy and hooked up Spacy by updating my pipeline to

`pipeline:

  • name: “SpacyNLP”
  • name: “SpacyEntityExtractor”
  • name: “SpacyTokenizer”
  • name: “RegexFeaturizer”
  • name: “SpacyFeaturizer”
  • name: “CRFEntityExtractor”
  • name: “EntitySynonymMapper”
  • name: “SklearnIntentClassifier”`

I have a few questions:

  1. I ran rasa shell nlu to test the recognition of names that were not encoded in my nlu.md file. I noticed that sometimes the extractor of the name was CRFEntityExtractor and at other times it was Spacy. When the extractor name was CRFEntityExtractor, the entity name was the name of the entity I defined. When it showed Spacy as the extractor, the entity name was PERSON. How can I ensure the Spacy extractor is used?
  2. For my slot_mappings function in my form, should I be using “name”: self.from_entity(entity=“PERSON”, not_intent=“chitchat”) instead of “name”: self.from_entity(entity=“name”, not_intent=“chitchat”). I’m guessing that if Spacy is extracting a PERSON or CITY or other object that is what might make sense to specify. Is that correct?

Thanks so much for your help!

Hi @d7x,

thanks for kind words. I am glad that I could help. So concerning your questions:

  1. This depends on the way you are extracting. If you currently use a FormAction to extract them, the slot mapping you mentioned below is the exact right way:

self.from_entity(entity=“PERSON”, not_intent=“chitchat”)

You might even want to consider to remove your custom names if Spacy does the job. Personally I tend to use the CRF ones if I want to narrow accepted names down to a set of predefined and trained ones. However even for this task there would be more possibilities.

  1. If you set your slot mappings this way, Rasa will only use the entity set as parameter entity. How about:
"name": [
     self.from_entity(entity=“PERSON”, not_intent=“chitchat”),
     self.from_entity(entity=“name”, not_intent=“chitchat”)
]

to respect both? Of course if you’d decide to remove either of them, don’t forget to remove it from the mapping.

Did that help?

Kind regards
Julian

Thanks Julian for answering my questions. I’ve updated my code and it’s now recognizing names which are not from the database more frequently.

  1. I’m not sure I understand the debug output that I’m seeing. It looks like the extractor which is recognizing all of my names is CRFEntityExtractor rather than SpacyEntityExtractor. At times I’ve seen SpacyEntityExtractor identified as the extractor of names but I’m not sure when one extractor is chosen over another for names that are common.

  2. Also, the performance seems to vary quite a bit. When I type names into the Spacy visualizer I find that they’re recognized with the type PERSON. However, using `self.from_entity(entity=“PERSON”, not_intent=“chitchat”), entities of names are not being recognized.

  3. I decided to try extracting city names as well and so I changed the name of the slot to GPE. I tried recognizing “i live in lisbon, portugal” However, the debugger showed Received user message ‘i live in lisbon, portugal.’ with intent ‘{‘name’: ‘inform’, ‘confidence’: 0.41268043945481514}’ and entities ‘[]’. This looks like the same issue as earlier in my post.

Hi @d7x,

you’re welcome. I try to address your questions as best as possible for the moment:

  1. I usually avoid using different extractors for the same type of entity. As far as I know, having two extractors for the same entity type results in two extraction results if successfull, but the first one is picked out of the list. This could easily be varified by watching the picked value.

  2. Did you varify that the model used for the visualizer is the same you used for the SpacyNLP component? There are different models pretrained on different types of datasets that influence the extraction process. If you used the right model and still fail to extract those entitiess that were successfully extracted by the visualizer, then we have to investigate further.

  3. I tried this with the latest english model and got the result:

If that doesn’t actually work in Rasa, have you tried using the parse endpoint of the HTTP API? I’d suggest instead of using the bot, first examine the results by starting it with rasa run -vv --enable-api and then send the message to the parse endpoint and posting your results here such that we can take a look at it.

Hope that helps!

Regards
Julian

My responses correspond to the numerated items in the previous post.

  1. I checked the extractors in my config and simplified them to only use the pretrained_embeddings_spacy pipeline. What’s odd is that sometimes Spacy is used and other times a different extractor is used.

Your input → my name is Myron Banks
2020-03-03 17:39:24 DEBUG rasa.core.tracker_store - Recreating tracker for id ‘default’ 2020-03-03 17:39:24 DEBUG rasa.core.processor - Received user message ‘my name is Myron Banks’ with intent ‘{‘name’: ‘request_restaurant’, ‘confidence’: 0.7758417611589892}’ and entities ‘[{‘entity’: ‘PERSON’, ‘value’: ‘Myron Banks’, ‘start’: 11, ‘confidence’: None, ‘end’: 22, ‘extractor’: ‘SpacyEntityExtractor’}]’

However, the CRFEntityExtractor was used when replying to a different question: Your input → greek
2020-03-03 17:40:27 DEBUG rasa.core.tracker_store - Recreating tracker for id ‘default’ 2020-03-03 17:40:27 DEBUG rasa.core.processor - Received user message ‘greek’ with intent ‘{‘name’: ‘inform’, ‘confidence’: 0.9919272139205069}’ and entities ‘[{‘start’: 0, ‘end’: 5, ‘value’: ‘greek’, ‘entity’: ‘cuisine’, ‘confidence’: 0.693647167339515, ‘extractor’: ‘CRFEntityExtractor’}]’

Question: I’m not quite sure why I’m seeing CRFEntityExtractor when I specified pretrained_embeddings_spacy for the pipeline.

Question: The extractor seems to be case-sensitive. When I typed my name is myron banks, it came back with entities but when I typed this response with capital letters, Spacy extracted the name. Is that correct or is there a setting for case sensitivity?

  1. I verified that I’m using the same model on displaCy

  2. This is an interesting approach for debugging. I wasn’t sure how to set up the test code to use the parse endpoint on the api. I specified the --endpoints command line parameter when running rasa shell and used the following in my config.yml

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

However, I get an error in my browser: Error: Method GET not allowed for URL /webhook

PS - I’d like to highlight one of your responses as a solution but I’m not seeing an option in the menu to do so.