koishi-plugin-best-cave 2.7.2 → 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.
Files changed (3) hide show
  1. package/lib/Utils.d.ts +12 -11
  2. package/lib/index.js +148 -133
  3. 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,22 +67,25 @@ 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
- * @param hashManager - HashManager 实例,如果启用则用于哈希计算和比较。
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, reviewManager: PendManager, cave: CaveObject, downloadedMedia: {
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, hashManager: HashManager, textHashesToStore: Omit<CaveHashObject, 'cave'>[], imageHashesToStore: Omit<CaveHashObject, 'cave'>[], aiManager: AIManager | null): Promise<void>;
84
+ }[], reusableIds: Set<number>, session: Session): Promise<'pending' | 'active' | 'delete'>;
85
+ /**
86
+ * @description 校验会话是否来自指定的管理群组。
87
+ * @param session 当前会话。
88
+ * @param config 插件配置。
89
+ * @returns 如果校验不通过,返回错误信息字符串;如果通过,返回 null。
90
+ */
91
+ export declare function requireAdmin(session: Session, config: Config): string | null;
package/lib/index.js CHANGED
@@ -206,100 +206,6 @@ var NameManager = class {
206
206
  }
207
207
  };
208
208
 
209
- // src/DataManager.ts
210
- var DataManager = class {
211
- /**
212
- * @constructor
213
- * @param ctx Koishi 上下文,用于数据库操作。
214
- * @param config 插件配置。
215
- * @param fileManager 文件管理器实例。
216
- * @param logger 日志记录器实例。
217
- */
218
- constructor(ctx, config, fileManager, logger2) {
219
- this.ctx = ctx;
220
- this.config = config;
221
- this.fileManager = fileManager;
222
- this.logger = logger2;
223
- }
224
- static {
225
- __name(this, "DataManager");
226
- }
227
- /**
228
- * @description 注册 `.export` 和 `.import` 子命令。
229
- * @param cave - 主 `cave` 命令实例。
230
- */
231
- registerCommands(cave) {
232
- const requireAdmin = /* @__PURE__ */ __name((action) => async ({ session }) => {
233
- if (session.channelId !== this.config.adminChannel?.split(":")[1]) return "此指令仅限在管理群组中使用";
234
- try {
235
- await session.send("正在处理,请稍候...");
236
- return await action();
237
- } catch (error) {
238
- this.logger.error("数据操作时发生错误:", error);
239
- return `操作失败: ${error.message}`;
240
- }
241
- }, "requireAdmin");
242
- cave.subcommand(".export", "导出回声洞数据", { hidden: true, authority: 4 }).usage("将所有回声洞数据导出到 cave.json 中。").action(requireAdmin(() => this.exportData()));
243
- cave.subcommand(".import", "导入回声洞数据", { hidden: true, authority: 4 }).usage("从 cave.json 中导入回声洞数据。").action(requireAdmin(() => this.importData()));
244
- }
245
- /**
246
- * @description 导出所有 'active' 状态的回声洞数据到 `cave.json`。
247
- * @returns 描述导出结果的消息字符串。
248
- */
249
- async exportData() {
250
- const fileName = "cave.json";
251
- const cavesToExport = await this.ctx.database.get("cave", { status: "active" });
252
- await this.fileManager.saveFile(fileName, Buffer.from(JSON.stringify(cavesToExport, null, 2)));
253
- return `成功导出 ${cavesToExport.length} 条数据`;
254
- }
255
- /**
256
- * @description 从 `cave.json` 文件导入回声洞数据。
257
- * @returns 描述导入结果的消息字符串。
258
- */
259
- async importData() {
260
- const fileName = "cave.json";
261
- let importedCaves;
262
- try {
263
- const fileContent = await this.fileManager.readFile(fileName);
264
- importedCaves = JSON.parse(fileContent.toString("utf-8"));
265
- if (!Array.isArray(importedCaves) || !importedCaves.length) throw new Error("导入文件格式无效或为空");
266
- } catch (error) {
267
- throw new Error(`读取导入文件失败: ${error.message}`);
268
- }
269
- const allDbCaves = await this.ctx.database.get("cave", {}, { fields: ["id"] });
270
- const existingIds = new Set(allDbCaves.map((c) => c.id));
271
- let maxId = allDbCaves.length > 0 ? Math.max(...allDbCaves.map((c) => c.id)) : 0;
272
- const nonConflictingCaves = [];
273
- const conflictingCaves = [];
274
- let invalidCount = 0;
275
- for (const importedCave of importedCaves) {
276
- if (typeof importedCave.id !== "number" || !Array.isArray(importedCave.elements)) {
277
- this.logger.warn(`回声洞(${importedCave.id})无效: ${JSON.stringify(importedCave)}`);
278
- invalidCount++;
279
- continue;
280
- }
281
- if (existingIds.has(importedCave.id)) {
282
- conflictingCaves.push(importedCave);
283
- } else {
284
- nonConflictingCaves.push({ ...importedCave, status: "active" });
285
- existingIds.add(importedCave.id);
286
- maxId = Math.max(maxId, importedCave.id);
287
- }
288
- }
289
- const newCavesFromConflicts = conflictingCaves.map((cave) => {
290
- maxId++;
291
- this.logger.info(`回声洞(${cave.id})已转移至(${maxId})`);
292
- return { ...cave, id: maxId, status: "active" };
293
- });
294
- const finalCavesToUpsert = [...nonConflictingCaves, ...newCavesFromConflicts];
295
- if (finalCavesToUpsert.length > 0) await this.ctx.database.upsert("cave", finalCavesToUpsert);
296
- return `成功导入 ${finalCavesToUpsert.length} 条数据`;
297
- }
298
- };
299
-
300
- // src/PendManager.ts
301
- var import_koishi2 = require("koishi");
302
-
303
209
  // src/Utils.ts
