koishi-plugin-best-cave 2.7.32 → 2.7.34

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.
@@ -26,6 +26,8 @@ export declare class AIManager {
26
26
  private fileManager;
27
27
  private http;
28
28
  private endpointIndex;
29
+ private failureCount;
30
+ private retryTime;
29
31
  /**
30
32
  * @description 用于分析的 AI 系统提示词。
31
33
  */
@@ -95,7 +97,7 @@ export declare class AIManager {
95
97
  * @param {any[]} messages - 发送给 AI 的消息数组。
96
98
  * @param {string} systemPrompt - 系统提示词。
97
99
  * @returns {Promise<T>} - 一个 Promise,解析为从 AI 响应中解析出的 JSON 对象。
98
- * @throws {Error} - 如果 AI 响应为空或无法解析为 JSON,则抛出错误。
100
+ * @throws {Error} - 如果 AI 服务持续失败,则抛出错误。
99
101
  */
100
102
  private requestAI;
101
103
  }
package/lib/index.js CHANGED
@@ -1112,6 +1112,8 @@ var AIManager = class {
1112
1112
  }
1113
1113
  http;
1114
1114
  endpointIndex = 0;
1115
+ failureCount = 0;
1116
+ retryTime = 0;
1115
1117
  /**
1116
1118
  * @description 用于分析的 AI 系统提示词。
1117
1119
  */
@@ -1243,7 +1245,7 @@ var AIManager = class {
1243
1245
  return await this.IsDuplicate(dummyCave, potentialDuplicates);
1244
1246
  } catch (error) {
1245
1247
  this.logger.error("查重回声洞出错:", error);
1246
- return [];
1248
+ throw error;
1247
1249
  }
1248
1250
  }
1249
1251
  /**
@@ -1271,7 +1273,7 @@ ${this.config.systemPrompt}`);
1271
1273
  return null;
1272
1274
  } catch (error) {
1273
1275
  this.logger.error(`分析回声洞(${cave.id})失败:`, error);
1274
- return null;
1276
+ throw error;
1275
1277
  }
1276
1278
  });
1277
1279
  const results = await Promise.all(analysisPromises);
@@ -1324,7 +1326,7 @@ ${candidatesText}`;
1324
1326
  return response || [];
1325
1327
  } catch (error) {
1326
1328
  this.logger.error(`比较回声洞(${mainCave.id})失败:`, error);
1327
- return [];
1329
+ throw error;
1328
1330
  }
1329
1331
  }
1330
1332
  /**
@@ -1347,28 +1349,51 @@ ${candidatesText}`;
1347
1349
  * @param {any[]} messages - 发送给 AI 的消息数组。
1348
1350
  * @param {string} systemPrompt - 系统提示词。
1349
1351
  * @returns {Promise<T>} - 一个 Promise,解析为从 AI 响应中解析出的 JSON 对象。
1350
- * @throws {Error} - 如果 AI 响应为空或无法解析为 JSON,则抛出错误。
1352
+ * @throws {Error} - 如果 AI 服务持续失败,则抛出错误。
1351
1353
  */
