Skip to content

Latest commit

 

History

History
 
 

plugins

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

简介

chatgpt-on-wechat 插件的思路对 bot-on-anything 进行插件化,期望能实现插件的共享使用,但是由于两个项目的架构存在较大差异,只能尽最大可能兼容 chatgpt-on-wechat 的插件,部分功能还需进行适配。

插件监听的事件:

事件顺序为 1、ON_HANDLE_CONTEXT --> 2、ON_BRIDGE_HANDLE_CONTEXT(ON_BRIDGE_HANDLE_STREAM_CONTEXT) --> 3、ON_DECORATE_REPLY

触发事件会产生事件的上下文EventContext,它可能包含了以下信息:

EventContext(Event事件类型, {'channel' : 本次消息的context, 'context': 本次消息用户的提问, 'reply': 当前AI回复, "args": 其他上下文参数})

插件处理函数可通过修改EventContext中的context、reply、args或者调用channel中对应的方法来实现功能。

class Event(Enum):

    ON_HANDLE_CONTEXT = 2   # 对应通道处理消息前
    """
    e_context = {  "channel": 消息channel,  "context" : 本次消息的context, "reply" : 目前的回复,初始为空 , "args": 其他上下文参数 }
    """

    ON_DECORATE_REPLY = 3   # 得到回复后准备装饰
    """
    e_context = {  "channel": 消息channel,  "context" : 本次消息的context, "reply" : 目前的回复 , "args": 其他上下文参数 }
    """

    ON_SEND_REPLY = 4       # 发送回复前
    """
    bot-on-anything 不支持ON_SEND_REPLY事件,请使用ON_BRIDGE_HANDLE_CONTEXT或者ON_BRIDGE_HANDLE_STREAM_CONTEXT事件
    """

    ON_BRIDGE_HANDLE_CONTEXT = 6   # 模型桥处理消息前
    """
    e_context = { "context" : 本次消息的context, "reply" : 目前的回复,初始为空 , "args": 其他上下文参数 , 模型桥会调用args.model指定的AI模型来进行回复 }
    """

    ON_BRIDGE_HANDLE_STREAM_CONTEXT = 7   # 模型桥处理流式消息前,流式对话的消息处理仅支持一次性返回,请直接返回结果
    """
    e_context = {  "context" : 本次消息的context, "reply" : 目前的回复,初始为空 , "args": 其他上下文参数 , 模型桥会调用args.model指定的AI模型来进行回复 }
    """

插件编写示例

plugins/selector为例,其中编写了一个通过判断前缀调用不同模型的Selector插件。

1. 创建插件

plugins目录下创建一个插件文件夹selector。然后,在该文件夹中创建同名selector.py文件。

plugins/
└── selector
    └── selector.py

2. 编写功能

selector.py文件中,创建插件类Selector,它继承自Plugin

在类定义之前需要使用@plugins.register装饰器注册插件,并填写插件的相关信息,其中desire_priority表示插件默认的优先级,越大优先级越高。Selector插件加载时读取了同目录下的selector.json文件,从中取出对应的模型和触发前缀,Selector插件为事件ON_HANDLE_CONTEXTON_BRIDGE_HANDLE_STREAM_CONTEXT绑定了一个处理函数select_model,它表示在模型桥调用指定模型之前,都会先由select_model函数预处理。

@plugins.register(name="Selector", desire_priority=99, hidden=True, desc="A model selector", version="0.1", author="RegimenArsenic")
class Selector(Plugin):
    def __init__(self):
        super().__init__()
        curdir = os.path.dirname(__file__)
        try:
            self.config = functions.load_json_file(curdir, "selector.json")
        except Exception as e:
            log.warn("[Selector] init failed")
            raise e
        self.handlers[Event.ON_HANDLE_CONTEXT] = self.select_model
        self.handlers[Event.ON_BRIDGE_HANDLE_STREAM_CONTEXT] = self.select_model
        log.info("[Selector] inited")

3. 编写事件处理函数

修改事件上下文

事件处理函数接收一个EventContext对象e_context作为参数。e_context包含了事件相关信息,利用e_context['key']来访问这些信息。

EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply , "args": 其他上下文参数})

处理函数中通过修改e_context对象中的事件相关信息来实现所需功能,比如更改e_context['reply']中的内容可以修改回复,更改e_context['context']中的内容可以修改用户提问。

决定是否交付给下个插件或默认逻辑

在处理函数结束时,还需要设置e_context对象的action属性,它决定如何继续处理事件。目前有以下三种处理方式:

  • EventAction.CONTINUE: 事件未结束,继续交给下个插件处理,如果没有下个插件,则交付给默认的事件处理逻辑。
  • EventAction.BREAK: 事件结束,不再给下个插件处理,交付给默认的处理逻辑。
  • EventAction.BREAK_PASS: 事件结束,不再给下个插件处理,跳过默认的处理逻辑。

示例处理函数

Selector插件通过判断前缀,如有@bing前缀,则修改调用模型为bing模型,若前缀为@gpt,则修改调用模型为chatgpt,否则就使用app里配置的原始模型插件,同时删去提问的前缀@bing或者@gpt

    def select_model(self, e_context: EventContext):
        model=e_context['args'].get('model')
        for selector in self.config.get("selector", []):
            prefix = selector.get('prefix', [])
            check_prefix=functions.check_prefix(e_context["context"], prefix)
            if (check_prefix):
                model=selector.get('model')
                if isinstance(check_prefix, str):
                    e_context["context"] = e_context["context"].split(check_prefix, 1)[1].strip()
                break
        log.debug(f"[Selector] select model {model}")
        e_context.action = EventAction.CONTINUE  # 事件继续,交付给下个插件或默认逻辑
        e_context['args']['model']=model
        return e_context