对话机器人 Rasa(十九):rasa 不同客户端类型区分处理 custom channel

文章目录

    使用场景

    例如,用 Rasa 实现一个自动聊天机器人,要同时实现多端:

    • 网页端
    • 微信小程序端
    • Android / iOS 原生 App 端
    • Windows 端

    每一端的回复内容会有些许差异,如:

    utter_greet

    • 网页端:欢迎使用大象计算器,地球上最不强大的计算器
    • 微信小程序端:欢迎使用大象计算器微信小程序,您也可以关注大象工具公众号接收各种骚扰信息

    突然想到 Rasa channel 是否可以实现这个功能,于是查了一下官方文档,看起来很挺合适。

    不同 channel 返回不同 response

    参考:

    https://rasa.com/docs/rasa/connectors/custom-connectors

    domain.yml 中这样配置:

    responses:
      utter_greet:
        - text: Hi! Welcome to my site.
        - text: Hi! Welcome to my Wechat mini app.
          channel: wechat
    

    第二条是针对 wechat 这个 channel 的特定返回信息。

    Custom Connectors 实现

    自定义 Channel 是通过 Custom Connectors 实现的,需实现 name 和 blueprint (蓝图) 方法:

    from rasa.core.channels.channel import InputChannel
    
    class Wechat(InputChannel):
        def name() -> Text:
            """Name of your custom channel."""
            return "wechat"
    

    完整代码参考官方文档:

    https://rasa.com/docs/rasa/connectors/custom-connectors

    即可。

    注意,如果需要使用 metadata, 官方的实现有问题,需要自己实现从 request 中解析 metadata 的逻辑。

    sanic blueprint 的用途

    https://sanic.dev/en/guide/best-practices/blueprints.html#overview

    可以理解为方便添加子目录路由解析。

    Blueprints are objects that can be used for sub-routing within an application. Instead of adding routes to the application instance, blueprints define similar methods for adding routes, which are then registered with the application in a flexible and pluggable manner.

    例如:

    # ./my_blueprint.py
    from sanic.response import json
    from sanic import Blueprint
    
    bp = Blueprint("my_blueprint")
    
    @bp.route("/")
    async def bp_root(request):
        return json({"my": "blueprint"})
    

    获取每个端独有的信息

    metadata = self.get_metadata(request)   # method to get metadata
    

    credentials.yml

    假如自定义渠道的代码定义在代码文件 addons/wechat_channel.py。

    则对应的配置为:

    addons.wechat_channel.Wechat:
    

    默认的配置为:

    rest:
    #  # you don't need to provide anything here - this channel doesn't
    #  # require any credentials
    
    #facebook:
    #  verify: "<verify>"
    #  secret: "<your secret>"
    #  page-access-token: "<your page access token>"
    
    #slack:
    #  slack_token: "<your slack token>"
    #  slack_channel: "<the slack channel>"
    #  slack_signing_secret: "<your slack signing secret>"
    
    #socketio:
    #  user_message_evt: <event name for user message>
    #  bot_message_evt: <event name for bot messages>
    #  session_persistence: <true/false>
    socketio:
      user_message_evt: user_uttered
      bot_message_evt: bot_uttered
      session_persistence: false
    

    客户端发送的数据格式

    curl --request POST \
         --url http://localhost:5005/webhooks/wechat/webhook \
         --header 'Content-Type: application/json' \
         --data '{
                "sender": "test_user",
                "message": "Hi there!",
                "metadata": {}
              }'
    

    TypeError: name() takes 0 positional arguments but 1 was given

    运行

    rasa run --enable-api --cors '*'
    

    报错:

    TypeError: name() takes 0 positional arguments but 1 was given

    def name() -> Text:  # 原代码
    
    def name(self) -> Text:   # 正确的代码
    

    GraphComponentException

    rasa run --enable-api --cors '*'
    

    rasa.engine.exceptions.GraphComponentException: Error running graph component for node run_RegexMessageHandler.

    rasa run --enable-api --cors '*' --credentials credentials.yml
    

    不加 credentials 参数也是一样的效果。

    参数 message 换成 text,因为代码中用的是 text,需要前后端统一。

    > curl --request POST \
    	--url http://localhost:5005/webhooks/windows/webhook \
    	--header 'Content-Type: application/json' \
    	--data '{
    	   "sender": "test_user",
    	   "text": "Hi there!",
    	   "metadata": {}
    	 }'
    

    测试

    • http://localhost:5005/webhooks/wechat/webhook
    • http://localhost:5005/webhooks/rest/webhook

    cors 参数

    • 对于新的自定义 channel ,启动 rasa 时,不加 cors 参数,curl 也可以正常访问。
    • 但是对于 rest channel,不加 cors 参数,curl 也可以正常访问

    坑爹的官方文档

    测试了一下,新 channel 和 rest channel 返回的消息是一样的。。。。

    原来,需要自定义一个 OutputChannel 替换掉官方文档中的 CollectingOutputChannel

    class WechatOutput(CollectingOutputChannel):
        @classmethod
        def name(cls) -> Text:
            return "wechat"
    

    然后就可以了。

    眼睛睁不开了,睡觉。

    查看合集

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

    关于作者 🌱

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