koishi-plugin-imx 1.0.3 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -35
- package/lib/index.d.ts +0 -9
- package/lib/index.js +0 -17
- package/package.json +27 -6
- package/lib/modules/health-check.d.ts +0 -8
- package/lib/modules/health-check.js +0 -60
- package/lib/modules/openai.d.ts +0 -9
- package/lib/modules/openai.js +0 -93
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# koishi-plugin-imx
|
|
2
2
|
|
|
3
|
-
这是一个将 IMX Bot 功能移植到 Koishi
|
|
3
|
+
这是一个将 IMX Bot 功能移植到 Koishi 平台的插件,提供丰富的聊天机器人功能。
|
|
4
4
|
|
|
5
|
-
## 功能特性
|
|
5
|
+
## ✨ 功能特性
|
|
6
6
|
|
|
7
7
|
### 🔄 复读机
|
|
8
8
|
- 自动检测连续重复的消息并进行复读
|
|
@@ -19,11 +19,6 @@
|
|
|
19
19
|
- 新成员加入欢迎
|
|
20
20
|
- `hitokoto` - 获取一言
|
|
21
21
|
|
|
22
|
-
### 🤖 OpenAI 集成
|
|
23
|
-
- `ask <message>` - 询问 AI
|
|
24
|
-
- `chat <message>` - AI 对话(支持上下文)
|
|
25
|
-
- `chat reset` - 重置对话上下文
|
|
26
|
-
- 支持 @ 机器人进行对话
|
|
27
22
|
|
|
28
23
|
### 📺 Bilibili 直播监控
|
|
29
24
|
- 监控指定 B站直播间开播状态
|
|
@@ -35,10 +30,6 @@
|
|
|
35
30
|
- 监控 Push、Issue、Pull Request 事件
|
|
36
31
|
- `github.test` - 测试 GitHub 通知功能
|
|
37
32
|
|
|
38
|
-
### 🏥 健康检查
|
|
39
|
-
- `health` - 查看系统健康状态
|
|
40
|
-
- 监控内存使用、运行时间等信息
|
|
41
|
-
|
|
42
33
|
## 安装
|
|
43
34
|
|
|
44
35
|
```bash
|
|
@@ -65,12 +56,6 @@ plugins:
|
|
|
65
56
|
watchChannels: ["channel-id-1", "channel-id-2"]
|
|
66
57
|
enableGreeting: true
|
|
67
58
|
|
|
68
|
-
# OpenAI 配置
|
|
69
|
-
openai:
|
|
70
|
-
apiKey: "your-openai-api-key"
|
|
71
|
-
model: "gpt-3.5-turbo"
|
|
72
|
-
temperature: 0.6
|
|
73
|
-
|
|
74
59
|
# Bilibili 配置
|
|
75
60
|
bilibili:
|
|
76
61
|
enabled: true
|
|
@@ -86,11 +71,6 @@ plugins:
|
|
|
86
71
|
webhookPort: 3000
|
|
87
72
|
watchChannels: ["channel-id"]
|
|
88
73
|
|
|
89
|
-
# 健康检查配置
|
|
90
|
-
healthCheck:
|
|
91
|
-
enabled: true
|
|
92
|
-
interval: 300000
|
|
93
|
-
|
|
94
74
|
# 错误通知配置
|
|
95
75
|
errorNotify:
|
|
96
76
|
enabled: true
|
|
@@ -104,10 +84,6 @@ plugins:
|
|
|
104
84
|
- `watchChannels`: 监听的频道ID列表
|
|
105
85
|
- `enableGreeting`: 是否启用自动问候功能
|
|
106
86
|
|
|
107
|
-
### OpenAI 配置
|
|
108
|
-
- `apiKey`: OpenAI API 密钥(必需)
|
|
109
|
-
- `model`: 使用的模型,默认为 `gpt-3.5-turbo`
|
|
110
|
-
- `temperature`: 温度参数,控制回复的随机性
|
|
111
87
|
|
|
112
88
|
### Bilibili 配置
|
|
113
89
|
- `enabled`: 是否启用 Bilibili 监控
|
|
@@ -132,18 +108,9 @@ tool.base64 -d SGVsbG8gV29ybGQ=
|
|
|
132
108
|
tool.md5 Hello World
|
|
133
109
|
```
|
|
134
110
|
|
|
135
|
-
### AI 对话
|
|
136
|
-
```
|
|
137
|
-
ask 什么是人工智能?
|
|
138
|
-
chat 你好
|
|
139
|
-
chat 继续之前的话题
|
|
140
|
-
chat reset
|
|
141
|
-
```
|
|
142
|
-
|
|
143
111
|
### 其他命令
|
|
144
112
|
```
|
|
145
113
|
hitokoto
|
|
146
|
-
health
|
|
147
114
|
bili.status
|
|
148
115
|
github.test
|
|
149
116
|
```
|
package/lib/index.d.ts
CHANGED
|
@@ -5,11 +5,6 @@ export interface Config {
|
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
token?: string;
|
|
7
7
|
};
|
|
8
|
-
openai?: {
|
|
9
|
-
apiKey: string;
|
|
10
|
-
model?: string;
|
|
11
|
-
temperature?: number;
|
|
12
|
-
};
|
|
13
8
|
bilibili?: {
|
|
14
9
|
enabled?: boolean;
|
|
15
10
|
};
|
|
@@ -17,10 +12,6 @@ export interface Config {
|
|
|
17
12
|
enabled?: boolean;
|
|
18
13
|
webhookSecret?: string;
|
|
19
14
|
};
|
|
20
|
-
healthCheck?: {
|
|
21
|
-
enabled?: boolean;
|
|
22
|
-
interval?: number;
|
|
23
|
-
};
|
|
24
15
|
errorNotify?: {
|
|
25
16
|
enabled?: boolean;
|
|
26
17
|
};
|
package/lib/index.js
CHANGED
|
@@ -37,10 +37,8 @@ exports.Config = exports.name = void 0;
|
|
|
37
37
|
exports.apply = apply;
|
|
38
38
|
const koishi_1 = require("koishi");
|
|
39
39
|
const mxSpace = __importStar(require("./modules/mx-space"));
|
|
40
|
-
const openai = __importStar(require("./modules/openai"));
|
|
41
40
|
const bilibili = __importStar(require("./modules/bilibili"));
|
|
42
41
|
const github = __importStar(require("./modules/github"));
|
|
43
|
-
const healthCheck = __importStar(require("./modules/health-check"));
|
|
44
42
|
const shared = __importStar(require("./shared"));
|
|
45
43
|
exports.name = 'imx';
|
|
46
44
|
exports.Config = koishi_1.Schema.object({
|
|
@@ -48,11 +46,6 @@ exports.Config = koishi_1.Schema.object({
|
|
|
48
46
|
baseUrl: koishi_1.Schema.string().description('MX Space API 地址'),
|
|
49
47
|
token: koishi_1.Schema.string().description('MX Space API Token').role('secret'),
|
|
50
48
|
}).description('MX Space 配置'),
|
|
51
|
-
openai: koishi_1.Schema.object({
|
|
52
|
-
apiKey: koishi_1.Schema.string().description('OpenAI API Key').role('secret').required(),
|
|
53
|
-
model: koishi_1.Schema.string().default('gpt-3.5-turbo').description('模型名称'),
|
|
54
|
-
temperature: koishi_1.Schema.number().min(0).max(2).default(0.6).description('温度参数'),
|
|
55
|
-
}).description('OpenAI 配置'),
|
|
56
49
|
bilibili: koishi_1.Schema.object({
|
|
57
50
|
enabled: koishi_1.Schema.boolean().default(false).description('启用 Bilibili 功能'),
|
|
58
51
|
}).description('Bilibili 配置'),
|
|
@@ -60,10 +53,6 @@ exports.Config = koishi_1.Schema.object({
|
|
|
60
53
|
enabled: koishi_1.Schema.boolean().default(false).description('启用 GitHub 功能'),
|
|
61
54
|
webhookSecret: koishi_1.Schema.string().description('GitHub Webhook Secret').role('secret'),
|
|
62
55
|
}).description('GitHub 配置'),
|
|
63
|
-
healthCheck: koishi_1.Schema.object({
|
|
64
|
-
enabled: koishi_1.Schema.boolean().default(true).description('启用健康检查'),
|
|
65
|
-
interval: koishi_1.Schema.number().default(300000).description('检查间隔(毫秒)'),
|
|
66
|
-
}).description('健康检查配置'),
|
|
67
56
|
errorNotify: koishi_1.Schema.object({
|
|
68
57
|
enabled: koishi_1.Schema.boolean().default(true).description('启用错误通知'),
|
|
69
58
|
}).description('错误通知配置'),
|
|
@@ -73,18 +62,12 @@ function apply(ctx, config) {
|
|
|
73
62
|
if (config.mxSpace) {
|
|
74
63
|
ctx.plugin(mxSpace, config.mxSpace);
|
|
75
64
|
}
|
|
76
|
-
if (config.openai?.apiKey) {
|
|
77
|
-
ctx.plugin(openai, config.openai);
|
|
78
|
-
}
|
|
79
65
|
if (config.bilibili?.enabled) {
|
|
80
66
|
ctx.plugin(bilibili, config.bilibili);
|
|
81
67
|
}
|
|
82
68
|
if (config.github?.enabled) {
|
|
83
69
|
ctx.plugin(github, config.github);
|
|
84
70
|
}
|
|
85
|
-
if (config.healthCheck?.enabled) {
|
|
86
|
-
ctx.plugin(healthCheck, config.healthCheck);
|
|
87
|
-
}
|
|
88
71
|
// 注册共享功能
|
|
89
72
|
ctx.plugin(shared);
|
|
90
73
|
}
|
package/package.json
CHANGED
|
@@ -1,29 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-imx",
|
|
3
|
-
"description": "Mix-Space Bot for Koishi",
|
|
4
|
-
"version": "1.
|
|
3
|
+
"description": "Mix-Space Bot for Koishi - 集成多种功能的聊天机器人插件",
|
|
4
|
+
"version": "1.1.3",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
8
|
-
"lib"
|
|
9
|
-
"dist"
|
|
8
|
+
"lib"
|
|
10
9
|
],
|
|
11
10
|
"license": "MIT",
|
|
11
|
+
"author": "sysfox",
|
|
12
|
+
"homepage": "https://github.com/sysfox/koishi-plugin-imx",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/sysfox/koishi-plugin-imx.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/sysfox/koishi-plugin-imx/issues"
|
|
19
|
+
},
|
|
12
20
|
"keywords": [
|
|
13
21
|
"chatbot",
|
|
14
22
|
"koishi",
|
|
15
23
|
"plugin",
|
|
16
|
-
"imx"
|
|
24
|
+
"imx",
|
|
25
|
+
"mx-space",
|
|
26
|
+
"bilibili",
|
|
27
|
+
"github"
|
|
17
28
|
],
|
|
18
29
|
"peerDependencies": {
|
|
19
30
|
"koishi": "^4.15.0"
|
|
20
31
|
},
|
|
32
|
+
"koishi": {
|
|
33
|
+
"description": {
|
|
34
|
+
"en": "A versatile chatbot plugin for Koishi, integrating multiple functionalities including Bilibili and GitHub.",
|
|
35
|
+
"zh": "一个多功能的聊天机器人插件,集成了 Bilibili 和 GitHub 等多种功能。"
|
|
36
|
+
},
|
|
37
|
+
"service": {
|
|
38
|
+
"required": [
|
|
39
|
+
"http"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
21
43
|
"dependencies": {
|
|
22
44
|
"@mx-space/api-client": "^1.4.3",
|
|
23
45
|
"axios": "^1.6.0",
|
|
24
46
|
"dayjs": "^1.11.9",
|
|
25
47
|
"socket.io-client": "^4.7.1",
|
|
26
|
-
"openai": "^4.0.0",
|
|
27
48
|
"randomcolor": "^0.6.2",
|
|
28
49
|
"remove-markdown": "^0.6.0"
|
|
29
50
|
},
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Context, Schema } from 'koishi';
|
|
2
|
-
export declare const name = "health-check";
|
|
3
|
-
export interface Config {
|
|
4
|
-
enabled?: boolean;
|
|
5
|
-
interval?: number;
|
|
6
|
-
}
|
|
7
|
-
export declare const Config: Schema<Config>;
|
|
8
|
-
export declare function apply(ctx: Context, config: Config): void;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Config = exports.name = void 0;
|
|
4
|
-
exports.apply = apply;
|
|
5
|
-
const koishi_1 = require("koishi");
|
|
6
|
-
exports.name = 'health-check';
|
|
7
|
-
exports.Config = koishi_1.Schema.object({
|
|
8
|
-
enabled: koishi_1.Schema.boolean().default(true).description('启用健康检查'),
|
|
9
|
-
interval: koishi_1.Schema.number().default(300000).description('检查间隔(毫秒)'),
|
|
10
|
-
});
|
|
11
|
-
class HealthCheckService {
|
|
12
|
-
checkFnList = [() => 'UP!'];
|
|
13
|
-
registerHealthCheck(checkFn) {
|
|
14
|
-
this.checkFnList.push(checkFn);
|
|
15
|
-
return () => {
|
|
16
|
-
const idx = this.checkFnList.findIndex((fn) => fn === checkFn);
|
|
17
|
-
return idx > -1 && this.checkFnList.splice(idx, 1);
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
async call() {
|
|
21
|
-
return Promise.all(this.checkFnList.map((fn) => fn()));
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function apply(ctx, config) {
|
|
25
|
-
const logger = ctx.logger('health-check');
|
|
26
|
-
if (!config.enabled) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const healthCheck = new HealthCheckService();
|
|
30
|
-
// 注册到上下文中供其他插件使用
|
|
31
|
-
ctx.provide('healthCheck', healthCheck);
|
|
32
|
-
ctx.command('health', '健康检查')
|
|
33
|
-
.action(async ({ session }) => {
|
|
34
|
-
try {
|
|
35
|
-
const results = await healthCheck.call();
|
|
36
|
-
return session?.send(`健康检查结果:\n${results.join('\n')}`);
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
logger.error('Health check failed:', error);
|
|
40
|
-
return session?.send('健康检查失败');
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
// 注册基本的健康检查
|
|
44
|
-
healthCheck.registerHealthCheck(() => {
|
|
45
|
-
return `服务状态: 运行中`;
|
|
46
|
-
});
|
|
47
|
-
healthCheck.registerHealthCheck(() => {
|
|
48
|
-
const uptime = process.uptime();
|
|
49
|
-
const hours = Math.floor(uptime / 3600);
|
|
50
|
-
const minutes = Math.floor((uptime % 3600) / 60);
|
|
51
|
-
return `运行时间: ${hours}小时${minutes}分钟`;
|
|
52
|
-
});
|
|
53
|
-
healthCheck.registerHealthCheck(() => {
|
|
54
|
-
const memUsage = process.memoryUsage();
|
|
55
|
-
const usedMB = Math.round(memUsage.heapUsed / 1024 / 1024);
|
|
56
|
-
const totalMB = Math.round(memUsage.heapTotal / 1024 / 1024);
|
|
57
|
-
return `内存使用: ${usedMB}MB / ${totalMB}MB`;
|
|
58
|
-
});
|
|
59
|
-
logger.info('Health check module loaded');
|
|
60
|
-
}
|
package/lib/modules/openai.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Context, Schema } from 'koishi';
|
|
2
|
-
export declare const name = "openai";
|
|
3
|
-
export interface Config {
|
|
4
|
-
apiKey: string;
|
|
5
|
-
model?: string;
|
|
6
|
-
temperature?: number;
|
|
7
|
-
}
|
|
8
|
-
export declare const Config: Schema<Config>;
|
|
9
|
-
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/modules/openai.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Config = exports.name = void 0;
|
|
7
|
-
exports.apply = apply;
|
|
8
|
-
const koishi_1 = require("koishi");
|
|
9
|
-
const openai_1 = __importDefault(require("openai"));
|
|
10
|
-
exports.name = 'openai';
|
|
11
|
-
exports.Config = koishi_1.Schema.object({
|
|
12
|
-
apiKey: koishi_1.Schema.string().description('OpenAI API Key').role('secret').required(),
|
|
13
|
-
model: koishi_1.Schema.string().default('gpt-3.5-turbo').description('使用的模型'),
|
|
14
|
-
temperature: koishi_1.Schema.number().min(0).max(2).default(0.6).description('温度参数'),
|
|
15
|
-
});
|
|
16
|
-
function apply(ctx, config) {
|
|
17
|
-
const logger = ctx.logger('openai');
|
|
18
|
-
if (!config.apiKey) {
|
|
19
|
-
logger.warn('OpenAI API Key not configured');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const openai = new openai_1.default({
|
|
23
|
-
apiKey: config.apiKey,
|
|
24
|
-
});
|
|
25
|
-
// 存储用户对话上下文
|
|
26
|
-
const userConversations = new Map();
|
|
27
|
-
async function generateResponse(userId, message) {
|
|
28
|
-
try {
|
|
29
|
-
let conversation = userConversations.get(userId) || [];
|
|
30
|
-
// 添加用户消息
|
|
31
|
-
conversation.push({ role: 'user', content: message });
|
|
32
|
-
// 限制对话历史长度
|
|
33
|
-
if (conversation.length > 10) {
|
|
34
|
-
conversation = conversation.slice(-10);
|
|
35
|
-
}
|
|
36
|
-
const response = await openai.chat.completions.create({
|
|
37
|
-
model: config.model || 'gpt-3.5-turbo',
|
|
38
|
-
messages: conversation,
|
|
39
|
-
temperature: config.temperature || 0.6,
|
|
40
|
-
max_tokens: 1000,
|
|
41
|
-
});
|
|
42
|
-
const reply = response.choices[0]?.message?.content;
|
|
43
|
-
if (reply) {
|
|
44
|
-
// 添加助手回复到对话历史
|
|
45
|
-
conversation.push({ role: 'assistant', content: reply });
|
|
46
|
-
userConversations.set(userId, conversation);
|
|
47
|
-
return reply;
|
|
48
|
-
}
|
|
49
|
-
return '抱歉,我无法生成回复。';
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
logger.error('OpenAI API error:', error);
|
|
53
|
-
return '抱歉,OpenAI 服务暂时不可用。';
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
ctx.command('ask <message:text>', '询问 AI')
|
|
57
|
-
.action(async ({ session }, message) => {
|
|
58
|
-
if (!message) {
|
|
59
|
-
return session?.send('请输入要询问的问题');
|
|
60
|
-
}
|
|
61
|
-
const userId = session?.userId;
|
|
62
|
-
const response = await generateResponse(userId, message);
|
|
63
|
-
return session?.send(response);
|
|
64
|
-
});
|
|
65
|
-
ctx.command('chat <message:text>', 'AI 对话')
|
|
66
|
-
.action(async ({ session }, message) => {
|
|
67
|
-
if (!message) {
|
|
68
|
-
return session?.send('请输入对话内容');
|
|
69
|
-
}
|
|
70
|
-
const userId = session?.userId;
|
|
71
|
-
// 重置对话
|
|
72
|
-
if (message.trim() === 'reset') {
|
|
73
|
-
userConversations.delete(userId);
|
|
74
|
-
return session?.send('ChatGPT: 已重置对话上下文');
|
|
75
|
-
}
|
|
76
|
-
const response = await generateResponse(userId, message);
|
|
77
|
-
return session?.send(response);
|
|
78
|
-
});
|
|
79
|
-
// 监听 @ 机器人的消息
|
|
80
|
-
ctx.middleware((session, next) => {
|
|
81
|
-
if (session.content && session.elements?.some(elem => elem.type === 'at' && elem.attrs?.id === ctx.bots[0]?.selfId)) {
|
|
82
|
-
const userId = session.userId;
|
|
83
|
-
generateResponse(userId, session.content).then(response => {
|
|
84
|
-
session.send(response);
|
|
85
|
-
}).catch(error => {
|
|
86
|
-
logger.error('Failed to generate response:', error);
|
|
87
|
-
});
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
return next();
|
|
91
|
-
});
|
|
92
|
-
logger.info('OpenAI module loaded');
|
|
93
|
-
}
|