koishi-plugin-best-cave 2.7.9 → 2.7.10

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 (2) hide show
  1. package/lib/index.js +48 -28
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -727,22 +727,33 @@ var HashManager = class {
727
727
  const cavesToProcess = allCaves.filter((cave2) => !hashedCaveIds.has(cave2.id));
728
728
  if (cavesToProcess.length === 0) return "无需补全回声洞哈希";
729
729
  await session.send(`开始补全 ${cavesToProcess.length} 个回声洞的哈希...`);
730
- const hashesToInsert = [];
730
+ let hashesToInsert = [];
731
731
  let processedCaveCount = 0;
732
+ let totalHashesGenerated = 0;
732
733
  let errorCount = 0;
734
+ const flushBatch = /* @__PURE__ */ __name(async () => {
735
+ if (hashesToInsert.length === 0) return;
736
+ await this.ctx.database.upsert("cave_hash", hashesToInsert);
737
+ totalHashesGenerated += hashesToInsert.length;
738
+ this.logger.info(`[${processedCaveCount}/${cavesToProcess.length}] 正在导入 ${hashesToInsert.length} 条回声洞哈希...`);
739
+ hashesToInsert = [];
740
+ }, "flushBatch");
733
741
  for (const cave2 of cavesToProcess) {
734
742
  processedCaveCount++;
735
743
  try {
736
744
  const newHashesForCave = await this.generateAllHashesForCave(cave2);
737
- if (newHashesForCave.length > 0) hashesToInsert.push(...newHashesForCave);
745
+ if (newHashesForCave.length > 0) {
746
+ hashesToInsert.push(...newHashesForCave);
747
+ }
748
+ if (hashesToInsert.length >= 100) await flushBatch();
738
749
  } catch (error) {
739
750
  errorCount++;
740
751
  this.logger.warn(`补全回声洞(${cave2.id})哈希时出错: ${error.message}`);
741
752
  }
742
753
  }
743
- if (hashesToInsert.length > 0) await this.ctx.database.upsert("cave_hash", hashesToInsert);
754
+ await flushBatch();
744
755
  const successCount = processedCaveCount - errorCount;
745
- return `已补全 ${successCount} 个回声洞的 ${hashesToInsert.length} 条哈希(失败 ${errorCount} 条)`;
756
+ return `已补全 ${successCount} 个回声洞的 ${totalHashesGenerated} 条哈希(失败 ${errorCount} 条)`;
746
757
  } catch (error) {
747
758
  this.logger.error("补全哈希失败:", error);
748
759
  return `操作失败: ${error.message}`;
@@ -1088,10 +1099,13 @@ var AIManager = class {
1088
1099
  const formatContent = /* @__PURE__ */ __name((elements) => elements.filter((el) => el.type === "text").map((el) => el.content).join(" "), "formatContent");
1089
1100
  const userMessage = {
1090
1101
  role: "user",
1091
- content: JSON.stringify({
1092
- new_content: { text: formatContent(newElements) },
1093
- existing_contents: potentialDuplicates.map((cave) => ({ id: cave.id, text: formatContent(cave.elements) }))
1094
- })
1102
+ content: [{
1103
+ type: "input_text",
1104
+ text: JSON.stringify({
1105
+ new_content: { text: formatContent(newElements) },
1106
+ existing_contents: potentialDuplicates.map((cave) => ({ id: cave.id, text: formatContent(cave.elements) }))
1107
+ })
1108
+ }]
1095
1109
  };
1096
1110
  const response = await this.requestAI([userMessage], this.config.aiCheckPrompt, this.config.aiCheckSchema);
1097
1111
  return {
@@ -1135,7 +1149,7 @@ var AIManager = class {
1135
1149
  async getAnalysis(elements, mediaToSave, mediaBuffers) {
1136
1150
  const userContent = [];
1137
1151
  const combinedText = elements.filter((el) => el.type === "text" && el.content).map((el) => el.content).join("\n");
1138
- if (combinedText.trim()) userContent.push({ type: "text", text: combinedText });
1152
+ if (combinedText.trim()) userContent.push({ type: "input_text", text: combinedText });
1139
1153
  const mediaMap = new Map(mediaBuffers?.map((m) => [m.fileName, m.buffer]));
1140
1154
  const imageElements = elements.filter((el) => el.type === "image" && el.file);
1141
1155
  for (const el of imageElements) {
@@ -1152,8 +1166,8 @@ var AIManager = class {
1152
1166
  if (buffer) {
1153
1167
  const mimeType = path3.extname(el.file).toLowerCase() === ".png" ? "image/png" : "image/jpeg";
1154
1168
  userContent.push({
1155
- type: "image_url",
1156
- image_url: { url: `data:${mimeType};base64,${buffer.toString("base64")}` }
1169
+ type: "input_image",
1170
+ image_url: `data:${mimeType};base64,${buffer.toString("base64")}`
1157
1171
  });
1158
1172
  }
1159
1173
  } catch (error) {
@@ -1184,22 +1198,28 @@ var AIManager = class {
1184
1198
  this.rateLimitResetTime = Date.now() + 6e4;
1185
1199
  this.requestCount = 0;
1186
1200
  }
1187
- let schema = JSON.parse(schemaString);
1188
- const toolName = "extract_data";
1201
+ let schema;
1202
+ try {
1203
+ schema = JSON.parse(schemaString);
1204
+ } catch (error) {
1205
+ this.logger.error("解析 JSON Schema 失败:", error);
1206
+ throw new Error("无效的 JSON Schema 配置");
1207
+ }
1189
1208
  const payload = {
1190
1209
  model: this.config.aiModel,
1191
- messages: [{ role: "system", content: systemPrompt }, ...messages],
1192
- tools: [{
1193
- type: "function",
1194
- function: {
1195
- name: toolName,
1196
- description: "根据提供的内容提取或分析信息。",
1197
- parameters: schema
1210
+ input: [
1211
+ { role: "system", content: systemPrompt },
1212
+ ...messages
1213
+ ],
1214
+ text: {
1215
+ format: {
1216
+ type: "json_schema",
1217
+ name: "extracted_data",
1218
+ schema
1198
1219
  }
1199
- }],
1200
- tool_choice: { type: "function", function: { name: toolName } }
1220
+ }
1201
1221
  };
1202
- const fullUrl = `${this.config.aiEndpoint.replace(/\/$/, "")}/chat/completions`;
1222
+ const fullUrl = `${this.config.aiEndpoint.replace(/\/$/, "")}/responses`;
1203
1223
  const headers = {
1204
1224
  "Content-Type": "application/json",
1205
1225
  "Authorization": `Bearer ${this.config.aiApiKey}`
@@ -1207,9 +1227,9 @@ var AIManager = class {
1207
1227
  try {
1208
1228
  this.requestCount++;
1209
1229
  const response = await this.http.post(fullUrl, payload, { headers, timeout: 9e4 });
1210
- const toolCall = response.choices?.[0]?.message?.tool_calls?.[0];
1211
- if (toolCall?.function?.arguments) {
1212
- return JSON.parse(toolCall.function.arguments);
1230
+ const responseText = response.output?.[0]?.content?.[0]?.text;
1231
+ if (responseText) {
1232
+ return JSON.parse(responseText);
1213
1233
  } else {
1214
1234
  this.logger.error("AI 响应格式不正确:", JSON.stringify(response));
1215
1235
  throw new Error("AI 响应格式不正确");
@@ -1249,8 +1269,8 @@ var Config = import_koishi3.Schema.intersect([
1249
1269
  import_koishi3.Schema.object({
1250
1270
  enablePend: import_koishi3.Schema.boolean().default(false).description("启用审核"),
1251
1271
  enableSimilarity: import_koishi3.Schema.boolean().default(false).description("启用查重"),
1252
- textThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(90).description("文本相似度阈值 (%)"),
1253
- imageThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(90).description("图片相似度阈值 (%)")
1272
+ textThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(95).description("文本相似度阈值 (%)"),
1273
+ imageThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(95).description("图片相似度阈值 (%)")
1254
1274
  }).description("复核配置"),
1255
1275
  import_koishi3.Schema.object({
1256
1276
  enableAI: import_koishi3.Schema.boolean().default(false).description("启用 AI"),
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.9",
4
+ "version": "2.7.10",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],