koishi-plugin-imgdraw-selfuse 0.0.8 → 0.1.1
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/index.d.ts +206 -2
- package/lib/index.js +193 -32
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -16,7 +16,41 @@ interface BlacklistEntry {
|
|
|
16
16
|
id: string;
|
|
17
17
|
createdAt: Date;
|
|
18
18
|
}
|
|
19
|
-
export declare const
|
|
19
|
+
export declare const BaseConfig: Schema<Schemastery.ObjectS<{
|
|
20
|
+
debug: Schema<boolean, boolean>;
|
|
21
|
+
apiStrategy: Schema<"sequence" | "roundrobin", "sequence" | "roundrobin">;
|
|
22
|
+
timeout: Schema<number, number>;
|
|
23
|
+
rateLimit: Schema<number, number>;
|
|
24
|
+
imgWaitTime: Schema<number, number>;
|
|
25
|
+
model: Schema<string, string>;
|
|
26
|
+
txt2imgModel: Schema<string, string>;
|
|
27
|
+
img2imgModel: Schema<string, string>;
|
|
28
|
+
maxImages: Schema<number, number>;
|
|
29
|
+
enableImgCompress: Schema<boolean, boolean>;
|
|
30
|
+
imgMaxWidth: Schema<number, number>;
|
|
31
|
+
imgMaxHeight: Schema<number, number>;
|
|
32
|
+
imgQuality: Schema<number, number>;
|
|
33
|
+
imgMaxFileSize: Schema<number, number>;
|
|
34
|
+
enableImg2ImgBase64: Schema<boolean, boolean>;
|
|
35
|
+
apiList: Schema<Schemastery.ObjectS<{
|
|
36
|
+
enable: Schema<boolean, boolean>;
|
|
37
|
+
apiKey: Schema<string, string>;
|
|
38
|
+
baseUrl: Schema<string, string>;
|
|
39
|
+
}>[], Schemastery.ObjectT<{
|
|
40
|
+
enable: Schema<boolean, boolean>;
|
|
41
|
+
apiKey: Schema<string, string>;
|
|
42
|
+
baseUrl: Schema<string, string>;
|
|
43
|
+
}>[]>;
|
|
44
|
+
enableTxt2Img: Schema<boolean, boolean>;
|
|
45
|
+
enableImg2Img: Schema<boolean, boolean>;
|
|
46
|
+
command: Schema<string, string>;
|
|
47
|
+
aliases: Schema<string[], string[]>;
|
|
48
|
+
img2imgCommand: Schema<string, string>;
|
|
49
|
+
img2imgAliases: Schema<string[], string[]>;
|
|
50
|
+
txt2imgPrompt: Schema<string, string>;
|
|
51
|
+
img2imgPrompt: Schema<string, string>;
|
|
52
|
+
blacklistAdmins: Schema<string[], string[]>;
|
|
53
|
+
}>, Schemastery.ObjectT<{
|
|
20
54
|
debug: Schema<boolean, boolean>;
|
|
21
55
|
apiStrategy: Schema<"sequence" | "roundrobin", "sequence" | "roundrobin">;
|
|
22
56
|
timeout: Schema<number, number>;
|
|
@@ -31,6 +65,7 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
31
65
|
imgMaxHeight: Schema<number, number>;
|
|
32
66
|
imgQuality: Schema<number, number>;
|
|
33
67
|
imgMaxFileSize: Schema<number, number>;
|
|
68
|
+
enableImg2ImgBase64: Schema<boolean, boolean>;
|
|
34
69
|
apiList: Schema<Schemastery.ObjectS<{
|
|
35
70
|
enable: Schema<boolean, boolean>;
|
|
36
71
|
apiKey: Schema<string, string>;
|
|
@@ -49,6 +84,39 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
49
84
|
txt2imgPrompt: Schema<string, string>;
|
|
50
85
|
img2imgPrompt: Schema<string, string>;
|
|
51
86
|
blacklistAdmins: Schema<string[], string[]>;
|
|
87
|
+
}>>;
|
|
88
|
+
export declare const PresetConfig: Schema<Schemastery.ObjectS<{
|
|
89
|
+
enablePresets: Schema<boolean, boolean>;
|
|
90
|
+
presets: Schema<Schemastery.ObjectS<{
|
|
91
|
+
enable: Schema<boolean, boolean>;
|
|
92
|
+
text: Schema<string, string>;
|
|
93
|
+
command: Schema<string, string>;
|
|
94
|
+
keyword: Schema<string, string>;
|
|
95
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
96
|
+
}>[], Schemastery.ObjectT<{
|
|
97
|
+
enable: Schema<boolean, boolean>;
|
|
98
|
+
text: Schema<string, string>;
|
|
99
|
+
command: Schema<string, string>;
|
|
100
|
+
keyword: Schema<string, string>;
|
|
101
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
102
|
+
}>[]>;
|
|
103
|
+
}>, Schemastery.ObjectT<{
|
|
104
|
+
enablePresets: Schema<boolean, boolean>;
|
|
105
|
+
presets: Schema<Schemastery.ObjectS<{
|
|
106
|
+
enable: Schema<boolean, boolean>;
|
|
107
|
+
text: Schema<string, string>;
|
|
108
|
+
command: Schema<string, string>;
|
|
109
|
+
keyword: Schema<string, string>;
|
|
110
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
111
|
+
}>[], Schemastery.ObjectT<{
|
|
112
|
+
enable: Schema<boolean, boolean>;
|
|
113
|
+
text: Schema<string, string>;
|
|
114
|
+
command: Schema<string, string>;
|
|
115
|
+
keyword: Schema<string, string>;
|
|
116
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
117
|
+
}>[]>;
|
|
118
|
+
}>>;
|
|
119
|
+
export declare const MessageConfig: Schema<Schemastery.ObjectS<{
|
|
52
120
|
messages: Schema<Schemastery.ObjectS<{
|
|
53
121
|
generating: Schema<string, string>;
|
|
54
122
|
waitImage: Schema<string, string>;
|
|
@@ -101,6 +169,59 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
101
169
|
blacklistListTitle: Schema<string, string>;
|
|
102
170
|
}>>;
|
|
103
171
|
}>, Schemastery.ObjectT<{
|
|
172
|
+
messages: Schema<Schemastery.ObjectS<{
|
|
173
|
+
generating: Schema<string, string>;
|
|
174
|
+
waitImage: Schema<string, string>;
|
|
175
|
+
timeout: Schema<string, string>;
|
|
176
|
+
empty: Schema<string, string>;
|
|
177
|
+
noApi: Schema<string, string>;
|
|
178
|
+
fail: Schema<string, string>;
|
|
179
|
+
modelTextOnly: Schema<string, string>;
|
|
180
|
+
needAssets: Schema<string, string>;
|
|
181
|
+
txt2imgDisabled: Schema<string, string>;
|
|
182
|
+
img2imgDisabled: Schema<string, string>;
|
|
183
|
+
rateLimit: Schema<string, string>;
|
|
184
|
+
alreadyWaiting: Schema<string, string>;
|
|
185
|
+
multiImageReceived: Schema<string, string>;
|
|
186
|
+
multiImageLimit: Schema<string, string>;
|
|
187
|
+
noImageReceived: Schema<string, string>;
|
|
188
|
+
blacklisted: Schema<string, string>;
|
|
189
|
+
noPermission: Schema<string, string>;
|
|
190
|
+
blacklistAddSuccess: Schema<string, string>;
|
|
191
|
+
blacklistRemoveSuccess: Schema<string, string>;
|
|
192
|
+
blacklistAddFail: Schema<string, string>;
|
|
193
|
+
blacklistRemoveFail: Schema<string, string>;
|
|
194
|
+
invalidUserId: Schema<string, string>;
|
|
195
|
+
blacklistListEmpty: Schema<string, string>;
|
|
196
|
+
blacklistListTitle: Schema<string, string>;
|
|
197
|
+
}>, Schemastery.ObjectT<{
|
|
198
|
+
generating: Schema<string, string>;
|
|
199
|
+
waitImage: Schema<string, string>;
|
|
200
|
+
timeout: Schema<string, string>;
|
|
201
|
+
empty: Schema<string, string>;
|
|
202
|
+
noApi: Schema<string, string>;
|
|
203
|
+
fail: Schema<string, string>;
|
|
204
|
+
modelTextOnly: Schema<string, string>;
|
|
205
|
+
needAssets: Schema<string, string>;
|
|
206
|
+
txt2imgDisabled: Schema<string, string>;
|
|
207
|
+
img2imgDisabled: Schema<string, string>;
|
|
208
|
+
rateLimit: Schema<string, string>;
|
|
209
|
+
alreadyWaiting: Schema<string, string>;
|
|
210
|
+
multiImageReceived: Schema<string, string>;
|
|
211
|
+
multiImageLimit: Schema<string, string>;
|
|
212
|
+
noImageReceived: Schema<string, string>;
|
|
213
|
+
blacklisted: Schema<string, string>;
|
|
214
|
+
noPermission: Schema<string, string>;
|
|
215
|
+
blacklistAddSuccess: Schema<string, string>;
|
|
216
|
+
blacklistRemoveSuccess: Schema<string, string>;
|
|
217
|
+
blacklistAddFail: Schema<string, string>;
|
|
218
|
+
blacklistRemoveFail: Schema<string, string>;
|
|
219
|
+
invalidUserId: Schema<string, string>;
|
|
220
|
+
blacklistListEmpty: Schema<string, string>;
|
|
221
|
+
blacklistListTitle: Schema<string, string>;
|
|
222
|
+
}>>;
|
|
223
|
+
}>>;
|
|
224
|
+
export declare const Config: Schema<Schemastery.ObjectS<{
|
|
104
225
|
debug: Schema<boolean, boolean>;
|
|
105
226
|
apiStrategy: Schema<"sequence" | "roundrobin", "sequence" | "roundrobin">;
|
|
106
227
|
timeout: Schema<number, number>;
|
|
@@ -115,6 +236,7 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
115
236
|
imgMaxHeight: Schema<number, number>;
|
|
116
237
|
imgQuality: Schema<number, number>;
|
|
117
238
|
imgMaxFileSize: Schema<number, number>;
|
|
239
|
+
enableImg2ImgBase64: Schema<boolean, boolean>;
|
|
118
240
|
apiList: Schema<Schemastery.ObjectS<{
|
|
119
241
|
enable: Schema<boolean, boolean>;
|
|
120
242
|
apiKey: Schema<string, string>;
|
|
@@ -133,6 +255,22 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
133
255
|
txt2imgPrompt: Schema<string, string>;
|
|
134
256
|
img2imgPrompt: Schema<string, string>;
|
|
135
257
|
blacklistAdmins: Schema<string[], string[]>;
|
|
258
|
+
}> | Schemastery.ObjectS<{
|
|
259
|
+
enablePresets: Schema<boolean, boolean>;
|
|
260
|
+
presets: Schema<Schemastery.ObjectS<{
|
|
261
|
+
enable: Schema<boolean, boolean>;
|
|
262
|
+
text: Schema<string, string>;
|
|
263
|
+
command: Schema<string, string>;
|
|
264
|
+
keyword: Schema<string, string>;
|
|
265
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
266
|
+
}>[], Schemastery.ObjectT<{
|
|
267
|
+
enable: Schema<boolean, boolean>;
|
|
268
|
+
text: Schema<string, string>;
|
|
269
|
+
command: Schema<string, string>;
|
|
270
|
+
keyword: Schema<string, string>;
|
|
271
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
272
|
+
}>[]>;
|
|
273
|
+
}> | Schemastery.ObjectS<{
|
|
136
274
|
messages: Schema<Schemastery.ObjectS<{
|
|
137
275
|
generating: Schema<string, string>;
|
|
138
276
|
waitImage: Schema<string, string>;
|
|
@@ -184,7 +322,73 @@ export declare const Config: Schema<Schemastery.ObjectS<{
|
|
|
184
322
|
blacklistListEmpty: Schema<string, string>;
|
|
185
323
|
blacklistListTitle: Schema<string, string>;
|
|
186
324
|
}>>;
|
|
187
|
-
}
|
|
325
|
+
}>, {
|
|
326
|
+
debug: boolean;
|
|
327
|
+
apiStrategy: "sequence" | "roundrobin";
|
|
328
|
+
timeout: number;
|
|
329
|
+
rateLimit: number;
|
|
330
|
+
imgWaitTime: number;
|
|
331
|
+
model: string;
|
|
332
|
+
txt2imgModel: string;
|
|
333
|
+
img2imgModel: string;
|
|
334
|
+
maxImages: number;
|
|
335
|
+
enableImgCompress: boolean;
|
|
336
|
+
imgMaxWidth: number;
|
|
337
|
+
imgMaxHeight: number;
|
|
338
|
+
imgQuality: number;
|
|
339
|
+
imgMaxFileSize: number;
|
|
340
|
+
enableImg2ImgBase64: boolean;
|
|
341
|
+
apiList: Schemastery.ObjectT<{
|
|
342
|
+
enable: Schema<boolean, boolean>;
|
|
343
|
+
apiKey: Schema<string, string>;
|
|
344
|
+
baseUrl: Schema<string, string>;
|
|
345
|
+
}>[];
|
|
346
|
+
enableTxt2Img: boolean;
|
|
347
|
+
enableImg2Img: boolean;
|
|
348
|
+
command: string;
|
|
349
|
+
aliases: string[];
|
|
350
|
+
img2imgCommand: string;
|
|
351
|
+
img2imgAliases: string[];
|
|
352
|
+
txt2imgPrompt: string;
|
|
353
|
+
img2imgPrompt: string;
|
|
354
|
+
blacklistAdmins: string[];
|
|
355
|
+
} & import("cosmokit", { with: { "resolution-mode": "import" } }).Dict & {
|
|
356
|
+
enablePresets: boolean;
|
|
357
|
+
presets: Schemastery.ObjectT<{
|
|
358
|
+
enable: Schema<boolean, boolean>;
|
|
359
|
+
text: Schema<string, string>;
|
|
360
|
+
command: Schema<string, string>;
|
|
361
|
+
keyword: Schema<string, string>;
|
|
362
|
+
enableKeywordMatch: Schema<boolean, boolean>;
|
|
363
|
+
}>[];
|
|
364
|
+
} & {
|
|
365
|
+
messages: Schemastery.ObjectT<{
|
|
366
|
+
generating: Schema<string, string>;
|
|
367
|
+
waitImage: Schema<string, string>;
|
|
368
|
+
timeout: Schema<string, string>;
|
|
369
|
+
empty: Schema<string, string>;
|
|
370
|
+
noApi: Schema<string, string>;
|
|
371
|
+
fail: Schema<string, string>;
|
|
372
|
+
modelTextOnly: Schema<string, string>;
|
|
373
|
+
needAssets: Schema<string, string>;
|
|
374
|
+
txt2imgDisabled: Schema<string, string>;
|
|
375
|
+
img2imgDisabled: Schema<string, string>;
|
|
376
|
+
rateLimit: Schema<string, string>;
|
|
377
|
+
alreadyWaiting: Schema<string, string>;
|
|
378
|
+
multiImageReceived: Schema<string, string>;
|
|
379
|
+
multiImageLimit: Schema<string, string>;
|
|
380
|
+
noImageReceived: Schema<string, string>;
|
|
381
|
+
blacklisted: Schema<string, string>;
|
|
382
|
+
noPermission: Schema<string, string>;
|
|
383
|
+
blacklistAddSuccess: Schema<string, string>;
|
|
384
|
+
blacklistRemoveSuccess: Schema<string, string>;
|
|
385
|
+
blacklistAddFail: Schema<string, string>;
|
|
386
|
+
blacklistRemoveFail: Schema<string, string>;
|
|
387
|
+
invalidUserId: Schema<string, string>;
|
|
388
|
+
blacklistListEmpty: Schema<string, string>;
|
|
389
|
+
blacklistListTitle: Schema<string, string>;
|
|
390
|
+
}>;
|
|
391
|
+
}>;
|
|
188
392
|
export type Config = any;
|
|
189
393
|
export declare function apply(ctx: Context, cfg: any): Promise<void>;
|
|
190
394
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Config = exports.inject = exports.name = void 0;
|
|
6
|
+
exports.Config = exports.MessageConfig = exports.PresetConfig = exports.BaseConfig = exports.inject = exports.name = void 0;
|
|
7
7
|
exports.apply = apply;
|
|
8
8
|
const koishi_1 = require("koishi");
|
|
9
9
|
const axios_1 = __importDefault(require("axios"));
|
|
@@ -24,8 +24,16 @@ exports.inject = {
|
|
|
24
24
|
optional: ['assets'],
|
|
25
25
|
};
|
|
26
26
|
const logger = new koishi_1.Logger('ai-image');
|
|
27
|
-
// ====================
|
|
28
|
-
|
|
27
|
+
// ==================== 预置提示词单项配置 ====================
|
|
28
|
+
const PresetItem = koishi_1.Schema.object({
|
|
29
|
+
enable: koishi_1.Schema.boolean().default(true).description('启用此预置提示词'),
|
|
30
|
+
text: koishi_1.Schema.string().default('').description('预置提示词文本(将自动添加到 prompt 前)'),
|
|
31
|
+
command: koishi_1.Schema.string().default('').description('触发指令(如 draw0,留空则自动生成 drawN)'),
|
|
32
|
+
keyword: koishi_1.Schema.string().default('').description('匹配关键词(如 猫娘,留空则不启用关键词匹配)'),
|
|
33
|
+
enableKeywordMatch: koishi_1.Schema.boolean().default(false).description('启用关键词匹配(用户 prompt 包含关键词时自动添加)'),
|
|
34
|
+
}).description('预置提示词配置项');
|
|
35
|
+
// ==================== 独立大类 1:AI 绘图插件配置 ====================
|
|
36
|
+
exports.BaseConfig = koishi_1.Schema.object({
|
|
29
37
|
debug: koishi_1.Schema.boolean().default(false).description('开启调试模式,输出完整请求日志'),
|
|
30
38
|
apiStrategy: koishi_1.Schema.union([
|
|
31
39
|
koishi_1.Schema.const('sequence').description('顺序模式'),
|
|
@@ -38,13 +46,16 @@ exports.Config = koishi_1.Schema.object({
|
|
|
38
46
|
txt2imgModel: koishi_1.Schema.string().default('').description('文生图专用模型,留空则使用通用模型'),
|
|
39
47
|
img2imgModel: koishi_1.Schema.string().default('').description('图生图专用模型,留空则使用通用模型'),
|
|
40
48
|
maxImages: koishi_1.Schema.number().default(5).description('图生图最大支持图片数量'),
|
|
41
|
-
// ====================
|
|
49
|
+
// ==================== 图片压缩配置 ====================
|
|
42
50
|
enableImgCompress: koishi_1.Schema.boolean().default(true).description('启用图生图图片压缩(推荐开启,可防止大图超时)'),
|
|
43
51
|
imgMaxWidth: koishi_1.Schema.number().default(1536).description('图片压缩最大宽度(像素)'),
|
|
44
52
|
imgMaxHeight: koishi_1.Schema.number().default(1536).description('图片压缩最大高度(像素)'),
|
|
45
53
|
imgQuality: koishi_1.Schema.number().default(85).description('JPEG 压缩质量 1-100(越高越清晰,建议 80-90)'),
|
|
46
54
|
imgMaxFileSize: koishi_1.Schema.number().default(3).description('图片最大体积(MB),超过会进一步压缩'),
|
|
47
55
|
// ==========================================================
|
|
56
|
+
// ==================== 图生图 base64 转换开关 ====================
|
|
57
|
+
enableImg2ImgBase64: koishi_1.Schema.boolean().default(true).description('图生图将图片转换为 base64(关闭则直接传 URL,部分 API 不需要 base64)'),
|
|
58
|
+
// ==========================================================
|
|
48
59
|
apiList: koishi_1.Schema.array(koishi_1.Schema.object({
|
|
49
60
|
enable: koishi_1.Schema.boolean().default(true).description('启用此 API'),
|
|
50
61
|
apiKey: koishi_1.Schema.string().description('API Key'),
|
|
@@ -52,13 +63,21 @@ exports.Config = koishi_1.Schema.object({
|
|
|
52
63
|
})).default([]).description('API 配置列表(支持多账号负载)'),
|
|
53
64
|
enableTxt2Img: koishi_1.Schema.boolean().default(true).description('启用文生图'),
|
|
54
65
|
enableImg2Img: koishi_1.Schema.boolean().default(true).description('启用图生图'),
|
|
55
|
-
command: koishi_1.Schema.string().default('draw').description('
|
|
66
|
+
command: koishi_1.Schema.string().default('draw').description('文生图主指令'),
|
|
56
67
|
aliases: koishi_1.Schema.array(String).default([]).description('文生图指令别名'),
|
|
57
68
|
img2imgCommand: koishi_1.Schema.string().default('imgdraw').description('图生图指令'),
|
|
58
69
|
img2imgAliases: koishi_1.Schema.array(String).default([]).description('图生图指令别名'),
|
|
59
70
|
txt2imgPrompt: koishi_1.Schema.string().default('请严格遵循我的要求生成一张图片,不要询问或添加额外说明,直接输出图片。你可以使用联网功能获取最新的数据或信息。要求:{prompt}').description('文生图提示词模板'),
|
|
60
71
|
img2imgPrompt: koishi_1.Schema.string().default('图片链接:{url} 请严格根据以下指令对提供的图片进行编辑或重绘,不要询问,直接输出结果。你可以使用联网功能获取最新的数据或信息。\n指令:{prompt}').description('图生图提示词模板'),
|
|
61
72
|
blacklistAdmins: koishi_1.Schema.array(String).default([]).description('允许管理黑名单的 QQ 号列表'),
|
|
73
|
+
}).description('AI 绘图插件配置');
|
|
74
|
+
// ==================== 独立大类 2:预置提示词配置 ====================
|
|
75
|
+
exports.PresetConfig = koishi_1.Schema.object({
|
|
76
|
+
enablePresets: koishi_1.Schema.boolean().default(false).description('启用预置提示词功能(仅用于文生图)'),
|
|
77
|
+
presets: koishi_1.Schema.array(PresetItem).default([]).description('预置提示词列表(可添加多个,支持指令触发和关键词匹配)'),
|
|
78
|
+
}).description('预置提示词配置');
|
|
79
|
+
// ==================== 独立大类 3:提示文案配置 ====================
|
|
80
|
+
exports.MessageConfig = koishi_1.Schema.object({
|
|
62
81
|
messages: koishi_1.Schema.object({
|
|
63
82
|
generating: koishi_1.Schema.string().default('⏳ 生成中...'),
|
|
64
83
|
waitImage: koishi_1.Schema.string().default('请在60秒内发送需要编辑的图片'),
|
|
@@ -85,7 +104,13 @@ exports.Config = koishi_1.Schema.object({
|
|
|
85
104
|
blacklistListEmpty: koishi_1.Schema.string().default('✅ 当前黑名单为空'),
|
|
86
105
|
blacklistListTitle: koishi_1.Schema.string().default('📋 当前黑名单:'),
|
|
87
106
|
}).description('提示文案配置'),
|
|
88
|
-
}).description('
|
|
107
|
+
}).description('提示文案配置');
|
|
108
|
+
// ==================== 组合配置(三个并列大类)====================
|
|
109
|
+
exports.Config = koishi_1.Schema.intersect([
|
|
110
|
+
exports.BaseConfig,
|
|
111
|
+
exports.PresetConfig,
|
|
112
|
+
exports.MessageConfig,
|
|
113
|
+
]);
|
|
89
114
|
// ==================== 主函数 ====================
|
|
90
115
|
async function apply(ctx, cfg) {
|
|
91
116
|
const debug = cfg.debug;
|
|
@@ -173,7 +198,7 @@ async function apply(ctx, cfg) {
|
|
|
173
198
|
return markdownMatch[1];
|
|
174
199
|
return null;
|
|
175
200
|
}
|
|
176
|
-
// ====================
|
|
201
|
+
// ==================== 图片压缩函数 ====================
|
|
177
202
|
async function compressImage(buffer) {
|
|
178
203
|
if (!sharp || !cfg.enableImgCompress) {
|
|
179
204
|
return buffer;
|
|
@@ -232,23 +257,36 @@ async function apply(ctx, cfg) {
|
|
|
232
257
|
}
|
|
233
258
|
}
|
|
234
259
|
// ==========================================================
|
|
235
|
-
// ==================== 修改:URL 转 base64
|
|
236
|
-
|
|
260
|
+
// ==================== 修改:URL 转 base64(支持开关)====================
|
|
261
|
+
/**
|
|
262
|
+
* 处理图片 URL,根据配置决定返回 base64 还是原始 URL
|
|
263
|
+
* @param url 图片 URL
|
|
264
|
+
* @param forceBase64 强制使用 base64(覆盖全局配置)
|
|
265
|
+
*/
|
|
266
|
+
async function processImageUrl(url, forceBase64) {
|
|
237
267
|
if (!url)
|
|
238
268
|
return null;
|
|
269
|
+
// 如果已经是 base64,检查是否需要压缩
|
|
239
270
|
if (url.startsWith('data:image/')) {
|
|
240
|
-
// 如果已经是 base64,检查是否需要压缩
|
|
241
271
|
if (cfg.enableImgCompress && sharp) {
|
|
242
272
|
return await compressBase64Image(url);
|
|
243
273
|
}
|
|
244
274
|
return url;
|
|
245
275
|
}
|
|
276
|
+
// 判断是否转换为 base64
|
|
277
|
+
const needBase64 = forceBase64 !== undefined ? forceBase64 : cfg.enableImg2ImgBase64;
|
|
278
|
+
if (!needBase64) {
|
|
279
|
+
// 直接返回 URL(不转换 base64)
|
|
280
|
+
if (debug)
|
|
281
|
+
logger.info('图生图使用原始 URL:', url.slice(0, 100));
|
|
282
|
+
return url;
|
|
283
|
+
}
|
|
284
|
+
// 转换为 base64
|
|
246
285
|
try {
|
|
247
286
|
const res = await axios_1.default.get(url, {
|
|
248
287
|
responseType: 'arraybuffer',
|
|
249
288
|
timeout: 30000,
|
|
250
289
|
});
|
|
251
|
-
// 压缩图片
|
|
252
290
|
const compressed = await compressImage(Buffer.from(res.data));
|
|
253
291
|
return `data:image/jpeg;base64,${compressed.toString('base64')}`;
|
|
254
292
|
}
|
|
@@ -257,6 +295,7 @@ async function apply(ctx, cfg) {
|
|
|
257
295
|
throw new Error('图片下载失败,请检查 selfUrl 是否可访问');
|
|
258
296
|
}
|
|
259
297
|
}
|
|
298
|
+
// ==========================================================
|
|
260
299
|
// 统一发送图片函数
|
|
261
300
|
async function sendImage(session, imgUrl) {
|
|
262
301
|
const trimmed = imgUrl.trim();
|
|
@@ -401,6 +440,68 @@ async function apply(ctx, cfg) {
|
|
|
401
440
|
}
|
|
402
441
|
return { success, fail };
|
|
403
442
|
}
|
|
443
|
+
// ==================== 预置提示词处理函数 ====================
|
|
444
|
+
/**
|
|
445
|
+
* 获取所有启用的预置提示词配置
|
|
446
|
+
*/
|
|
447
|
+
function getEnabledPresets() {
|
|
448
|
+
if (!cfg.enablePresets || !cfg.presets)
|
|
449
|
+
return [];
|
|
450
|
+
return cfg.presets.filter((p) => p.enable && p.text);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* 根据指令名查找匹配的预置提示词
|
|
454
|
+
* @param cmd 指令名,如 "draw0"
|
|
455
|
+
*/
|
|
456
|
+
function findPresetByCommand(cmd) {
|
|
457
|
+
const presets = getEnabledPresets();
|
|
458
|
+
for (const preset of presets) {
|
|
459
|
+
const presetCmd = preset.command?.trim();
|
|
460
|
+
if (presetCmd && presetCmd === cmd) {
|
|
461
|
+
return preset;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* 根据用户 prompt 关键词匹配预置提示词
|
|
468
|
+
* @param prompt 用户输入的 prompt
|
|
469
|
+
*/
|
|
470
|
+
function findPresetsByKeyword(prompt) {
|
|
471
|
+
const presets = getEnabledPresets();
|
|
472
|
+
const matched = [];
|
|
473
|
+
if (!prompt)
|
|
474
|
+
return matched;
|
|
475
|
+
const lowerPrompt = prompt.toLowerCase();
|
|
476
|
+
for (const preset of presets) {
|
|
477
|
+
if (preset.enableKeywordMatch && preset.keyword) {
|
|
478
|
+
const keywords = preset.keyword.split(/[,,|\/\s]+/).map((k) => k.trim().toLowerCase()).filter(Boolean);
|
|
479
|
+
for (const kw of keywords) {
|
|
480
|
+
if (lowerPrompt.includes(kw)) {
|
|
481
|
+
matched.push(preset);
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return matched;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* 拼接预置提示词和用户 prompt
|
|
491
|
+
* @param prompt 用户输入的原始 prompt
|
|
492
|
+
* @param presets 要应用的预置提示词列表
|
|
493
|
+
*/
|
|
494
|
+
function buildPromptWithPresets(prompt, presets) {
|
|
495
|
+
if (!presets || presets.length === 0)
|
|
496
|
+
return prompt;
|
|
497
|
+
const presetTexts = presets.map((p) => p.text.trim()).filter(Boolean);
|
|
498
|
+
if (presetTexts.length === 0)
|
|
499
|
+
return prompt;
|
|
500
|
+
const combinedPreset = presetTexts.join(',');
|
|
501
|
+
// 预置提示词放在前面,用户 prompt 在后面
|
|
502
|
+
return `${combinedPreset},${prompt}`;
|
|
503
|
+
}
|
|
504
|
+
// ==========================================================
|
|
404
505
|
// ==================== 核心生成函数 ====================
|
|
405
506
|
async function generate(session, prompt, imageUrl, modelOverride) {
|
|
406
507
|
if (!checkRateLimit()) {
|
|
@@ -417,14 +518,14 @@ async function apply(ctx, cfg) {
|
|
|
417
518
|
const model = modelOverride || cfg.model;
|
|
418
519
|
let content;
|
|
419
520
|
if (imageUrl) {
|
|
420
|
-
const
|
|
421
|
-
if (!
|
|
422
|
-
await safeSend(session, cfg.messages.fail + '
|
|
521
|
+
const processedUrl = await processImageUrl(imageUrl);
|
|
522
|
+
if (!processedUrl) {
|
|
523
|
+
await safeSend(session, cfg.messages.fail + '(图片处理失败)');
|
|
423
524
|
return;
|
|
424
525
|
}
|
|
425
526
|
content = [
|
|
426
527
|
{ type: 'text', text: prompt },
|
|
427
|
-
{ type: 'image_url', image_url: { url:
|
|
528
|
+
{ type: 'image_url', image_url: { url: processedUrl } },
|
|
428
529
|
];
|
|
429
530
|
}
|
|
430
531
|
else {
|
|
@@ -483,14 +584,14 @@ async function apply(ctx, cfg) {
|
|
|
483
584
|
}
|
|
484
585
|
const model = modelOverride || cfg.model;
|
|
485
586
|
const finalPrompt = prompt.replace('{url}', imageUrls.join(', '));
|
|
486
|
-
const
|
|
487
|
-
if (
|
|
488
|
-
await safeSend(session, cfg.messages.fail + '
|
|
587
|
+
const processedUrls = (await Promise.all(imageUrls.map(url => processImageUrl(url)))).filter((url) => url !== null);
|
|
588
|
+
if (processedUrls.length === 0) {
|
|
589
|
+
await safeSend(session, cfg.messages.fail + '(图片处理失败)');
|
|
489
590
|
return;
|
|
490
591
|
}
|
|
491
592
|
const content = [
|
|
492
593
|
{ type: 'text', text: finalPrompt },
|
|
493
|
-
...
|
|
594
|
+
...processedUrls.map(url => ({ type: 'image_url', image_url: { url } })),
|
|
494
595
|
];
|
|
495
596
|
const body = {
|
|
496
597
|
model,
|
|
@@ -577,30 +678,90 @@ async function apply(ctx, cfg) {
|
|
|
577
678
|
}
|
|
578
679
|
return cleanHtmlTags(textParts.join(' '));
|
|
579
680
|
}
|
|
681
|
+
// ==================== 新增:文生图核心逻辑(支持预置提示词)====================
|
|
682
|
+
async function doTxt2Img(session, rawPrompt, explicitPresets) {
|
|
683
|
+
if (!session)
|
|
684
|
+
return;
|
|
685
|
+
if (await isBlacklisted(session.userId)) {
|
|
686
|
+
await safeSend(session, cfg.messages.blacklisted);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (!cfg.enableTxt2Img) {
|
|
690
|
+
await safeSend(session, cfg.messages.txt2imgDisabled);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
let prompt = cleanHtmlTags(rawPrompt || '');
|
|
694
|
+
if (!prompt) {
|
|
695
|
+
await safeSend(session, cfg.messages.empty);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
// 处理预置提示词
|
|
699
|
+
const appliedPresets = [];
|
|
700
|
+
// 1. 显式指定的预置提示词(通过指令触发)
|
|
701
|
+
if (explicitPresets && explicitPresets.length > 0) {
|
|
702
|
+
appliedPresets.push(...explicitPresets);
|
|
703
|
+
}
|
|
704
|
+
// 2. 关键词匹配(仅在未通过指令触发时,或允许叠加时)
|
|
705
|
+
if (cfg.enablePresets) {
|
|
706
|
+
const keywordPresets = findPresetsByKeyword(prompt);
|
|
707
|
+
for (const kp of keywordPresets) {
|
|
708
|
+
// 避免重复添加
|
|
709
|
+
if (!appliedPresets.some((p) => p.text === kp.text)) {
|
|
710
|
+
appliedPresets.push(kp);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
// 拼接预置提示词
|
|
715
|
+
if (appliedPresets.length > 0) {
|
|
716
|
+
prompt = buildPromptWithPresets(prompt, appliedPresets);
|
|
717
|
+
if (debug) {
|
|
718
|
+
logger.info(`应用预置提示词: ${appliedPresets.map((p) => p.command || 'keyword').join(', ')}`);
|
|
719
|
+
logger.info(`最终 prompt: ${prompt.slice(0, 200)}...`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
await safeSend(session, cfg.messages.generating);
|
|
723
|
+
const finalPrompt = cfg.txt2imgPrompt.replace('{prompt}', prompt);
|
|
724
|
+
const model = cfg.txt2imgModel || cfg.model;
|
|
725
|
+
await generate(session, finalPrompt, undefined, model);
|
|
726
|
+
}
|
|
727
|
+
// ==========================================================
|
|
580
728
|
// ==================== 命令注册 ====================
|
|
729
|
+
// 主文生图指令
|
|
581
730
|
const cmd = ctx.command(`${cfg.command} <raw:text>`, 'draw');
|
|
582
731
|
cfg.aliases.forEach((alias) => cmd.alias(alias));
|
|
583
732
|
cmd.action(async ({ session }, raw) => {
|
|
584
733
|
try {
|
|
585
|
-
|
|
586
|
-
return;
|
|
587
|
-
if (await isBlacklisted(session.userId))
|
|
588
|
-
return safeSend(session, cfg.messages.blacklisted);
|
|
589
|
-
if (!cfg.enableTxt2Img)
|
|
590
|
-
return safeSend(session, cfg.messages.txt2imgDisabled);
|
|
591
|
-
const prompt = cleanHtmlTags(raw || '');
|
|
592
|
-
if (!prompt)
|
|
593
|
-
return safeSend(session, cfg.messages.empty);
|
|
594
|
-
await safeSend(session, cfg.messages.generating);
|
|
595
|
-
const finalPrompt = cfg.txt2imgPrompt.replace('{prompt}', prompt);
|
|
596
|
-
const model = cfg.txt2imgModel || cfg.model;
|
|
597
|
-
await generate(session, finalPrompt, undefined, model);
|
|
734
|
+
await doTxt2Img(session, raw);
|
|
598
735
|
}
|
|
599
736
|
catch (e) {
|
|
600
737
|
logger.error('文生图命令异常', e);
|
|
601
738
|
await safeSend(session, cfg.messages.fail);
|
|
602
739
|
}
|
|
603
740
|
});
|
|
741
|
+
// ==================== 新增:预置提示词指令注册 ====================
|
|
742
|
+
if (cfg.enablePresets && cfg.presets) {
|
|
743
|
+
const presets = getEnabledPresets();
|
|
744
|
+
for (let i = 0; i < presets.length; i++) {
|
|
745
|
+
const preset = presets[i];
|
|
746
|
+
const presetCmd = preset.command?.trim() || `draw${i}`;
|
|
747
|
+
// 注册指令
|
|
748
|
+
const pCmd = ctx.command(`${presetCmd} <raw:text>`, `使用预置提示词: ${preset.text.slice(0, 20)}...`);
|
|
749
|
+
pCmd.action(async ({ session }, raw) => {
|
|
750
|
+
try {
|
|
751
|
+
if (debug)
|
|
752
|
+
logger.info(`预置指令触发: ${presetCmd}, 预置文本: ${preset.text.slice(0, 50)}`);
|
|
753
|
+
await doTxt2Img(session, raw, [preset]);
|
|
754
|
+
}
|
|
755
|
+
catch (e) {
|
|
756
|
+
logger.error(`预置指令 ${presetCmd} 异常`, e);
|
|
757
|
+
await safeSend(session, cfg.messages.fail);
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
if (debug)
|
|
761
|
+
logger.info(`注册预置提示词指令: ${presetCmd}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// ==========================================================
|
|
604
765
|
// ==================== 修改:图生图命令支持合并消息 ====================
|
|
605
766
|
const imgCmd = ctx.command(`${cfg.img2imgCommand} <raw:text>`, 'imgdraw');
|
|
606
767
|
cfg.img2imgAliases.forEach((alias) => imgCmd.alias(alias));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-imgdraw-selfuse",
|
|
3
|
-
"description": "修改自ai-image的画图插件,支持openai兼容api,增加base64
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "修改自ai-image的画图插件,支持openai兼容api,增加base64转换自由开启,增加图文合并消息图生图,增加预置提示词",
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|