koishi-plugin-openai-compatible 1.0.2 → 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/lib/database.d.ts DELETED
@@ -1,29 +0,0 @@
1
- export interface UserPrompt {
2
- userId: string;
3
- prompt: string;
4
- createdAt: Date;
5
- updatedAt: Date;
6
- }
7
- export interface ChatHistory {
8
- userId: string;
9
- messages: {
10
- role: 'system' | 'user' | 'assistant';
11
- content: string;
12
- timestamp: Date;
13
- }[];
14
- lastUpdated: Date;
15
- }
16
- declare const tables: {
17
- 'openai.userPrompts': {
18
- userId: string;
19
- prompt: string;
20
- createdAt: string;
21
- updatedAt: string;
22
- };
23
- 'openai.chatHistories': {
24
- userId: string;
25
- messages: string;
26
- lastUpdated: string;
27
- };
28
- };
29
- export default tables;
package/lib/database.js DELETED
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tables = {
4
- 'openai.userPrompts': {
5
- userId: 'string',
6
- prompt: 'text',
7
- createdAt: 'timestamp',
8
- updatedAt: 'timestamp'
9
- },
10
- 'openai.chatHistories': {
11
- userId: 'string',
12
- messages: 'json',
13
- lastUpdated: 'timestamp'
14
- }
15
- };
16
- exports.default = tables;
package/lib/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import { Context, Schema } from 'koishi';
2
- import { Config as ConfigInterface } from './config';
3
- export declare const name = "openai-compatible";
4
- export declare const usage = "## \uD83E\uDD16 OpenAI\u517C\u5BB9\u804A\u5929\u63D2\u4EF6\n\n\u8BE5\u63D2\u4EF6\u652F\u6301\u4E0E\u6240\u6709\u517C\u5BB9OpenAI API\u7684\u5927\u6A21\u578B\u8FDB\u884C\u804A\u5929\u4EA4\u4E92\u3002\n\n### \u914D\u7F6E\u8BF4\u660E\n\n- **apiEndpoint**: API\u7AEF\u70B9URL\uFF0C\u4F8B\u5982 \"https://api.openai.com/v1\"\n- **apiKey**: API\u5BC6\u94A5\n- **model**: \u4F7F\u7528\u7684\u6A21\u578B\u540D\u79F0\uFF0C\u4F8B\u5982 \"gpt-3.5-turbo\"\n- **temperature**: \u6E29\u5EA6\u53C2\u6570\uFF0C\u63A7\u5236\u56DE\u590D\u7684\u968F\u673A\u6027 (0-2)\n- **maxTokens**: \u6700\u5927\u751F\u6210\u7684token\u6570\u91CF\n- **systemPrompt**: \u7CFB\u7EDF\u9884\u8BBE\u63D0\u793A\u8BCD\uFF08\u53EF\u9009\uFF09\n- **commandName**: \u81EA\u5B9A\u4E49\u6307\u4EE4\u540D\uFF08\u53EF\u9009\uFF0C\u5982\u4E0D\u8BBE\u7F6E\u5219\u9ED8\u8BA4\u5904\u7406\u6240\u6709\u6D88\u606F\uFF09\n- **triggerPrefix**: \u89E6\u53D1\u524D\u7F00\uFF08\u53EF\u9009\uFF0C\u4EC5\u5728\u672A\u8BBE\u7F6EcommandName\u65F6\u6709\u6548\uFF09\n- **userPrompts**: \u7279\u5B9A\u7528\u6237\u7684\u9884\u8BBE\u63D0\u793A\u8BCD\uFF08\u53EF\u9009\uFF0C\u683C\u5F0F\u4E3A {\"\u7528\u6237ID\": \"\u9884\u8BBE\u63D0\u793A\u8BCD\"}\uFF09\n- **thinkingPrompt**: \u601D\u8003\u63D0\u793A\u8BCD\uFF08\u53EF\u9009\uFF0C\u7559\u7A7A\u5219\u4E0D\u663E\u793A\u601D\u8003\u63D0\u793A\uFF09\n\n### \u4F7F\u7528\u65B9\u6CD5\n\n\u5982\u679C\u8BBE\u7F6E\u4E86\u81EA\u5B9A\u4E49\u6307\u4EE4\u540D\uFF0C\u53EF\u4EE5\u901A\u8FC7 `/\u6307\u4EE4\u540D \u4F60\u7684\u95EE\u9898` \u6765\u4F7F\u7528\u3002\n\u5982\u679C\u672A\u8BBE\u7F6E\u6307\u4EE4\u540D\uFF0C\u5219\u6240\u6709\u6D88\u606F\u90FD\u4F1A\u89E6\u53D1\u63D2\u4EF6\uFF08\u53EF\u901A\u8FC7\u524D\u7F00\u8FC7\u6EE4\uFF09\u3002\n\n### \u793A\u4F8B\n\n```\n/chat \u4ECA\u5929\u5929\u6C14\u600E\u4E48\u6837\uFF1F\n```\n\n\u6216\u8005\u5728\u672A\u8BBE\u7F6E\u6307\u4EE4\u540D\u7684\u60C5\u51B5\u4E0B\u76F4\u63A5\u53D1\u9001\u6D88\u606F\uFF1A\n\n```\n\u4ECA\u5929\u5929\u6C14\u600E\u4E48\u6837\uFF1F\n```\n";
5
- export declare const Config: Schema<ConfigInterface>;
6
- export declare function apply(ctx: Context, config: ConfigInterface): void;
package/lib/index.js DELETED
@@ -1,173 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Config = exports.usage = exports.name = void 0;
4
- exports.apply = apply;
5
- const koishi_1 = require("koishi");
6
- const service_1 = require("./service");
7
- exports.name = 'openai-compatible';
8
- exports.usage = `## 🤖 OpenAI兼容聊天插件
9
-
10
- 该插件支持与所有兼容OpenAI API的大模型进行聊天交互。
11
-
12
- ### 配置说明
13
-
14
- - **apiEndpoint**: API端点URL,例如 "https://api.openai.com/v1"
15
- - **apiKey**: API密钥
16
- - **model**: 使用的模型名称,例如 "gpt-3.5-turbo"
17
- - **temperature**: 温度参数,控制回复的随机性 (0-2)
18
- - **maxTokens**: 最大生成的token数量
19
- - **systemPrompt**: 系统预设提示词(可选)
20
- - **commandName**: 自定义指令名(可选,如不设置则默认处理所有消息)
21
- - **triggerPrefix**: 触发前缀(可选,仅在未设置commandName时有效)
22
- - **userPrompts**: 特定用户的预设提示词(可选,格式为 {"用户ID": "预设提示词"})
23
- - **thinkingPrompt**: 思考提示词(可选,留空则不显示思考提示)
24
-
25
- ### 使用方法
26
-
27
- 如果设置了自定义指令名,可以通过 \`/指令名 你的问题\` 来使用。
28
- 如果未设置指令名,则所有消息都会触发插件(可通过前缀过滤)。
29
-
30
- ### 示例
31
-
32
- \`\`\`
33
- /chat 今天天气怎么样?
34
- \`\`\`
35
-
36
- 或者在未设置指令名的情况下直接发送消息:
37
-
38
- \`\`\`
39
- 今天天气怎么样?
40
- \`\`\`
41
- `;
42
- exports.Config = koishi_1.Schema.object({
43
- apiEndpoint: koishi_1.Schema.string()
44
- .description('API端点URL')
45
- .default('https://api.openai.com/v1')
46
- .required(),
47
- apiKey: koishi_1.Schema.string()
48
- .description('API密钥')
49
- .role('secret')
50
- .required(),
51
- model: koishi_1.Schema.string()
52
- .description('使用的模型名称')
53
- .default('gpt-3.5-turbo')
54
- .required(),
55
- temperature: koishi_1.Schema.number()
56
- .description('温度参数,控制回复的随机性 (0-2)')
57
- .default(0.7)
58
- .min(0)
59
- .max(2),
60
- maxTokens: koishi_1.Schema.number()
61
- .description('最大生成的token数量')
62
- .default(2000)
63
- .min(1),
64
- systemPrompt: koishi_1.Schema.string()
65
- .description('系统预设提示词(可选)')
66
- .default('你是一个有用的AI助手。'),
67
- commandName: koishi_1.Schema.string()
68
- .description('自定义指令名(可选,如不设置则默认处理所有消息)'),
69
- triggerPrefix: koishi_1.Schema.string()
70
- .description('触发前缀(可选,仅在未设置commandName时有效)')
71
- .default(''),
72
- userPrompts: koishi_1.Schema.dict(koishi_1.Schema.string())
73
- .description('特定用户的预设提示词(可选,格式为 {"用户ID": "预设提示词"})')
74
- .default({}),
75
- thinkingPrompt: koishi_1.Schema.string()
76
- .description('思考提示词(可选,留空则不显示思考提示)')
77
- .default(''),
78
- });
79
- function apply(ctx, config) {
80
- // 创建服务实例
81
- const service = new service_1.OpenAICompatibleService(ctx, config);
82
- // 注册管理命令
83
- ctx.command('ai管理', '管理AI插件')
84
- .usage('管理OpenAI兼容插件的设置和用户预设')
85
- .userFields(['authority'])
86
- .action(({ session }) => {
87
- if (session.user.authority < 3)
88
- return '权限不足';
89
- return '管理功能已启用';
90
- });
91
- // 设置用户预设命令
92
- ctx.command('ai预设 <userId:string> <prompt:text>', '设置用户专属AI行为')
93
- .usage('设置用户专属AI行为\n示例:ai预设 123456 你是一个专业翻译')
94
- .example('ai预设 123456 你是一个专业翻译')
95
- .action(async ({ session }, userId, prompt) => {
96
- if (!userId || !prompt)
97
- return '请提供用户ID和预设提示词';
98
- service.setUserPrompt(userId, prompt);
99
- return `已为用户 ${userId} 设置预设提示词`;
100
- });
101
- // 移除用户预设命令
102
- ctx.command('ai清除 <userId:string>', '删除用户专属设置')
103
- .usage('移除特定用户的预设提示词')
104
- .example('ai清除 123456')
105
- .action(async ({ session }, userId) => {
106
- if (!userId)
107
- return '请提供用户ID';
108
- service.removeUserPrompt(userId);
109
- return `已移除用户 ${userId} 的预设提示词`;
110
- });
111
- // 清除用户历史命令
112
- ctx.command('ai清除记录 <userId:string>', '清除用户聊天历史')
113
- .usage('清除特定用户的聊天历史')
114
- .example('ai清除记录 123456')
115
- .action(async ({ session }, userId) => {
116
- if (!userId)
117
- return '请提供用户ID';
118
- service.clearHistory(userId);
119
- return `已清除用户 ${userId} 的聊天历史`;
120
- });
121
- // 如果设置了指令名,则注册指令
122
- if (config.commandName) {
123
- ctx.command(config.commandName, '与AI助手对话')
124
- .action(async ({ session }, text) => {
125
- if (!text)
126
- return '请输入您想问的内容。';
127
- try {
128
- // 仅当配置了思考提示时才发送
129
- if (config.thinkingPrompt) {
130
- session.send(koishi_1.h.text(config.thinkingPrompt));
131
- }
132
- const response = await service.chat(session.userId, text);
133
- return response;
134
- }
135
- catch (error) {
136
- ctx.logger('openai-compatible').error(error);
137
- return `发生错误: ${error.message || '未知错误'}`;
138
- }
139
- });
140
- }
141
- else {
142
- // 如果没有设置指令名,则处理所有消息
143
- ctx.middleware(async (session, next) => {
144
- // 如果是自己发送的消息,则跳过
145
- if (session.userId === session.bot.selfId)
146
- return next();
147
- // 检查前缀
148
- const content = session.content;
149
- if (config.triggerPrefix && !content.startsWith(config.triggerPrefix)) {
150
- return next();
151
- }
152
- // 去除前缀
153
- const text = config.triggerPrefix
154
- ? content.slice(config.triggerPrefix.length).trim()
155
- : content.trim();
156
- if (!text)
157
- return next();
158
- try {
159
- // 仅当配置了思考提示时才发送
160
- if (config.thinkingPrompt) {
161
- await session.send(koishi_1.h.text(config.thinkingPrompt));
162
- }
163
- // 获取回复
164
- const response = await service.chat(session.userId, text);
165
- return response;
166
- }
167
- catch (error) {
168
- ctx.logger('openai-compatible').error(error);
169
- return `发生错误: ${error.message || '未知错误'}`;
170
- }
171
- });
172
- }
173
- }
package/lib/service.d.ts DELETED
@@ -1,37 +0,0 @@
1
- import { Context, Service } from 'koishi';
2
- import { Config } from './config';
3
- export declare class OpenAICompatibleService extends Service {
4
- config: Config;
5
- private readonly historyMaxLength;
6
- private readonly historyExpireTime;
7
- private histories;
8
- constructor(ctx: Context, config: Config);
9
- /**
10
- * 清理过期的历史记录
11
- */
12
- private cleanExpiredHistories;
13
- /**
14
- * 获取用户的聊天历史
15
- */
16
- private getUserHistory;
17
- /**
18
- * 添加消息到历史记录
19
- */
20
- private addMessageToHistory;
21
- /**
22
- * 与AI进行聊天
23
- */
24
- chat(userId: string, content: string): Promise<string>;
25
- /**
26
- * 清除用户的聊天历史
27
- */
28
- clearHistory(userId: string): void;
29
- /**
30
- * 设置特定用户的预设提示词
31
- */
32
- setUserPrompt(userId: string, prompt: string): Promise<void>;
33
- /**
34
- * 移除特定用户的预设提示词
35
- */
36
- removeUserPrompt(userId: string): void;
37
- }
package/lib/service.js DELETED
@@ -1,190 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpenAICompatibleService = void 0;
4
- const koishi_1 = require("koishi");
5
- class OpenAICompatibleService extends koishi_1.Service {
6
- constructor(ctx, config) {
7
- super(ctx, 'openai-compatible');
8
- this.historyMaxLength = 10; // 历史记录最大长度
9
- this.historyExpireTime = 30 * 60 * 1000; // 历史记录过期时间(30分钟)
10
- this.histories = new Map();
11
- this.config = config;
12
- this.ctx = ctx;
13
- // 初始化数据库
14
- ctx.model.extend('openai.userPrompts', {
15
- userId: 'string',
16
- prompt: 'text',
17
- createdAt: 'timestamp',
18
- updatedAt: 'timestamp',
19
- }, {
20
- primary: 'userId'
21
- });
22
- ctx.model.extend('openai.chatHistories', {
23
- userId: 'string',
24
- messages: 'json',
25
- lastUpdated: 'timestamp',
26
- }, {
27
- primary: 'userId'
28
- });
29
- // 定期清理过期的历史记录
30
- ctx.setInterval(() => {
31
- this.cleanExpiredHistories();
32
- }, 5 * 60 * 1000); // 每5分钟清理一次
33
- }
34
- /**
35
- * 清理过期的历史记录
36
- */
37
- async cleanExpiredHistories() {
38
- const expireTime = new Date(Date.now() - this.historyExpireTime);
39
- await this.ctx.database.remove('openai.chatHistories', {
40
- lastUpdated: { $lt: expireTime }
41
- });
42
- }
43
- /**
44
- * 获取用户的聊天历史
45
- */
46
- getUserHistory(userId) {
47
- if (!this.histories.has(userId)) {
48
- this.histories.set(userId, {
49
- userId,
50
- messages: [],
51
- lastUpdated: Date.now()
52
- });
53
- }
54
- return this.histories.get(userId);
55
- }
56
- /**
57
- * 添加消息到历史记录
58
- */
59
- addMessageToHistory(userId, message) {
60
- const history = this.getUserHistory(userId);
61
- // 如果是系统消息,检查是否已存在系统消息,如果存在则替换
62
- if (message.role === 'system') {
63
- const systemIndex = history.messages.findIndex(m => m.role === 'system');
64
- if (systemIndex >= 0) {
65
- history.messages[systemIndex] = message;
66
- history.lastUpdated = Date.now();
67
- return;
68
- }
69
- }
70
- // 添加新消息
71
- history.messages.push(message);
72
- // 如果超过最大长度,移除最早的非系统消息
73
- if (history.messages.length > this.historyMaxLength) {
74
- const systemMessage = history.messages.find(m => m.role === 'system');
75
- history.messages = systemMessage
76
- ? [systemMessage, ...history.messages.slice(-this.historyMaxLength + 1)]
77
- : history.messages.slice(-this.historyMaxLength);
78
- }
79
- history.lastUpdated = Date.now();
80
- }
81
- /**
82
- * 与AI进行聊天
83
- */
84
- async chat(userId, content) {
85
- // 获取用户历史记录
86
- const history = this.getUserHistory(userId);
87
- // 如果是首次对话且有系统提示,添加系统提示
88
- if (history.messages.length === 0) {
89
- // 检查是否有特定用户的预设提示词
90
- const userPrompt = this.config.userPrompts?.[userId];
91
- const systemPrompt = userPrompt || this.config.systemPrompt;
92
- if (systemPrompt) {
93
- this.addMessageToHistory(userId, {
94
- role: 'system',
95
- content: systemPrompt
96
- });
97
- }
98
- }
99
- // 添加用户消息
100
- this.addMessageToHistory(userId, {
101
- role: 'user',
102
- content
103
- });
104
- try {
105
- // 调用API
106
- const response = await this.ctx.http.post(`${this.config.apiEndpoint}/chat/completions`, {
107
- model: this.config.model,
108
- messages: history.messages,
109
- temperature: this.config.temperature,
110
- max_tokens: this.config.maxTokens
111
- }, {
112
- headers: {
113
- 'Content-Type': 'application/json',
114
- 'Authorization': `Bearer ${this.config.apiKey}`
115
- }
116
- });
117
- // 处理响应
118
- const assistantMessage = response.choices[0]?.message;
119
- if (!assistantMessage || !assistantMessage.content) {
120
- throw new Error('API返回的响应格式不正确');
121
- }
122
- // 添加助手回复到历史记录
123
- this.addMessageToHistory(userId, {
124
- role: 'assistant',
125
- content: assistantMessage.content
126
- });
127
- return assistantMessage.content;
128
- }
129
- catch (error) {
130
- this.ctx.logger('openai-compatible').error('API调用失败:', error);
131
- // 从历史记录中移除最后一条用户消息(因为没有得到回复)
132
- history.messages.pop();
133
- // 处理 ctx.http 的错误
134
- if (error.status) {
135
- throw new Error(`API调用失败: ${error.status} ${error.statusText || 'Bad Request'}`);
136
- }
137
- else if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
138
- throw new Error('API请求超时或无响应');
139
- }
140
- else {
141
- throw new Error(`请求错误: ${error.message || '未知错误'}`);
142
- }
143
- }
144
- }
145
- /**
146
- * 清除用户的聊天历史
147
- */
148
- clearHistory(userId) {
149
- this.histories.delete(userId);
150
- }
151
- /**
152
- * 设置特定用户的预设提示词
153
- */
154
- async setUserPrompt(userId, prompt) {
155
- await this.ctx.database.upsert('openai.userPrompts', [{
156
- userId,
157
- prompt,
158
- updatedAt: new Date()
159
- }]);
160
- // 如果用户已有历史记录,更新系统提示
161
- if (this.histories.has(userId)) {
162
- const history = this.getUserHistory(userId);
163
- const systemIndex = history.messages.findIndex(m => m.role === 'system');
164
- if (systemIndex >= 0) {
165
- // 替换现有的系统提示
166
- history.messages[systemIndex] = {
167
- role: 'system',
168
- content: prompt
169
- };
170
- }
171
- else if (history.messages.length > 0) {
172
- // 在开头插入系统提示
173
- history.messages.unshift({
174
- role: 'system',
175
- content: prompt
176
- });
177
- }
178
- history.lastUpdated = Date.now();
179
- }
180
- }
181
- /**
182
- * 移除特定用户的预设提示词
183
- */
184
- removeUserPrompt(userId) {
185
- if (this.config.userPrompts && this.config.userPrompts[userId]) {
186
- delete this.config.userPrompts[userId];
187
- }
188
- }
189
- }
190
- exports.OpenAICompatibleService = OpenAICompatibleService;
package/src/config.ts DELETED
@@ -1,23 +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
-
14
- export interface Message {
15
- role: 'system' | 'user' | 'assistant'
16
- content: string
17
- }
18
-
19
- export interface ChatHistory {
20
- userId: string
21
- messages: Message[]
22
- lastUpdated: number
23
- }
package/src/database.ts DELETED
@@ -1,34 +0,0 @@
1
- import { Tables } from 'koishi'
2
-
3
- export interface UserPrompt {
4
- userId: string
5
- prompt: string
6
- createdAt: Date
7
- updatedAt: Date
8
- }
9
-
10
- export interface ChatHistory {
11
- userId: string
12
- messages: {
13
- role: 'system' | 'user' | 'assistant'
14
- content: string
15
- timestamp: Date
16
- }[]
17
- lastUpdated: Date
18
- }
19
-
20
- const tables = {
21
- 'openai.userPrompts': {
22
- userId: 'string',
23
- prompt: 'text',
24
- createdAt: 'timestamp',
25
- updatedAt: 'timestamp'
26
- },
27
- 'openai.chatHistories': {
28
- userId: 'string',
29
- messages: 'json',
30
- lastUpdated: 'timestamp'
31
- }
32
- };
33
-
34
- export default tables;