koishi-plugin-aka-ai-generator 0.7.6 → 0.7.8
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 +224 -100
- package/lib/services/UserManager.d.ts +24 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -914,7 +914,7 @@ var YunwuVideoProvider = class {
|
|
|
914
914
|
} else {
|
|
915
915
|
duration = 25;
|
|
916
916
|
}
|
|
917
|
-
const
|
|
917
|
+
const buildRequestBody = /* @__PURE__ */ __name((watermark) => ({
|
|
918
918
|
images: [`data:${mimeType};base64,${imageBase64}`],
|
|
919
919
|
model: this.config.modelId,
|
|
920
920
|
orientation,
|
|
@@ -922,29 +922,42 @@ var YunwuVideoProvider = class {
|
|
|
922
922
|
size: "large",
|
|
923
923
|
// 高清1080p
|
|
924
924
|
duration,
|
|
925
|
-
watermark
|
|
926
|
-
//
|
|
925
|
+
watermark,
|
|
926
|
+
// 优先无水印;若接口不允许则降级有水印
|
|
927
927
|
private: false
|
|
928
928
|
// 默认视频会发布
|
|
929
|
-
};
|
|
929
|
+
}), "buildRequestBody");
|
|
930
930
|
logger?.info("提交视频生成任务", {
|
|
931
931
|
model: this.config.modelId,
|
|
932
932
|
promptLength: prompt.length,
|
|
933
|
-
duration
|
|
934
|
-
orientation
|
|
933
|
+
duration,
|
|
934
|
+
orientation
|
|
935
935
|
});
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
936
|
+
const doCreate = /* @__PURE__ */ __name(async (watermark) => {
|
|
937
|
+
return await ctx.http.post(
|
|
938
|
+
`${this.config.apiBase}/v1/video/create`,
|
|
939
|
+
buildRequestBody(watermark),
|
|
940
|
+
{
|
|
941
|
+
headers: {
|
|
942
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
943
|
+
"Content-Type": "application/json",
|
|
944
|
+
"Accept": "application/json"
|
|
945
|
+
},
|
|
946
|
+
timeout: this.config.apiTimeout * 1e3
|
|
947
|
+
}
|
|
948
|
+
);
|
|
949
|
+
}, "doCreate");
|
|
950
|
+
let response;
|
|
951
|
+
try {
|
|
952
|
+
response = await doCreate(false);
|
|
953
|
+
} catch (e) {
|
|
954
|
+
logger?.warn("无水印创建任务失败,尝试有水印", { error: sanitizeError(e) });
|
|
955
|
+
response = await doCreate(true);
|
|
956
|
+
}
|
|
957
|
+
if (response?.error || response?.status && response.status >= 400) {
|
|
958
|
+
logger?.warn("无水印创建任务返回错误,尝试有水印", { status: response?.status, error: response?.error, response: response?.data });
|
|
959
|
+
response = await doCreate(true);
|
|
960
|
+
}
|
|
948
961
|
if (response.error) {
|
|
949
962
|
const errorMsg = response.error.message || response.error.type || "创建任务失败";
|
|
950
963
|
throw new Error(sanitizeString(errorMsg));
|
|
@@ -1172,7 +1185,9 @@ var UserManager = class {
|
|
|
1172
1185
|
usersCache = null;
|
|
1173
1186
|
pendingVideoCache = null;
|
|
1174
1187
|
activeTasks = /* @__PURE__ */ new Map();
|
|
1175
|
-
// userId -> requestId
|
|
1188
|
+
// userId -> requestId (图像任务锁)
|
|
1189
|
+
activeVideoTasks = /* @__PURE__ */ new Map();
|
|
1190
|
+
// userId -> requestId (视频任务锁,独立于图像任务)
|
|
1176
1191
|
rateLimitMap = /* @__PURE__ */ new Map();
|
|
1177
1192
|
// userId -> timestamps
|
|
1178
1193
|
securityBlockMap = /* @__PURE__ */ new Map();
|
|
@@ -1191,6 +1206,7 @@ var UserManager = class {
|
|
|
1191
1206
|
}
|
|
1192
1207
|
}
|
|
1193
1208
|
// --- 任务管理 ---
|
|
1209
|
+
// 图像任务锁(原有逻辑保持不变)
|
|
1194
1210
|
startTask(userId) {
|
|
1195
1211
|
if (this.activeTasks.has(userId)) return false;
|
|
1196
1212
|
this.activeTasks.set(userId, "processing");
|
|
@@ -1202,6 +1218,18 @@ var UserManager = class {
|
|
|
1202
1218
|
isTaskActive(userId) {
|
|
1203
1219
|
return this.activeTasks.has(userId);
|
|
1204
1220
|
}
|
|
1221
|
+
// 视频任务锁(独立于图像任务,不影响图像生成)
|
|
1222
|
+
startVideoTask(userId) {
|
|
1223
|
+
if (this.activeVideoTasks.has(userId)) return false;
|
|
1224
|
+
this.activeVideoTasks.set(userId, "processing");
|
|
1225
|
+
return true;
|
|
1226
|
+
}
|
|
1227
|
+
endVideoTask(userId) {
|
|
1228
|
+
this.activeVideoTasks.delete(userId);
|
|
1229
|
+
}
|
|
1230
|
+
isVideoTaskActive(userId) {
|
|
1231
|
+
return this.activeVideoTasks.has(userId);
|
|
1232
|
+
}
|
|
1205
1233
|
// --- 权限管理 ---
|
|
1206
1234
|
isAdmin(userId, config) {
|
|
1207
1235
|
return config.adminUsers && config.adminUsers.includes(userId);
|
|
@@ -1324,6 +1352,61 @@ var UserManager = class {
|
|
|
1324
1352
|
await this.savePendingVideoTasksInternal();
|
|
1325
1353
|
});
|
|
1326
1354
|
}
|
|
1355
|
+
/**
|
|
1356
|
+
* 获取某个用户最近一次未扣费的待结算视频任务
|
|
1357
|
+
*/
|
|
1358
|
+
async getLatestPendingVideoTaskForUser(userId) {
|
|
1359
|
+
const data = await this.loadPendingVideoTasks();
|
|
1360
|
+
const tasks = Object.values(data.tasks).filter((t) => t.userId === userId && !t.charged).sort((a, b) => {
|
|
1361
|
+
const ta = Date.parse(a.createdAt || "") || 0;
|
|
1362
|
+
const tb = Date.parse(b.createdAt || "") || 0;
|
|
1363
|
+
return tb - ta;
|
|
1364
|
+
});
|
|
1365
|
+
return tasks[0] || null;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* 统计某个用户未扣费的待结算视频任务数量
|
|
1369
|
+
*/
|
|
1370
|
+
async countPendingVideoTasksForUser(userId) {
|
|
1371
|
+
const data = await this.loadPendingVideoTasks();
|
|
1372
|
+
return Object.values(data.tasks).filter((t) => t.userId === userId && !t.charged).length;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* 列出某个用户所有未扣费的待结算视频任务
|
|
1376
|
+
*/
|
|
1377
|
+
async listPendingVideoTasksForUser(userId) {
|
|
1378
|
+
const data = await this.loadPendingVideoTasks();
|
|
1379
|
+
return Object.values(data.tasks).filter((t) => t.userId === userId && !t.charged).sort((a, b) => {
|
|
1380
|
+
const ta = Date.parse(a.createdAt || "") || 0;
|
|
1381
|
+
const tb = Date.parse(b.createdAt || "") || 0;
|
|
1382
|
+
return tb - ta;
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* 添加待结算视频任务,并检查上限(默认max=1)
|
|
1387
|
+
* @returns {Promise<{success: boolean, message?: string}>} 成功返回 {success: true},失败返回 {success: false, message: '错误信息'}
|
|
1388
|
+
*/
|
|
1389
|
+
async addPendingVideoTaskWithLimit(task, max = 1) {
|
|
1390
|
+
await this.loadPendingVideoTasks();
|
|
1391
|
+
return await this.pendingLock.acquire(async () => {
|
|
1392
|
+
if (!this.pendingVideoCache) {
|
|
1393
|
+
this.pendingVideoCache = { version: "1.0.0", lastUpdate: (/* @__PURE__ */ new Date()).toISOString(), tasks: {} };
|
|
1394
|
+
}
|
|
1395
|
+
const currentCount = Object.values(this.pendingVideoCache.tasks).filter((t) => t.userId === task.userId && !t.charged).length;
|
|
1396
|
+
if (currentCount >= max) {
|
|
1397
|
+
return {
|
|
1398
|
+
success: false,
|
|
1399
|
+
message: `您当前已有 ${currentCount} 个视频正在生成中(最多允许 ${max} 个),请先使用"查询视频"查看进度或等待完成`
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
if (this.pendingVideoCache.tasks[task.taskId]) {
|
|
1403
|
+
return { success: true };
|
|
1404
|
+
}
|
|
1405
|
+
this.pendingVideoCache.tasks[task.taskId] = task;
|
|
1406
|
+
await this.savePendingVideoTasksInternal();
|
|
1407
|
+
return { success: true };
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1327
1410
|
// 获取特定用户数据
|
|
1328
1411
|
async getUserData(userId, userName) {
|
|
1329
1412
|
await this.loadUsersData();
|
|
@@ -2314,8 +2397,8 @@ ${infoParts.join("\n")}`;
|
|
|
2314
2397
|
if (!limitCheck.allowed) {
|
|
2315
2398
|
return limitCheck.message;
|
|
2316
2399
|
}
|
|
2317
|
-
if (!userManager.
|
|
2318
|
-
return "
|
|
2400
|
+
if (!userManager.startVideoTask(userId)) {
|
|
2401
|
+
return "您有一个视频任务正在进行中,请等待完成";
|
|
2319
2402
|
}
|
|
2320
2403
|
let createdTaskId = null;
|
|
2321
2404
|
try {
|
|
@@ -2350,15 +2433,6 @@ ${infoParts.join("\n")}`;
|
|
|
2350
2433
|
if (!validRatios.includes(ratio)) {
|
|
2351
2434
|
return `宽高比必须是以下之一: ${validRatios.join(", ")}`;
|
|
2352
2435
|
}
|
|
2353
|
-
await session.send(
|
|
2354
|
-
`🎬 开始生成视频...
|
|
2355
|
-
📝 描述:${prompt}
|
|
2356
|
-
⏱️ 时长:${duration}秒
|
|
2357
|
-
📐 宽高比:${ratio}
|
|
2358
|
-
⚠️ 预计需要 1-3 分钟,请耐心等待
|
|
2359
|
-
💡 提示:生成过程中可继续使用其他功能`
|
|
2360
|
-
);
|
|
2361
|
-
const startTime = Date.now();
|
|
2362
2436
|
const taskId = await videoProvider.createVideoTask(
|
|
2363
2437
|
prompt,
|
|
2364
2438
|
imageUrls[0],
|
|
@@ -2368,7 +2442,7 @@ ${infoParts.join("\n")}`;
|
|
|
2368
2442
|
}
|
|
2369
2443
|
);
|
|
2370
2444
|
createdTaskId = taskId;
|
|
2371
|
-
await userManager.
|
|
2445
|
+
const addResult = await userManager.addPendingVideoTaskWithLimit({
|
|
2372
2446
|
taskId,
|
|
2373
2447
|
userId,
|
|
2374
2448
|
userName,
|
|
@@ -2376,64 +2450,119 @@ ${infoParts.join("\n")}`;
|
|
|
2376
2450
|
credits: videoCredits,
|
|
2377
2451
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2378
2452
|
charged: false
|
|
2379
|
-
});
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
const totalTime = Math.floor((Date.now() - startTime) / 1e3);
|
|
2387
|
-
await session.send(`✅ 视频生成完成!(耗时 ${totalTime} 秒)`);
|
|
2388
|
-
} catch (error) {
|
|
2389
|
-
logger.error("视频生成失败", { userId, error: sanitizeError(error) });
|
|
2390
|
-
const errorMsg = error.message || "";
|
|
2391
|
-
if (errorMsg.includes("任务ID:")) {
|
|
2392
|
-
return errorMsg;
|
|
2453
|
+
}, 1);
|
|
2454
|
+
if (!addResult.success) {
|
|
2455
|
+
try {
|
|
2456
|
+
await userManager.deletePendingVideoTask(taskId);
|
|
2457
|
+
} catch {
|
|
2458
|
+
}
|
|
2459
|
+
return addResult.message || "队列已满,请先查询已有任务";
|
|
2393
2460
|
}
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2461
|
+
await session.send("开始生成视频...");
|
|
2462
|
+
} catch (error) {
|
|
2463
|
+
logger.error("视频生成任务提交失败", { userId, error: sanitizeError(error) });
|
|
2464
|
+
if (createdTaskId) {
|
|
2465
|
+
try {
|
|
2466
|
+
await userManager.deletePendingVideoTask(createdTaskId);
|
|
2467
|
+
} catch {
|
|
2468
|
+
}
|
|
2397
2469
|
}
|
|
2398
|
-
|
|
2470
|
+
const errorMsg = error.message || "";
|
|
2471
|
+
return `视频生成任务提交失败:${sanitizeString(errorMsg)}`;
|
|
2399
2472
|
} finally {
|
|
2400
|
-
userManager.
|
|
2473
|
+
userManager.endVideoTask(userId);
|
|
2401
2474
|
}
|
|
2402
2475
|
});
|
|
2403
2476
|
}
|
|
2404
2477
|
if (config.enableVideoGeneration && videoProvider) {
|
|
2405
|
-
ctx.command("查询视频
|
|
2478
|
+
ctx.command("查询视频 [taskId:string]", "查询视频生成状态(不传任务ID则查询自己所有待生成任务)").action(async ({ session }, taskId) => {
|
|
2406
2479
|
if (!session?.userId) return "会话无效";
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
const status = await videoProvider.queryTaskStatus(taskId.trim());
|
|
2413
|
-
if (status.status === "completed" && status.videoUrl) {
|
|
2414
|
-
const trimmedTaskId = taskId.trim();
|
|
2480
|
+
const trimmedTaskId = (taskId || "").trim();
|
|
2481
|
+
if (trimmedTaskId) {
|
|
2482
|
+
try {
|
|
2483
|
+
await session.send("正在查询视频生成状态...");
|
|
2484
|
+
const status = await videoProvider.queryTaskStatus(trimmedTaskId);
|
|
2415
2485
|
const pending = await userManager.getPendingVideoTask(trimmedTaskId);
|
|
2416
2486
|
if (pending && pending.userId && pending.userId !== session.userId) {
|
|
2417
2487
|
return "该任务ID不属于当前用户,无法查询";
|
|
2418
2488
|
}
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2489
|
+
if (status.status === "completed" && status.videoUrl) {
|
|
2490
|
+
await session.send(import_koishi2.h.video(status.videoUrl));
|
|
2491
|
+
if (pending && !pending.charged) {
|
|
2492
|
+
await recordUserUsage(session, pending.commandName, pending.credits, false);
|
|
2493
|
+
await userManager.markPendingVideoTaskCharged(trimmedTaskId);
|
|
2494
|
+
await userManager.deletePendingVideoTask(trimmedTaskId);
|
|
2495
|
+
}
|
|
2496
|
+
return "视频生成完成!";
|
|
2497
|
+
} else if (status.status === "processing" || status.status === "pending") {
|
|
2498
|
+
const progressText = status.progress ? `(进度:${status.progress}%)` : "";
|
|
2499
|
+
return `视频正在生成中${progressText},请稍后再次查询`;
|
|
2500
|
+
} else if (status.status === "failed") {
|
|
2501
|
+
if (pending && !pending.charged) {
|
|
2502
|
+
await userManager.deletePendingVideoTask(trimmedTaskId);
|
|
2503
|
+
}
|
|
2504
|
+
return `视频生成失败:${status.error || "未知错误"}`;
|
|
2505
|
+
} else {
|
|
2506
|
+
return `❓ 未知状态:${status.status}`;
|
|
2507
|
+
}
|
|
2508
|
+
} catch (error) {
|
|
2509
|
+
logger.error("查询视频任务失败", { taskId: trimmedTaskId, error: sanitizeError(error) });
|
|
2510
|
+
return `查询失败:${sanitizeString(error.message)}`;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
try {
|
|
2514
|
+
const pendingTasks = await userManager.listPendingVideoTasksForUser(session.userId);
|
|
2515
|
+
if (pendingTasks.length === 0) {
|
|
2516
|
+
return "你当前没有可查询的待生成视频任务";
|
|
2517
|
+
}
|
|
2518
|
+
await session.send(`正在查询 ${pendingTasks.length} 个视频任务状态...`);
|
|
2519
|
+
let completedCount = 0;
|
|
2520
|
+
let processingCount = 0;
|
|
2521
|
+
let failedCount = 0;
|
|
2522
|
+
const messages = [];
|
|
2523
|
+
for (const task of pendingTasks) {
|
|
2524
|
+
try {
|
|
2525
|
+
const status = await videoProvider.queryTaskStatus(task.taskId);
|
|
2526
|
+
if (status.status === "completed" && status.videoUrl) {
|
|
2527
|
+
await session.send(import_koishi2.h.video(status.videoUrl));
|
|
2528
|
+
if (!task.charged) {
|
|
2529
|
+
await recordUserUsage(session, task.commandName, task.credits, false);
|
|
2530
|
+
await userManager.markPendingVideoTaskCharged(task.taskId);
|
|
2531
|
+
await userManager.deletePendingVideoTask(task.taskId);
|
|
2532
|
+
}
|
|
2533
|
+
completedCount++;
|
|
2534
|
+
messages.push(`任务 ${task.taskId.substring(0, 20)}... 已完成`);
|
|
2535
|
+
} else if (status.status === "processing" || status.status === "pending") {
|
|
2536
|
+
processingCount++;
|
|
2537
|
+
const progressText = status.progress ? `(进度:${status.progress}%)` : "";
|
|
2538
|
+
messages.push(`任务 ${task.taskId.substring(0, 20)}... 生成中${progressText}`);
|
|
2539
|
+
} else if (status.status === "failed") {
|
|
2540
|
+
if (!task.charged) {
|
|
2541
|
+
await userManager.deletePendingVideoTask(task.taskId);
|
|
2542
|
+
}
|
|
2543
|
+
failedCount++;
|
|
2544
|
+
messages.push(`任务 ${task.taskId.substring(0, 20)}... 失败:${status.error || "未知错误"}`);
|
|
2545
|
+
} else {
|
|
2546
|
+
messages.push(`❓ 任务 ${task.taskId.substring(0, 20)}... 状态:${status.status}`);
|
|
2547
|
+
}
|
|
2548
|
+
} catch (error) {
|
|
2549
|
+
logger.error("查询单个视频任务失败", { taskId: task.taskId, error: sanitizeError(error) });
|
|
2550
|
+
messages.push(`⚠️ 任务 ${task.taskId.substring(0, 20)}... 查询失败:${sanitizeString(error.message)}`);
|
|
2424
2551
|
}
|
|
2425
|
-
return "✅ 视频已生成完成!";
|
|
2426
|
-
} else if (status.status === "processing" || status.status === "pending") {
|
|
2427
|
-
const progressText = status.progress ? `(进度:${status.progress}%)` : "";
|
|
2428
|
-
return `⏳ 视频正在生成中${progressText},请稍后再次查询
|
|
2429
|
-
任务ID:${taskId}`;
|
|
2430
|
-
} else if (status.status === "failed") {
|
|
2431
|
-
return `❌ 视频生成失败:${status.error || "未知错误"}`;
|
|
2432
|
-
} else {
|
|
2433
|
-
return `❓ 未知状态:${status.status}`;
|
|
2434
2552
|
}
|
|
2553
|
+
let summary = `查询结果汇总:
|
|
2554
|
+
`;
|
|
2555
|
+
if (completedCount > 0) summary += `已完成:${completedCount} 个
|
|
2556
|
+
`;
|
|
2557
|
+
if (processingCount > 0) summary += `生成中:${processingCount} 个
|
|
2558
|
+
`;
|
|
2559
|
+
if (failedCount > 0) summary += `失败:${failedCount} 个
|
|
2560
|
+
`;
|
|
2561
|
+
summary += `
|
|
2562
|
+
${messages.join("\n")}`;
|
|
2563
|
+
return summary;
|
|
2435
2564
|
} catch (error) {
|
|
2436
|
-
logger.error("
|
|
2565
|
+
logger.error("查询视频任务列表失败", { userId: session.userId, error: sanitizeError(error) });
|
|
2437
2566
|
return `查询失败:${sanitizeString(error.message)}`;
|
|
2438
2567
|
}
|
|
2439
2568
|
});
|
|
@@ -2455,8 +2584,8 @@ ${infoParts.join("\n")}`;
|
|
|
2455
2584
|
if (!limitCheck.allowed) {
|
|
2456
2585
|
return limitCheck.message;
|
|
2457
2586
|
}
|
|
2458
|
-
if (!userManager.
|
|
2459
|
-
return "
|
|
2587
|
+
if (!userManager.startVideoTask(userId)) {
|
|
2588
|
+
return "您有一个视频任务正在进行中,请等待完成";
|
|
2460
2589
|
}
|
|
2461
2590
|
let createdTaskId = null;
|
|
2462
2591
|
try {
|
|
@@ -2472,11 +2601,6 @@ ${infoParts.join("\n")}`;
|
|
|
2472
2601
|
if (extraText) {
|
|
2473
2602
|
finalPrompt += " - " + extraText;
|
|
2474
2603
|
}
|
|
2475
|
-
await session.send(
|
|
2476
|
-
`🎬 开始生成视频(${style.commandName})...
|
|
2477
|
-
📝 描述:${finalPrompt}
|
|
2478
|
-
⏱️ 预计需要 1-3 分钟`
|
|
2479
|
-
);
|
|
2480
2604
|
const taskId = await videoProvider.createVideoTask(
|
|
2481
2605
|
finalPrompt,
|
|
2482
2606
|
imageUrls[0],
|
|
@@ -2486,7 +2610,7 @@ ${infoParts.join("\n")}`;
|
|
|
2486
2610
|
}
|
|
2487
2611
|
);
|
|
2488
2612
|
createdTaskId = taskId;
|
|
2489
|
-
await userManager.
|
|
2613
|
+
const addResult = await userManager.addPendingVideoTaskWithLimit({
|
|
2490
2614
|
taskId,
|
|
2491
2615
|
userId,
|
|
2492
2616
|
userName,
|
|
@@ -2494,27 +2618,27 @@ ${infoParts.join("\n")}`;
|
|
|
2494
2618
|
credits: videoCredits,
|
|
2495
2619
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2496
2620
|
charged: false
|
|
2497
|
-
});
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
await session.send(`✅ 视频生成完成!`);
|
|
2505
|
-
} catch (error) {
|
|
2506
|
-
logger.error("视频风格转换失败", { userId, style: style.commandName, error: sanitizeError(error) });
|
|
2507
|
-
const errorMsg = error.message || "";
|
|
2508
|
-
if (errorMsg.includes("任务ID:")) {
|
|
2509
|
-
return errorMsg;
|
|
2621
|
+
}, 1);
|
|
2622
|
+
if (!addResult.success) {
|
|
2623
|
+
try {
|
|
2624
|
+
await userManager.deletePendingVideoTask(taskId);
|
|
2625
|
+
} catch {
|
|
2626
|
+
}
|
|
2627
|
+
return addResult.message || "队列已满,请先查询已有任务";
|
|
2510
2628
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2629
|
+
await session.send(`开始生成视频(${style.commandName})...`);
|
|
2630
|
+
} catch (error) {
|
|
2631
|
+
logger.error("视频风格转换任务提交失败", { userId, style: style.commandName, error: sanitizeError(error) });
|
|
2632
|
+
if (createdTaskId) {
|
|
2633
|
+
try {
|
|
2634
|
+
await userManager.deletePendingVideoTask(createdTaskId);
|
|
2635
|
+
} catch {
|
|
2636
|
+
}
|
|
2514
2637
|
}
|
|
2515
|
-
|
|
2638
|
+
const errorMsg = error.message || "";
|
|
2639
|
+
return `视频生成任务提交失败:${sanitizeString(errorMsg)}`;
|
|
2516
2640
|
} finally {
|
|
2517
|
-
userManager.
|
|
2641
|
+
userManager.endVideoTask(userId);
|
|
2518
2642
|
}
|
|
2519
2643
|
});
|
|
2520
2644
|
logger.info(`已注册视频风格命令: ${style.commandName}`);
|
|
@@ -67,6 +67,7 @@ export declare class UserManager {
|
|
|
67
67
|
private usersCache;
|
|
68
68
|
private pendingVideoCache;
|
|
69
69
|
private activeTasks;
|
|
70
|
+
private activeVideoTasks;
|
|
70
71
|
private rateLimitMap;
|
|
71
72
|
private securityBlockMap;
|
|
72
73
|
private securityWarningMap;
|
|
@@ -74,6 +75,9 @@ export declare class UserManager {
|
|
|
74
75
|
startTask(userId: string): boolean;
|
|
75
76
|
endTask(userId: string): void;
|
|
76
77
|
isTaskActive(userId: string): boolean;
|
|
78
|
+
startVideoTask(userId: string): boolean;
|
|
79
|
+
endVideoTask(userId: string): void;
|
|
80
|
+
isVideoTaskActive(userId: string): boolean;
|
|
77
81
|
isAdmin(userId: string, config: Config): boolean;
|
|
78
82
|
private loadUsersData;
|
|
79
83
|
private saveUsersDataInternal;
|
|
@@ -86,6 +90,26 @@ export declare class UserManager {
|
|
|
86
90
|
getPendingVideoTask(taskId: string): Promise<PendingVideoTask | null>;
|
|
87
91
|
markPendingVideoTaskCharged(taskId: string): Promise<PendingVideoTask | null>;
|
|
88
92
|
deletePendingVideoTask(taskId: string): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* 获取某个用户最近一次未扣费的待结算视频任务
|
|
95
|
+
*/
|
|
96
|
+
getLatestPendingVideoTaskForUser(userId: string): Promise<PendingVideoTask | null>;
|
|
97
|
+
/**
|
|
98
|
+
* 统计某个用户未扣费的待结算视频任务数量
|
|
99
|
+
*/
|
|
100
|
+
countPendingVideoTasksForUser(userId: string): Promise<number>;
|
|
101
|
+
/**
|
|
102
|
+
* 列出某个用户所有未扣费的待结算视频任务
|
|
103
|
+
*/
|
|
104
|
+
listPendingVideoTasksForUser(userId: string): Promise<PendingVideoTask[]>;
|
|
105
|
+
/**
|
|
106
|
+
* 添加待结算视频任务,并检查上限(默认max=1)
|
|
107
|
+
* @returns {Promise<{success: boolean, message?: string}>} 成功返回 {success: true},失败返回 {success: false, message: '错误信息'}
|
|
108
|
+
*/
|
|
109
|
+
addPendingVideoTaskWithLimit(task: PendingVideoTask, max?: number): Promise<{
|
|
110
|
+
success: boolean;
|
|
111
|
+
message?: string;
|
|
112
|
+
}>;
|
|
89
113
|
getUserData(userId: string, userName: string): Promise<UserData>;
|
|
90
114
|
getAllUsers(): Promise<UsersData>;
|
|
91
115
|
updateUsersBatch(updates: (data: UsersData) => void): Promise<void>;
|