koishi-plugin-ai-video 0.0.2 → 0.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/index.js +144 -90
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -39,12 +39,12 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
39
39
|
}).description('基本设置'),
|
|
40
40
|
koishi_1.Schema.object({
|
|
41
41
|
proxyEnabled: koishi_1.Schema.boolean().default(false).description('启用代理'),
|
|
42
|
-
proxyProtocol: koishi_1.Schema.union([koishi_1.Schema.const('http'), koishi_1.Schema.const('https')]).default('http'),
|
|
43
|
-
proxyHost: koishi_1.Schema.string().default(''),
|
|
44
|
-
proxyPort: koishi_1.Schema.number().default(8080),
|
|
45
|
-
proxyAuth: koishi_1.Schema.boolean().default(false),
|
|
46
|
-
proxyUsername: koishi_1.Schema.string().default(''),
|
|
47
|
-
proxyPassword: koishi_1.Schema.string().role('secret').default(''),
|
|
42
|
+
proxyProtocol: koishi_1.Schema.union([koishi_1.Schema.const('http'), koishi_1.Schema.const('https')]).default('http').description('代理协议'),
|
|
43
|
+
proxyHost: koishi_1.Schema.string().default('').description('代理主机地址'),
|
|
44
|
+
proxyPort: koishi_1.Schema.number().default(8080).description('代理端口'),
|
|
45
|
+
proxyAuth: koishi_1.Schema.boolean().default(false).description('启用代理认证'),
|
|
46
|
+
proxyUsername: koishi_1.Schema.string().default('').description('代理用户名'),
|
|
47
|
+
proxyPassword: koishi_1.Schema.string().role('secret').default('').description('代理密码'),
|
|
48
48
|
}).description('代理设置'),
|
|
49
49
|
koishi_1.Schema.object({
|
|
50
50
|
useCustomApi: koishi_1.Schema.boolean().default(false).description('使用自定义API'),
|
|
@@ -52,26 +52,30 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
52
52
|
apiKey: koishi_1.Schema.string().role('secret').default('').description('API密钥'),
|
|
53
53
|
model: koishi_1.Schema.string().default('agnes-video-v2.0').description('模型'),
|
|
54
54
|
img2videoModel: koishi_1.Schema.string().default('').description('图生视频模型'),
|
|
55
|
-
videoDuration: koishi_1.Schema.number().default(0).description('
|
|
56
|
-
videoResolution: koishi_1.Schema.string().default('').description('
|
|
55
|
+
videoDuration: koishi_1.Schema.number().default(0).description('默认视频时长(秒)'),
|
|
56
|
+
videoResolution: koishi_1.Schema.string().default('').description('默认视频分辨率(宽x高)'),
|
|
57
57
|
txt2videoPrompt: koishi_1.Schema.string().default('').description('文生视频提示模板'),
|
|
58
58
|
img2videoPrompt: koishi_1.Schema.string().default('').description('图生视频提示模板'),
|
|
59
|
-
customHeaders: koishi_1.Schema.string().role('textarea').default('{}').description('自定义请求头'),
|
|
59
|
+
customHeaders: koishi_1.Schema.string().role('textarea').default('{}').description('自定义请求头(JSON)'),
|
|
60
60
|
}).description('内置API'),
|
|
61
61
|
koishi_1.Schema.object({
|
|
62
|
-
apiStrategy: koishi_1.Schema.union([
|
|
62
|
+
apiStrategy: koishi_1.Schema.union([
|
|
63
|
+
koishi_1.Schema.const('sequence').description('顺序使用'),
|
|
64
|
+
koishi_1.Schema.const('roundrobin').description('轮询使用')
|
|
65
|
+
]).default('roundrobin').description('API调用策略'),
|
|
63
66
|
customApiList: koishi_1.Schema.array(koishi_1.Schema.object({
|
|
64
|
-
enable: koishi_1.Schema.boolean().default(true),
|
|
65
|
-
endpoint: koishi_1.Schema.string().default('https://apihub.agnes-ai.com/v1/videos'),
|
|
66
|
-
apiKey: koishi_1.Schema.string().role('secret').default(''),
|
|
67
|
-
model: koishi_1.Schema.string().default('agnes-video-v2.0'),
|
|
68
|
-
img2videoModel: koishi_1.Schema.string().default(''),
|
|
69
|
-
videoDuration: koishi_1.Schema.number().default(0),
|
|
70
|
-
videoResolution: koishi_1.Schema.string().default(''),
|
|
71
|
-
txt2videoPrompt: koishi_1.Schema.string().default(''),
|
|
72
|
-
img2videoPrompt: koishi_1.Schema.string().default(''),
|
|
67
|
+
enable: koishi_1.Schema.boolean().default(true).description('启用'),
|
|
68
|
+
endpoint: koishi_1.Schema.string().default('https://apihub.agnes-ai.com/v1/videos').description('API端点'),
|
|
69
|
+
apiKey: koishi_1.Schema.string().role('secret').default('').description('API密钥'),
|
|
70
|
+
model: koishi_1.Schema.string().default('agnes-video-v2.0').description('模型'),
|
|
71
|
+
img2videoModel: koishi_1.Schema.string().default('').description('图生视频模型'),
|
|
72
|
+
videoDuration: koishi_1.Schema.number().default(0).description('默认视频时长(秒)'),
|
|
73
|
+
videoResolution: koishi_1.Schema.string().default('').description('默认视频分辨率(宽x高)'),
|
|
74
|
+
txt2videoPrompt: koishi_1.Schema.string().default('').description('文生视频提示模板'),
|
|
75
|
+
img2videoPrompt: koishi_1.Schema.string().default('').description('图生视频提示模板'),
|
|
73
76
|
customHeaders: koishi_1.Schema.string().role('textarea')
|
|
74
|
-
.default('{"Authorization":"Bearer {apiKey}","Content-Type":"application/json"}')
|
|
77
|
+
.default('{"Authorization":"Bearer {apiKey}","Content-Type":"application/json"}')
|
|
78
|
+
.description('自定义请求头(JSON)'),
|
|
75
79
|
bodyTemplate: koishi_1.Schema.string().role('textarea')
|
|
76
80
|
.default(JSON.stringify({
|
|
77
81
|
txt2videoBody: { model: '{model}', prompt: '{prompt}', height: 768, width: 1152, num_frames: 121, frame_rate: 24 },
|
|
@@ -80,41 +84,41 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
80
84
|
pollUrlTemplate: 'https://apihub.agnes-ai.com/agnesapi?video_id={task_id}',
|
|
81
85
|
taskIdPath: 'video_id',
|
|
82
86
|
}, null, 2))
|
|
83
|
-
.description('自定义请求体'),
|
|
87
|
+
.description('自定义请求体(JSON模板)'),
|
|
84
88
|
})).default([]).description('自定义API列表'),
|
|
85
89
|
}).description('自定义API配置'),
|
|
86
90
|
koishi_1.Schema.object({
|
|
87
|
-
blacklistAdmins: koishi_1.Schema.array(String).default([]).description('管理员QQ'),
|
|
91
|
+
blacklistAdmins: koishi_1.Schema.array(String).default([]).description('管理员QQ号'),
|
|
88
92
|
}).description('权限管理'),
|
|
89
93
|
koishi_1.Schema.object({
|
|
90
94
|
messages: koishi_1.Schema.object({
|
|
91
|
-
generating: koishi_1.Schema.string().default('视频生成中,请耐心等待...'),
|
|
92
|
-
enterCollect: koishi_1.Schema.string().default('已进入收集模式,请继续发送图片/文字。发送「开始」触发生成,发送「取消」退出。当前已收集: 0 张图片, 0 段文字'),
|
|
93
|
-
collectUpdate: koishi_1.Schema.string().default('当前已收集: {images} 张图片, 文字已更新'),
|
|
94
|
-
collectTimeout: koishi_1.Schema.string().default('收集超时,已自动退出'),
|
|
95
|
-
empty: koishi_1.Schema.string().default('[提示] 请输入提示词或上传图片'),
|
|
96
|
-
noApi: koishi_1.Schema.string().default('[提示] 未配置可用API'),
|
|
97
|
-
fail: koishi_1.Schema.string().default('[提示] 视频生成失败'),
|
|
98
|
-
noContent: koishi_1.Schema.string().default('(未返回任何视频内容)'),
|
|
99
|
-
templateError: koishi_1.Schema.string().default('(模板配置错误)'),
|
|
100
|
-
txt2videoDisabled: koishi_1.Schema.string().default('[提示] 文生视频功能未启用'),
|
|
101
|
-
img2videoDisabled: koishi_1.Schema.string().default('[提示] 图生视频功能未启用'),
|
|
102
|
-
rateLimit: koishi_1.Schema.string().default('[提示] 调用次数已达上限'),
|
|
103
|
-
needAssets: koishi_1.Schema.string().default('[提示] 图生视频需要正确配置 assets 服务'),
|
|
104
|
-
blacklisted: koishi_1.Schema.string().default('[提示] 你已被加入黑名单'),
|
|
105
|
-
noPermission: koishi_1.Schema.string().default('[提示] 无权限管理黑名单'),
|
|
106
|
-
blacklistAddSuccess: koishi_1.Schema.string().default('已将 {targets} 加入黑名单'),
|
|
107
|
-
blacklistRemoveSuccess: koishi_1.Schema.string().default('已将 {targets} 移出黑名单'),
|
|
108
|
-
blacklistAddFail: koishi_1.Schema.string().default('{targets} 已在黑名单或无效'),
|
|
109
|
-
blacklistRemoveFail: koishi_1.Schema.string().default('{targets} 不在黑名单'),
|
|
110
|
-
invalidUserId: koishi_1.Schema.string().default('无效QQ号:{targets}'),
|
|
111
|
-
blacklistListEmpty: koishi_1.Schema.string().default('黑名单为空'),
|
|
112
|
-
blacklistListTitle: koishi_1.Schema.string().default('当前黑名单:'),
|
|
113
|
-
noLastTask: koishi_1.Schema.string().default('没有上一次记录,无法重绘'),
|
|
114
|
-
redrawing: koishi_1.Schema.string().default('正在重绘上一次文生视频...'),
|
|
115
|
-
redrawImg2Video: koishi_1.Schema.string().default('[提示] 重绘仅支持文生视频'),
|
|
116
|
-
cancelCollect: koishi_1.Schema.string().default('已取消收集模式'),
|
|
117
|
-
pollWaiting: koishi_1.Schema.string().default('视频生成中(异步轮询),请稍后...'),
|
|
95
|
+
generating: koishi_1.Schema.string().default('视频生成中,请耐心等待...').description('生成中提示'),
|
|
96
|
+
enterCollect: koishi_1.Schema.string().default('已进入收集模式,请继续发送图片/文字。发送「开始」触发生成,发送「取消」退出。当前已收集: 0 张图片, 0 段文字').description('进入收集模式提示'),
|
|
97
|
+
collectUpdate: koishi_1.Schema.string().default('当前已收集: {images} 张图片, 文字已更新').description('收集更新提示'),
|
|
98
|
+
collectTimeout: koishi_1.Schema.string().default('收集超时,已自动退出').description('收集超时提示'),
|
|
99
|
+
empty: koishi_1.Schema.string().default('[提示] 请输入提示词或上传图片').description('空输入提示'),
|
|
100
|
+
noApi: koishi_1.Schema.string().default('[提示] 未配置可用API').description('无API提示'),
|
|
101
|
+
fail: koishi_1.Schema.string().default('[提示] 视频生成失败').description('生成失败提示'),
|
|
102
|
+
noContent: koishi_1.Schema.string().default('(未返回任何视频内容)').description('无内容提示'),
|
|
103
|
+
templateError: koishi_1.Schema.string().default('(模板配置错误)').description('模板错误提示'),
|
|
104
|
+
txt2videoDisabled: koishi_1.Schema.string().default('[提示] 文生视频功能未启用').description('文生视频禁用提示'),
|
|
105
|
+
img2videoDisabled: koishi_1.Schema.string().default('[提示] 图生视频功能未启用').description('图生视频禁用提示'),
|
|
106
|
+
rateLimit: koishi_1.Schema.string().default('[提示] 调用次数已达上限').description('频率限制提示'),
|
|
107
|
+
needAssets: koishi_1.Schema.string().default('[提示] 图生视频需要正确配置 assets 服务').description('需要Assets提示'),
|
|
108
|
+
blacklisted: koishi_1.Schema.string().default('[提示] 你已被加入黑名单').description('黑名单提示'),
|
|
109
|
+
noPermission: koishi_1.Schema.string().default('[提示] 无权限管理黑名单').description('无权限提示'),
|
|
110
|
+
blacklistAddSuccess: koishi_1.Schema.string().default('已将 {targets} 加入黑名单').description('添加黑名单成功提示'),
|
|
111
|
+
blacklistRemoveSuccess: koishi_1.Schema.string().default('已将 {targets} 移出黑名单').description('移除黑名单成功提示'),
|
|
112
|
+
blacklistAddFail: koishi_1.Schema.string().default('{targets} 已在黑名单或无效').description('添加黑名单失败提示'),
|
|
113
|
+
blacklistRemoveFail: koishi_1.Schema.string().default('{targets} 不在黑名单').description('移除黑名单失败提示'),
|
|
114
|
+
invalidUserId: koishi_1.Schema.string().default('无效QQ号:{targets}').description('无效用户ID提示'),
|
|
115
|
+
blacklistListEmpty: koishi_1.Schema.string().default('黑名单为空').description('黑名单为空提示'),
|
|
116
|
+
blacklistListTitle: koishi_1.Schema.string().default('当前黑名单:').description('黑名单标题提示'),
|
|
117
|
+
noLastTask: koishi_1.Schema.string().default('没有上一次记录,无法重绘').description('无上一次任务提示'),
|
|
118
|
+
redrawing: koishi_1.Schema.string().default('正在重绘上一次文生视频...').description('重绘中文生视频提示'),
|
|
119
|
+
redrawImg2Video: koishi_1.Schema.string().default('[提示] 重绘仅支持文生视频').description('重绘图生视频提示'),
|
|
120
|
+
cancelCollect: koishi_1.Schema.string().default('已取消收集模式').description('取消收集提示'),
|
|
121
|
+
pollWaiting: koishi_1.Schema.string().default('视频生成中(异步轮询),请稍后...').description('轮询等待提示'),
|
|
118
122
|
}).description('消息文本'),
|
|
119
123
|
}).description('消息文本'),
|
|
120
124
|
]);
|
|
@@ -147,8 +151,6 @@ async function apply(ctx, cfg) {
|
|
|
147
151
|
return apiCallTimestamps.length + 1 <= cfg.rateLimit;
|
|
148
152
|
}
|
|
149
153
|
function recordApiCall() { apiCallTimestamps.push(Date.now()); }
|
|
150
|
-
const BUILTIN_TXT2VIDEO = { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}' };
|
|
151
|
-
const BUILTIN_IMG2VIDEO = { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}', image_url: '{url}' };
|
|
152
154
|
function parseApiEntry(entry) {
|
|
153
155
|
if (!entry.endpoint)
|
|
154
156
|
return null;
|
|
@@ -167,8 +169,8 @@ async function apply(ctx, cfg) {
|
|
|
167
169
|
if (entry.bodyTemplate) {
|
|
168
170
|
try {
|
|
169
171
|
const tmpl = JSON.parse(entry.bodyTemplate);
|
|
170
|
-
txt2videoBody = tmpl.txt2videoBody ||
|
|
171
|
-
img2videoBody = tmpl.img2videoBody ||
|
|
172
|
+
txt2videoBody = tmpl.txt2videoBody || { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}' };
|
|
173
|
+
img2videoBody = tmpl.img2videoBody || { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}', image_url: '{url}' };
|
|
172
174
|
responseVideoPath = tmpl.responseVideoPath || 'video_url';
|
|
173
175
|
pollUrlTemplate = tmpl.pollUrlTemplate || '';
|
|
174
176
|
taskIdPath = tmpl.taskIdPath || '';
|
|
@@ -178,8 +180,8 @@ async function apply(ctx, cfg) {
|
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
else {
|
|
181
|
-
txt2videoBody =
|
|
182
|
-
img2videoBody =
|
|
183
|
+
txt2videoBody = { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}' };
|
|
184
|
+
img2videoBody = { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}', image_url: '{url}' };
|
|
183
185
|
responseVideoPath = 'video_url';
|
|
184
186
|
pollUrlTemplate = '';
|
|
185
187
|
taskIdPath = '';
|
|
@@ -215,8 +217,8 @@ async function apply(ctx, cfg) {
|
|
|
215
217
|
return {
|
|
216
218
|
endpoint: cfg.apiEndpoint || 'https://apihub.agnes-ai.com/v1/videos',
|
|
217
219
|
headers,
|
|
218
|
-
txt2videoBody:
|
|
219
|
-
img2videoBody:
|
|
220
|
+
txt2videoBody: { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}' },
|
|
221
|
+
img2videoBody: { model: '{model}', prompt: '{prompt}', duration: '{duration}', size: '{size}', image_url: '{url}' },
|
|
220
222
|
responseVideoPath: 'video_url',
|
|
221
223
|
pollUrlTemplate: '',
|
|
222
224
|
taskIdPath: '',
|
|
@@ -249,15 +251,27 @@ async function apply(ctx, cfg) {
|
|
|
249
251
|
return buildBuiltinApi();
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
|
-
function resolveTemplate(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
254
|
+
function resolveTemplate(templateObj, vars) {
|
|
255
|
+
if (templateObj === null || templateObj === undefined)
|
|
256
|
+
return templateObj;
|
|
257
|
+
if (typeof templateObj === 'string') {
|
|
258
|
+
const match = templateObj.match(/^\{(\w+)\}$/);
|
|
259
|
+
if (match && vars.hasOwnProperty(match[1])) {
|
|
260
|
+
return vars[match[1]];
|
|
261
|
+
}
|
|
262
|
+
return templateObj;
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(templateObj)) {
|
|
265
|
+
return templateObj.map(item => resolveTemplate(item, vars));
|
|
266
|
+
}
|
|
267
|
+
if (typeof templateObj === 'object') {
|
|
268
|
+
const result = {};
|
|
269
|
+
for (const key of Object.keys(templateObj)) {
|
|
270
|
+
result[key] = resolveTemplate(templateObj[key], vars);
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
return templateObj;
|
|
261
275
|
}
|
|
262
276
|
function getValueByPath(obj, path) {
|
|
263
277
|
if (!obj || !path)
|
|
@@ -333,7 +347,7 @@ async function apply(ctx, cfg) {
|
|
|
333
347
|
logger.error('发送失败', e);
|
|
334
348
|
}
|
|
335
349
|
}
|
|
336
|
-
async function
|
|
350
|
+
async function sendSingleVideo(session, url) {
|
|
337
351
|
const mode = cfg.videoSendMode;
|
|
338
352
|
if (mode === 'url')
|
|
339
353
|
await safeSend(session, url);
|
|
@@ -366,7 +380,12 @@ async function apply(ctx, cfg) {
|
|
|
366
380
|
if (promptTemplate)
|
|
367
381
|
finalPrompt = promptTemplate.replace('{prompt}', prompt).replace('{url}', imageUrl);
|
|
368
382
|
const bodyTemplate = isImg2Video ? api.img2videoBody : api.txt2videoBody;
|
|
369
|
-
const vars = {
|
|
383
|
+
const vars = {
|
|
384
|
+
model,
|
|
385
|
+
prompt: finalPrompt,
|
|
386
|
+
duration,
|
|
387
|
+
size: resolution,
|
|
388
|
+
};
|
|
370
389
|
if (isImg2Video)
|
|
371
390
|
vars.url = imageUrl;
|
|
372
391
|
let body;
|
|
@@ -374,10 +393,13 @@ async function apply(ctx, cfg) {
|
|
|
374
393
|
body = resolveTemplate(bodyTemplate, vars);
|
|
375
394
|
}
|
|
376
395
|
catch {
|
|
377
|
-
|
|
396
|
+
await safeSend(session, cfg.messages.fail + cfg.messages.templateError);
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
if (!validateEndpoint(api.endpoint)) {
|
|
400
|
+
await safeSend(session, cfg.messages.fail + '(端点无效)');
|
|
401
|
+
return null;
|
|
378
402
|
}
|
|
379
|
-
if (!validateEndpoint(api.endpoint))
|
|
380
|
-
return safeSend(session, cfg.messages.fail + '(端点无效)');
|
|
381
403
|
const sensitive = api.headers?.Authorization?.split(' ')[1] || '';
|
|
382
404
|
if (debug)
|
|
383
405
|
logger.info('API请求', JSON.stringify(sanitizeForLog(body, sensitive)));
|
|
@@ -393,32 +415,62 @@ async function apply(ctx, cfg) {
|
|
|
393
415
|
if (cfg.pollEnabled && api.taskIdPath) {
|
|
394
416
|
const taskId = getValueByPath(res, api.taskIdPath);
|
|
395
417
|
if (taskId) {
|
|
396
|
-
const pollUrl = api.pollUrlTemplate.replace('{
|
|
397
|
-
safeSend(session, cfg.messages.pollWaiting);
|
|
418
|
+
const pollUrl = api.pollUrlTemplate.replace('{task_id}', taskId);
|
|
419
|
+
await safeSend(session, cfg.messages.pollWaiting);
|
|
398
420
|
res = await pollForResult(pollUrl, api.headers, cfg.pollInterval, cfg.pollTimeout);
|
|
399
421
|
}
|
|
400
422
|
}
|
|
401
423
|
const videoUrl = getValueByPath(res, api.responseVideoPath) || findVideoUrl(res);
|
|
402
|
-
|
|
403
|
-
await sendVideo(session, videoUrl);
|
|
404
|
-
else
|
|
405
|
-
await safeSend(session, cfg.messages.fail + cfg.messages.noContent);
|
|
406
|
-
const userId = `${session.guildId || 'private'}-${session.userId}`;
|
|
407
|
-
lastTaskMap.set(userId, { prompt, imageUrl, isImg2Video, model });
|
|
424
|
+
return videoUrl || null;
|
|
408
425
|
}
|
|
409
426
|
catch (err) {
|
|
410
427
|
logger.error('视频生成失败', err);
|
|
411
|
-
safeSend(session, cfg.messages.fail + ' [' + (err.message?.slice(0, 100) || '未知错误') + ']');
|
|
428
|
+
await safeSend(session, cfg.messages.fail + ' [' + (err.message?.slice(0, 100) || '未知错误') + ']');
|
|
429
|
+
return null;
|
|
412
430
|
}
|
|
413
431
|
}
|
|
414
|
-
async function
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
432
|
+
async function generateVideos(session, prompt, imageUrl, count) {
|
|
433
|
+
const videoUrls = [];
|
|
434
|
+
for (let i = 0; i < count; i++) {
|
|
435
|
+
if (!checkRateLimit()) {
|
|
436
|
+
await safeSend(session, cfg.messages.rateLimit);
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
const api = getApi();
|
|
440
|
+
if (!api) {
|
|
441
|
+
await safeSend(session, cfg.messages.noApi);
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
recordApiCall();
|
|
445
|
+
const url = await customGenerateVideo(session, api, prompt, imageUrl);
|
|
446
|
+
if (url)
|
|
447
|
+
videoUrls.push(url);
|
|
448
|
+
if (i < count - 1)
|
|
449
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
450
|
+
}
|
|
451
|
+
if (videoUrls.length === 0) {
|
|
452
|
+
await safeSend(session, cfg.messages.fail + cfg.messages.noContent);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (videoUrls.length === 1 || !cfg.enableForward) {
|
|
456
|
+
for (const url of videoUrls) {
|
|
457
|
+
await sendSingleVideo(session, url);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
const children = videoUrls.map(url => (0, koishi_1.h)('message', koishi_1.h.video(url)));
|
|
462
|
+
try {
|
|
463
|
+
await safeSend(session, (0, koishi_1.h)('message', { forward: true }, ...children));
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
for (const url of videoUrls)
|
|
467
|
+
await sendSingleVideo(session, url);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const userId = `${session.guildId || 'private'}-${session.userId}`;
|
|
471
|
+
if (videoUrls.length > 0) {
|
|
472
|
+
lastTaskMap.set(userId, { prompt, imageUrl, isImg2Video: !!imageUrl, model: 'multiple' });
|
|
473
|
+
}
|
|
422
474
|
}
|
|
423
475
|
function startTimer(session, key, collect) {
|
|
424
476
|
return setTimeout(() => {
|
|
@@ -459,6 +511,8 @@ async function apply(ctx, cfg) {
|
|
|
459
511
|
await safeSend(session, cfg.messages.enterCollect);
|
|
460
512
|
});
|
|
461
513
|
ctx.on('message', async (session) => {
|
|
514
|
+
if (session.command)
|
|
515
|
+
return;
|
|
462
516
|
if (!session || !session.elements)
|
|
463
517
|
return;
|
|
464
518
|
const key = `${session.guildId || 'private'}-${session.userId}`;
|
|
@@ -478,7 +532,7 @@ async function apply(ctx, cfg) {
|
|
|
478
532
|
if (!collect.prompt && !collect.imageUrl)
|
|
479
533
|
return safeSend(session, cfg.messages.empty);
|
|
480
534
|
await safeSend(session, cfg.messages.generating);
|
|
481
|
-
return
|
|
535
|
+
return generateVideos(session, collect.prompt || '默认', collect.imageUrl, cfg.maxVideos);
|
|
482
536
|
}
|
|
483
537
|
if (imgs.length > 0 && !collect.imageUrl) {
|
|
484
538
|
const assets = ctx.assets;
|
|
@@ -515,7 +569,7 @@ async function apply(ctx, cfg) {
|
|
|
515
569
|
if (last.isImg2Video)
|
|
516
570
|
return safeSend(session, cfg.messages.redrawImg2Video);
|
|
517
571
|
await safeSend(session, cfg.messages.redrawing);
|
|
518
|
-
return
|
|
572
|
+
return generateVideos(session, last.prompt, '', cfg.maxVideos);
|
|
519
573
|
});
|
|
520
574
|
function isValidQQ(id) { return /^\d{5,11}$/.test(id); }
|
|
521
575
|
async function isBlacklisted(userId) {
|