Skip to content

如何添加一个新的 AI 对话机器人

Sun Zhigang edited this page May 26, 2023 · 5 revisions

为 ChatALL 增加新的 AI 对话机器人,最简单情况只需要三步:

  1. src/bots/,复制 TemplateBot.js 创建一个 XXXXBot.js 文件
  2. XXXXBot.js 中实现 _sendPrompt()
  3. 把对 XXXXBot.js 的引用添加到 src/App.vue

下面开始一步步介绍。假定已经 clone 了最新代码。

Hello world!

假定你要支持的 AI 大模型叫「KnowNothing」,那么按以下步骤可以快速跑起一个 Hello world。

第一步:用模板创建 js 文件

src/bots/,复制 TemplateBot.js 创建一个 KnowNothingBot.js 文件。

第二步:修改 js 文件

修改 KnowNothingBot.js 的类名和前两个成员变量的初始值如下:

export default class KnowNothingBot extends Bot {
  static _brandId = "KnowNothing"; // Brand id of the bot, should be unique. Used in i18n.
  static _className = "KnowNothingBot"; // Class name of the bot
  ...

第三步:让代码生效

修改 src/bots/index.js,找到如下代码:

// Bots
import ChatGPT35Bot from "@/bots/openai/ChatGPT35Bot";
import ChatGPT4Bot from "@/bots/openai/ChatGPT4Bot";
import ChatGPTBrowsingBot from "@/bots/openai/ChatGPTBrowsingBot";
import BingChatPreciseBot from "@/bots/microsoft/BingChatPreciseBot";
import BingChatBalancedBot from "@/bots/microsoft/BingChatBalancedBot";
import BingChatCreativeBot from "@/bots/microsoft/BingChatCreativeBot";
import SparkBot from "@/bots/SparkBot";
import BardBot from "@/bots/BardBot";
import OpenAIAPI35Bot from "@/bots/openai/OpenAIAPI35Bot";
import OpenAIAPI4Bot from "@/bots/openai/OpenAIAPI4Bot";
import MOSSBot from "@/bots/MOSSBot";

任意位置增加一行:

import KnowNothingBot from '@/bots/KnowNothingBot';

再找到:

const all = [
  ChatGPT35Bot.getInstance(),
  ChatGPT4Bot.getInstance(),
  OpenAIAPI35Bot.getInstance(),
  OpenAIAPI4Bot.getInstance(),
  BingChatCreativeBot.getInstance(),
  BingChatBalancedBot.getInstance(),
  BingChatPreciseBot.getInstance(),
  WenxinQianfanBot.getInstance(),
  SparkBot.getInstance(),
  MOSSBot.getInstance(),
  BardBot.getInstance(),
],

把你的 bot 放进去。注意,这里对各个 bot 的引用顺序,决定了它们在图标栏出现的顺序。比如,你希望你的 bot 在 ChatGPT 和 Bing Chat 之间,那么:

const all = [
  ChatGPT35Bot.getInstance(),
  ChatGPT4Bot.getInstance(),
  KnowNothingBot.getInstance(),  // You are here
  OpenAIAPI35Bot.getInstance(),
  OpenAIAPI4Bot.getInstance(),
  ...
],

第四步:运行

是的,hello world 已经完成了。在项目目录下,执行下面命令(假定你已经安装了 npm):

npm install
npm run electron:serve

图标栏里看到它了吗?选择它,然后发个消息试试吧!

增加设置组件

需要在设置组件里实现登录、API key 配置等功能,这是完成其它核心功能的基础。但如果你的 bot 不需要登录,或者不在意把 key 直接放到代码里(非常不建议这么做),那么可以跳过本节。

创建设置组件

设置组件要建在 src/components/BotSettings/ 下,文件名是 KnowNothingBotSettings.vue

现有的设置组件可以当做模板:

  1. 如果只需要登录能力,那么可以复制 BardBotSettings.vue,修改 import Bot from "@/bots/BardBot";import Bot from "@/bots/KnowNothingBot"; 就完工了。(有些网站做了不少安全防范阻止 ChatALL 之类的客户端访问。如果遇到这种情况,那要做很多 hack 工作)
  2. 如果只需要配置 key,那么可以复制 WenxinQianfanBotSettings.vue,但要做的工作就有点儿多了。
  3. 如果有复杂的多项配置,那么要做的工作就更多了。

增加设置项

ChatALL 的设置组件使用 Vuetify 3 实现。访问官方文档可以查看和测试它支持的丰富组件。通过参考已有代码,基本可以完成开发工作,这里不再赘述。

ChatALL 的设置参数通过 vuex-persist 库保存在 local storage 中。这个库很好用,虽然文档不太好读。简要介绍下怎么用。

首先,在 src/store/index.js 中添加两段代码:

export default createStore({
  state: {
    ...
    knowNothing: {
      setting1: "",
      setting2: "",
    },
    ...
  },
  mutations: {
    ...
    setKnowNothing(state, { setting1, setting2 }) {
      state.knowNothing = { setting1, setting2 };
    },
    ...
  },
  ...
});

setting1setting2 可以根据你的情况进行任意增删修改,包括建立下级对象。但一定在最顶层是个 knowNothing 对象,哪怕只有一个配置项。

然后在 KnowNothingBotSettings.vue 中,添加:

export default {
  ...
  methods: {
    ...mapMutations(["setKnowNothing"]),
    setSetting1(value){
      this.setKnowNothing({
        ...this.knowNothing,
        setting1: value
      })
    },
    setSetting2(value){
      this.setKnowNothing({
        ...this.knowNothing,
        setting2: value
      })
    },
  },
  computed: {
    ...mapState(["knowNothing"])
  }
}

最后,把 Vuetify 组件的 v-model 指向对应的 knowNothing.xxx,生效动作指向对应的 setXxx() 函数。例如:

<v-text-field
  v-model="knowNothing.setting1"
  @change="setSetting1($event.target.value)"
></v-text-field>

完工!运行后,打开 DevTools,可以在 Application 下查看存储是否正确。

在 KnowNothingBot.js 中使用设置的参数非常简单:

...
import store from "@/store";
...
store.state.knowNothing.setting1
store.state.knowNothing.setting2
const { setting1, setting2 } = store.state.knowNothing;
...

实现核心功能

实现 checkAvailability()

ChatALL 会在首次启动、页面刷新(Command+R 或 Ctrl+R)和完成设置等时,调用此函数,来刷新这个 bot 的可用状态。

一般情况,它完成如下工作:

  1. 检查登录是否有效
  2. 检查 API key 是否配置正确
  3. 检查其它影响运行的条件是否满足

如果一切正常,要执行:

this.constructor._isAvailable = true;

否则执行:

this.constructor._isAvailable = false;

最后一定要:

return this.isAvailable();

实现 _sendPrompt()

这是最核心的功能,完成发送和接收消息。

现有代码是不错的参考:

  1. 如果接口是普通 http 调用,可以参考 BardBot.js
  2. 如果接口是 SSE,可以参考 ChatGPTBot.js
  3. 如果接口是 WebSocket,可以参考 BingChatBot.js

发送消息和解析接收到的消息要根据 bot 的具体情况而处理。得到响应,或者出错了,要这么处理:

  1. 收到返回的部分文本,调用 onUpdateResponse(callbackParam, {});
  2. 如果返回数据中并不包含目前为止的所有文本,而是每次只返回最新的那部分,需要自己完成所有文本的拼装,再调用 onUpdateResponse(callbackParam, {content: text, done: false)};
  3. 得到所有文本后,调用 onUpdateResponse(callbackParam, {content: text, done: true)}; 完成所有数据的更新。如果文本之前已经都 onUpdateResponse 过,那么调用 onUpdateResponse(callbackParam, {done: true)}; 可以达到同样效果
  4. 正常结束,最后调用 resolve()
  5. 如果出错,需要调用 reject(error)。这个 error 既可以是个异常,也可以是个错误信息字符串。ChatALL 会自动处理它,把它显示给用户

实现 createConversation()

ChatALL 将来会实现历史消息保存功能,且支持多个 chat/thread/session/conversation(随便叫哪个)。实现 createConversation() 主要是为了兼容未来,现在不做也可以。

所以,这段就不写了吧……

其它

自定义图标

图标文件放到 src/assets/bots/knownothing-logo.png,修改 KnowNothingBot.js

static _logoFilename = "knownothing-logo.png";

多语言支持

多语言资源放在 src/i18n/locales 下,用语言代码命名的 .json 文件中。你需要至少为你的 bot 添加:

en.json

    "knowNothing": {
        "name": "Know Nothing"
    },

zh.json

    "knowNothing": {
        "name": "啥都不懂"
    },

以及其它字符串。

在 JavaScript 代码里这样调用多语言:

import i18n from "@/i18n";
...
i18n.global.t("knowNothing.stringName")
...

在 HTML 代码里是这样:

{{ $t("knowNothing.stringName") }}

定制 user-agent

有些网站会限制特定浏览器才能访问,所以需要在 KnowNothingBot.js 中:

static _userAgent = "THE_RIGHT_USER_AGENT";

最后

没了...欢迎提交 PR!