1352
1354
  async requestAI(messages, systemPrompt) {
1353
- const endpointConfig = this.config.endpoints[this.endpointIndex];
1354
- this.endpointIndex = (this.endpointIndex + 1) % this.config.endpoints.length;
1355
- const payload = { model: endpointConfig.model, messages: [{ role: "system", content: systemPrompt }, ...messages] };
1356
- const fullUrl = `${endpointConfig.url.replace(/\/$/, "")}/chat/completions`;
1357
- const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${endpointConfig.key}` };
1358
- const response = await this.http.post(fullUrl, payload, { headers, timeout: 6e5 });
1359
- const content = response?.choices?.[0]?.message?.content;
1360
- if (!content?.trim()) throw new Error("响应为空");
1361
- const jsonBlockMatch = content.match(/```json\s*([\s\S]*?)\s*```/i);
1362
- if (jsonBlockMatch && jsonBlockMatch[1]) try {
1363
- return JSON.parse(jsonBlockMatch[1]);
1364
- } catch (e) {
1355
+ const now = Date.now();
1356
+ if (now < this.retryTime) {
1357
+ const waitTime = this.retryTime - now;
1358
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
1365
1359
  }
1366
1360
  try {
1367
- return JSON.parse(content);
1368
- } catch (e) {
1361
+ const endpointConfig = this.config.endpoints[this.endpointIndex];
1362
+ this.endpointIndex = (this.endpointIndex + 1) % this.config.endpoints.length;
1363
+ const payload = { model: endpointConfig.model, messages: [{ role: "system", content: systemPrompt }, ...messages] };
1364
+ const fullUrl = `${endpointConfig.url.replace(/\/$/, "")}/chat/completions`;
1365
+ const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${endpointConfig.key}` };
1366
+ const response = await this.http.post(fullUrl, payload, { headers, timeout: 6e5 });
1367
+ const content = response?.choices?.[0]?.message?.content;
1368
+ if (!content?.trim()) throw new Error();
1369
+ const potentialStrings = /* @__PURE__ */ new Set();
1370
+ const jsonBlockMatch = content.match(/```json\s*([\s\S]*?)\s*```/i);
1371
+ if (jsonBlockMatch?.[1]) potentialStrings.add(jsonBlockMatch[1]);
1372
+ const firstBrace = content.indexOf("{");
1373
+ const lastBrace = content.lastIndexOf("}");
1374
+ const firstBracket = content.indexOf("[");
1375
+ const lastBracket = content.lastIndexOf("]");
1376
+ if (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) {
1377
+ if (lastBrace > firstBrace) potentialStrings.add(content.substring(firstBrace, lastBrace + 1));
1378
+ } else if (firstBracket !== -1) {
1379
+ if (lastBracket > firstBracket) potentialStrings.add(content.substring(firstBracket, lastBracket + 1));
1380
+ }
1381
+ potentialStrings.add(content);
1382
+ for (const jsonString of potentialStrings) {
1383
+ try {
1384
+ const result = JSON.parse(jsonString);
1385
+ this.failureCount = 0;
1386
+ return result;
1387
+ } catch (e) {
1388
+ }
1389
+ }
1390
+ this.logger.error("原始响应:", JSON.stringify(response, null, 2));
1391
+ throw new Error();
1392
+ } catch (error) {
1393
+ this.failureCount++;
1394
+ if (this.failureCount >= 3) this.retryTime = Date.now() + 6e4;
1395
+ throw error;
1369
1396
  }
1370
- this.logger.error("原始响应:", JSON.stringify(response, null, 2));
1371
- throw new Error();
1372
1397
  }
1373
1398
  };
1374
1399
 
@@ -1387,28 +1412,74 @@ var usage = `
1387
1412
  <p>🐛 遇到问题?请通过 <strong>Issues</strong> 提交反馈,或加入 QQ 群 <a href="https://qm.qq.com/q/PdLMx9Jowq" style="color:#e0574a;text-decoration:none;"><strong>855571375</strong></a> 进行交流</p>
1388
1413
  </div>
1389
1414
  `;
