How to run custom action in background?

Hi All, I’m beginner of Rasa and I facing issue when I’m writing custom actions.

I made my own server, and declared 1variable which is changing every 1 second. And I want that when Rasa is running (with >rasa shell command) Rasa detect the variable is changing and start to talk to user (like this: dispatch.utter_message("Data is change to ",new_val))

The problem is that I don’t know how to run the custom action in background… I want to detect and start conversation the data changing while it’s already conversation with user. So I tried override the “action_session_start” because that action is executed in every conversation. But It was not working… How can I run the custom action everytime and send a message to user sometimes? I’m really appreciate it if you give me some information.

Hello and welcome to the forum :slight_smile:

You can POST the following JSON to http://localhost:5055/webhook/:

{
  next_action: action_name,
  sender_id: conversation_id
}

Thank you for reply! BTW Where can I put that code? endpoints.yml file?

@Jungeun-Park-kr is you are running action server on second terminal i.e rasa run actions?

Yes! But I think event listener is not working on Rasa… Rasa ignore my dataChangeListener and just doing other conversation.

@Jungeun-Park-kr can you share rasa --version please.

@Jungeun-Park-kr can you share the actions.py file for custom action you have written?

Tip: The best thumb rule is we just write the custom action code in actions.py and run the action sever in second terminal while using command rasa run actions and in first terminal we run rasa shell --debug I never changed the action _session_start or is your use case is different?

It’s like this! Rasa Version : 2.8.12 Minimum Compatible Version: 2.8.9 Rasa SDK Version : 2.8.2 Rasa X Version : None Python Version : 3.8.8 Operating System : Windows-10-10.0.19041-SP0

Also my actions.py

# This files contains your custom actions which can be used to run
# custom Python code.

# See this guide on how to implement these action:
# https://rasa.com/docs/rasa/custom-actions


# This is a simple example for a custom action which utters "Hello World!"

from typing import Any, Text, Dict, List

from rasa_sdk import Action, Tracker
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.events import SlotSet, SessionStarted, ActionExecuted, EventType


# Add codes for using OPCUA
# from asyncua import Client, Node, ua
from opcua import Client, Node, ua
import asyncio
import time


class SubscriptionHandler():
    def __init__(self, dispatcher) -> None:
        self._dispatcher = dispatcher

    def datachange_notification(self, node: Node, val, data):
        print('#############datachange_notification %r %s' %(node, val),'###################')
        self._dispatcher.utter_message(text=('datachange_notification %r %s' %(node, val)))
        # Talk to user that data has changed


class ActionSessionStart(Action):
    def name(self) -> Text:
        return "action_session_start"

    async def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
        
        client = Client(url='opc.tcp://141.82.166.100:4840/freeopcua/server/')
        client.connect()
        node = client.get_node("ns=2;i=2")
        
        handler = SubscriptionHandler(dispatcher)
        # We create a Client Subscription.
        subscription = client.create_subscription(500, handler)
        nodes = [
            node,
        ]
        subscription.subscribe_data_change(nodes)
        
        return []


class ActionUtterSupplyTestValue(Action):
    def name(self) -> Text:
        return "action_utter_supply_test_value"

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

        client = Client(url='opc.tcp://141.82.166.100:4840/freeopcua/server/')
        client.connect()
        dispatcher.utter_message(text='Client connected')
        node = client.get_node("ns=2;i=2")
        value = node.get_value()
        dispatcher.utter_message(text=f'test value is {value}')
        return []

@Jungeun-Park-kr what is your use case can you briefly elaborate, what you trying to do?

Thanks for your tip! I also think that for my use case, I’m not sure that I need action_session_start

I want to detect the variable is changing or not every time, and if it changes I want to notify to user… Is it possible?

@Jungeun-Park-kr what do you mean by variable? for sending a message to user did you mean by email or as a response in the chat itself?

And for that, I need to register DataChangeListener for my variable using Opcua API.

And I want to keep that EventLisener while Rasa is running.

I mean latter one! response in the chat itself!

@Jungeun-Park-kr first you need to check the API is giving you the status 200 (connected or not) while using custom action and then you can do the other parts.

I don’t know how to check API status in Rasa, but in my other environment it’s working fine.(like eclipse…)

But when I’m using SubscriptionHandler() in Rasa, always time our error occurs.

@Jungeun-Park-kr well I am not expert in eclipse, but you can search something on google.

okay, thank you so much!

I have one more question, do you know how to implement next_action for my custom action?

No no.

In your endpoints.yml add:

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

and in credentials.yml add:

rest:

rasa:
  url: "http://localhost:5002/api"

Then you just POST the JSON {next_action: action_name, sender_id: id} to the HTTP API at http://localhost:5055/webhook/.

If you don’t know what REST, HTTP API, and POST mean, look at this tutorial.

1 Like

next_action is just the name of the action you want to trigger.

For example

{
  next_action: "action_notify_data_changed",
  sender_id: "user123"
}
1 Like

!!Edited I just forgot “” for name… Never mind! Sorry!

Thanks for information! So I tried that in my custom action like down below:

data = {
            "next_action": "action_notify_data_changed",
            "sender_id": "default"
        }
        res = requests.post('http://localhost:5055/webhook/', data=json.dumps(data))

But I got an NameError like this…

Exception occurred while handling uri: 'http://localhost:5055/webhook'
Traceback (most recent call last):
  File "c:\users\je991\anaconda3\lib\site-packages\sanic\app.py", line 939, in handle_request
    response = await response
  File "c:\users\je991\anaconda3\lib\site-packages\rasa_sdk\endpoint.py", line 104, in webhook
    result = await executor.run(action_call)
  File "c:\users\je991\anaconda3\lib\site-packages\rasa_sdk\executor.py", line 397, in run
    events = await utils.call_potential_coroutine(
  File "c:\users\je991\anaconda3\lib\site-packages\rasa_sdk\utils.py", line 230, in call_potential_coroutine
    return await coroutine_or_return_value
  File "C:\Users\je991\project_test\actions\actions.py", line 175, in run
    next_action: "action_notify_data_changed",
NameError: name 'next_action' is not defined

Do you know what is the problem in my code?