Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 实验性添加dalle #753

Merged
merged 3 commits into from
Mar 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ MODEL="gpt-3.5-turbo"
CHAT_PRIVATE_TRIGGER_KEYWORD=
TEMPERATURE=
BLOCK_WORDS="SB, VPN"
CHATGPT_BLOCK_WORDS="VPN"
CHATGPT_BLOCK_WORDS="VPN"
WECHATY_PUPPET=wechaty-puppet-wechat
30 changes: 1 addition & 29 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
"qrcode": "^1.5.1",
"uuid": "^9.0.0",
"wechaty": "^1.20.2",
"wechaty-puppet-wechat": "^1.18.4",
"wechaty-puppet-wechat4u": "^1.10.2"
"wechaty-puppet-wechat": "^1.18.4"
},
"devDependencies": {
"@types/async-retry": "^1.4.5",
Expand All @@ -29,7 +28,12 @@
"ts-node": "^10.9.1"
},
"nodemonConfig": {
"watch": "src",
"watch": [
"src/*.ts"
],
"ignore": [
"src/main.ts"
],
"ext": "ts",
"exec": "node --loader ts-node/esm src/main.ts",
"delay": 500
Expand Down
108 changes: 76 additions & 32 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { config } from "./config.js";
import {ContactImpl, ContactInterface, RoomImpl, RoomInterface} from "wechaty/impls";
import { Message } from "wechaty";
import {getCompletion} from "./openai.js";
import {addSessionByUsername, clearUserData, setPromptByUsername} from "./data.js";
import {FileBox} from "file-box";
import {chatgpt, dalle} from "./openai.js";
import DBUtils from "./data.js";
enum MessageType {
Unknown = 0,

Attachment = 1, // Attach(6),
Audio = 2, // Audio(1), Voice(34)
Contact = 3, // ShareCard(42)
Expand All @@ -23,8 +23,13 @@ enum MessageType {
Video = 15, // Video(4), Video(43)
Post = 16, // Moment, Channel, Tweet, etc
}

const SINGLE_MESSAGE_MAX_SIZE = 500;
type Speaker = RoomImpl | ContactImpl;
interface ICommand{
name:string;
description:string;
exec: (talker:Speaker, text:string) => Promise<void>;
}
export class ChatGPTBot {
chatPrivateTriggerKeyword = config.chatPrivateTriggerKeyword;
chatTriggerRule = config.chatTriggerRule? new RegExp(config.chatTriggerRule): undefined;
Expand All @@ -45,12 +50,11 @@ export class ChatGPTBot {
}
return regEx
}
async command(talker:RoomInterface|ContactInterface, text:string): Promise<void> {
// 找到第一个空格之前的字符串
const command = text.split(" ")[0];
console.log(`command: ${command}`);
switch (command) {
case "help":
private readonly commands:ICommand[] = [
{
name: "help",
description: "显示帮助信息",
exec: async (talker) => {
await this.trySay(talker,"========\n" +
"/cmd help\n" +
"# 显示帮助信息\n" +
Expand All @@ -59,27 +63,47 @@ export class ChatGPTBot {
"/cmd clear\n" +
"# 清除自上次启动以来的所有会话\n" +
"========");
break;
case "prompt":
let prompt = text.slice(command.length+1);
}
},
{
name: "prompt",
description: "设置当前会话的prompt",
exec: async (talker, prompt) => {
if (talker instanceof RoomImpl) {
setPromptByUsername(talker.id, prompt);
await this.trySay(talker,"设置成功!");
}else if (talker instanceof ContactImpl) {
setPromptByUsername(talker.name(), prompt);
await this.trySay(talker,"设置成功");
DBUtils.setPrompt(await talker.topic(), prompt);
}else {
DBUtils.setPrompt(talker.name(), prompt);
}
break;
case "clear":
console.log("清除会话");
}
},
{
name: "clear",
description: "清除自上次启动以来的所有会话",
exec: async (talker) => {
if (talker instanceof RoomImpl) {
clearUserData(talker.id);
await this.trySay(talker,"清除成功!");
}else if (talker instanceof ContactImpl) {
clearUserData(talker.name());
await this.trySay(talker,"清除成功");
DBUtils.clearHistory(await talker.topic());
}else{
DBUtils.clearHistory(talker.name());
}
break;
}
}
]

/**
* EXAMPLE:
* /cmd help
* /cmd prompt <PROMPT>
* /cmd clear
* @param contact
* @param rawText
*/
async command(contact: any, rawText: string): Promise<void> {
const [commandName, ...args] = rawText.split(/\s+/);
const command = this.commands.find(
(command) => command.name === commandName
);
if (command) {
await command.exec(contact, args.join(" "));
}
}
// remove more times conversation and mention
Expand All @@ -102,8 +126,8 @@ export class ChatGPTBot {
return text
}
async getGPTMessage(talkerName: string,text: string): Promise<string> {
let gptMessage = await getCompletion(talkerName,text);
addSessionByUsername(talkerName, {assistantMsg:gptMessage});
let gptMessage = await chatgpt(talkerName,text);
DBUtils.addAssistantMessage(talkerName,gptMessage);
return gptMessage;
}
// Check if the message returned by chatgpt contains masked words]
Expand Down Expand Up @@ -193,7 +217,7 @@ export class ChatGPTBot {
text: string,
room: RoomInterface
) {
const gptMessage = await this.getGPTMessage(room.id,text);
const gptMessage = await this.getGPTMessage(await room.topic(),text);
const result = `@${talker.name()} ${text}\n\n------\n ${gptMessage}`;
await this.trySay(room, result);
}
Expand All @@ -214,8 +238,28 @@ export class ChatGPTBot {
}
if (rawText.startsWith("/cmd ")){
console.log(`🤖 Command: ${rawText}`)
const text = rawText.slice(5) // 「/cmd 」一共5个字符(注意空格)
return await this.command(privateChat?talker:room, text);
const cmdContent = rawText.slice(5) // 「/cmd 」一共5个字符(注意空格)
if (privateChat) {
await this.command(talker, cmdContent);
}else{
await this.command(room, cmdContent);
}
return;
}
// 使用DallE生成图片
if (rawText.startsWith("/img")){
console.log(`🤖 Image: ${rawText}`)
const imgContent = rawText.slice(4)
if (privateChat) {
let url = await dalle(talker.name(), imgContent) as string;
const fileBox = FileBox.fromUrl(url)
message.say(fileBox)
}else{
let url = await dalle(await room.topic(), imgContent) as string;
const fileBox = FileBox.fromUrl(url)
message.say(fileBox)
}
return;
}
if (this.triggerGPTMessage(rawText, privateChat)) {
const text = this.cleanMessage(rawText, privateChat);
Expand Down
Loading