It seems rasa doesn't listen to action server

I’ve been building rasa assistance using financial demo. It’s been working fine until today, whenever I give an intent to rasa that is going to interact with custom actions it’s failed. Here is error message from rasa shell --debug

'''Your input ->  give name
2022-01-12 20:37:29 DEBUG    rasa.core.lock_store  - Issuing ticket for conversation '7ddcf19fa4ee46a288784dcd24e9bd0c'.
2022-01-12 20:37:29 DEBUG    rasa.core.lock_store  - Acquiring lock for conversation '7ddcf19fa4ee46a288784dcd24e9bd0c'.
2022-01-12 20:37:29 DEBUG    rasa.core.lock_store  - Acquired lock for conversation '7ddcf19fa4ee46a288784dcd24e9bd0c'.
2022-01-12 20:37:29 DEBUG    rasa.core.tracker_store  - Could not find tracker for conversation ID '7ddcf19fa4ee46a288784dcd24e9bd0c'.
2022-01-12 20:37:29 DEBUG    rasa.core.processor  - Starting a new session for conversation ID '7ddcf19fa4ee46a288784dcd24e9bd0c'.
2022-01-12 20:37:29 ERROR    rasa.core.processor  - Encountered an exception while running action 'action_session_start'.Bot will continue, but the actions events are lost. Please check the logs of your action server for more information.
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\processor.py", line 772, in _run_action
    events = await action.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\action.py", line 672, in run
    raise RasaException(
rasa.shared.exceptions.RasaException: Failed to execute custom action 'action_session_start' because no endpoint is configured to run this custom action. Please take a look at the docs and set an endpoint configuration via the --endpoints flag. https://rasa.com/docs/rasa/custom-actions'''

I don’t see any logs from action server Here is what I’m seeing from rasa run actions --port 5056 --debug

'''2022-01-12 20:23:27 INFO     rasa_sdk.endpoint  - Starting action endpoint server...
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_pay_cc'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_transaction_search'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_transfer_money'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_show_balance'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_show_recipients'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_show_transfer_charge'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_session_start'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_restart'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_ask_transaction_search_form_zz_confirm_form'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_switch_forms_ask'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_switch_forms_deny'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_switch_forms_affirm'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_switch_back_ask'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_weather_api'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_ask_last_name'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_handoff_options'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'action_handoff'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'validate_cc_payment_form'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'validate_transaction_search_form'.
2022-01-12 20:23:27 INFO     rasa_sdk.executor  - Registered function for 'validate_transfer_money_form'.
2022-01-12 20:23:27 INFO     rasa_sdk.endpoint  - Action endpoint is up and running on http://0.0.0.0:5056
2022-01-12 20:23:27 DEBUG    rasa_sdk.utils  - Using the default number of Sanic workers (1).'''

This is an endpoint for action server configured in endpoint.yml

'''action_endpoint:
url: "https://localhost:5056/webhook"'''

It’s been working without issue, any code has not been changed in actions.py. Any insights on this would be appreciated.

Hello and Welcome to the forum @jpark2111.

Can you please share the rasa --version and I’d recommend you to please cross-check the code and error stated problem in your project.

Suggested Solution:

action_endpoint:
url: "http://localhost:5056/webhook

I guess you are running on the local machine?

Can you please remove the s from the https ?

Ref: financial-demo/endpoints.yml at main · RasaHQ/financial-demo · GitHub

I hope this will solve your issue and good luck!

  1. local environment rasa --version
Rasa Version      :         2.8.11
Minimum Compatible Version: 2.8.9
Rasa SDK Version  :         2.8.2
Rasa X Version    :         0.42.5
Python Version    :         3.8.0
Operating System  :         Windows-10-10.0.22000-SP0
Python Path       :         c:\users\v-jeapark\appdata\local\programs\python\python38\python.exe

anaconda environment

Rasa Version      :         2.8.9
Minimum Compatible Version: 2.8.9
Rasa SDK Version  :         2.8.2
Rasa X Version    :         0.39.3
Python Version    :         3.8.12
Operating System  :         Windows-10-10.0.22000-SP0
Python Path       :         C:\Users\v-jeapark\Anaconda3\envs\rasa3\python.exe

quick question here, is it going to be issue if rasa --version is different in local env and conda env?

  1. Yes, I’ve been testing on local machine and sorry I’ve been using http for endpoint, it was not working so I was just doing experiment. I put it back to http://localhost:5056/webhook

and I’m still getting same error. I run rasa shell --debug and rasa run actions --port 5056 --debug in same conda env

Error message:

