koishi-plugin-openai-compatible 1.0.3 → 1.0.4
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 +51 -97
- package/dist/index.js +97 -0
- package/package.json +18 -42
- package/src/index.ts +91 -155
- package/tsconfig.json +8 -13
- package/lib/config.d.ts +0 -21
- package/lib/config.js +0 -2
- package/lib/database.d.ts +0 -29
- package/lib/database.js +0 -16
- package/lib/index.d.ts +0 -6
- package/lib/index.js +0 -173
- package/lib/service.d.ts +0 -38
- package/lib/service.js +0 -191
- package/src/config.ts +0 -23
- package/src/database.ts +0 -34
- package/src/service.ts +0 -226
- package/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -1,106 +1,60 @@
|
|
|
1
1
|
# koishi-plugin-openai-compatible
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Koishi plugin for interacting with OpenAI-compatible APIs.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- 支持系统预设提示词
|
|
12
|
-
- 支持为特定用户设置专属预设提示词
|
|
13
|
-
- 可选的自定义指令名
|
|
14
|
-
- 支持会话上下文记忆
|
|
15
|
-
- 自动清理过期的聊天历史
|
|
16
|
-
- 提供管理命令,方便管理用户预设和历史记录
|
|
17
|
-
|
|
18
|
-
## 安装
|
|
5
|
+
## Features
|
|
6
|
+
- Supports all OpenAI-compatible APIs.
|
|
7
|
+
- Configurable API endpoint, model, and parameters.
|
|
8
|
+
- Customizable prompts (system, user-specific, and thinking prompts).
|
|
9
|
+
- Blacklist support for blocking specific users.
|
|
10
|
+
- Flexible command or message-based interaction.
|
|
19
11
|
|
|
12
|
+
## Installation
|
|
20
13
|
```bash
|
|
21
14
|
npm install koishi-plugin-openai-compatible
|
|
22
15
|
```
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- Claude API(通过兼容层)
|
|
68
|
-
- 本地部署的开源模型(如通过LM Studio、ollama等提供的兼容API)
|
|
69
|
-
- 各种云服务提供的兼容OpenAI的API端点
|
|
70
|
-
|
|
71
|
-
## 管理命令
|
|
72
|
-
|
|
73
|
-
插件提供了一系列管理命令,用于管理用户预设和聊天历史:
|
|
74
|
-
|
|
75
|
-
### 设置用户预设
|
|
76
|
-
|
|
77
|
-
为特定用户设置专属的系统提示词:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
/openai-admin.set-user-prompt <用户ID> <预设提示词>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
例如:
|
|
84
|
-
```
|
|
85
|
-
/openai-admin.set-user-prompt 123456 你是一个专业的翻译助手,擅长中英文互译。
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 移除用户预设
|
|
89
|
-
|
|
90
|
-
移除特定用户的专属系统提示词:
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
/openai-admin.remove-user-prompt <用户ID>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### 清除用户历史
|
|
97
|
-
|
|
98
|
-
清除特定用户的聊天历史记录:
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
/openai-admin.clear-history <用户ID>
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## 许可证
|
|
105
|
-
|
|
17
|
+
## Configuration
|
|
18
|
+
```ts
|
|
19
|
+
export interface Config {
|
|
20
|
+
apiEndpoint: string
|
|
21
|
+
apiKey: string
|
|
22
|
+
model: string
|
|
23
|
+
temperature?: number
|
|
24
|
+
maxTokens?: number
|
|
25
|
+
systemPrompt?: string
|
|
26
|
+
commandName?: string
|
|
27
|
+
triggerPrefix?: string
|
|
28
|
+
userPrompts?: Record<string, string>
|
|
29
|
+
thinkingPrompt?: string
|
|
30
|
+
blacklist?: string[]
|
|
31
|
+
blacklistResponse?: string
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
1. **Command Mode**: If `commandName` is set, use `/commandName your question`.
|
|
37
|
+
2. **Message Mode**: If no `commandName` is set, all messages trigger the plugin (filtered by `triggerPrefix` if set).
|
|
38
|
+
|
|
39
|
+
## Example
|
|
40
|
+
```ts
|
|
41
|
+
// koishi.config.ts
|
|
42
|
+
import OpenAICompatible from 'koishi-plugin-openai-compatible'
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
plugins: {
|
|
46
|
+
'openai-compatible': {
|
|
47
|
+
apiEndpoint: 'https://api.openai.com/v1',
|
|
48
|
+
apiKey: 'your-api-key',
|
|
49
|
+
model: 'gpt-3.5-turbo',
|
|
50
|
+
temperature: 1,
|
|
51
|
+
maxTokens: 2048,
|
|
52
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
53
|
+
commandName: 'chat',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
106
60
|
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
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 = 'openai-compatible';
|
|
7
|
+
exports.Config = koishi_1.Schema.object({
|
|
8
|
+
apiEndpoint: koishi_1.Schema.string().required().description('API endpoint URL, e.g., "https://api.openai.com/v1"'),
|
|
9
|
+
apiKey: koishi_1.Schema.string().required().description('API key'),
|
|
10
|
+
model: koishi_1.Schema.string().required().description('Model name, e.g., "gpt-3.5-turbo"'),
|
|
11
|
+
temperature: koishi_1.Schema.number().min(0).max(2).default(1).description('Controls randomness of responses (0-2)'),
|
|
12
|
+
maxTokens: koishi_1.Schema.number().min(1).default(2048).description('Maximum number of tokens to generate'),
|
|
13
|
+
systemPrompt: koishi_1.Schema.string().description('System prompt (optional)'),
|
|
14
|
+
commandName: koishi_1.Schema.string().description('Custom command name (optional)'),
|
|
15
|
+
triggerPrefix: koishi_1.Schema.string().description('Trigger prefix (optional, used when no commandName is set)'),
|
|
16
|
+
userPrompts: koishi_1.Schema.dict(koishi_1.Schema.string()).description('User-specific prompts (optional)'),
|
|
17
|
+
thinkingPrompt: koishi_1.Schema.string().description('Thinking prompt (optional)'),
|
|
18
|
+
blacklist: koishi_1.Schema.array(koishi_1.Schema.string()).description('List of blacklisted user IDs (optional)'),
|
|
19
|
+
blacklistResponse: koishi_1.Schema.string().description('Response for blacklisted users (text or image URL)'),
|
|
20
|
+
});
|
|
21
|
+
function apply(ctx, config) {
|
|
22
|
+
const { apiEndpoint, apiKey, model, temperature, maxTokens, systemPrompt, commandName, triggerPrefix, userPrompts, thinkingPrompt, blacklist, blacklistResponse } = config;
|
|
23
|
+
// Register command if commandName is provided
|
|
24
|
+
if (commandName) {
|
|
25
|
+
ctx.command(commandName, 'Chat with OpenAI-compatible API')
|
|
26
|
+
.action(async ({ session }, ...args) => {
|
|
27
|
+
if (!session || !session.userId || blacklist?.includes(session.userId)) {
|
|
28
|
+
return blacklistResponse || 'You are not allowed to use this command.';
|
|
29
|
+
}
|
|
30
|
+
const userPrompt = !session || !session.userId ? '' : userPrompts?.[session.userId] || '';
|
|
31
|
+
const prompt = args.join(' ');
|
|
32
|
+
const fullPrompt = systemPrompt ? `${systemPrompt}\n${userPrompt}\n${prompt}` : `${userPrompt}\n${prompt}`;
|
|
33
|
+
if (thinkingPrompt) {
|
|
34
|
+
if (session)
|
|
35
|
+
session.send(thinkingPrompt);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const response = await ctx.http.post(`${apiEndpoint}/chat/completions`, {
|
|
39
|
+
model,
|
|
40
|
+
messages: [
|
|
41
|
+
{ role: 'user', content: fullPrompt },
|
|
42
|
+
],
|
|
43
|
+
temperature,
|
|
44
|
+
max_tokens: maxTokens,
|
|
45
|
+
}, {
|
|
46
|
+
headers: {
|
|
47
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
return response.choices[0].message.content;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
ctx.logger.error('OpenAI API error:', error);
|
|
55
|
+
return 'Failed to get response from the API.';
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Handle all messages if no commandName is provided
|
|
61
|
+
ctx.middleware(async (session, next) => {
|
|
62
|
+
if (!session || !session.userId || blacklist?.includes(session.userId)) {
|
|
63
|
+
return blacklistResponse || 'You are not allowed to use this command.';
|
|
64
|
+
}
|
|
65
|
+
const content = session.content;
|
|
66
|
+
if (!content || (triggerPrefix && !content.startsWith(triggerPrefix)))
|
|
67
|
+
return next();
|
|
68
|
+
const userPrompt = !session || !session.userId ? '' : userPrompts?.[session.userId] || '';
|
|
69
|
+
const prompt = !content ? '' : triggerPrefix ? content.slice(triggerPrefix.length) : content;
|
|
70
|
+
const fullPrompt = systemPrompt ? `${systemPrompt}\n${userPrompt}\n${prompt}` : `${userPrompt}\n${prompt}`;
|
|
71
|
+
if (thinkingPrompt) {
|
|
72
|
+
if (session)
|
|
73
|
+
session.send(thinkingPrompt);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const response = await ctx.http.post(`${apiEndpoint}/chat/completions`, {
|
|
77
|
+
model,
|
|
78
|
+
messages: [
|
|
79
|
+
{ role: 'user', content: fullPrompt },
|
|
80
|
+
],
|
|
81
|
+
temperature,
|
|
82
|
+
max_tokens: maxTokens,
|
|
83
|
+
}, {
|
|
84
|
+
headers: {
|
|
85
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
return response.choices[0].message.content;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
ctx.logger.error('OpenAI API error:', error);
|
|
93
|
+
return 'Failed to get response from the API.';
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
package/package.json
CHANGED
|
@@ -1,43 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@koishijs/plugin-help": "^2.4.5",
|
|
22
|
-
"koishi": "^4.0.0"
|
|
23
|
-
},
|
|
24
|
-
"peerDependencies": {
|
|
25
|
-
"koishi": "^4.0.0"
|
|
26
|
-
},
|
|
27
|
-
"koishi": {
|
|
28
|
-
"description": {
|
|
29
|
-
"en": "Chat plugin compatible with OpenAI API",
|
|
30
|
-
"zh": "兼容OpenAI API的聊天插件"
|
|
31
|
-
},
|
|
32
|
-
"service": {
|
|
33
|
-
"required": [
|
|
34
|
-
"database"
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@types/node": "^24.3.1",
|
|
40
|
-
"typescript": "^5.9.2"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
2
|
+
"name": "koishi-plugin-openai-compatible",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "A Koishi plugin for OpenAI compatibility",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"dev": "tsc --watch"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"koishi": "^4.0.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"typescript": "^5.0.0"
|
|
15
|
+
},
|
|
16
|
+
"keywords": ["koishi", "plugin", "openai"],
|
|
17
|
+
"author": "Your Name",
|
|
18
|
+
"license": "MIT"
|
|
19
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,176 +1,112 @@
|
|
|
1
|
-
import { Context, Schema
|
|
2
|
-
import { OpenAICompatibleService } from './service'
|
|
3
|
-
import { Config as ConfigInterface } from './config'
|
|
1
|
+
import { Context, Schema } from 'koishi'
|
|
4
2
|
|
|
5
3
|
export const name = 'openai-compatible'
|
|
6
|
-
export const usage = `## 🤖 OpenAI兼容聊天插件
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
export interface Config {
|
|
6
|
+
apiEndpoint: string
|
|
7
|
+
apiKey: string
|
|
8
|
+
model: string
|
|
9
|
+
temperature?: number
|
|
10
|
+
maxTokens?: number
|
|
11
|
+
systemPrompt?: string
|
|
12
|
+
commandName?: string
|
|
13
|
+
triggerPrefix?: string
|
|
14
|
+
userPrompts?: Record<string, string>
|
|
15
|
+
thinkingPrompt?: string
|
|
16
|
+
blacklist?: string[]
|
|
17
|
+
blacklistResponse?: string
|
|
18
|
+
}
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
如果设置了自定义指令名,可以通过 \`/指令名 你的问题\` 来使用。
|
|
26
|
-
如果未设置指令名,则所有消息都会触发插件(可通过前缀过滤)。
|
|
27
|
-
|
|
28
|
-
### 示例
|
|
29
|
-
|
|
30
|
-
\`\`\`
|
|
31
|
-
/chat 今天天气怎么样?
|
|
32
|
-
\`\`\`
|
|
33
|
-
|
|
34
|
-
或者在未设置指令名的情况下直接发送消息:
|
|
20
|
+
export const Config: Schema<Config> = Schema.object({
|
|
21
|
+
apiEndpoint: Schema.string().required().description('API endpoint URL, e.g., "https://api.openai.com/v1"'),
|
|
22
|
+
apiKey: Schema.string().required().description('API key'),
|
|
23
|
+
model: Schema.string().required().description('Model name, e.g., "gpt-3.5-turbo"'),
|
|
24
|
+
temperature: Schema.number().min(0).max(2).default(1).description('Controls randomness of responses (0-2)'),
|
|
25
|
+
maxTokens: Schema.number().min(1).default(2048).description('Maximum number of tokens to generate'),
|
|
26
|
+
systemPrompt: Schema.string().description('System prompt (optional)'),
|
|
27
|
+
commandName: Schema.string().description('Custom command name (optional)'),
|
|
28
|
+
triggerPrefix: Schema.string().description('Trigger prefix (optional, used when no commandName is set)'),
|
|
29
|
+
userPrompts: Schema.dict(Schema.string()).description('User-specific prompts (optional)'),
|
|
30
|
+
thinkingPrompt: Schema.string().description('Thinking prompt (optional)'),
|
|
31
|
+
blacklist: Schema.array(Schema.string()).description('List of blacklisted user IDs (optional)'),
|
|
32
|
+
blacklistResponse: Schema.string().description('Response for blacklisted users (text or image URL)'),
|
|
33
|
+
})
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
\`\`\`
|
|
39
|
-
`
|
|
35
|
+
export function apply(ctx: Context, config: Config) {
|
|
36
|
+
const { apiEndpoint, apiKey, model, temperature, maxTokens, systemPrompt, commandName, triggerPrefix, userPrompts, thinkingPrompt, blacklist, blacklistResponse } = config
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
.description('使用的模型名称')
|
|
52
|
-
.default('gpt-3.5-turbo')
|
|
53
|
-
.required(),
|
|
54
|
-
temperature: Schema.number()
|
|
55
|
-
.description('温度参数,控制回复的随机性 (0-2)')
|
|
56
|
-
.default(0.7)
|
|
57
|
-
.min(0)
|
|
58
|
-
.max(2),
|
|
59
|
-
maxTokens: Schema.number()
|
|
60
|
-
.description('最大生成的token数量')
|
|
61
|
-
.default(2000)
|
|
62
|
-
.min(1),
|
|
63
|
-
systemPrompt: Schema.string()
|
|
64
|
-
.description('系统预设提示词(可选)')
|
|
65
|
-
.default('你是一个有用的AI助手。'),
|
|
66
|
-
commandName: Schema.string()
|
|
67
|
-
.description('自定义指令名(可选,如不设置则默认处理所有消息)'),
|
|
68
|
-
triggerPrefix: Schema.string()
|
|
69
|
-
.description('触发前缀(可选,仅在未设置commandName时有效)')
|
|
70
|
-
.default(''),
|
|
71
|
-
userPrompts: Schema.dict(Schema.string())
|
|
72
|
-
.description('特定用户的预设提示词(可选,格式为 {"用户ID": "预设提示词"})')
|
|
73
|
-
.default({}),
|
|
74
|
-
thinkingPrompt: Schema.string()
|
|
75
|
-
.description('思考提示词(可选,留空则不显示思考提示)')
|
|
76
|
-
.default(''),
|
|
77
|
-
})
|
|
38
|
+
// Register command if commandName is provided
|
|
39
|
+
if (commandName) {
|
|
40
|
+
ctx.command(commandName, 'Chat with OpenAI-compatible API')
|
|
41
|
+
.action(async ({ session }, ...args) => {
|
|
42
|
+
if (!session || !session.userId || blacklist?.includes(session.userId)) {
|
|
43
|
+
return blacklistResponse || 'You are not allowed to use this command.'
|
|
44
|
+
}
|
|
45
|
+
const userPrompt = !session || !session.userId ? '' : userPrompts?.[session.userId] || ''
|
|
46
|
+
const prompt = args.join(' ')
|
|
47
|
+
const fullPrompt = systemPrompt ? `${systemPrompt}\n${userPrompt}\n${prompt}` : `${userPrompt}\n${prompt}`
|
|
78
48
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// 注册管理命令
|
|
84
|
-
ctx.command('ai管理', '管理AI插件')
|
|
85
|
-
.usage('管理OpenAI兼容插件的设置和用户预设')
|
|
86
|
-
.userFields(['authority'])
|
|
87
|
-
.action(({ session }) => {
|
|
88
|
-
if (session.user.authority < 3) return '权限不足'
|
|
89
|
-
return '管理功能已启用'
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
// 设置用户预设命令
|
|
93
|
-
ctx.command('ai预设 <userId:string> <prompt:text>', '设置用户专属AI行为')
|
|
94
|
-
.usage('设置用户专属AI行为\n示例:ai预设 123456 你是一个专业翻译')
|
|
95
|
-
.example('ai预设 123456 你是一个专业翻译')
|
|
96
|
-
.action(async ({ session }, userId, prompt) => {
|
|
97
|
-
if (!userId || !prompt) return '请提供用户ID和预设提示词'
|
|
98
|
-
|
|
99
|
-
service.setUserPrompt(userId, prompt)
|
|
100
|
-
return `已为用户 ${userId} 设置预设提示词`
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
// 移除用户预设命令
|
|
104
|
-
ctx.command('ai清除 <userId:string>', '删除用户专属设置')
|
|
105
|
-
.usage('移除特定用户的预设提示词')
|
|
106
|
-
.example('ai清除 123456')
|
|
107
|
-
.action(async ({ session }, userId) => {
|
|
108
|
-
if (!userId) return '请提供用户ID'
|
|
109
|
-
|
|
110
|
-
service.removeUserPrompt(userId)
|
|
111
|
-
return `已移除用户 ${userId} 的预设提示词`
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
// 清除用户历史命令
|
|
115
|
-
ctx.command('ai清除记录 <userId:string>', '清除用户聊天历史')
|
|
116
|
-
.usage('清除特定用户的聊天历史')
|
|
117
|
-
.example('ai清除记录 123456')
|
|
118
|
-
.action(async ({ session }, userId) => {
|
|
119
|
-
if (!userId) return '请提供用户ID'
|
|
120
|
-
|
|
121
|
-
service.clearHistory(userId)
|
|
122
|
-
return `已清除用户 ${userId} 的聊天历史`
|
|
123
|
-
})
|
|
49
|
+
if (thinkingPrompt) {
|
|
50
|
+
if (session) session.send(thinkingPrompt)
|
|
51
|
+
}
|
|
124
52
|
|
|
125
|
-
// 如果设置了指令名,则注册指令
|
|
126
|
-
if (config.commandName) {
|
|
127
|
-
ctx.command(config.commandName, '与AI助手对话')
|
|
128
|
-
.action(async ({ session }, text) => {
|
|
129
|
-
if (!text) return '请输入您想问的内容。'
|
|
130
|
-
|
|
131
53
|
try {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
54
|
+
const response = await ctx.http.post(`${apiEndpoint}/chat/completions`, {
|
|
55
|
+
model,
|
|
56
|
+
messages: [
|
|
57
|
+
{ role: 'user', content: fullPrompt },
|
|
58
|
+
],
|
|
59
|
+
temperature,
|
|
60
|
+
max_tokens: maxTokens,
|
|
61
|
+
}, {
|
|
62
|
+
headers: {
|
|
63
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return response.choices[0].message.content
|
|
138
69
|
} catch (error) {
|
|
139
|
-
ctx.logger('
|
|
140
|
-
return
|
|
70
|
+
ctx.logger.error('OpenAI API error:', error)
|
|
71
|
+
return 'Failed to get response from the API.'
|
|
141
72
|
}
|
|
142
73
|
})
|
|
143
74
|
} else {
|
|
144
|
-
//
|
|
75
|
+
// Handle all messages if no commandName is provided
|
|
145
76
|
ctx.middleware(async (session, next) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// 检查前缀
|
|
77
|
+
if (!session || !session.userId || blacklist?.includes(session.userId)) {
|
|
78
|
+
return blacklistResponse || 'You are not allowed to use this command.'
|
|
79
|
+
}
|
|
150
80
|
const content = session.content
|
|
151
|
-
if (
|
|
152
|
-
|
|
81
|
+
if (!content || (triggerPrefix && !content.startsWith(triggerPrefix))) return next()
|
|
82
|
+
|
|
83
|
+
const userPrompt = !session || !session.userId ? '' : userPrompts?.[session.userId] || ''
|
|
84
|
+
const prompt = !content ? '' : triggerPrefix ? content.slice(triggerPrefix.length) : content
|
|
85
|
+
const fullPrompt = systemPrompt ? `${systemPrompt}\n${userPrompt}\n${prompt}` : `${userPrompt}\n${prompt}`
|
|
86
|
+
|
|
87
|
+
if (thinkingPrompt) {
|
|
88
|
+
if (session) session.send(thinkingPrompt)
|
|
153
89
|
}
|
|
154
|
-
|
|
155
|
-
// 去除前缀
|
|
156
|
-
const text = config.triggerPrefix
|
|
157
|
-
? content.slice(config.triggerPrefix.length).trim()
|
|
158
|
-
: content.trim()
|
|
159
|
-
|
|
160
|
-
if (!text) return next()
|
|
161
|
-
|
|
90
|
+
|
|
162
91
|
try {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
92
|
+
const response = await ctx.http.post(`${apiEndpoint}/chat/completions`, {
|
|
93
|
+
model,
|
|
94
|
+
messages: [
|
|
95
|
+
{ role: 'user', content: fullPrompt },
|
|
96
|
+
],
|
|
97
|
+
temperature,
|
|
98
|
+
max_tokens: maxTokens,
|
|
99
|
+
}, {
|
|
100
|
+
headers: {
|
|
101
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
102
|
+
'Content-Type': 'application/json',
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
return response.choices[0].message.content
|
|
171
107
|
} catch (error) {
|
|
172
|
-
ctx.logger('
|
|
173
|
-
return
|
|
108
|
+
ctx.logger.error('OpenAI API error:', error)
|
|
109
|
+
return 'Failed to get response from the API.'
|
|
174
110
|
}
|
|
175
111
|
})
|
|
176
112
|
}
|
package/tsconfig.json
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"
|
|
4
|
-
"outDir": "lib",
|
|
5
|
-
"target": "es2020",
|
|
3
|
+
"target": "ES2020",
|
|
6
4
|
"module": "commonjs",
|
|
7
|
-
"
|
|
8
|
-
"composite": true,
|
|
9
|
-
"incremental": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
5
|
+
"strict": true,
|
|
11
6
|
"esModuleInterop": true,
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src"
|
|
15
11
|
},
|
|
16
|
-
"include": [
|
|
17
|
-
|
|
18
|
-
]
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules"]
|
|
19
14
|
}
|
package/lib/config.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export interface Config {
|
|
2
|
-
apiEndpoint: string;
|
|
3
|
-
apiKey: string;
|
|
4
|
-
model: string;
|
|
5
|
-
temperature: number;
|
|
6
|
-
maxTokens: number;
|
|
7
|
-
systemPrompt: string;
|
|
8
|
-
commandName?: string;
|
|
9
|
-
triggerPrefix?: string;
|
|
10
|
-
userPrompts?: Record<string, string>;
|
|
11
|
-
thinkingPrompt?: string;
|
|
12
|
-
}
|
|
13
|
-
export interface Message {
|
|
14
|
-
role: 'system' | 'user' | 'assistant';
|
|
15
|
-
content: string;
|
|
16
|
-
}
|
|
17
|
-
export interface ChatHistory {
|
|
18
|
-
userId: string;
|
|
19
|
-
messages: Message[];
|
|
20
|
-
lastUpdated: number;
|
|
21
|
-
}
|
package/lib/config.js
DELETED