1390
- var DEFAULT_PROMPT = `1."rating" (整数, 0-100): 对内容进行严格且有区分度的评分,以下为评分标准:
1391
- - 基础分: 50
1392
- +10至+20: 高原创性、创意或艺术性。
1393
- +10至+20: 非常搞笑、幽默或有很强的笑点。
1394
- +10至+20: 引人深思、感人或有强烈的共鸣。
1395
- +5至+15: 玩梗巧妙或二创质量高,能识别出具体梗/文化背景。
1396
- -10至-20: 内容质量低下(如图片模糊、有压缩痕迹、文字错别字)。
1397
- -10至-20: 内容意义不明或非常无聊。
1398
- -5至-15: 简单或低创意的烂梗、过时流行语。
1399
- -20至-30: 几乎没有信息量的内容。
1400
- 2."type" (字符串): 对内容进行严格且标准的分类,以下为分类标准:
1415
+ var DEFAULT_PROMPT = `1."rating" (整数): 对内容进行公正客观的评分,以下为评分标准:
1416
+ 从以下维度分别评分,每项0-10分,总分为各项之和,最高100分。
1417
+ - 原创性: 评估内容的创意和独特性。
1418
+ - 10分: 完全原创的梗或高质量的二次创作,展现出独特的巧思。
1419
+ - 7-9分: 对现有梗或模板进行了巧妙的改造或融合,赋予了新的趣味。
1420
+ - 4-6分: 直接使用了较为流行的模板或创意,但结合了新的元素或语境。
1421
+ - 1-3分: 简单套用常见模板,缺乏个人想法,或是陈旧内容的再次利用。
1422
+ - 0分: 完全照搬或低质量的复制。
1423
+ - 内容价值: 评估内容所蕴含的幽默、情感或信息价值。
1424
+ - 10分: 能引发强烈共鸣或深度思考,具有极高的娱乐性或启发性。
1425
+ - 7-9分: 幽默感强,能让人会心一笑,或是在特定圈层中具有高度相关性。
1426
+ - 4-6分: 内容有趣,有一定记忆点,但可能受众较窄或深度不足。
1427
+ - 1-3分: 内容平淡,笑点模糊或表达主观,难以引起共鸣。
1428
+ - 0分: 内容空洞、无意义或令人不适。
1429
+ - 视觉呈现: 评估图像的质量和元素的协调性。
1430
+ - 10分: 构图、P图技术或截图时机堪称完美,视觉元素清晰且极具表现力。
1431
+ - 7-9分: 图像清晰,元素搭配得当,能有效服务于主题表达。
1432
+ - 4-6分: 图像基本清晰,但可能存在P图痕迹明显、元素杂乱或压缩痕迹等问题。
1433
+ - 1-3分: 图像模糊、分辨率低,或视觉元素(如文字、贴图)严重影响观感。
1434
+ - 0分: 图像完全无法辨认或引起生理不适。
1435
+ - 文本功底: 评估内容中的文字表达能力。
1436
+ - 10分: 文字精炼、幽默且一语中的,与图片配合天衣无缝。
1437
+ - 7-9分: 文字通顺,能准确表达核心笑点或信息。
1438
+ - 4-6分: 文字基本通顺,但可能存在错别字或表达略显啰嗦。
1439
+ - 1-3分: 文字表达不清,存在语病,或与图片关联性不强。
1440
+ - 5分(基准分): 内容中不包含任何文本元素时,此项计为5分。
1441
+ - 传播潜力: 评估内容被二次创作、分享和讨论的可能性。
1442
+ - 10分: “梗”感十足,极易引发模仿、分享和病毒式传播。
1443
+ - 7-9分: 具有成为热点的潜质,易于在社交圈内传播和讨论。
1444
+ - 4-6分: 内容有趣,可能会被小范围分享,但缺乏破圈传播的潜力。
1445
+ - 1-3分: 内容过于小众或个人化,难以被大众理解和传播。
1446
+ - 0分: 内容无法引发任何分享或讨论的意愿。
1447
+ - 娱乐效果: 评估内容的趣味性和吸引力。
1448
+ - 10分: 极度搞笑或有趣,能立刻吸引用户注意力并带来强烈的愉悦感。
1449
+ - 7-9分: 具有明显的笑点或趣味性,能有效调动观看者的情绪。
1450
+ - 4-6分: 内容有一定趣味,但可能需要特定背景知识才能理解笑点。
1451
+ - 1-3分: 趣味性较弱,难以引人发笑或产生兴趣。
1452
+ - 0分: 内容枯燥乏味或令人反感。
1453
+ - 逻辑清晰度: 评估内容的叙事或表达是否连贯易懂。
1454
+ - 10分: 无论是笑话、故事还是玩梗,逻辑都非常清晰,核心意图一目了然。
1455
+ - 7-9分: 内容主旨明确,大部分人都能轻松理解其意图。
1456
+ - 4-6分: 整体可以理解,但可能在某些细节上存在逻辑跳跃或模糊之处。
1457
+ - 1-3分: 逻辑混乱,表达不知所云,需要费力猜测其含义。
1458
+ - 0分: 完全没有逻辑可言。
1459
+ - 制作完成度: 评估内容的完整度和精良程度。
1460
+ - 10分: 无论是P图、对话截图还是漫画,细节处理到位,内容完整精致。
1461
+ - 7-9分: 内容完整,制作较为用心,没有明显的半成品痕迹。
1462
+ - 4-6分: 内容主体完整,但在细节上(如裁剪、打码)存在瑕疵。
1463
+ - 1-3分: 内容残缺不全,或制作粗糙,有明显的未完成感。
1464
+ - 0分: 内容严重残缺或制作质量极差。
1465
+ - 内容导向: 评估内容是否积极健康。
1466
+ - 10分: 内容积极向上,或为中性、善意的幽默,能带来正面情绪。
1467
+ - 5-9分: 内容中性,不包含明显的价值观偏向。
1468
+ - 1-4分: 可能包含一些有争议、冒犯性或易引战的元素。
1469
+ - 0分: 包含强烈的攻击性、歧视性或宣扬不良价值观的内容。
1470
+ - 内容合规性: 评估内容是否符合社区规范。
1471
+ - 10分: 内容完全合规。
1472
+ - 0分: 包含广告/引流/二维码、令人不适的图像、人身攻击或违反法律法规的内容,此项直接为0分。
1473
+ 2."type" (字符串): 对内容进行准确且规范的分类,以下为分类规范:
1401
1474
  - Game: 与电子游戏直接相关或源自于电子游戏的内容。