Bot loaded. Type a message and press enter (use '/stop' to exit):
Your input ->  give name
2022-01-13 09:42:43 DEBUG    rasa.core.lock_store  - Issuing ticket for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:42:43 DEBUG    rasa.core.lock_store  - Acquiring lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:42:43 DEBUG    rasa.core.lock_store  - Acquired lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:42:43 DEBUG    rasa.core.tracker_store  - Could not find tracker for conversation ID '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Starting a new session for conversation ID '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:42:43 ERROR    rasa.core.processor  - Encountered an exception while running action 'action_session_start'.Bot will continue, but the actions events are lost. Please check the logs of your action server for more information.
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\processor.py", line 772, in _run_action
    events = await action.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\action.py", line 672, in run
    raise RasaException(
rasa.shared.exceptions.RasaException: Failed to execute custom action 'action_session_start' because no endpoint is configured to run this custom action. Please take a look at the docs and set an endpoint configuration via the --endpoints flag. https://rasa.com/docs/rasa/custom-actions
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Policy prediction ended with events '[]'.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Action 'action_session_start' ended with events '[]'.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Current slot values:
        first_name: None
        last_name: None
        AA_CONTINUE_FORM: None
        PERSON: None
        account_type: None
        amount-of-money: None
        amount_transferred: 0
        credit_card: None
        currency: $
        end_time: None
        end_time_formatted: None
        grain: None
        handoff_to: None
        next_form_name: None
        number: None
        payment_amount_type:
        previous_form_name: None
        repeated_validation_failures: None
        requested_slot: None
        search_type: None
        start_time: None
        start_time_formatted: None
        time: None
        time_formatted: None
        vendor_name: None
        zz_confirm_form: None
        session_started_metadata: None
2022-01-13 09:42:43 DEBUG    urllib3.connectionpool  - Starting new HTTP connection (1): localhost:8000
2022-01-13 09:42:43 DEBUG    urllib3.connectionpool  - http://localhost:8000 "POST /parse HTTP/1.1" 200 None
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Received user message 'give name' with intent '{'id': 710270590669098245, 'name': 'request_names', 'confidence': 0.9962879419326782}' and entities '[]'
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Logged UserUtterance - tracker now has 2 events.
2022-01-13 09:42:43 DEBUG    rasa.core.policies.memoization  - Current tracker state:
[state 1] previous action name: action_session_start
2022-01-13 09:42:43 DEBUG    rasa.core.policies.memoization  - Launch DeLorean...
2022-01-13 09:42:43 DEBUG    rasa.core.policies.memoization  - Current tracker state [{}, {'prev_action': {'action_name': 'action_session_start'}}]
2022-01-13 09:42:43 DEBUG    rasa.core.policies.memoization  - There is no memorised next action
2022-01-13 09:42:43 DEBUG    rasa.core.policies.ted_policy  - TED predicted 'action_listen' based on user intent.
2022-01-13 09:42:43 DEBUG    rasa.core.policies.rule_policy  - Current tracker state:
[state 1] user intent: request_names | previous action name: action_session_start
2022-01-13 09:42:43 DEBUG    rasa.core.policies.rule_policy  - There is no applicable rule.
2022-01-13 09:42:43 DEBUG    rasa.core.policies.ensemble  - Predicted next action using policy_1_TEDPolicy.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Predicted next action 'action_listen' with confidence 0.43.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Policy prediction ended with events '[]'.
2022-01-13 09:42:43 DEBUG    rasa.core.processor  - Action 'action_listen' ended with events '[]'.
2022-01-13 09:42:43 DEBUG    rasa.core.lock_store  - Deleted lock for conversation '6abb62f5a4834a5688918b585cd2086e'.

After this happen I put same input again and now it seems it can talke to action server

Your input ->  give name
2022-01-13 09:45:28 ERROR    asyncio  - Exception in callback _ProactorBasePipeTransport._call_connection_lost(None)
handle: <Handle _ProactorBasePipeTransport._call_connection_lost(None) created at C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py:108>
source_traceback: Object created at (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\windows_events.py", line 316, in run_forever
    super().run_forever()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\base_events.py", line 570, in run_forever
    self._run_once()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\base_events.py", line 1851, in _run_once
    handle._run()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 318, in _loop_reading
    self._data_received(data)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 255, in _data_received
    self._eof_received()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 244, in _eof_received
    self.close()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 108, in close
    self._loop.call_soon(self._call_connection_lost, None)
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 162, in _call_connection_lost
    self._sock.shutdown(socket.SHUT_RDWR)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
2022-01-13 09:45:30 DEBUG    rasa.core.lock_store  - Issuing ticket for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:45:30 DEBUG    rasa.core.lock_store  - Acquiring lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:45:30 DEBUG    rasa.core.lock_store  - Acquired lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:45:30 DEBUG    rasa.core.tracker_store  - Recreating tracker for id '6abb62f5a4834a5688918b585cd2086e'
2022-01-13 09:45:30 DEBUG    urllib3.connectionpool  - Starting new HTTP connection (1): localhost:8000
2022-01-13 09:45:30 DEBUG    urllib3.connectionpool  - http://localhost:8000 "POST /parse HTTP/1.1" 200 None
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Received user message 'give name' with intent '{'id': 710270590669098245, 'name': 'request_names', 'confidence': 0.9962879419326782}' and entities '[]'
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Logged UserUtterance - tracker now has 4 events.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Current tracker state:
[state 1] previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Launch DeLorean...
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Current tracker state [{}, {'user': {'intent': 'request_names'}, 'prev_action': {'action_name': 'action_listen'}}]
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - There is a memorised next action 'name_form'
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ted_policy  - TED predicted 'utter_slots_values' based on user intent.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.rule_policy  - Current tracker state:
[state 1] user intent: request_names | previous action name: action_session_start
[state 2] user text: give name | previous action name: action_listen
2022-01-13 09:45:30 DEBUG    rasa.core.policies.rule_policy  - There is no applicable rule.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.rule_policy  - Current tracker state:
[state 1] user intent: request_names | previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
2022-01-13 09:45:30 DEBUG    rasa.core.policies.rule_policy  - There is a rule for the next action 'name_form'.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ensemble  - Made prediction using user intent.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ensemble  - Added `DefinePrevUserUtteredFeaturization(False)` event.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ensemble  - Predicted next action using policy_2_RulePolicy.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Predicted next action 'name_form' with confidence 1.00.
2022-01-13 09:45:30 DEBUG    rasa.core.actions.forms  - Activated the form 'name_form'.
2022-01-13 09:45:30 DEBUG    rasa.core.actions.forms  - No pre-filled required slots to validate.
2022-01-13 09:45:30 DEBUG    rasa.core.actions.forms  - Validating user input 'UserUttered(text: give name, intent: request_names, use_text_for_featurization: False)'.
2022-01-13 09:45:30 DEBUG    rasa.core.actions.forms  - Validating extracted slots: {}
2022-01-13 09:45:30 DEBUG    rasa.core.actions.forms  - Request next slot 'first_name'
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Policy prediction ended with events '[<rasa.shared.core.events.DefinePrevUserUtteredFeaturization object at 0x000001AE29DD2220>]'.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Action 'name_form' ended with events '[<rasa.shared.core.events.ActiveLoop object at 0x000001AE29F57790>, <rasa.shared.core.events.SlotSet object at 0x000001AE172FF370>, BotUttered('What is your first name?', {"elements": null, "quick_replies": null, "buttons": null, "attachment": null, "image": null, "custom": null}, {"utter_action": "utter_ask_first_name"}, 1642095930.448578)]'.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Current slot values:
        first_name: None
        last_name: None
        AA_CONTINUE_FORM: None
        PERSON: None
        account_type: None
        amount-of-money: None
        amount_transferred: 0
        credit_card: None
        currency: $
        end_time: None
        end_time_formatted: None
        grain: None
        handoff_to: None
        next_form_name: None
        number: None
        payment_amount_type:
        previous_form_name: None
        repeated_validation_failures: None
        requested_slot: first_name
        search_type: None
        start_time: None
        start_time_formatted: None
        time: None
        time_formatted: None
        vendor_name: None
        zz_confirm_form: None
        session_started_metadata: None
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Current tracker state:
[state 1] previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
[state 3] user intent: request_names | previous action name: name_form
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Launch DeLorean...
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - Current tracker state [{}, {'prev_action': {'action_name': 'name_form'}}]
2022-01-13 09:45:30 DEBUG    rasa.core.policies.memoization  - There is no memorised next action
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ted_policy  - TED predicted 'utter_submit' based on user intent.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.rule_policy  - Predicted 'action_listen' after loop 'name_form'.
2022-01-13 09:45:30 DEBUG    rasa.core.policies.ensemble  - Predicted next action using policy_2_RulePolicy.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Predicted next action 'action_listen' with confidence 1.00.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Policy prediction ended with events '[]'.
2022-01-13 09:45:30 DEBUG    rasa.core.processor  - Action 'action_listen' ended with events '[]'.
2022-01-13 09:45:30 DEBUG    rasa.core.lock_store  - Deleted lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
What is your first name?
Your input ->

And tried to go with the flow I set up in name_form and it shows same error again I had at first

What is your first name?
Your input ->  jay
2022-01-13 09:47:46 ERROR    asyncio  - Exception in callback _ProactorBasePipeTransport._call_connection_lost(None)
handle: <Handle _ProactorBasePipeTransport._call_connection_lost(None) created at C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py:108>
source_traceback: Object created at (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\windows_events.py", line 316, in run_forever
    super().run_forever()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\base_events.py", line 570, in run_forever
    self._run_once()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\base_events.py", line 1851, in _run_once
    handle._run()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 318, in _loop_reading
    self._data_received(data)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 255, in _data_received
    self._eof_received()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 244, in _eof_received
    self.close()
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 108, in close
    self._loop.call_soon(self._call_connection_lost, None)
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\asyncio\proactor_events.py", line 162, in _call_connection_lost
    self._sock.shutdown(socket.SHUT_RDWR)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
2022-01-13 09:47:49 DEBUG    rasa.core.lock_store  - Issuing ticket for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:47:49 DEBUG    rasa.core.lock_store  - Acquiring lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:47:49 DEBUG    rasa.core.lock_store  - Acquired lock for conversation '6abb62f5a4834a5688918b585cd2086e'.
2022-01-13 09:47:49 DEBUG    rasa.core.tracker_store  - Recreating tracker for id '6abb62f5a4834a5688918b585cd2086e'
2022-01-13 09:47:49 DEBUG    rasa.nlu.classifiers.fallback_classifier  - NLU confidence 0.3264239430427551 for intent 'pay_cc' is lower than NLU threshold 0.70.
2022-01-13 09:47:49 DEBUG    urllib3.connectionpool  - Starting new HTTP connection (1): localhost:8000
2022-01-13 09:47:49 DEBUG    urllib3.connectionpool  - http://localhost:8000 "POST /parse HTTP/1.1" 200 None
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Received user message 'jay' with intent '{'name': 'nlu_fallback', 'confidence': 0.7}' and entities '[{'entity': 'PERSON', 'value': 'jay', 'start': 0, 'confidence': None, 'end': 3, 'extractor': 'SpacyEntityExtractor'}]'
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Current slot values:
        first_name: None
        last_name: None
        AA_CONTINUE_FORM: None
        PERSON: jay
        account_type: None
        amount-of-money: None
        amount_transferred: 0
        credit_card: None
        currency: $
        end_time: None
        end_time_formatted: None
        grain: None
        handoff_to: None
        next_form_name: None
        number: None
        payment_amount_type:
        previous_form_name: None
        repeated_validation_failures: None
        requested_slot: first_name
        search_type: None
        start_time: None
        start_time_formatted: None
        time: None
        time_formatted: None
        vendor_name: None
        zz_confirm_form: None
        session_started_metadata: None
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Logged UserUtterance - tracker now has 12 events.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Current tracker state:
[state 1] previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
[state 3] user intent: request_names | previous action name: name_form
[state 4] user intent: nlu_fallback | user entities: ('PERSON',) | previous action name: action_listen
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Launch DeLorean...
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Current tracker state [{}, {'user': {'intent': 'nlu_fallback', 'entities': ('PERSON',)}, 'prev_action': {'action_name': 'action_listen'}}]
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - There is no memorised next action
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ted_policy  - TED predicted 'transaction_search_form' based on user intent.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.rule_policy  - Current tracker state:
[state 1] user intent: request_names | previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
[state 3] user intent: request_names | previous action name: name_form | active loop: {'name': 'name_form'}
[state 4] user text: jay | previous action name: action_listen | active loop: {'name': 'name_form'}
2022-01-13 09:47:49 DEBUG    rasa.core.policies.rule_policy  - There is no applicable rule.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.rule_policy  - Predicted loop 'name_form'.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ensemble  - Made prediction using user intent.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ensemble  - Added `DefinePrevUserUtteredFeaturization(False)` event.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ensemble  - Predicted next action using policy_2_RulePolicy.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Predicted next action 'name_form' with confidence 1.00.
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Validating user input 'UserUttered(text: jay, intent: nlu_fallback, entities: jay (Type: PERSON, Role: None, Group: None), use_text_for_featurization: False)'.
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Trying to extract requested slot 'first_name' ...
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Got mapping '{'type': 'from_text'}'
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Successfully extracted 'jay' for requested slot 'first_name'
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Validating extracted slots: {'first_name': 'jay'}
2022-01-13 09:47:49 DEBUG    rasa.core.actions.forms  - Request next slot 'last_name'
2022-01-13 09:47:49 ERROR    rasa.core.processor  - Encountered an exception while running action 'name_form'.Bot will continue, but the actions events are lost. Please check the logs of your action server for more information.
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\processor.py", line 772, in _run_action
    events = await action.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\loops.py", line 29, in run
    events += await self.do(output_channel, nlg, tracker, domain, events)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 759, in do
    events += await self.request_next_slot(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 587, in request_next_slot
    bot_message_events = await self._ask_for_slot(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 645, in _ask_for_slot
    return await action_to_ask_for_next_slot.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\action.py", line 672, in run
    raise RasaException(
rasa.shared.exceptions.RasaException: Failed to execute custom action 'action_ask_last_name' because no endpoint is configured to run this custom action. Please take a look at the docs and set an endpoint configuration via the --endpoints flag. https://rasa.com/docs/rasa/custom-actions
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Policy prediction ended with events '[<rasa.shared.core.events.DefinePrevUserUtteredFeaturization object at 0x000001AE248BE5E0>]'.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Action 'name_form' ended with events '[]'.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Current slot values:
        first_name: None
        last_name: None
        AA_CONTINUE_FORM: None
        PERSON: jay
        account_type: None
        amount-of-money: None
        amount_transferred: 0
        credit_card: None
        currency: $
        end_time: None
        end_time_formatted: None
        grain: None
        handoff_to: None
        next_form_name: None
        number: None
        payment_amount_type:
        previous_form_name: None
        repeated_validation_failures: None
        requested_slot: first_name
        search_type: None
        start_time: None
        start_time_formatted: None
        time: None
        time_formatted: None
        vendor_name: None
        zz_confirm_form: None
        session_started_metadata: None
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Current tracker state:
[state 1] previous action name: action_session_start
[state 2] user intent: request_names | previous action name: action_listen
[state 3] user intent: request_names | previous action name: name_form
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Launch DeLorean...
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - Current tracker state [{}, {'prev_action': {'action_name': 'name_form'}}]
2022-01-13 09:47:49 DEBUG    rasa.core.policies.memoization  - There is no memorised next action
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ted_policy  - TED predicted 'utter_submit' based on user intent.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.rule_policy  - Predicted 'action_listen' after loop 'name_form'.
2022-01-13 09:47:49 DEBUG    rasa.core.policies.ensemble  - Predicted next action using policy_2_RulePolicy.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Predicted next action 'action_listen' with confidence 1.00.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Policy prediction ended with events '[]'.
2022-01-13 09:47:49 DEBUG    rasa.core.processor  - Action 'action_listen' ended with events '[]'.
2022-01-13 09:47:49 DEBUG    rasa.core.lock_store  - Deleted lock for conversation '6abb62f5a4834a5688918b585cd2086e'.

Any insight?

It’s highly recommended that you should work in the environment, I personally use conda environment.

Now its listing and communicating?

Can you please tell me now what is the current issue as I can see rasa and rasa server is communicating. Is there any code issue now? me confused sorry.

ERROR    rasa.core.processor  - Encountered an exception while running action 'action_session_start'.Bot will continue, but the actions events are lost. Please check the logs of your action server for more information.
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\processor.py", line 772, in _run_action
    events = await action.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\action.py", line 672, in run
    raise RasaException(
rasa.shared.exceptions.RasaException: Failed to execute custom action 'action_session_start' because no endpoint is configured to run this custom action. Please take a look at the docs and set an endpoint configuration via the --endpoints flag. https://rasa.com/docs/rasa/custom-actions
ERROR    rasa.core.processor  - Encountered an exception while running action 'name_form'.Bot will continue, but the actions events are lost. Please check the logs of your action server for more information.
Traceback (most recent call last):
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\processor.py", line 772, in _run_action
    events = await action.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\loops.py", line 29, in run
    events += await self.do(output_channel, nlg, tracker, domain, events)
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 759, in do
    events += await self.request_next_slot(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 587, in request_next_slot
    bot_message_events = await self._ask_for_slot(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\forms.py", line 645, in _ask_for_slot
    return await action_to_ask_for_next_slot.run(
  File "C:\Users\v-jeapark\Anaconda3\envs\rasa3\lib\site-packages\rasa\core\actions\action.py", line 672, in run
    raise RasaException(
rasa.shared.exceptions.RasaException: Failed to execute custom action 'action_ask_last_name' because no endpoint is configured to run this custom action. Please take a look at the docs and set an endpoint configuration via the --endpoints flag. https://rasa.com/docs/rasa/custom-actions

These are the errors I’m getting. It’s not communicating with action server and why. It’s been working fine. One thing I want to mention that I was trying to connect to database in cloud so I installed pyodbc library and added some code and the errors occurred. I removed all the codes related to database I tested tho. Installing pyodbc should not impact this issue either. So want to know why I’m getting this error

@jpark2111 please share some files as reference i.e stories, or rules.yml , endpoints.yml, action.py, and domain.yml or are you cloned the financial demo GitHub repo?

I cloned it and added some.

endpoints.yml

version: "2.0"
# This file contains the different endpoints your bot can use.

# Server where the models are pulled from.
# https://rasa.com/docs/rasa/user-guide/running-the-server/#fetching-models-from-a-server/

#models:
#  url: http://my-server.com/models/default_core@latest
#  wait_time_between_pulls:  10   # [optional](default: 100)

# Server which runs your custom actions.
# https://rasa.com/docs/rasa/core/actions/#custom-actions/

action_endpoint:
url: "http://localhost:5056/webhook/"

# action_endpoint:
#  url: "http://app:5055/webhook"

# Tracker store which is used to store the conversations.
# By default the conversations are stored in memory.
# https://rasa.com/docs/rasa/api/tracker-stores/

#tracker_store:
#    type: redis
#    url: <host of the redis instance, e.g. localhost>
#    port: <port of your redis instance, usually 6379>
#    db: <number of your database within redis, e.g. 0>
#    password: <password used for authentication>
#    use_ssl: <whether or not the communication is encrypted, default false>

#tracker_store:
#    type: mongod
#    url: <url to your mongo instance, e.g. mongodb://localhost:27017>
#    db: <name of the db within your mongo instance, e.g. rasa>
#    username: <username used for authentication>
#    password: <password used for authentication>

# Event broker which all conversation events should be streamed to.
# https://rasa.com/docs/rasa/api/event-brokers/

#event_broker:
#  url: localhost
#  username: username
#  password: password
#  queue: queue

stories.yml

version: "2.0"

stories:

- story: say ok when user affirms after utter_help
  steps:
  - action: utter_help
  - intent: affirm
  - action: utter_ok

- story: say ok when user affirms after action_show_balance
  steps:
  - action: action_show_balance
  - intent: affirm
  - action: utter_ok

- story: say ok when user affirms after action_show_recipients
  steps:
  - action: action_show_recipients
  - intent: affirm
  - action: utter_ok
  
- story: say ok when user affirms after action_show_transfer_charge
  steps:
  - action: action_show_transfer_charge
  - intent: affirm
  - action: utter_ok

- story: story_ask name and remember it
  steps:
  - intent: request_names
  - action: name_form
  - active_loop: name_form
  - slot_was_set:
    - requested_slot: first_name
  - slot_was_set:
    - first_name: vincent
  - slot_was_set:
    - requested_slot: last_name
  - slot_was_set:
    - last_name: vincent-mcvincent
  - slot_was_set:
    - requested_slot: null
  - active_loop: null
  - action: utter_submit
  - action: utter_slots_values

rules.yml

version: "2.0"

rules:

- rule: Confirm that the bot is not a human
  steps:
  - intent: check_human
  - action: utter_bot
  
- rule: Ask the user to rephrase whenever they send a message with low NLU confidence
  steps:
  - intent: nlu_fallback
  - action: utter_default

- rule: answer out of scope
  steps:
  - intent: out_of_scope
  - action: utter_out_of_scope
    
- rule: greet
  steps:
  - intent: greet
  - action: utter_greet
  - action: utter_help

- rule: say goodbye
  steps:
  - intent: goodbye
  - action: utter_goodbye
  
- rule: help
  steps:
  - intent: help
  - action: utter_help

- rule: thankyou
  steps:
  - intent: thankyou
  - action: utter_noworries
  
- rule: is there a transfer charge
  steps:
  - intent: ask_transfer_charge
  - action: action_show_transfer_charge
  
- rule: Show list of known recipients
  steps:
  - intent: check_recipients
  - action: action_show_recipients
  
- rule: Show balance (bank account or credit card, based on account_type)
  steps:
  - intent: check_balance
  - action: action_show_balance
        
- rule: Activate cc_payment_form when no other form is active
  condition:
  # this condition allows stories to handle form switching
  - active_loop: null
  steps:
  - intent: pay_cc
  - action: cc_payment_form
  - active_loop: cc_payment_form
  
- rule: Activate transfer_money_form when no other form is active
  condition:
  # this condition allows stories to handle form switching
  - active_loop: null
  steps:
  - intent: transfer_money
  - action: transfer_money_form
  - active_loop: transfer_money_form
  
- rule: Activate transaction_search_form when no other form is active
  condition:
  # this condition allows stories to handle form switching
  - active_loop: null
  steps:
  - or:
    - intent: search_transactions
    - intent: check_earnings
  - action: transaction_search_form
  - active_loop: transaction_search_form
  
- rule: Submit cc_payment_form while not switched from previous form
  condition:
  - active_loop: cc_payment_form
  - slot_was_set:
    - previous_form_name: null
  steps:
  - action: cc_payment_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: action_pay_cc
  
- rule: Submit transfer_money_form while not switched from previous form
  condition:
  - active_loop: transfer_money_form
  - slot_was_set:
    - previous_form_name: null
  steps:
  - action: transfer_money_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: action_transfer_money
  
- rule: Submit transaction_search_form while not switched from previous form
  condition:
  - active_loop: transaction_search_form
  - slot_was_set:
    - previous_form_name: null
  steps:
  - action: transaction_search_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: action_transaction_search

- rule: Show user money options
  steps:
  - intent: prompt
  - action: utter_prompt

- rule: show weather
  steps: 
  - intent: weather
  - action: action_weather_api

- rule: Activate Form
  steps:
  - intent: request_names
  - action: name_form
  - active_loop: name_form

- rule: Submit Form
  condition:
  - active_loop: name_form
  steps:
  - action: name_form
  - active_loop: null
  - slot_was_set:
    - requested_slot: null
  - action: utter_submit
  - action: utter_slots_values

domain.yml

version: '2.0'
session_config:
  session_expiration_time: 0
  carry_over_slots_to_new_session: true
intents:
- request_names:
    use_entities: []
- nlu_fallback
- check_human
- transfer_money:
    use_entities: []
- inform
- pay_cc:
    use_entities: []
- greet
- goodbye
- affirm
- deny
- thankyou
- ask_transfer_charge
- search_transactions:
    use_entities: []
- check_balance:
    use_entities:
    - account_type
    - credit_card
- check_earnings:
    use_entities: []
- check_recipients
- out_of_scope
- session_start
- restart
- trigger_handoff
- handoff
- human_handoff
- help
- prompt:
    use_entities: []
- weather:
    use_entities: []
entities:
- PERSON
- account_type
- amount-of-money
- credit_card
- handoff_to
- number
- payment_date
- search_type
- time
- vendor_name
slots:
  first_name:
    type: text
    influence_conversation: true
  last_name:
    type: text
    influence_conversation: true
  AA_CONTINUE_FORM:
    type: any
    influence_conversation: false
  PERSON:
    type: any
    influence_conversation: false
  account_type:
    type: any
    influence_conversation: false
  amount-of-money:
    type: any
    influence_conversation: false
  amount_transferred:
    type: any
    initial_value: 0
    influence_conversation: false
  credit_card:
    type: any
    influence_conversation: false
  currency:
    type: any
    initial_value: $
    influence_conversation: false
  end_time:
    type: any
    influence_conversation: false
  end_time_formatted:
    type: any
    influence_conversation: false
  grain:
    type: any
    influence_conversation: false
  handoff_to:
    type: any
    influence_conversation: false
  next_form_name:
    type: text
    influence_conversation: true
  number:
    type: any
    influence_conversation: false
  payment_amount_type:
    type: any
    initial_value: ''
    influence_conversation: false
  previous_form_name:
    type: text
    influence_conversation: true
  repeated_validation_failures:
    type: any
    influence_conversation: false
  requested_slot:
    type: any
    influence_conversation: false
  search_type:
    type: any
    influence_conversation: false
  start_time:
    type: any
    influence_conversation: false
  start_time_formatted:
    type: any
    influence_conversation: false
  time:
    type: any
    influence_conversation: false
  time_formatted:
    type: any
    influence_conversation: false
  vendor_name:
    type: any
    influence_conversation: false
  zz_confirm_form:
    type: any
    influence_conversation: false
responses:
  utter_out_of_scope:
  - text: Sorry, I'm not sure how to respond to that. Type "help" for assistance.
  utter_ask_transfer_money_form_amount-of-money:
  - text: How much money do you want to transfer?
  utter_ask_transfer_money_form_PERSON:
  - text: Who do you want to transfer money to?
  utter_goodbye:
  - text: Bye
  utter_noworries:
  - text: You're welcome :)
  utter_transfer_complete:
  - text: Successfully transferred {currency}{amount-of-money} to {PERSON}.
  utter_transfer_charge:
  - text: You are entitled to six transfers within a statement cycle before being charged. For subsequent transfers you will be charged {currency}10 per transaction.
  utter_ask_cc_payment_form_amount-of-money:
  - text: How much do you want to pay?
  utter_ask_cc_payment_form_credit_card:
  - text: Towards which credit card account do you want to make a payment?
  utter_ask_cc_payment_form_time:
  - text: For which date would you like to schedule the payment?
  utter_ask_transaction_search_form_vendor_name:
  - text: For which vendor do you want to see transactions?  e.g Starbucks, Target, Amazon
  utter_ask_transaction_search_form_time:
  - text: In which timeframe would you like to search for transactions?
  utter_ask_transaction_search_form_search_type:
  - buttons:
    - payload: /inform{"search_type":"deposit"}'
      title: Incoming (earnings)
    - payload: /inform{"search_type":"spend"}'
      title: Outgoing (spending)
    text: Would you like to search incoming or outgoing transactions?
  utter_no_payment_amount:
  - text: Sorry, I don't understand that payment amount.
  utter_no_paymentdate:
  - text: Sorry, that is not a valid payment date.
  utter_no_creditcard:
  - text: Sorry, that is not a valid credit card account to make payments towards.
  utter_no_vendor_name:
  - text: Sorry, that's not a recognized vendor.
  utter_no_transactdate:
  - text: Sorry, that's not a recognized time frame.
  utter_cc_pay_scheduled:
  - text: Payment of {currency}{amount-of-money}{payment_amount_type} towards your {credit_card} account scheduled to be paid at {time_formatted}.
  utter_searching_spend_transactions:
  - text: Searching transactions{vendor_name} between {start_time_formatted} and {end_time_formatted}...
  utter_found_spend_transactions:
  - text: I found {numtransacts} transactions{vendor_name} totalling {currency}{total}.
  utter_searching_deposit_transactions:
  - text: Searching deposits made to your account between {start_time_formatted} and {end_time_formatted}...
  utter_found_deposit_transactions:
  - text: I found {numtransacts} deposits made to your account totalling {currency}{total}
  utter_ask_rephrase:
  - text: I didn't quite understand that. Can you rephrase?
  utter_ok:
  - text: 👍
  utter_ask_continue:
  - text: Would you like to continue?
  utter_default:
  - text: I didn't quite understand that. Could you rephrase?
  utter_ask_cc_payment_form_AA_CONTINUE_FORM:
  - buttons:
    - payload: /affirm
      title: Yes
    - payload: /deny
      title: No, cancel the transaction
    text: Would you like to continue scheduling the credit card payment?
  utter_ask_transfer_money_form_AA_CONTINUE_FORM:
  - buttons:
    - payload: /affirm
      title: Yes
    - payload: /deny
      title: No, cancel the transfer
    text: Would you like to continue scheduling the money transfer?
  utter_ask_transaction_search_form_AA_CONTINUE_FORM:
  - buttons:
    - payload: /affirm
      title: Yes
    - payload: /deny
      title: No, cancel the search
    text: Would you like to continue the transaction search?
  utter_ask_cc_payment_form_zz_confirm_form:
  - buttons:
    - payload: /affirm
      title: Yes
    - payload: /deny
      title: No, cancel the transaction
    text: Would you like to schedule a payment of {currency}{amount-of-money}{payment_amount_type} towards your {credit_card} account for {time_formatted}?
  utter_ask_transfer_money_form_zz_confirm_form:
  - buttons:
    - payload: /affirm
      title: Yes
    - payload: /deny
      title: No, cancel the transaction
    text: Would you like to transfer {currency}{amount-of-money} to {PERSON}?
  utter_cc_pay_cancelled:
  - text: Credit card account payment cancelled.
  utter_transfer_cancelled:
  - text: Transfer cancelled.
  utter_transaction_search_cancelled:
  - text: Transaction search cancelled.
  utter_account_balance:
  - text: Your bank account balance is {currency}{init_account_balance}.
  utter_changed_account_balance:
  - text: Your bank account balance was {currency}{init_account_balance} and is now {currency}{account_balance} after transfers and payments.
  utter_unknown_recipient:
  - text: Sorry, {PERSON} is not in your list of known recipients.
  utter_insufficient_funds:
  - text: Sorry, you don't have enough money to do that!
  utter_insufficient_funds_specific:
  - text: The {payment_amount_type} on your {credit_card} credit card is {amount-of-money}, so you have insufficient funds to pay it off.
  utter_credit_card_balance:
  - text: The current balance for your {credit_card} account is {currency}{credit_card_balance}.
  utter_nothing_due:
  - text: Your don't owe any money on your {credit_card} credit card bill.
  utter_recipients:
  - text: These are your known recpients to whom you can send money:{formatted_recipients}
  utter_greet:
  - text: Hi! I'm your Financial Assistant!
  utter_ask_handoff:
  - text: It looks like you want to be transferred to a human agent.
  utter_handoff:
  - text: Alright, I'll try to transfer you.
  utter_wouldve_handed_off:
  - text: If you were talking to me via chatroom, I would have handed you off to {handoffhost}.
  utter_no_handoff:
  - text: Since you haven't configured a host to hand off to, I can't send you anywhere!
  utter_ask_whatelse:
  - text: What else can I help you with?
  utter_bot:
  - text: I'm a virtual assistant made with Rasa.
  utter_help:
  - text: |-
      I can help you with your financial accounts. 
      You can ask me things like: 
      - What's my account balance? 
      - Pay off my credit card 
      - What did I spend at Target last month? 
      - I need to transfer money
  utter_prompt:
  - text: |-
      - Savings
      - Investing
      - Insurance
      - Buying a House
      - Work Benefits
      - Life Event
  utter_weather:
  - text: The temperature is {temp}.[Learn more about Rasa here.](www.rasa.com)
  utter_ask_first_name:
  - text: What is your first name?
  utter_submit:
  - text: Ok, Thanks!
  utter_slots_values:
  - text: I'll remember that your name is {first_name} {last_name}!
actions:
- action_ask_last_name
- action_ask_transaction_search_form_zz_confirm_form
- action_handoff
- action_handoff_options
- action_pay_cc
- action_restart
- action_session_start
- action_show_balance
- action_show_recipients
- action_show_transfer_charge
- action_switch_back_ask
- action_switch_forms_affirm
- action_switch_forms_ask
- action_switch_forms_deny
- action_transaction_search
- action_transfer_money
- action_weather_api
- utter_slots_values
- utter_submit
- validate_cc_payment_form
- validate_transaction_search_form
- validate_transfer_money_form
forms:
  name_form:
    required_slots:
      first_name:
      - type: from_text
      last_name:
      - type: from_text
  cc_payment_form:
    required_slots:
      AA_CONTINUE_FORM:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - cc_payment_form
        type: from_text
      amount-of-money:
      - entity: amount-of-money
        not_intent:
        - check_balance
        - check_earnings
        type: from_entity
      - entity: number
        not_intent:
        - check_balance
        - check_earnings
        type: from_entity
      - intent:
        - inform
        - cc_payment_form
        type: from_text
      credit_card:
      - entity: credit_card
        type: from_entity
      - intent:
        - inform
        - cc_payment_form
        type: from_text
      time:
      - entity: time
        type: from_entity
      - intent:
        - inform
        - cc_payment_form
        type: from_text
      zz_confirm_form:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - cc_payment_form
        type: from_text
  transfer_money_form:
    required_slots:
      AA_CONTINUE_FORM:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - transfer_money_form
        type: from_text
      PERSON:
      - entity: PERSON
        type: from_entity
      - intent:
        - inform
        - transfer_money_form
        type: from_text
      amount-of-money:
      - entity: amount-of-money
        not_intent:
        - check_balance
        - check_earnings
        type: from_entity
      - entity: number
        not_intent:
        - check_balance
        - check_earnings
        type: from_entity
      - intent:
        - inform
        - transfer_money_form
        type: from_text
      zz_confirm_form:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - transfer_money_form
        type: from_text
  transaction_search_form:
    required_slots:
      AA_CONTINUE_FORM:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - transaction_search_form
        type: from_text
      search_type:
      - intent: search_transactions
        type: from_trigger_intent
        value: spend
      - intent: check_earnings
        type: from_trigger_intent
        value: deposit
      - entity: search_type
        type: from_entity
      time:
      - entity: time
        type: from_entity
      - intent:
        - inform
        - transaction_search_form
        type: from_text
      zz_confirm_form:
      - intent: affirm
        type: from_intent
        value: yes
      - intent: deny
        type: from_intent
        value: no
      - intent:
        - inform
        - transaction_search_form
        type: from_text

actions.py

"""Custom actions"""
import os
from typing import Dict, Text, Any, List
import logging
from dateutil import parser
import sqlalchemy as sa
import requests
# import pyodbc

from rasa_sdk.interfaces import Action
from rasa_sdk.events import (
    SlotSet,
    EventType,
    ActionExecuted,
    SessionStarted,
    Restarted,
    FollowupAction,
    UserUtteranceReverted,
)
from rasa_sdk import Tracker
from rasa_sdk.executor import CollectingDispatcher

from actions.parsing import (
    parse_duckling_time_as_interval,
    parse_duckling_time,
    get_entity_details,
    parse_duckling_currency,
)

from actions.profile_db import create_database, ProfileDB

from actions.custom_forms import CustomFormValidationAction


logger = logging.getLogger(__name__)

# The profile database is created/connected to when the action server starts
# It is populated the first time `ActionSessionStart.run()` is called .

PROFILE_DB_NAME = os.environ.get("PROFILE_DB_NAME", "profile")
PROFILE_DB_URL = os.environ.get("PROFILE_DB_URL", f"sqlite:///{PROFILE_DB_NAME}.db")
ENGINE = sa.create_engine(PROFILE_DB_URL)
create_database(ENGINE, PROFILE_DB_NAME)

profile_db = ProfileDB(ENGINE)

# driver = 'ODBC Driver 17 for SQL Server'
# server = 'rasa-test.database.windows.net'
# database = 'rasa-test'
# username = 'wealthBuild'
# password = 'azureSql!23'
# connectionString = pyodbc.connect("DRIVER=" + driver
#                                     + ";SERVER=" + server
#                                     + ";DATABASE=" + database
#                                     + ";UID=" + username
#                                     + ";PWD=" + password)

# cursor = connectionString.cursor()



NEXT_FORM_NAME = {
    "pay_cc": "cc_payment_form",
    "transfer_money": "transfer_money_form",
    "search_transactions": "transaction_search_form",
    "check_earnings": "transaction_search_form",
}

FORM_DESCRIPTION = {
    "cc_payment_form": "credit card payment",
    "transfer_money_form": "money transfer",
    "transaction_search_form": "transaction search",
}


class ActionPayCC(Action):
    """Pay credit card."""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_pay_cc"

    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Executes the action"""

        slots = {
            "AA_CONTINUE_FORM": None,
            "zz_confirm_form": None,
            "credit_card": None,
            "account_type": None,
            "amount-of-money": None,
            "time": None,
            "time_formatted": None,
            "start_time": None,
            "end_time": None,
            "start_time_formatted": None,
            "end_time_formatted": None,
            "grain": None,
            "number": None,
        }

        if tracker.get_slot("zz_confirm_form") == "yes":
            credit_card = tracker.get_slot("credit_card")
            amount_of_money = float(tracker.get_slot("amount-of-money"))
            amount_transferred = float(tracker.get_slot("amount_transferred"))
            profile_db.pay_off_credit_card(
                tracker.sender_id, credit_card, amount_of_money
            )

            dispatcher.utter_message(response="utter_cc_pay_scheduled")

            slots["amount_transferred"] = amount_transferred + amount_of_money
        else:
            dispatcher.utter_message(response="utter_cc_pay_cancelled")

        return [SlotSet(slot, value) for slot, value in slots.items()]


class ValidatePayCCForm(CustomFormValidationAction):
    """Validates Slots of the cc_payment_form"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "validate_cc_payment_form"

    def amount_from_balance(
        self, dispatcher, tracker, credit_card_name, balance_type
    ) -> Dict[Text, Any]:
        amount_balance = profile_db.get_credit_card_balance(
            tracker.sender_id, credit_card_name, balance_type
        )
        account_balance = profile_db.get_account_balance(tracker.sender_id)
        if account_balance < float(amount_balance):
            dispatcher.utter_message(response="utter_insufficient_funds")
            return {"amount-of-money": None}
        return {
            "amount-of-money": f"{amount_balance:.2f}",
            "payment_amount_type": f"(your {balance_type})",
        }

    async def validate_amount_of_money(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'amount-of-money' slot"""
        if not value:
            return {"amount-of-money": None}

        account_balance = profile_db.get_account_balance(tracker.sender_id)
        # check if user asked to pay the full or the minimum balance
        if type(value) is str:
            credit_card_name = tracker.get_slot("credit_card")
            if credit_card_name:
                credit_card = profile_db.get_credit_card(
                    tracker.sender_id, credit_card_name
                )
            else:
                credit_card = None
            balance_types = profile_db.list_balance_types()
            if value and value.lower() in balance_types:
                balance_type = value.lower()
                if not credit_card:
                    dispatcher.utter_message(
                        f"I see you'd like to pay the {balance_type}."
                    )
                    return {"amount-of-money": balance_type}
                slots_to_set = self.amount_from_balance(
                    dispatcher, tracker, credit_card_name, balance_type
                )
                if float(slots_to_set.get("amount-of-money")) == 0:
                    dispatcher.utter_message(
                        response="utter_nothing_due", **slots_to_set
                    )
                    return {
                        "amount-of-money": None,
                        "credit_card": None,
                        "payment_amount_type": None,
                    }
                return slots_to_set

        try:
            entity = get_entity_details(
                tracker, "amount-of-money"
            ) or get_entity_details(tracker, "number")
            amount_currency = parse_duckling_currency(entity)
            if not amount_currency:
                raise TypeError
            if account_balance < float(amount_currency.get("amount-of-money")):
                dispatcher.utter_message(response="utter_insufficient_funds")
                return {"amount-of-money": None}
            return amount_currency
        except (TypeError, AttributeError):
            pass

        dispatcher.utter_message(response="utter_no_payment_amount")
        return {"amount-of-money": None}

    async def validate_credit_card(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'credit_card' slot"""
        if value and value.lower() in profile_db.list_credit_cards(tracker.sender_id):
            amount = tracker.get_slot("amount-of-money")
            credit_card_slot = {"credit_card": value.title()}
            balance_types = profile_db.list_balance_types()
            if amount and amount.lower() in balance_types:
                updated_amount = self.amount_from_balance(
                    dispatcher, tracker, value.lower(), amount
                )
                if float(updated_amount.get("amount-of-money")) == 0:
                    dispatcher.utter_message(
                        response="utter_nothing_due", **updated_amount
                    )
                    return {
                        "amount-of-money": None,
                        "credit_card": None,
                        "payment_amount_type": None,
                    }
                account_balance = profile_db.get_account_balance(tracker.sender_id)
                if account_balance < float(updated_amount.get("amount-of-money")):
                    dispatcher.utter_message(
                        response="utter_insufficient_funds_specific", **updated_amount
                    )
                    return {"amount-of-money": None}
                return {**credit_card_slot, **updated_amount}
            return credit_card_slot

        dispatcher.utter_message(response="utter_no_creditcard")
        return {"credit_card": None}

    async def explain_credit_card(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Explains 'credit_card' slot"""
        dispatcher.utter_message("You have the following credits cards:")
        for credit_card in profile_db.list_credit_cards(tracker.sender_id):
            current_balance = profile_db.get_credit_card_balance(
                tracker.sender_id, credit_card
            )
            dispatcher.utter_message(
                response="utter_credit_card_balance",
                **{
                    "credit_card": credit_card.title(),
                    "amount-of-money": f"{current_balance:.2f}",
                },
            )
        return {}

    async def validate_time(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'time' slot"""
        timeentity = get_entity_details(tracker, "time")
        parsedtime = timeentity and parse_duckling_time(timeentity)
        if not parsedtime:
            dispatcher.utter_message(response="utter_no_transactdate")
            return {"time": None}
        return parsedtime

    async def validate_zz_confirm_form(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'zz_confirm_form' slot"""
        if value in ["yes", "no"]:
            return {"zz_confirm_form": value}

        return {"zz_confirm_form": None}


class ActionTransactionSearch(Action):
    """Searches for a transaction"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_transaction_search"

    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict]:
        """Executes the action"""
        slots = {
            "AA_CONTINUE_FORM": None,
            "zz_confirm_form": None,
            "time": None,
            "time_formatted": None,
            "start_time": None,
            "end_time": None,
            "start_time_formatted": None,
            "end_time_formatted": None,
            "grain": None,
            "search_type": None,
            "vendor_name": None,
        }

        if tracker.get_slot("zz_confirm_form") == "yes":
            search_type = tracker.get_slot("search_type")
            deposit = search_type == "deposit"
            vendor = tracker.get_slot("vendor_name")
            vendor_name = f" at {vendor.title()}" if vendor else ""
            start_time = parser.isoparse(tracker.get_slot("start_time"))
            end_time = parser.isoparse(tracker.get_slot("end_time"))
            transactions = profile_db.search_transactions(
                tracker.sender_id,
                start_time=start_time,
                end_time=end_time,
                deposit=deposit,
                vendor=vendor,
            )

            aliased_transactions = transactions.subquery()
            total = profile_db.session.query(
                sa.func.sum(aliased_transactions.c.amount)
            )[0][0]
            if not total:
                total = 0
            numtransacts = transactions.count()
            slotvars = {
                "total": f"{total:.2f}",
                "numtransacts": numtransacts,
                "start_time_formatted": tracker.get_slot("start_time_formatted"),
                "end_time_formatted": tracker.get_slot("end_time_formatted"),
                "vendor_name": vendor_name,
            }

            dispatcher.utter_message(
                response=f"utter_searching_{search_type}_transactions",
                **slotvars,
            )
            dispatcher.utter_message(
                response=f"utter_found_{search_type}_transactions", **slotvars
            )
        else:
            dispatcher.utter_message(response="utter_transaction_search_cancelled")

        return [SlotSet(slot, value) for slot, value in slots.items()]


class ValidateTransactionSearchForm(CustomFormValidationAction):
    """Validates Slots of the transaction_search_form"""

    def name(self) -> Text:
        """Unique identifier of the form"""
        return "validate_transaction_search_form"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Custom validates the filled slots"""
        events = await super().run(dispatcher, tracker, domain)

        # For 'spend' type transactions we need to know the vendor_name
        search_type = tracker.get_slot("search_type")
        if search_type == "spend":
            vendor_name = tracker.get_slot("vendor_name")
            if not vendor_name:
                events.append(SlotSet("requested_slot", "vendor_name"))

        return events

    async def validate_search_type(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'search_type' slot"""
        if value in ["spend", "deposit"]:
            return {"search_type": value}

        return {"search_type": None}

    async def validate_vendor_name(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'vendor_name' slot"""
        if value and value.lower() in profile_db.list_vendors():
            return {"vendor_name": value}

        dispatcher.utter_message(response="utter_no_vendor_name")
        return {"vendor_name": None}

    async def validate_time(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'time' slot"""
        timeentity = get_entity_details(tracker, "time")
        parsedinterval = timeentity and parse_duckling_time_as_interval(timeentity)
        if not parsedinterval:
            dispatcher.utter_message(response="utter_no_transactdate")
            return {"time": None}

        return parsedinterval


class ActionTransferMoney(Action):
    """Transfers Money."""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_transfer_money"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the action"""
        slots = {
            "AA_CONTINUE_FORM": None,
            "zz_confirm_form": None,
            "PERSON": None,
            "amount-of-money": None,
            "number": None,
        }

        if tracker.get_slot("zz_confirm_form") == "yes":
            amount_of_money = float(tracker.get_slot("amount-of-money"))
            from_account_number = profile_db.get_account_number(
                profile_db.get_account_from_session_id(tracker.sender_id)
            )
            to_account_number = profile_db.get_account_number(
                profile_db.get_recipient_from_name(
                    tracker.sender_id, tracker.get_slot("PERSON")
                )
            )
            profile_db.transact(
                from_account_number,
                to_account_number,
                amount_of_money,
            )

            dispatcher.utter_message(response="utter_transfer_complete")

            amount_transferred = float(tracker.get_slot("amount_transferred"))
            slots["amount_transferred"] = amount_transferred + amount_of_money
        else:
            dispatcher.utter_message(response="utter_transfer_cancelled")

        return [SlotSet(slot, value) for slot, value in slots.items()]


class ValidateTransferMoneyForm(CustomFormValidationAction):
    """Validates Slots of the transfer_money_form"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "validate_transfer_money_form"

    async def validate_PERSON(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'PERSON' slot"""
        # It is possible that both Spacy & DIET extracted the PERSON
        # Just pick the first one
        if isinstance(value, list):
            value = value[0]

        name = value.lower() if value else None
        known_recipients = profile_db.list_known_recipients(tracker.sender_id)
        first_names = [name.split()[0] for name in known_recipients]
        if name is not None and name in known_recipients:
            return {"PERSON": name.title()}

        if name in first_names:
            index = first_names.index(name)
            fullname = known_recipients[index]
            return {"PERSON": fullname.title()}

        dispatcher.utter_message(response="utter_unknown_recipient", PERSON=value)
        return {"PERSON": None}

    async def explain_PERSON(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Explains 'PERSON' slot"""
        recipients = profile_db.list_known_recipients(tracker.sender_id)
        formatted_recipients = "\n" + "\n".join(
            [f"- {recipient.title()}" for recipient in recipients]
        )
        dispatcher.utter_message(
            response="utter_recipients",
            formatted_recipients=formatted_recipients,
        )
        return {}

    async def validate_amount_of_money(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'amount-of-money' slot"""
        account_balance = profile_db.get_account_balance(tracker.sender_id)
        try:
            entity = get_entity_details(
                tracker, "amount-of-money"
            ) or get_entity_details(tracker, "number")
            amount_currency = parse_duckling_currency(entity)
            if not amount_currency:
                raise TypeError
            if account_balance < float(amount_currency.get("amount-of-money")):
                dispatcher.utter_message(response="utter_insufficient_funds")
                return {"amount-of-money": None}
            return amount_currency
        except (TypeError, AttributeError):
            dispatcher.utter_message(response="utter_no_payment_amount")
            return {"amount-of-money": None}

    async def validate_zz_confirm_form(
        self,
        value: Text,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> Dict[Text, Any]:
        """Validates value of 'zz_confirm_form' slot"""
        if value in ["yes", "no"]:
            return {"zz_confirm_form": value}

        return {"zz_confirm_form": None}


class ActionShowBalance(Action):
    """Shows the balance of bank or credit card accounts"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_show_balance"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        account_type = tracker.get_slot("account_type")

        if account_type == "credit":
            # show credit card balance
            credit_card = tracker.get_slot("credit_card")
            available_cards = profile_db.list_credit_cards(tracker.sender_id)

            if credit_card and credit_card.lower() in available_cards:
                current_balance = profile_db.get_credit_card_balance(
                    tracker.sender_id, credit_card
                )
                dispatcher.utter_message(
                    response="utter_credit_card_balance",
                    **{
                        "credit_card": credit_card.title(),
                        "credit_card_balance": f"{current_balance:.2f}",
                    },
                )
            else:
                for credit_card in profile_db.list_credit_cards(tracker.sender_id):
                    current_balance = profile_db.get_credit_card_balance(
                        tracker.sender_id, credit_card
                    )
                    dispatcher.utter_message(
                        response="utter_credit_card_balance",
                        **{
                            "credit_card": credit_card.title(),
                            "credit_card_balance": f"{current_balance:.2f}",
                        },
                    )
        else:
            # show bank account balance
            account_balance = profile_db.get_account_balance(tracker.sender_id)
            amount = tracker.get_slot("amount_transferred")
            if amount:
                amount = float(tracker.get_slot("amount_transferred"))
                init_account_balance = account_balance + amount
                dispatcher.utter_message(
                    response="utter_changed_account_balance",
                    init_account_balance=f"{init_account_balance:.2f}",
                    account_balance=f"{account_balance:.2f}",
                )
            else:
                dispatcher.utter_message(
                    response="utter_account_balance",
                    init_account_balance=f"{account_balance:.2f}",
                )

        events = []
        active_form_name = tracker.active_form.get("name")
        if active_form_name:
            # keep the tracker clean for the predictions with form switch stories
            events.append(UserUtteranceReverted())
            # trigger utter_ask_{form}_AA_CONTINUE_FORM, by making it the requested_slot
            events.append(SlotSet("AA_CONTINUE_FORM", None))
            # avoid that bot goes in listen mode after UserUtteranceReverted
            events.append(FollowupAction(active_form_name))

        return events


class ActionShowRecipients(Action):
    """Lists the contents of then known_recipients slot"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_show_recipients"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        recipients = profile_db.list_known_recipients(tracker.sender_id)
        formatted_recipients = "\n" + "\n".join(
            [f"- {recipient.title()}" for recipient in recipients]
        )
        dispatcher.utter_message(
            response="utter_recipients",
            formatted_recipients=formatted_recipients,
        )

        events = []
        active_form_name = tracker.active_form.get("name")
        if active_form_name:
            # keep the tracker clean for the predictions with form switch stories
            events.append(UserUtteranceReverted())
            # trigger utter_ask_{form}_AA_CONTINUE_FORM, by making it the requested_slot
            events.append(SlotSet("AA_CONTINUE_FORM", None))
            # # avoid that bot goes in listen mode after UserUtteranceReverted
            events.append(FollowupAction(active_form_name))

        return events


class ActionShowTransferCharge(Action):
    """Lists the transfer charges"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_show_transfer_charge"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        dispatcher.utter_message(response="utter_transfer_charge")

        events = []
        active_form_name = tracker.active_form.get("name")
        if active_form_name:
            # keep the tracker clean for the predictions with form switch stories
            events.append(UserUtteranceReverted())
            # trigger utter_ask_{form}_AA_CONTINUE_FORM, by making it the requested_slot
            events.append(SlotSet("AA_CONTINUE_FORM", None))
            # # avoid that bot goes in listen mode after UserUtteranceReverted
            events.append(FollowupAction(active_form_name))

        return events


class ActionSessionStart(Action):
    """Executes at start of session"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_session_start"

    @staticmethod
    def _slot_set_events_from_tracker(
        tracker: "Tracker",
    ) -> List["SlotSet"]:
        """Fetches SlotSet events from tracker and carries over keys and values"""

        # when restarting most slots should be reset
        relevant_slots = ["currency"]

        return [
            SlotSet(
                key=event.get("name"),
                value=event.get("value"),
            )
            for event in tracker.events
            if event.get("event") == "slot" and event.get("name") in relevant_slots
        ]

    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[EventType]:
        """Executes the custom action"""
        # the session should begin with a `session_started` event
        events = [SessionStarted()]

        events.extend(self._slot_set_events_from_tracker(tracker))

        # create a mock profile by populating database with values specific to tracker.sender_id
        profile_db.populate_profile_db(tracker.sender_id)
        currency = profile_db.get_currency(tracker.sender_id)

        # initialize slots from mock profile
        events.append(SlotSet("currency", currency))

        # add `action_listen` at the end
        events.append(ActionExecuted("action_listen"))

        return events


class ActionRestart(Action):
    """Executes after restart of a session"""

    def name(self) -> Text:
        """Unique identifier of the action"""
        return "action_restart"

    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[EventType]:
        """Executes the custom action"""
        return [Restarted(), FollowupAction("action_session_start")]


class ActionAskTransactionSearchFormConfirm(Action):
    """Asks for the 'zz_confirm_form' slot of 'transaction_search_form'

    A custom action is used instead of an 'utter_ask' response because a different
    question is asked based on 'search_type' and 'vendor_name' slots.
    """

    def name(self) -> Text:
        return "action_ask_transaction_search_form_zz_confirm_form"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        search_type = tracker.get_slot("search_type")
        vendor_name = tracker.get_slot("vendor_name")
        start_time_formatted = tracker.get_slot("start_time_formatted")
        end_time_formatted = tracker.get_slot("end_time_formatted")

        if vendor_name:
            vendor_name = f" with {vendor_name}"
        else:
            vendor_name = ""
        if search_type == "spend":
            text = (
                f"Do you want to search for transactions{vendor_name} between "
                f"{start_time_formatted} and {end_time_formatted}?"
            )
        elif search_type == "deposit":
            text = (
                f"Do you want to search deposits made to your account between "
                f"{start_time_formatted} and {end_time_formatted}?"
            )
        buttons = [
            {"payload": "/affirm", "title": "Yes"},
            {"payload": "/deny", "title": "No"},
        ]

        dispatcher.utter_message(text=text, buttons=buttons)

        return []


class ActionSwitchFormsAsk(Action):
    """Asks to switch forms"""

    def name(self) -> Text:
        return "action_switch_forms_ask"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        active_form_name = tracker.active_form.get("name")
        intent_name = tracker.latest_message["intent"]["name"]
        next_form_name = NEXT_FORM_NAME.get(intent_name)

        if (
            active_form_name not in FORM_DESCRIPTION.keys()
            or next_form_name not in FORM_DESCRIPTION.keys()
        ):
            logger.debug(
                f"Cannot create text for `active_form_name={active_form_name}` & "
                f"`next_form_name={next_form_name}`"
            )
            next_form_name = None
        else:
            text = (
                f"We haven't completed the {FORM_DESCRIPTION[active_form_name]} yet. "
                f"Are you sure you want to switch to {FORM_DESCRIPTION[next_form_name]}?"
            )
            buttons = [
                {"payload": "/affirm", "title": "Yes"},
                {"payload": "/deny", "title": "No"},
            ]
            dispatcher.utter_message(text=text, buttons=buttons)
        return [SlotSet("next_form_name", next_form_name)]


class ActionSwitchFormsDeny(Action):
    """Does not switch forms"""

    def name(self) -> Text:
        return "action_switch_forms_deny"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        active_form_name = tracker.active_form.get("name")

        if active_form_name not in FORM_DESCRIPTION.keys():
            logger.debug(
                f"Cannot create text for `active_form_name={active_form_name}`."
            )
        else:
            text = f"Ok, let's continue with the {FORM_DESCRIPTION[active_form_name]}."
            dispatcher.utter_message(text=text)

        return [SlotSet("next_form_name", None)]


class ActionSwitchFormsAffirm(Action):
    """Switches forms"""

    def name(self) -> Text:
        return "action_switch_forms_affirm"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        active_form_name = tracker.active_form.get("name")
        next_form_name = tracker.get_slot("next_form_name")

        if (
            active_form_name not in FORM_DESCRIPTION.keys()
            or next_form_name not in FORM_DESCRIPTION.keys()
        ):
            logger.debug(
                f"Cannot create text for `active_form_name={active_form_name}` & "
                f"`next_form_name={next_form_name}`"
            )
        else:
            text = (
                f"Great. Let's switch from the {FORM_DESCRIPTION[active_form_name]} "
                f"to {FORM_DESCRIPTION[next_form_name]}. "
                f"Once completed, you will have the option to switch back."
            )
            dispatcher.utter_message(text=text)

        return [
            SlotSet("previous_form_name", active_form_name),
            SlotSet("next_form_name", None),
        ]


class ActionSwitchBackAsk(Action):
    """Asks to switch back to previous form"""

    def name(self) -> Text:
        return "action_switch_back_ask"

    async def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:
        """Executes the custom action"""
        previous_form_name = tracker.get_slot("previous_form_name")

        if previous_form_name not in FORM_DESCRIPTION.keys():
            logger.debug(
                f"Cannot create text for `previous_form_name={previous_form_name}`"
            )
            previous_form_name = None
        else:
            text = (
                f"Would you like to go back to the "
                f"{FORM_DESCRIPTION[previous_form_name]} now?."
            )
            buttons = [
                {"payload": "/affirm", "title": "Yes"},
                {"payload": "/deny", "title": "No"},
            ]
            dispatcher.utter_message(text=text, buttons=buttons)

        return [SlotSet("previous_form_name", None)]


class ActionShowWeather(Action):
    """show weather"""

    def name(self) -> Text:
        return "action_weather_api"

    async def run(
        self,
        dispatcher: CollectingDispatcher,
        tracker: Tracker,
        domain: Dict[Text, Any],
    ) -> List[Dict[Text, Any]]:

        address = "https://int-api.mx.com/users/USR-8fe5e260-fe63-47dd-b8cd-438cd5a48b94/accounts?page=1&records_per_page=10"
        headers = {
            "Accept": "application/vnd.mx.api.v1+json",
            "Content-Type": "application/json",
        }
        userName = "653f7dba-265c-4d70-ba21-3b94dc126361"
        password = "0effbf747bfe42043998c4510489cf39d39c30ed"
        json = requests.get(
            address, verify=False, headers=headers, auth=(userName, password)
        ).json()["accounts"][0]["balance"]
        buttons = [
            {"payload": "/affirm", "title": "Yes"},
            {"payload": "/deny", "title": "No"},
        ]
        dispatcher.utter_message(response="utter_weather", temp=json, buttons=buttons)

        return []


class AskForSlotAction(Action):
    def name(self) -> Text:
        return "action_ask_last_name"

    def run(
        self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict
    ) -> List[EventType]:

        first_name = tracker.get_slot("first_name")
        dispatcher.utter_message(text=f"So {first_name}, what is your last name?")

        return []

@nik202 just heads up if you were able to find any related issue on the yml files I posted

@jpark2111 Can I ask you about your use case or project? i am aware of this financial demo code, but I guess you updated some code and it’s really very hard for me to comment, but I will see and get back to you :slight_smile:

@nik202 So I’m a newbie to rasa :slight_smile: just started using it for test purpose at first and finally started to build it. I’ve been doing research and setting up environment, thought financial demo would be a great start for our project and it’s been working great. I cloned the repo again to see if there is any issue with action server and works just fine. Now I’m curious why my current rasa stack has been giving me those errors :frowning:

@jpark2111 yes, you are messed with your updated code. So please I’d recommend examining every line of code which you had mentioned and you are good to go. If you need any help please message me here.

@nik202 Thank you for your responses, having a quick question, I’d like to connect rasa to our own database to store and retrieve data, our database is SQL server. I’ve been using pyodbc library in actions.py to connect rasa to sql so that I can store data from user input into our database, for instance. But I’ve started thinking if I need another web API for CRUD operation. We already have frontend app using react, dotnet api and sql database. Rasa will need to be hooked up with react and sql as well. What’s the common case when you use rasa to interact with external database such as sql server? Will there be a performance issue once you use pyodbc? Or do I really need to build another API app? I’m totally new to python so there are lots of things to be figured out

@jpark2111 Is that your current issue is sorted?

@jpark2111

Normally, we use the SQL or tracker store to store the bot/user conversation and for fetching the data from the server, if we have some database.

Well, I never used pyodc in any of my use cases, but I don’t think there should be any issue in performance.

@nik202 The question is not related to the issue I was having, it has been resolved with starting with project by cloning a fresh repo. I’d like to hear an insight from you about a common case of rasa when an external database needs to be connected.

@jpark2111 That’s why I asked that your previous issue be sorted, so you can close this thread as a solution, as when the other user visits this thread they will get confused and follow the different path. I hope you understand. I always reply to related issue topics only, but I can see you have issues so I just replied, I hope you don’t mind and try to understand the forum and other users’ concerns. :slight_smile:

@jpark2111 I already answered this in my previous post, if you have any example or use-case please feel free to share and I will help you at its best.

1 Like