304
210
  var import_koishi = require("koishi");
305
211
  var path2 = __toESM(require("path"));
@@ -576,30 +482,121 @@ async function performSimilarityChecks(ctx, config, hashManager, finalElementsFo
576
482
  return { duplicate: false, textHashesToStore, imageHashesToStore };
577
483
  }
578
484
  __name(performSimilarityChecks, "performSimilarityChecks");
579
- async function handleFileUploads(ctx, config, fileManager, logger2, reviewManager, cave, downloadedMedia, reusableIds, session, hashManager, textHashesToStore, imageHashesToStore, aiManager) {
485
+ async function handleFileUploads(ctx, config, fileManager, logger2, cave, downloadedMedia, reusableIds, session) {
580
486
  try {
581
- if (aiManager) await aiManager.analyzeAndStore(cave, downloadedMedia);
582
487
  await Promise.all(downloadedMedia.map((item) => fileManager.saveFile(item.fileName, item.buffer)));
583
488
  const needsReview = config.enablePend && session.channelId !== config.adminChannel?.split(":")[1];
584
489
  const finalStatus = needsReview ? "pending" : "active";
585
490
  await ctx.database.upsert("cave", [{ id: cave.id, status: finalStatus }]);
586
- if (hashManager) {
587
- const allHashesToInsert = [...textHashesToStore, ...imageHashesToStore].map((h5) => ({ ...h5, cave: cave.id }));
588
- if (allHashesToInsert.length > 0) await ctx.database.upsert("cave_hash", allHashesToInsert);
589
- }
590
- if (finalStatus === "pending" && reviewManager) {
591
- const [finalCave] = await ctx.database.get("cave", { id: cave.id });
592
- if (finalCave) reviewManager.sendForPend(finalCave);
593
- }
491
+ return finalStatus;
594
492
  } catch (fileProcessingError) {
595
493
  logger2.error(`回声洞(${cave.id})文件处理失败:`, fileProcessingError);
596
494
  await ctx.database.upsert("cave", [{ id: cave.id, status: "delete" }]);
597
495
  cleanupPendingDeletions(ctx, fileManager, logger2, reusableIds);
496
+ return "delete";
598
497
  }
599
498
  }
600
499
  __name(handleFileUploads, "handleFileUploads");
500
+ function requireAdmin(session, config) {
501
+ if (session.cid !== config.adminChannel) return "此指令仅限在管理群组中使用";
502
+ return null;
503
+ }
504
+ __name(requireAdmin, "requireAdmin");
505
+
506
+ // src/DataManager.ts
507
+ var DataManager = class {
508
+ /**
509
+ * @constructor
510
+ * @param ctx Koishi 上下文,用于数据库操作。
511
+ * @param config 插件配置。
512
+ * @param fileManager 文件管理器实例。
513
+ * @param logger 日志记录器实例。
514
+ */
515
+ constructor(ctx, config, fileManager, logger2) {
516
+ this.ctx = ctx;
517
+ this.config = config;
518
+ this.fileManager = fileManager;
519
+ this.logger = logger2;
520
+ }
521
+ static {
522
+ __name(this, "DataManager");
523
+ }
524
+ /**
525
+ * @description 注册 `.export` 和 `.import` 子命令。
526
+ * @param cave - 主 `cave` 命令实例。
527
+ */
528
+ registerCommands(cave) {
529
+ const commandAction = /* @__PURE__ */ __name((action) => async ({ session }) => {
530
+ const adminError = requireAdmin(session, this.config);
531
+ if (adminError) return adminError;
532
+ try {
533
+ await session.send("正在处理,请稍候...");
534
+ return await action();
535
+ } catch (error) {
536
+ this.logger.error("数据操作时发生错误:", error);
537
+ return `操作失败: ${error.message}`;
538
+ }
539
+ }, "commandAction");
540
+ cave.subcommand(".export", "导出回声洞数据", { hidden: true, authority: 4 }).usage("将所有回声洞数据导出到 cave.json 中。").action(commandAction(() => this.exportData()));
541
+ cave.subcommand(".import", "导入回声洞数据", { hidden: true, authority: 4 }).usage("从 cave.json 中导入回声洞数据。").action(commandAction(() => this.importData()));
542
+ }
543
+ /**
544
+ * @description 导出所有 'active' 状态的回声洞数据到 `cave.json`。
545
+ * @returns 描述导出结果的消息字符串。
546
+ */
547
+ async exportData() {
548
+ const fileName = "cave.json";
549
+ const cavesToExport = await this.ctx.database.get("cave", { status: "active" });
550
+ await this.fileManager.saveFile(fileName, Buffer.from(JSON.stringify(cavesToExport, null, 2)));
551
+ return `成功导出 ${cavesToExport.length} 条数据`;
552
+ }
553
+ /**
554
+ * @description 从 `cave.json` 文件导入回声洞数据。
555
+ * @returns 描述导入结果的消息字符串。
556
+ */
557
+ async importData() {
558
+ const fileName = "cave.json";
559
+ let importedCaves;
560
+ try {
561
+ const fileContent = await this.fileManager.readFile(fileName);
562
+ importedCaves = JSON.parse(fileContent.toString("utf-8"));
563
+ if (!Array.isArray(importedCaves) || !importedCaves.length) throw new Error("导入文件格式无效或为空");
564
+ } catch (error) {
565
+ throw new Error(`读取导入文件失败: ${error.message}`);
566
+ }
567
+ const allDbCaves = await this.ctx.database.get("cave", {}, { fields: ["id"] });
568
+ const existingIds = new Set(allDbCaves.map((c) => c.id));
569
+ let maxId = allDbCaves.length > 0 ? Math.max(...allDbCaves.map((c) => c.id)) : 0;
570
+ const nonConflictingCaves = [];
571
+ const conflictingCaves = [];
572
+ let invalidCount = 0;
573
+ for (const importedCave of importedCaves) {
574
+ if (typeof importedCave.id !== "number" || !Array.isArray(importedCave.elements)) {
575
+ this.logger.warn(`回声洞(${importedCave.id})无效: ${JSON.stringify(importedCave)}`);
576
+ invalidCount++;
577
+ continue;
578
+ }
579
+ if (existingIds.has(importedCave.id)) {
580
+ conflictingCaves.push(importedCave);
581
+ } else {
582
+ nonConflictingCaves.push({ ...importedCave, status: "active" });
583
+ existingIds.add(importedCave.id);
584
+ maxId = Math.max(maxId, importedCave.id);
585
+ }
586
+ }
587
+ const newCavesFromConflicts = conflictingCaves.map((cave) => {
588
+ maxId++;
589
+ this.logger.info(`回声洞(${cave.id})已转移至(${maxId})`);
590
+ return { ...cave, id: maxId, status: "active" };
591
+ });
592
+ const finalCavesToUpsert = [...nonConflictingCaves, ...newCavesFromConflicts];
593
+ if (finalCavesToUpsert.length > 0) await this.ctx.database.upsert("cave", finalCavesToUpsert);
594
+ return `成功导入 ${finalCavesToUpsert.length} 条数据`;
595
+ }
596
+ };
601
597
 
602
598
  // src/PendManager.ts
599
+ var import_koishi2 = require("koishi");
603
600
  var PendManager = class {
604
601
  /**
605
602
  * @param ctx Koishi 上下文。
@@ -623,12 +620,8 @@ var PendManager = class {
623
620
  * @param cave - 主 `cave` 命令实例。
624
621
  */
625
622
  registerCommands(cave) {
626
- const requireAdmin = /* @__PURE__ */ __name((session) => {
627
- if (session.channelId !== this.config.adminChannel?.split(":")[1]) return "此指令仅限在管理群组中使用";
628
- return null;
629
- }, "requireAdmin");
630
623
  const pend = cave.subcommand(".pend [id:posint]", "审核回声洞", { hidden: true }).usage("查询待审核的回声洞列表,或指定 ID 查看对应待审核的回声洞。").action(async ({ session }, id) => {
631
- const adminError = requireAdmin(session);
624
+ const adminError = requireAdmin(session, this.config);
632
625
  if (adminError) return adminError;
633
626
  if (id) {
634
627
  const [targetCave] = await this.ctx.database.get("cave", { id });
@@ -644,7 +637,7 @@ var PendManager = class {
644
637
  ${pendingCaves.map((c) => c.id).join("|")}`;
645
638
  });
646
639
  const createPendAction = /* @__PURE__ */ __name((actionType) => async ({ session }, ...ids) => {
647
- const adminError = requireAdmin(session);
640
+ const adminError = requireAdmin(session, this.config);
648
641
  if (adminError) return adminError;
649
642
  let idsToProcess = ids;
650
643
  if (idsToProcess.length === 0) {
@@ -1015,7 +1008,8 @@ var AIManager = class {
1015
1008
  */
1016
1009
  registerCommands(cave) {
1017
1010
  cave.subcommand(".ai", "分析回声洞", { hidden: true, authority: 4 }).usage("分析尚未分析的回声洞,补全回声洞记录。").action(async ({ session }) => {
1018
- if (session.channelId !== this.config.adminChannel?.split(":")[1]) return "此指令仅限在管理群组中使用";
1011
+ const adminError = requireAdmin(session, this.config);
1012
+ if (adminError) return adminError;
1019
1013
  try {
1020
1014
  const allCaves = await this.ctx.database.get("cave", { status: "active" });
1021
1015
  const analyzedCaveIds = new Set((await this.ctx.database.get("cave_meta", {})).map((meta) => meta.cave));
@@ -1078,7 +1072,8 @@ var AIManager = class {
1078
1072
  }
1079
1073
  if (potentialDuplicates.length === 0) return { duplicate: false };
1080
1074
  const { payload } = await this.prepareDedupePayload(newElements, potentialDuplicates);
1081
- const response = await this.http.post(`${this.config.aiEndpoint}:generateContent?key=${this.config.aiApiKey}`, payload, { headers: { "Content-Type": "application/json" }, timeout: 9e4 });
1075
+ const fullUrl = `${this.config.aiEndpoint}/models/${this.config.aiModel}:generateContent?key=${this.config.aiApiKey}`;
1076
+ const response = await this.http.post(fullUrl, payload, { headers: { "Content-Type": "application/json" }, timeout: 9e4 });
1082
1077
  return this.parseDedupeResponse(response);
1083
1078
  } catch (error) {
1084
1079
  this.logger.error("查重回声洞出错:", error);
@@ -1097,6 +1092,7 @@ var AIManager = class {
1097
1092
  if (analysisResult) await this.ctx.database.upsert("cave_meta", [{ cave: cave.id, ...analysisResult }]);
1098
1093
  } catch (error) {
1099
1094
  this.logger.error(`分析回声洞(${cave.id})失败:`, error);
1095
+ throw error;
1100
1096
  }
1101
1097
  }
1102
1098
  /**
@@ -1109,7 +1105,8 @@ var AIManager = class {
1109
1105
  async getAnalysis(elements, mediaToSave, mediaBuffers) {
1110
1106
  const { payload } = await this.preparePayload(this.config.AnalysePrompt, this.config.aiAnalyseSchema, elements, mediaToSave, mediaBuffers);
1111
1107
  if (!payload.contents) return null;
1112
- const response = await this.http.post(`${this.config.aiEndpoint}:generateContent?key=${this.config.aiApiKey}`, payload, { headers: { "Content-Type": "application/json" }, timeout: 6e4 });
1108
+ const fullUrl = `${this.config.aiEndpoint}/models/${this.config.aiModel}:generateContent?key=${this.config.aiApiKey}`;
1109
+ const response = await this.http.post(fullUrl, payload, { headers: { "Content-Type": "application/json" }, timeout: 6e4 });
1113
1110
  return this.parseAnalysisResponse(response);
1114
1111
  }
1115
1112
  /**
@@ -1160,9 +1157,17 @@ var AIManager = class {
1160
1157
  if (parts.length <= 1) return { payload: {} };
1161
1158
  try {
1162
1159
  const schema = JSON.parse(schemaString);
1163
- return { payload: { contents: [{ parts }], generationConfig: { response_schema: schema } } };
1160
+ return {
1161
+ payload: {
1162
+ contents: [{ parts }],
1163
+ generationConfig: {
1164
+ responseMimeType: "application/json",
1165
+ responseSchema: schema
1166
+ }
1167
+ }
1168
+ };
1164
1169
  } catch (error) {
1165
- this.logger.error("解析JSON Schema失败:", error);
1170
+ this.logger.error("分析 JSON Schema 解析失败:", error);
1166
1171
  return { payload: {} };
1167
1172
  }
1168
1173
  }
@@ -1178,15 +1183,20 @@ var AIManager = class {
1178
1183
  new_content: { text: formatContent(newElements) },
1179
1184
  existing_contents: existingCaves.map((cave) => ({ id: cave.id, text: formatContent(cave.elements) }))
1180
1185
  });
1181
- const fullPrompt = `${this.config.aiCheckPrompt}
1182
-
1183
- 以下是需要处理的数据:
1184
- ${payloadContent}`;
1186
+ const parts = [{ text: this.config.aiCheckPrompt }, { text: payloadContent }];
1185
1187
  try {
1186
1188
  const schema = JSON.parse(this.config.aiCheckSchema);
1187
- return { payload: { contents: [{ parts: [{ text: fullPrompt }] }], generationConfig: { response_schema: schema } } };
1189
+ return {
1190
+ payload: {
1191
+ contents: [{ parts }],
1192
+ generationConfig: {
1193
+ responseMimeType: "application/json",
1194
+ responseSchema: schema
1195
+ }
1196
+ }
1197
+ };
1188
1198
  } catch (error) {
1189
- this.logger.error("解析查重JSON Schema失败:", error);
1199
+ this.logger.error("查重 JSON Schema 解析失败:", error);
1190
1200
  return { payload: {} };
1191
1201
  }
1192
1202
  }
@@ -1197,7 +1207,8 @@ ${payloadContent}`;
1197
1207
  */
1198
1208
  parseAnalysisResponse(response) {
1199
1209
  try {
1200
- const content = response.candidates.content.parts.text;
1210
+ if (!response?.candidates?.[0]?.content?.parts?.[0]?.text) throw new Error("分析响应解析失败");
1211
+ const content = response.candidates[0].content.parts[0].text;
1201
1212
  const parsed = JSON.parse(content);
1202
1213
  const keywords = Array.isArray(parsed.keywords) ? parsed.keywords : [];
1203
1214
  return {
@@ -1207,7 +1218,7 @@ ${payloadContent}`;
1207
1218
  };
1208
1219
  } catch (error) {
1209
1220
  this.logger.error("分析响应解析失败:", error, "原始响应:", JSON.stringify(response));
1210
- return { keywords: [], description: "解析失败", rating: 0 };
1221
+ throw error;
1211
1222
  }
1212
1223
  }
1213
1224
  /**
@@ -1217,13 +1228,14 @@ ${payloadContent}`;
1217
1228
  */
1218
1229
  parseDedupeResponse(response) {
1219
1230
  try {
1220
- const content = response.candidates.content.parts.text;
1231
+ if (!response?.candidates?.[0]?.content?.parts?.[0]?.text) throw new Error("查重响应解析失败");
1232
+ const content = response.candidates[0].content.parts[0].text;
1221
1233
  const parsed = JSON.parse(content);
1222
1234
  if (parsed.duplicate === true && parsed.id) return { duplicate: true, id: Number(parsed.id) };
1223
1235
  return { duplicate: false };
1224
1236
  } catch (error) {
1225
1237
  this.logger.error("查重响应解析失败:", error, "原始响应:", JSON.stringify(response));
1226
- return { duplicate: false };
1238
+ throw error;
1227
1239
  }
1228
1240
  }
1229
1241
  };
@@ -1405,22 +1417,25 @@ function apply(ctx, config) {
1405
1417
  }
1406
1418
  const userName = (config.enableName ? await profileManager.getNickname(session.userId) : null) || session.username;
1407
1419
  const needsReview = config.enablePend && session.channelId !== config.adminChannel?.split(":")[1];
1408
- const initialStatus = hasMedia ? "preload" : needsReview ? "pending" : "active";
1420
+ let finalStatus = hasMedia ? "preload" : needsReview ? "pending" : "active";
1409
1421
  const newCave = await ctx.database.create("cave", {
1410
1422
  id: newId,
1411
1423
  elements: finalElementsForDb,
1412
1424
  channelId: session.channelId,
1413
1425
  userId: session.userId,
1414
1426
  userName,
1415
- status: initialStatus,
1427
+ status: finalStatus,
1416
1428
  time: creationTime
1417
1429
  });
1418
- if (hasMedia) {
1419
- handleFileUploads(ctx, config, fileManager, logger, reviewManager, newCave, downloadedMedia, reusableIds, session, hashManager, textHashesToStore, imageHashesToStore, aiManager);
1420
- } else {
1421
- if (aiManager) await aiManager.analyzeAndStore(newCave);
1422
- if (hashManager && textHashesToStore.length > 0) await ctx.database.upsert("cave_hash", textHashesToStore.map((h5) => ({ ...h5, cave: newCave.id })));
1423
- if (initialStatus === "pending") reviewManager.sendForPend(newCave);
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);
1424
1439
  }
1425
1440
  return needsReview ? `提交成功,序号为(${newCave.id})` : `添加成功,序号为(${newCave.id})`;
1426
1441
  } catch (error) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "功能强大、高度可定制的回声洞。支持丰富的媒体类型、内容查重、人工审核、用户昵称、数据迁移以及本地/S3 双重文件存储后端。",
4
- "version": "2.7.2",
4
+ "version": "2.7.4",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],