对话机器人 Rasa(三十四): Socket.IO channel 设置 session id

文章目录

    在之前的 Rasa 笔记中记录过 Sender ID 的使用,即 session id 的管理:

    对话机器人 Rasa(十二):用户会话 Session 管理

    对于基于 HTTP 的自定义渠道,session id 比较好处理,直接获取请求中的 sender 等自定义的字段值即可。

    但是,对于基于 socket.io channel 来说,代码修改相对复杂一些,还有额外的概念。这里记录一下。

    session_persistence

    参考官方文档:

    https://rasa.com/docs/rasa/connectors/your-own-website/

    socketio:
      user_message_evt: user_uttered
      bot_message_evt: bot_uttered
      session_persistence: true/false
    

    这里有个 SESSION PERSISTENCE 的概念。

    By default, the SocketIO channel uses the socket id as sender_id, which causes the session to restart at every page reload. session_persistence can be set to true to avoid that. In that case, the frontend is responsible for generating a session id and sending it to the Rasa Core server by emitting the event session_request with {session_id: [session_id]} immediately after the connect event.

    因为默认情况下,session_persistence 为 false 时,使用的是 socket id 作为 session_id/sender_id,
    这样做的弊端是,页面刷新,会导致 socket.io 连接重连,更换 socket id,于是无法判断为同一个用户的会话。

    解决方案就是,将 session_persistence 设置为 true,然后在前端自己生成一个 session_id/sender_id,
    当然也可以从 server 端获取一个 session_id/sender_id,默认的 socketio.py 也内置了这个逻辑。参考下面的 session_request 事件里的代码。

    内置 socketio.py 的代码

    默认的 session_id 的代码

    @sio.on("session_request", namespace=self.namespace)
    async def session_request(sid: Text, data: Optional[Dict]) -> None:
        if data is None:
            data = {}
        if "session_id" not in data or data["session_id"] is None:
            data["session_id"] = uuid.uuid4().hex
        if self.session_persistence:
            sio.enter_room(sid, data["session_id"])
        await sio.emit("session_confirm", data["session_id"], room=sid)
        logger.debug(f"User {sid} connected to socketIO endpoint.")
    
    @sio.on(self.user_message_evt, namespace=self.namespace)
    async def handle_message(sid: Text, data: Dict) -> None:
        output_channel = SocketIOOutput(sio, self.bot_message_evt)
    
        if self.session_persistence:
            if not data.get("session_id"):
                rasa.shared.utils.io.raise_warning(
                    "A message without a valid session_id "
                    "was received. This message will be "
                    "ignored. Make sure to set a proper "
                    "session id using the "
                    "`session_request` socketIO event."
                )
                return
            sender_id = data["session_id"]
        else:
            sender_id = sid
    
        metadata = data.get(self.metadata_key, {})
        if isinstance(metadata, Text):
            metadata = json.loads(metadata)
        message = UserMessage(
            # data.get("message", ""),
            data.get("text", ""),
            output_channel,
            sender_id,
            input_channel=self.name(),
            metadata=metadata,
        )
        await on_new_message(message)
    
    return socketio_webhook
    

    修改逻辑

    • 将 session_persistence 设置为 true
    • session_request 事件中的逻辑先忽略, 即客户端不主动调用 session_request 中的逻辑
    • 将请求中的 session_id 改成自定义字段名,例如 sender,减少客户端的兼容性修改
    • 后续,将 enter_room 的逻辑加进来

    查看合集

    📖 对话机器人 Rasa 中文系列教程

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式