koishi-plugin-best-cave 2.7.3 → 2.7.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/Utils.d.ts +5 -11
- package/lib/index.js +39 -28
- package/package.json +1 -1
package/lib/Utils.d.ts
CHANGED
|
@@ -2,8 +2,6 @@ import { Context, h, Logger, Session } from 'koishi';
|
|
|
2
2
|
import { CaveObject, Config, StoredElement } from './index';
|
|
3
3
|
import { FileManager } from './FileManager';
|
|
4
4
|
import { HashManager, CaveHashObject } from './HashManager';
|
|
5
|
-
import { PendManager } from './PendManager';
|
|
6
|
-
import { AIManager } from './AIManager';
|
|
7
5
|
/**
|
|
8
6
|
* @description 构建一条用于发送的完整回声洞消息,处理不同存储后端的资源链接。
|
|
9
7
|
* @param cave 回声洞对象。
|
|
@@ -69,25 +67,21 @@ export declare function performSimilarityChecks(ctx: Context, config: Config, ha
|
|
|
69
67
|
imageHashesToStore?: Omit<CaveHashObject, 'cave'>[];
|
|
70
68
|
}>;
|
|
71
69
|
/**
|
|
72
|
-
* @description
|
|
70
|
+
* @description 异步处理文件上传,并在成功后更新回声洞状态。
|
|
73
71
|
* @param ctx - Koishi 上下文。
|
|
74
72
|
* @param config - 插件配置。
|
|
75
73
|
* @param fileManager - FileManager 实例,用于保存文件。
|
|
76
74
|
* @param logger - 日志记录器实例。
|
|
77
|
-
* @param reviewManager - ReviewManager 实例,用于提交审核。
|
|
78
75
|
* @param cave - 刚刚在数据库中创建的 `preload` 状态的回声洞对象。
|
|
79
76
|
* @param downloadedMedia - 需要保存的媒体文件及其 Buffer。
|
|
80
77
|
* @param reusableIds - 可复用 ID 的内存缓存。
|
|
81
|
-
* @param session -
|
|
82
|
-
* @
|
|
83
|
-
* @param textHashesToStore - 已预先计算好的、待存入数据库的文本哈希对象数组。
|
|
84
|
-
* @param imageHashesToStore - 已预先计算好的、待存入数据库的图片哈希对象数组。
|
|
85
|
-
* @param aiManager - AIManager 实例,如果启用则用于 AI 分析。
|
|
78
|
+
* @param session - 触发此操作的用户会话。
|
|
79
|
+
* @returns 成功则返回最终状态 ('pending' or 'active'),失败则返回 'delete'。
|
|
86
80
|
*/
|
|
87
|
-
export declare function handleFileUploads(ctx: Context, config: Config, fileManager: FileManager, logger: Logger,
|
|
81
|
+
export declare function handleFileUploads(ctx: Context, config: Config, fileManager: FileManager, logger: Logger, cave: CaveObject, downloadedMedia: {
|
|
88
82
|
fileName: string;
|
|
89
83
|
buffer: Buffer;
|
|
90
|
-
}[], reusableIds: Set<number>, session: Session
|
|
84
|
+
}[], reusableIds: Set<number>, session: Session): Promise<'pending' | 'active' | 'delete'>;
|
|
91
85
|
/**
|
|
92
86
|
* @description 校验会话是否来自指定的管理群组。
|
|
93
87
|
* @param session 当前会话。
|
package/lib/index.js
CHANGED
|
@@ -482,25 +482,18 @@ async function performSimilarityChecks(ctx, config, hashManager, finalElementsFo
|
|
|
482
482
|
return { duplicate: false, textHashesToStore, imageHashesToStore };
|
|
483
483
|
}
|
|
484
484
|
__name(performSimilarityChecks, "performSimilarityChecks");
|
|
485
|
-
async function handleFileUploads(ctx, config, fileManager, logger2,
|
|
485
|
+
async function handleFileUploads(ctx, config, fileManager, logger2, cave, downloadedMedia, reusableIds, session) {
|
|
486
486
|
try {
|
|
487
|
-
if (aiManager) await aiManager.analyzeAndStore(cave, downloadedMedia);
|
|
488
487
|
await Promise.all(downloadedMedia.map((item) => fileManager.saveFile(item.fileName, item.buffer)));
|
|
489
488
|
const needsReview = config.enablePend && session.channelId !== config.adminChannel?.split(":")[1];
|
|
490
489
|
const finalStatus = needsReview ? "pending" : "active";
|
|
491
490
|
await ctx.database.upsert("cave", [{ id: cave.id, status: finalStatus }]);
|
|
492
|
-
|
|
493
|
-
const allHashesToInsert = [...textHashesToStore, ...imageHashesToStore].map((h5) => ({ ...h5, cave: cave.id }));
|
|
494
|
-
if (allHashesToInsert.length > 0) await ctx.database.upsert("cave_hash", allHashesToInsert);
|
|
495
|
-
}
|
|
496
|
-
if (finalStatus === "pending" && reviewManager) {
|
|
497
|
-
const [finalCave] = await ctx.database.get("cave", { id: cave.id });
|
|
498
|
-
if (finalCave) reviewManager.sendForPend(finalCave);
|
|
499
|
-
}
|
|
491
|
+
return finalStatus;
|
|
500
492
|
} catch (fileProcessingError) {
|
|
501
493
|
logger2.error(`回声洞(${cave.id})文件处理失败:`, fileProcessingError);
|
|
502
494
|
await ctx.database.upsert("cave", [{ id: cave.id, status: "delete" }]);
|
|
503
495
|
cleanupPendingDeletions(ctx, fileManager, logger2, reusableIds);
|
|
496
|
+
return "delete";
|
|
504
497
|
}
|
|
505
498
|
}
|
|
506
499
|
__name(handleFileUploads, "handleFileUploads");
|
|
@@ -1164,9 +1157,17 @@ var AIManager = class {
|
|
|
1164
1157
|
if (parts.length <= 1) return { payload: {} };
|
|
1165
1158
|
try {
|
|
1166
1159
|
const schema = JSON.parse(schemaString);
|
|
1167
|
-
return {
|
|
1160
|
+
return {
|
|
1161
|
+
payload: {
|
|
1162
|
+
contents: [{ parts }],
|
|
1163
|
+
generationConfig: {
|
|
1164
|
+
responseMimeType: "application/json",
|
|
1165
|
+
responseSchema: schema
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1168
1169
|
} catch (error) {
|
|
1169
|
-
this.logger.error("
|
|
1170
|
+
this.logger.error("分析 JSON Schema 解析失败:", error);
|
|
1170
1171
|
return { payload: {} };
|
|
1171
1172
|
}
|
|
1172
1173
|
}
|
|
@@ -1182,15 +1183,20 @@ var AIManager = class {
|
|
|
1182
1183
|
new_content: { text: formatContent(newElements) },
|
|
1183
1184
|
existing_contents: existingCaves.map((cave) => ({ id: cave.id, text: formatContent(cave.elements) }))
|
|
1184
1185
|
});
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
以下是需要处理的数据:
|
|
1188
|
-
${payloadContent}`;
|
|
1186
|
+
const parts = [{ text: this.config.aiCheckPrompt }, { text: payloadContent }];
|
|
1189
1187
|
try {
|
|
1190
1188
|
const schema = JSON.parse(this.config.aiCheckSchema);
|
|
1191
|
-
return {
|
|
1189
|
+
return {
|
|
1190
|
+
payload: {
|
|
1191
|
+
contents: [{ parts }],
|
|
1192
|
+
generationConfig: {
|
|
1193
|
+
responseMimeType: "application/json",
|
|
1194
|
+
responseSchema: schema
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1192
1198
|
} catch (error) {
|
|
1193
|
-
this.logger.error("
|
|
1199
|
+
this.logger.error("查重 JSON Schema 解析失败:", error);
|
|
1194
1200
|
return { payload: {} };
|
|
1195
1201
|
}
|
|
1196
1202
|
}
|
|
@@ -1201,6 +1207,7 @@ ${payloadContent}`;
|
|
|
1201
1207
|
*/
|
|
1202
1208
|
parseAnalysisResponse(response) {
|
|
1203
1209
|
try {
|
|
1210
|
+
if (!response?.candidates?.[0]?.content?.parts?.[0]?.text) throw new Error("分析响应解析失败");
|
|
1204
1211
|
const content = response.candidates[0].content.parts[0].text;
|
|
1205
1212
|
const parsed = JSON.parse(content);
|
|
1206
1213
|
const keywords = Array.isArray(parsed.keywords) ? parsed.keywords : [];
|
|
@@ -1211,7 +1218,7 @@ ${payloadContent}`;
|
|
|
1211
1218
|
};
|
|
1212
1219
|
} catch (error) {
|
|
1213
1220
|
this.logger.error("分析响应解析失败:", error, "原始响应:", JSON.stringify(response));
|
|
1214
|
-
|
|
1221
|
+
throw error;
|
|
1215
1222
|
}
|
|
1216
1223
|
}
|
|
1217
1224
|
/**
|
|
@@ -1221,13 +1228,14 @@ ${payloadContent}`;
|
|
|
1221
1228
|
*/
|
|
1222
1229
|
parseDedupeResponse(response) {
|
|
1223
1230
|
try {
|
|
1231
|
+
if (!response?.candidates?.[0]?.content?.parts?.[0]?.text) throw new Error("查重响应解析失败");
|
|
1224
1232
|
const content = response.candidates[0].content.parts[0].text;
|
|
1225
1233
|
const parsed = JSON.parse(content);
|
|
1226
1234
|
if (parsed.duplicate === true && parsed.id) return { duplicate: true, id: Number(parsed.id) };
|
|
1227
1235
|
return { duplicate: false };
|
|
1228
1236
|
} catch (error) {
|
|
1229
1237
|
this.logger.error("查重响应解析失败:", error, "原始响应:", JSON.stringify(response));
|
|
1230
|
-
|
|
1238
|
+
throw error;
|
|
1231
1239
|
}
|
|
1232
1240
|
}
|
|
1233
1241
|
};
|
|
@@ -1409,22 +1417,25 @@ function apply(ctx, config) {
|
|
|
1409
1417
|
}
|
|
1410
1418
|
const userName = (config.enableName ? await profileManager.getNickname(session.userId) : null) || session.username;
|
|
1411
1419
|
const needsReview = config.enablePend && session.channelId !== config.adminChannel?.split(":")[1];
|
|
1412
|
-
|
|
1420
|
+
let finalStatus = hasMedia ? "preload" : needsReview ? "pending" : "active";
|
|
1413
1421
|
const newCave = await ctx.database.create("cave", {
|
|
1414
1422
|
id: newId,
|
|
1415
1423
|
elements: finalElementsForDb,
|
|
1416
1424
|
channelId: session.channelId,
|
|
1417
1425
|
userId: session.userId,
|
|
1418
1426
|
userName,
|
|
1419
|
-
status:
|
|
1427
|
+
status: finalStatus,
|
|
1420
1428
|
time: creationTime
|
|
1421
1429
|
});
|
|
1422
|
-
if (hasMedia)
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
if (aiManager) await aiManager.analyzeAndStore(newCave);
|
|
1426
|
-
if (hashManager
|
|
1427
|
-
|
|
1430
|
+
if (hasMedia) finalStatus = await handleFileUploads(ctx, config, fileManager, logger, newCave, downloadedMedia, reusableIds, session);
|
|
1431
|
+
if (finalStatus !== "preload" && finalStatus !== "delete") {
|
|
1432
|
+
newCave.status = finalStatus;
|
|
1433
|
+
if (aiManager) await aiManager.analyzeAndStore(newCave, downloadedMedia);
|
|
1434
|
+
if (hashManager) {
|
|
1435
|
+
const allHashesToInsert = [...textHashesToStore, ...imageHashesToStore].map((h5) => ({ ...h5, cave: newCave.id }));
|
|
1436
|
+
if (allHashesToInsert.length > 0) await ctx.database.upsert("cave_hash", allHashesToInsert);
|
|
1437
|
+
}
|
|
1438
|
+
if (finalStatus === "pending" && reviewManager) reviewManager.sendForPend(newCave);
|
|
1428
1439
|
}
|
|
1429
1440
|
return needsReview ? `提交成功,序号为(${newCave.id})` : `添加成功,序号为(${newCave.id})`;
|
|
1430
1441
|
} catch (error) {
|