1402
1475
  - ACG: 与动漫、漫画及广义二次元文化紧密相关的内容。
1403
- - Internet: 源于互联网的通用流行文化、迷因(Meme)或社群现象。
1476
+ - Internet: 源于互联网的流行文化、迷因或社群现象。
1404
1477
  - Reality: 取材于现实世界的日常经验和场景的内容。
1405
- - Creative: 具有独特的原创性、艺术性或巧妙构思的内容。
1406
- - Other: 不适合归入以上任何一类的无关内容或小众内容。
1407
- 3."keywords" (字符串数组): 从内容中提取全面且细分的关键词,以下为提取准则:
1408
- - 直接提取: 优先从文字内容中直接提取核心词汇,而不是进行归纳或总结。提取图片中可辨识的对象、场景或文字。
1409
- - 简洁规范: 关键词必须简短且为规范化、普遍使用的词语。例如,使用“明日方舟”而非“粥”,使用“梗”而非“梗图”。
1410
- - 全面细分: 提取多个不同维度的关键词,包括但不限于:人物/对象、场景/地点、事件/行为、特定梗/文化元素。
1411
- - 避免宽泛: 确保关键词具体且相关,避免使用过于宽泛或模糊的术语,避免近似关键词,所有词应完整定义内容。`;
1478
+ - Creative: 具有原创性、艺术性或巧妙构思的内容。
1479
+ - Other: 不适合归入以上任何一类的无关或小众内容。
1480
+ 3."keywords" (字符串数组): 从内容中直接提取具体且全面的关键词,以下为提取准则:
1481
+ - 必须源自可直接识别的文字、对象、场景等元素,仅在无文字元素时才可使用适当的词汇进行描述。
1482
+ - 关键词必须规范且简短,通过多个不同维度关键词准确定义内容,禁止用模糊、笼统的概括性词汇。`;
1412
1483
  var logger = new import_koishi3.Logger("best-cave");
1413
1484
  var Config = import_koishi3.Schema.intersect([
1414
1485
  import_koishi3.Schema.object({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-best-cave",
3
3
  "description": "功能强大、高度可定制的回声洞插件。支持丰富的媒体类型、内容查重、AI分析、人工审核、用户昵称、数据迁移以及本地/S3 双重文件存储后端。",
4
- "version": "2.7.32",
4
+ "version": "2.7.34",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],