Hello! I have a custom connector thats gets some data, and sends it as metadata to the action_session_start. It works fine when using the boot right after boot, but if I wait for the session to end, or use /session_start, my custom connector does not send metadata to the action_session_start, implying in unexpected behavior
import logging
from sanic import Blueprint, response
from sanic.request import Request
from typing import Text, Dict, Any, List, Iterable, Optional, Callable, Awaitable
from rasa.core.channels.channel import UserMessage, OutputChannel, InputChannel
from sanic.response import HTTPResponse
from crisp_api import Crisp
logger = logging.getLogger(__name__)
class CrispBot(OutputChannel):
@classmethod
def name(cls) -> Text:
return "crisp"
def __init__(self, identifier: Text, key: Text, website_id: Text) -> None:
self.identifier = identifier
self.key = key
self.website_id = website_id
self.client = Crisp()
self.client.set_tier("plugin")
self.client.authenticate(identifier, key)
async def send_text_message(
self, recipient_id: Text, text: Text, **kwargs: Any
) -> None:
"""Send message to output channel"""
self.client.website.send_message_in_conversation(
self.website_id, recipient_id,
{
"type": "text",
"content": text,
"from": "operator",
"origin": "chat"
}
)
class CrispInput(InputChannel):
"""crisp input channel implementation."""
@classmethod
def name(cls) -> Text:
return "crisp"
@classmethod
def from_credentials(cls, credentials: Optional[Dict[Text, Any]]) -> InputChannel:
if not credentials:
cls.raise_missing_credentials_exception()
return cls(
credentials.get("identifier"),
credentials.get("key"),
credentials.get("website_id")
)
def __init__(self, identifier: Text, key: Text, website_id: Text) -> None:
self.identifier = identifier
self.key = key
self.website_id = website_id
async def send_message(
self,
text: Optional[Text],
website_id: Optional[Text],
user_id: Optional[Text],
sender_name: Optional[Text],
recipient_id: Optional[Text],
on_new_message: Callable[[UserMessage], Awaitable[Any]]
) -> None:
output_channel = self.get_output_channel()
print("Sending message to Crisp: {}".format(text))
print("session_id :", recipient_id)
user_msg = UserMessage(
text,
output_channel,
recipient_id,
input_channel=self.name(),
metadata={"website_id": website_id, "session_id": recipient_id, "user_id": user_id, "nickname": sender_name},
)
await on_new_message(user_msg)
def blueprint(
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
) -> Blueprint:
crisp_custom_webhook = Blueprint("crisp_custom_webhook", __name__)
@crisp_custom_webhook.route("/", methods=["GET"])
async def health(_: Request) -> HTTPResponse:
return response.json({"status": "ok"})
@crisp_custom_webhook.route("/webhook", methods=["GET", "POST"])
async def receive(request: Request) -> HTTPResponse:
data = request.json.get('data')
print("Received message from Crisp: {}".format(data))
print(data)
if data:
website_id = data.get('website_id')
print("website_id :", website_id)
user_id = data.get('user').get('user_id')
print("user_id :", user_id)
sender_name = data.get('user').get("nickname")
print("sender_name :", sender_name)
text = data.get("content", None)
print("text :", text)
session_id = data.get("session_id", None)
print("session_id :", session_id)
await self.send_message(
text = text, website_id = website_id, user_id = user_id, sender_name = sender_name, recipient_id = session_id, on_new_message= on_new_message
)
return response.text("")
return crisp_custom_webhook
def get_output_channel(self) -> OutputChannel:
return CrispBot(self.identifier, self.key, self.website_id)
# Rasa Requirements for SDK
from datetime import datetime, timedelta
from typing import Dict, Text, Any, List, Union, Optional, NewType
import pytz
from rasa_sdk import Action, Tracker, FormValidationAction
from rasa_sdk.types import DomainDict
from rasa_sdk.events import (
SlotSet,
ActionExecuted,
UserUttered,
SessionStarted,
EventType,
FollowupAction,
UserUtteranceReverted,
Restarted,
ActionReverted,
)
from rasa_sdk.executor import CollectingDispatcher
from crisp_api import *
from actions.util import *
from actions.crisp_api import CrispBot
import os
class ActionSessionStart(Action):
def name(self) -> Text:
return "action_session_start"
async def run(
self, dispatcher, tracker: Tracker, domain: Dict[Text, Any]
) -> List[Dict[Text, Any]]:
events = [SessionStarted()]
Crisp = CrispBot()
try:
metadata = tracker.get_slot("session_started_metadata")
print("metadata: ", metadata)
events.append(
SlotSet(
"user_id",
metadata.get("session_id"),
)
)
current_conv = Crisp.get_conversation(metadata.get('session_id'))
current_conv_messages = Crisp.get_messages_in_conversation(metadata.get('session_id'))
if not get_last_message_timestamp(current_conv_messages):
events.append(
SlotSet(
"bot_active",
True,
)
)
else:
last_message_timestamp = int(get_last_message_timestamp(current_conv_messages))/1000
last_timestamp = datetime.fromtimestamp(last_message_timestamp)
# Getting the current date and time
dt = datetime.now()
result_time = dt - last_timestamp
debug = False
minutes = parseYaml(os.path.join("config.yml"))["session_config"]["session_expiration_time"]
print("result_time: ", result_time)
if result_time > timedelta(minutes=minutes):
print("sou maior")
events.append(
SlotSet(
"bot_active",
True,
)
)
else:
print("nao sou maior")
events.append(
SlotSet(
"bot_active",
False,
)
)
if current_conv is not None:
if 'segments' in current_conv['meta']:
segments = current_conv['meta']['segments']
events.append(
SlotSet(
"segments",
segments,
)
)
if 'email' in current_conv['meta']:
email = current_conv['meta']['email']
if email != '':
events.append(
SlotSet(
"email",
email,
)
)
if 'phone' in current_conv['meta']:
phone = current_conv['meta']['phone']
events.append(
SlotSet(
"phone",
phone,
)
)
if 'people_id' in current_conv:
people_id = current_conv['people_id']
people_data = Crisp.get_people_data(people_id)
events.append(
SlotSet(
"crisp_verified",
True,
)
)
events.append(
SlotSet(
"people_id",
current_conv['people_id'],
)
)
events.append(
SlotSet(
"nickname",
metadata.get("nickname"),
)
)
print("people data: ", people_data)
if 'ead_id' in people_data:
print('caindo aqui ead id')
ead_id = people_data['ead_id']
events.append(
SlotSet(
"ead_id",
ead_id,
)
)
events.append(
SlotSet(
"platform_verified",
True,
)
)
else:
events.append(
SlotSet(
"crisp_verified",
False,
)
)
except Exception as e:
print("Exception: ", e)
print("erro ao pegar os dados do usuario")
events.append(ActionExecuted("action_listen"))
events.insert(0,SessionStarted())
return events
I get Exception: ‘NoneType’ object has no attribute ‘get’. Because metadata is None in a_starter when i call /action_session_start