wechat-chatgpt 是什么?
它是一个可以让一个微信账号变成一个 ChatGPT 机器人的工具。
例如:你可以向它问一些关于编程的问题
wechat-chatgpt 实现步骤:
- 通过 wechaty 库实现获取二维码编号
- 通过 qrcode 库将二维码编号转换成终端二维码
- 扫码二维码监听 login 登录事件获取微信用户信息
- 监听 message 事件获取微信号收到的所有消息
- 将消息内容交给 chatGPTBot 发送 (监测消息类型 → 通过 chatgpt库和token 请求ChatGPT得到回复 → 将回复通过wechaty发到微信)
// main.ts
import { WechatyBuilder } from "wechaty";
import QRCode from "qrcode";
import { ChatGPTBot } from "./chatgpt.js";
const chatGPTBot = new ChatGPTBot();
// 获取Wechaty实例
const bot = WechatyBuilder.build({
name: "wechat-assistant", // generate xxxx.memory-card.json and save login data for the next login
});
async function main() {
bot
.on("scan", async (qrcode, status) => {
const url = `https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`;
console.log(`Scan QR Code to login: ${status}\n${url}`);
console.log(
await QRCode.toString(qrcode, { type: "terminal", small: true }) // 显示二维码
);
})
.on("login", async (user) => { // 监听登录成功
console.log(`User ${user} logged in`);
chatGPTBot.setBotName(user.name());
await chatGPTBot.startGPTBot();
})
.on("message", async (message) => { // 监听微信收到的所有消息
if (message.text().startsWith("/ping ")) {
await message.say("pong");
return;
}
try {
console.log(`Message: ${message}`);
await chatGPTBot.onMessage(message);
} catch (e) {
console.error(e);
}
});
try {
await bot.start(); // 开始运行
} catch (e) {
console.error(
`⚠️ Bot start failed, can you log in through wechat on the web?: ${e}`
);
}
}
main();
ChatGPTBot 和 ChatGPTPoole 两个类各自的作用:
import { ChatGPTAPI } from "chatgpt";
// 总结: 操作 ChatGPT 获取 token,发送消息,接收ChatGPT消息,创建会话池关联会话等
class ChatGPTPoole {
getSessionToken, // 获取 ChatGPT 账户 token 用到 python 来获取 (token在Cookies内需要借助python获取)
resetAccount, // 重置 chatGPTPools 内的不可用账号,删除对于 conversationsPool 的发信息对象
startPools, // new ChatGPTAPI 实例化所有ChatGPT账户
getConversation, // 通过 conversationsPool 获取会话id 对于的发信息实例 (或者负载均衡获取一个发信息实例)
sendMessage, // 像 ChatGPT 发送消息
error2msg, // 分析返回的错误消息,进行归类
}
// 总结: 接收微信消息,判断消息是否回复,交给ChatGPTPoole去发送ChatGPT消息,根据消息类型特殊处理对于的回复到微信
class ChatGPTBot {
setBotName, // 设置称呼
chatGroupTiggerKeyword, // 获取群聊天关键字(称呼)
startGPTBot, // 调用 ChatGPTPoole.startPools 内部 new ChatGPTAPI 实例化所有ChatGPT账户
cleanMessage, // 清理用户传递过来的消息(删除里面的对自己的称呼)
getGPTMessage, // 调用 ChatGPTPoole.sendMessage 向ChatGPT发送消息
trySay, // 将ChatGPT返回的消息发送到微信 (字数过长500分段发)
tiggerGPTMessage, // 判断消息是否需要回复
isNonsense, // 过滤不需要回复的系统消息
onPrivateMessage, // 发送私聊消息
onGroupMessage, // 发送群聊消息
onMessage, // 监听微信发来的消息
}
聊天池概念:
将 config.yaml
内 chatGPTAccountPool
中所有的ChatGPT账户存储到 chatGPTPools 数组中,便于后续对聊天请求进行负载均衡,分发到各个ChatGPT账户,减少每条消息的响应时间
import { ChatGPTAPI, ChatGPTConversation } from "chatgpt";
// ChatGPTAPI池
chatGPTPools: Array<IChatGPTItem> | [] = [];
// 对话池
conversationsPool: Map<string, IConversationItem> = new Map();
// 聊天池-负载均衡
get chatGPTAPI(): IChatGPTItem {
return this.chatGPTPools[
Math.floor(Math.random() * this.chatGPTPools.length)
];
}
// 随机获取会话项表单池
getConversation(talkid: string): IConversationItem {
// 去对话池找, 找不到就负载均衡随机分配一个
if (this.conversationsPool.has(talkid)) {
return this.conversationsPool.get(talkid) as IConversationItem;
}
const chatGPT = this.chatGPTAPI;
if (!chatGPT) {
throw new Error("⚠️ No chatgpt item in pool");
}
const conversation = chatGPT.chatGpt.getConversation(); // 获取chatGPTAPI的对话
const conversationItem = {
conversation, // conversation.sendMessage("发信息给 chatGPT")
account: chatGPT.account,
};
this.conversationsPool.set(talkid, conversationItem); // 存储会话
return conversationItem;
}
/*
chatGPTPools: 聊天池存储:talkid 对应对方聊天人id,存池的目的是后续这个发言依旧是和这个 ChatGPT实例对应
{
chatGpt: new ChatGPTAPI({
sessionToken: account.session_token, // ChatGPT sdk通过 token 就能实例化
}),
account,
}
*/
/*
conversationsPool: 存储处理该会话id对应的ChatGPT实例
{
talkid: {
conversation: chatGPT.chatGpt.getConversation(),
account: chatGPT.account,
}
}
*/
node使用本地json文件作为缓存:
缓存 config.yaml
内 chatGPTAccountPool
中所有的ChatGPT邮箱密码账户通过 generate_session.py
获取到的
import fs from "fs";
export class Cache {
private _cache: Record<string, any>;
constructor(private _file: string) {
if (fs.existsSync(_file)) {
this._cache = JSON.parse(fs.readFileSync(_file, "utf-8"));
} else {
this._cache = {};
}
}
get(key: string) {
return this._cache[key];
}
async set(key: string, value: any) {
this._cache[key] = value;
fs.writeFileSync(this._file, JSON.stringify(this._cache));
}
async delete(key: string) {
delete this._cache[key];
fs.writeFileSync(this._file, JSON.stringify(this._cache));
}
}
// 使用
const cache = new Cache("cache.json");
cache.set(email, "需要存储的字符串")
cache.get(email) // 需要存储的字符串
cache.delete(email)
如何实现一个简单的 wechat-chatgpt ?下面就是一个简单的例子
wechat-chatgpt 简写版本:
import { WechatyBuilder } from "wechaty";
import { ChatGPTAPI } from "chatgpt";
import QRCode from "qrcode";
// 通过 session_token 登录 ChatGPTAPI
const chatGpt = new ChatGPTAPI({
sessionToken: "session_token", // 去 https://chat.openai.com/chat 打开看控制台 -> Application -> Cookies -> __Secure-next-auth.session-token
});
const bot = WechatyBuilder.build({
name: "wechat-assistant", // generate xxxx.memory-card.json and save login data for the next login
});
bot.on("scan", async (qrcode, status) => {
const url = `https://wechaty.js.org/qrcode/${encodeURIComponent(qrcode)}`;
console.log(`Scan QR Code to login: ${status}\n${url}`);
console.log(
await QRCode.toString(qrcode, { type: "terminal", small: true }), // 显示二维码
);
})
.on("login", async user => {
console.log(`User ${user} logged in`);
})
.on("message", async message => {
const talker = message.talker();
const room = message.room();
const rawText = message.text();
// 获取chatGTP返回的消息
const gptMessage = await chatGpt.getConversation().sendMessage(rawText); // 发信息 rawText 给 chatGPT
// 回复到微信
if (!!room) {
// 群聊
room.say(gptMessage);
} else {
// 私聊
talker.say(gptMessage);
}
});
bot.start(); // 开始