koishi-plugin-best-cave 2.7.31 → 2.7.32

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.
@@ -27,7 +27,7 @@ export declare class AIManager {
27
27
  private http;
28
28
  private endpointIndex;
29
29
  /**
30
- * @description AI 分析系统提示词,使用 'type' 作为主分类字段。
30
+ * @description 用于分析的 AI 系统提示词。
31
31
  */
32
32
  private readonly ANALYSIS_SYSTEM_PROMPT;
33
33
  /**
package/lib/index.d.ts CHANGED
@@ -63,6 +63,9 @@ export interface Config {
63
63
  key: string;
64
64
  model: string;
65
65
  }[];
66
+ enableApprove: boolean;
67
+ approveThreshold: number;
68
+ systemPrompt: string;
66
69
  }
67
70
  export declare const Config: Schema<Config>;
68
71
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -1113,36 +1113,14 @@ var AIManager = class {
1113
1113
  http;
1114
1114
  endpointIndex = 0;
1115
1115
  /**
1116
- * @description AI 分析系统提示词,使用 'type' 作为主分类字段。
1116
+ * @description 用于分析的 AI 系统提示词。
1117
1117
  */
1118
1118
  ANALYSIS_SYSTEM_PROMPT = `你需要分析给定的内容,并按照以下规则进行评分、分类和提取内容中的关键词。
1119
- 你的回复必须且只能是一个JSON对象,禁止含有任何其他内容,例如{"rating": 88,"type": "Game","keywords": ["Minecraft", "Nether"]}
1120
- 1."rating" (整数, 0-100): 对内容进行严格且有区分度的评分,以下为评分标准:
1121
- - 基础分: 50
1122
- +10至+20: 高原创性、创意或艺术性。
1123
- +10至+20: 非常搞笑、幽默或有很强的笑点。
1124
- +10至+20: 引人深思、感人或有强烈的共鸣。
1125
- +5至+15: 玩梗巧妙或二创质量高,能识别出具体梗/文化背景。
1126
- -10至-20: 内容质量低下(如图片模糊、有压缩痕迹、文字错别字)。
1127
- -10至-20: 内容意义不明或非常无聊。
1128
- -5至-15: 简单或低创意的烂梗、过时流行语。
1129
- -20至-30: 几乎没有信息量的内容。
1130
- 2."type" (字符串): 对内容进行严格且标准的分类,以下为分类标准:
1131
- - Game: 与电子游戏直接相关或源自于电子游戏的内容。
1132
- - ACG: 与动漫、漫画及广义二次元文化紧密相关的内容。
1133
- - Internet: 源于互联网的通用流行文化、迷因(Meme)或社群现象。
1134
- - Reality: 取材于现实世界的日常经验和场景的内容。
1135
- - Creative: 具有独特的原创性、艺术性或巧妙构思的内容。
1136
- - Other: 不适合归入以上任何一类的无关内容或小众内容。
1137
- 3."keywords" (字符串数组): 从内容中提取全面且细分的关键词,以下为提取准则:
1138
- - 直接提取: 优先从文字内容中直接提取核心词汇,而不是进行归纳或总结。提取图片中可辨识的对象、场景或文字。
1139
- - 简洁规范: 关键词必须简短且为规范化、普遍使用的词语。例如,使用“明日方舟”而非“粥”,使用“梗”而非“梗图”。
1140
- - 全面细分: 提取多个不同维度的关键词,包括但不限于:人物/对象、场景/地点、事件/行为、特定梗/文化元素。
1141
- - 避免宽泛: 确保关键词具体且相关,避免使用过于宽泛或模糊的术语,避免近似关键词,所有词应完整定义内容。`;
1119
+ 你的回复必须且只能是一个JSON对象,禁止含有任何其他内容,例如{"rating": 88,"type": "Game","keywords": ["Minecraft", "Nether"]}。`;
1142
1120
  /**
1143
1121
  * @description 用于查重的 AI 系统提示词。
1144
1122
  */
1145
- DUPLICATE_SYSTEM_PROMPT = `你需要比较给定的“新内容”(content_new)与“候选内容”(candidate_contents),识别内容语义或核心思想重复的候选内容。
1123
+ DUPLICATE_SYSTEM_PROMPT = `你需要比较给定的“新内容”与“候选内容”,识别内容语义或核心思想重复的候选内容。
1146
1124
  你的回复必须且只能是一个JSON数组,禁止含有任何其他内容,只包含重复项ID,例如[1, 2],若无重复,则返回[]。`;
1147
1125
  /**
1148
1126
  * @description 注册与 AI 功能相关的管理命令。
@@ -1280,7 +1258,8 @@ var AIManager = class {
1280
1258
  const contentForAI = await this.prepareContent(cave, mediaBuffers ? new Map(mediaBuffers.map((m) => [m.fileName, m.buffer])) : void 0);
1281
1259
  if (!contentForAI) return null;
1282
1260
  const userMessage = { role: "user", content: contentForAI };
1283
- const response = await this.requestAI([userMessage], this.ANALYSIS_SYSTEM_PROMPT);
1261
+ const response = await this.requestAI([userMessage], `${this.ANALYSIS_SYSTEM_PROMPT}
1262
+ ${this.config.systemPrompt}`);
1284
1263
  if (response) {
1285
1264
  return {
1286
1265
  cave: cave.id,
@@ -1311,7 +1290,7 @@ var AIManager = class {
1311
1290
  try {
1312
1291
  const buffer = mediaMap?.get(el.file) ?? await this.fileManager.readFile(el.file);
1313
1292
  const mimeType = path3.extname(el.file).toLowerCase() === ".png" ? "image/png" : "image/jpeg";
1314
- return { type: "image_url", image: { url: `data:${mimeType};base64,${buffer.toString("base64")}` } };
1293
+ return { type: "image_url", image_url: { url: `data:${mimeType};base64,${buffer.toString("base64")}` } };
1315
1294
  } catch (error) {
1316
1295
  this.logger.warn(`读取文件(${el.file})失败:`, error);
1317
1296
  return null;
@@ -1334,10 +1313,12 @@ var AIManager = class {
1334
1313
  async IsDuplicate(mainCave, candidateCaves) {
1335
1314
  try {
1336
1315
  const formatContent = /* @__PURE__ */ __name((elements) => elements.filter((el) => el.type === "text" && el.content).map((el) => el.content).join(" "), "formatContent");
1337
- const userMessageContent = {
1338
- content_new: { text: formatContent(mainCave.elements) },
1339
- candidate_contents: candidateCaves.map((cave) => ({ id: cave.id, text: formatContent(cave.elements) }))
1340
- };
1316
+ const newContentText = formatContent(mainCave.elements);
1317
+ const candidatesText = candidateCaves.map((cave) => `{"id": ${cave.id}, "text": "${formatContent(cave.elements).replace(/"/g, '\\"')}"}`).join("\n");
1318
+ const userMessageContent = `新内容:
1319
+ ${newContentText}
1320
+ 候选内容:
1321
+ ${candidatesText}`;
1341
1322
  const userMessage = { role: "user", content: JSON.stringify(userMessageContent) };
1342
1323
  const response = await this.requestAI([userMessage], this.DUPLICATE_SYSTEM_PROMPT);
1343
1324
  return response || [];
@@ -1406,6 +1387,28 @@ var usage = `
1406
1387
  <p>🐛 遇到问题?请通过 <strong>Issues</strong> 提交反馈,或加入 QQ 群 <a href="https://qm.qq.com/q/PdLMx9Jowq" style="color:#e0574a;text-decoration:none;"><strong>855571375</strong></a> 进行交流</p>
1407
1388
  </div>
1408
1389
  `;
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" (字符串): 对内容进行严格且标准的分类,以下为分类标准:
1401
+ - Game: 与电子游戏直接相关或源自于电子游戏的内容。
1402
+ - ACG: 与动漫、漫画及广义二次元文化紧密相关的内容。
1403
+ - Internet: 源于互联网的通用流行文化、迷因(Meme)或社群现象。
1404
+ - Reality: 取材于现实世界的日常经验和场景的内容。
1405
+ - Creative: 具有独特的原创性、艺术性或巧妙构思的内容。
1406
+ - Other: 不适合归入以上任何一类的无关内容或小众内容。
1407
+ 3."keywords" (字符串数组): 从内容中提取全面且细分的关键词,以下为提取准则:
1408
+ - 直接提取: 优先从文字内容中直接提取核心词汇,而不是进行归纳或总结。提取图片中可辨识的对象、场景或文字。
1409
+ - 简洁规范: 关键词必须简短且为规范化、普遍使用的词语。例如,使用“明日方舟”而非“粥”,使用“梗”而非“梗图”。
1410
+ - 全面细分: 提取多个不同维度的关键词,包括但不限于:人物/对象、场景/地点、事件/行为、特定梗/文化元素。
1411
+ - 避免宽泛: 确保关键词具体且相关,避免使用过于宽泛或模糊的术语,避免近似关键词,所有词应完整定义内容。`;
1409
1412
  var logger = new import_koishi3.Logger("best-cave");
1410
1413
  var Config = import_koishi3.Schema.intersect([
1411
1414
  import_koishi3.Schema.object({
@@ -1423,11 +1426,14 @@ var Config = import_koishi3.Schema.intersect([
1423
1426
  }).description("复核配置"),
1424
1427
  import_koishi3.Schema.object({
1425
1428
  enableAI: import_koishi3.Schema.boolean().default(false).description("启用 AI"),
1429
+ enableApprove: import_koishi3.Schema.boolean().default(false).description("启用自动审核"),
1430
+ approveThreshold: import_koishi3.Schema.number().min(0).max(100).step(1).default(80).description("评分阈值"),
1426
1431
  endpoints: import_koishi3.Schema.array(import_koishi3.Schema.object({
1427
1432
  url: import_koishi3.Schema.string().description("端点 (Endpoint)").role("link").required(),
1428
- key: import_koishi3.Schema.string().description("密钥 (API Key)").role("secret").required(),
1433
+ key: import_koishi3.Schema.string().description("密钥 (API Key)").role("secret"),
1429
1434
  model: import_koishi3.Schema.string().description("模型 (Model)").required()
1430
- })).description("端点列表").role("table")
1435
+ })).description("端点列表").role("table"),
1436
+ systemPrompt: import_koishi3.Schema.string().role("textarea").default(DEFAULT_PROMPT).description("系统提示词")
1431
1437
  }).description("模型配置"),
1432
1438
  import_koishi3.Schema.object({
1433
1439
  localPath: import_koishi3.Schema.string().description("文件映射路径"),
@@ -1553,15 +1559,23 @@ function apply(ctx, config) {
1553
1559
  }
1554
1560
  }
1555
1561
  if (hasMedia) await Promise.all(downloadedMedia.map((item) => fileManager.saveFile(item.fileName, item.buffer)));
1562
+ let analysisResult;
1556
1563
  if (aiManager) {
1557
1564
  const analyses = await aiManager.analyze([newCave], downloadedMedia);
1558
- if (analyses.length > 0) await ctx.database.upsert("cave_meta", analyses);
1565
+ if (analyses.length > 0) {
1566
+ analysisResult = analyses[0];
1567
+ await ctx.database.upsert("cave_meta", analyses);
1568
+ }
1559
1569
  }
1560
1570
  if (hashManager) {
1561
1571
  const allHashesToInsert = [...textHashesToStore, ...imageHashesToStore].map((h4) => ({ ...h4, cave: newCave.id }));
1562
1572
  if (allHashesToInsert.length > 0) await ctx.database.upsert("cave_hash", allHashesToInsert);
1563
1573
  }
1564
- if (finalStatus === "pending" && reviewManager) reviewManager.sendForPend(newCave);
1574
+ if (finalStatus === "pending" && reviewManager) {
1575
+ if (analysisResult && config.enableApprove && analysisResult.rating >= config.approveThreshold) {
1576
+ await ctx.database.upsert("cave", [{ id: newCave.id, status: "active" }]);
1577
+ } else reviewManager.sendForPend(newCave);
1578
+ }
1565
1579
  } catch (error) {
1566
1580
  logger.error(`回声洞(${newId})处理失败:`, error);
1567
1581
  await ctx.database.upsert("cave", [{ id: newId, status: "delete" }]);
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.31",
4
+ "version": "2.7.32",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],