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.
- package/lib/AIManager.d.ts +1 -1
- package/lib/index.d.ts +3 -0
- package/lib/index.js +49 -35
- package/package.json +1 -1
package/lib/AIManager.d.ts
CHANGED
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
|
|
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 =
|
|
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",
|
|
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
|
|
1338
|
-
|
|
1339
|
-
|
|
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")
|
|
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)
|
|
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)
|
|
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" }]);
|