Repository: opsdroid/opsdroid

Issue:
KeyError:  'confidence'
<!-- Before you post an issue or if you are unsure about something join our matrix channel https://app.element.io/#/room/#opsdroid-general:matrix.org and ask away! We are more than happy to help you. -->
# Description
I am trying to build chatbot using opsdroid, matrix and rasanlu but I am not able to extract entities. getting following error: ```
entity["entity"], entity["value"], entity["confidence"]
KeyError: 'confidence'
```
## Expected Functionality
When user give message "Current price of GOOGLE" it should extract the entity [GOOG]


## Experienced Functionality
Getting `KeyEroor: 'confidence'`

## Versions
- **Opsdroid version:** v0.25.0
- **Python version:** 3.8.12
- **OS/Docker version:** 20.10.7
- **RASA version:** 2.8.1

## Configuration File
Please include your version of the configuration file below.

```
configuration.yaml
welcome-message: false

logging:
  level: info

connectors:
  matrix:
    # Required
    homeserver: $MATRIX_SERVER
    mxid: $MATRIX_MXID
    access_token: $MATRIX_TOKEN
    device_name: "opsdroid"
    enable_encryption: true
    device_id: $DEVICE_ID # A unique string to use as an ID for a persistent opsdroid device
    store_path: "/home/woyce-1-5/opsdroid/e2ee-keys" # Path to the directory where the matrix store will be saved
    rooms:
      main:
        alias: $MATRIX_ROOM_MAIN
        # Send messages as msgType: m.notice
        send_m_notice: True

parsers:
  rasanlu:
    url: http://rasa:5005
    #models-path: models
    token: ###########
    #min-score: 0.99999
    min-score: 0.9999

skills:
  fortune:
    path: /skills/fortune
    config:
      mxid: $MATRIX_MXID
      cmd_joke: '/home/opsdroid/.local/bin/fortune /skills/fortune/computers'
      cmd_cookie: '/home/opsdroid/.local/bin/fortune /skills/fortune/cookies'
```

```
intents.yml
version: "2.0"

intents:
  - greetings
  - add
  - bye
  - tell_a_joke
  - price:
      use_entities:
        - ticker
  - add stock
  

entities:
  - ticker



nlu:
- intent: greetings
  examples: |
    - Hii
    - hi
    - hey
    - Hello
    - Heya
    - wassup

- intent: add
  examples: |
    - add stock AAPL for 9 days
    - add stock MSFT 12 to monitor list
    - add my stock GOOG 19
    - add TSLA 14  days
    
- intent: Bye
  examples: |
    - Bye
    - bie
    - by
    - see you
    - see ya

- intent: tell_a_joke
  examples: |
    - Tell me a joke
    - One more joke
    - Do you know jokes
    - Can you tell a joke
    - Can you say something funny
    - Would you entertain me
    - What about a joke

- intent: this_is_funny
  examples: |
    - This is funny
    - That's a funny one
    - Hahaha
    - That's a good one

- intent: price
  examples: |
    - current price of [TSLA]{"entity":"ticker"}
    - tell me current price of [AMZN]{"entity":"ticker"}
    - I want to know the current price of [NSRGY]{"entity":"ticker"}
    - tell me about the current price of [AAPL]{"entity":"ticker"}```



## Additional Details
Any other details you wish to include such as screenshots, console messages, etc.


<!-- Love opsdroid? Please consider supporting our collective:
 +👉  https://opencollective.com/opsdroid/donate -->
![err](https://user-images.githubusercontent.com/94842066/153544954-7f4dbbdb-d212-4903-8419-b3831dc45313.png)



Discussion:
The [Rasa API](https://rasa.com/docs/rasa/pages/http-api#operation/parseModelMessage) states the key is `confidence` but the fact is the key is `confidence_entity`. 🙂 

Resolving patch:
diff --git a/opsdroid/parsers/rasanlu.py b/opsdroid/parsers/rasanlu.py
--- a/opsdroid/parsers/rasanlu.py
+++ b/opsdroid/parsers/rasanlu.py
@@ -289,9 +289,18 @@ async def parse_rasanlu(opsdroid, skills, message, config):
                     if matcher["rasanlu_intent"] == result["intent"]["name"]:
                         message.rasanlu = result
                         for entity in result["entities"]:
-                            message.update_entity(
-                                entity["entity"], entity["value"], entity["confidence"]
-                            )
+                            if "confidence_entity" in entity:
+                                message.update_entity(
+                                    entity["entity"],
+                                    entity["value"],
+                                    entity["confidence_entity"],
+                                )
+                            elif "extractor" in entity:
+                                message.update_entity(
+                                    entity["entity"],
+                                    entity["value"],
+                                    entity["extractor"],
+                                )
                         matched_skills.append(
                             {
                                 "score": confidence,


Test patch:
diff --git a/tests/test_parser_rasanlu.py b/tests/test_parser_rasanlu.py
--- a/tests/test_parser_rasanlu.py
+++ b/tests/test_parser_rasanlu.py
@@ -131,7 +131,7 @@ async def test_parse_rasanlu(self):
                             "end": 32,
                             "entity": "state",
                             "extractor": "ner_crf",
-                            "confidence": 0.854,
+                            "confidence_entity": 0.854,
                             "start": 25,
                             "value": "running",
                         }
@@ -175,7 +175,7 @@ async def test_parse_rasanlu_entities(self):
                             "value": "chinese",
                             "entity": "cuisine",
                             "extractor": "CRFEntityExtractor",
-                            "confidence": 0.854,
+                            "confidence_entity": 0.854,
                             "processors": [],
                         }
                     ],
@@ -190,6 +190,30 @@ async def test_parse_rasanlu_entities(self):
                     skill["message"].entities["cuisine"]["value"], "chinese"
                 )
 
+            with amock.patch.object(rasanlu, "call_rasanlu") as mocked_call_rasanlu:
+                mocked_call_rasanlu.return_value = {
+                    "text": "show me chinese restaurants",
+                    "intent": {"name": "restaurant_search", "confidence": 0.98343},
+                    "entities": [
+                        {
+                            "start": 8,
+                            "end": 15,
+                            "value": "chinese",
+                            "entity": "cuisine",
+                            "extractor": "RegexEntityExtractor",
+                        }
+                    ],
+                }
+                [skill] = await rasanlu.parse_rasanlu(
+                    opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
+                )
+
+                self.assertEqual(len(skill["message"].entities.keys()), 1)
+                self.assertTrue("cuisine" in skill["message"].entities.keys())
+                self.assertEqual(
+                    skill["message"].entities["cuisine"]["value"], "chinese"
+                )
+
     async def test_parse_rasanlu_raises(self):
         with OpsDroid() as opsdroid:
             opsdroid.config["parsers"] = [
@@ -215,7 +239,7 @@ async def test_parse_rasanlu_raises(self):
                             "end": 32,
                             "entity": "state",
                             "extractor": "ner_crf",
-                            "confidence": 0.854,
+                            "confidence_entity": 0.854,
                             "start": 25,
                             "value": "running",
                         }