koishi-plugin-best-cave 2.7.8 → 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.
- package/lib/index.js +47 -40
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -722,10 +722,11 @@ var HashManager = class {
|
|
|
722
722
|
if (requireAdmin(session, this.config)) return requireAdmin(session, this.config);
|
|
723
723
|
try {
|
|
724
724
|
const allCaves = await this.ctx.database.get("cave", { status: "active" });
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const
|
|
728
|
-
|
|
725
|
+
const existingHashes = await this.ctx.database.get("cave_hash", {}, { fields: ["cave"] });
|
|
726
|
+
const hashedCaveIds = new Set(existingHashes.map((h4) => h4.cave));
|
|
727
|
+
const cavesToProcess = allCaves.filter((cave2) => !hashedCaveIds.has(cave2.id));
|
|
728
|
+
if (cavesToProcess.length === 0) return "无需补全回声洞哈希";
|
|
729
|
+
await session.send(`开始补全 ${cavesToProcess.length} 个回声洞的哈希...`);
|
|
729
730
|
let hashesToInsert = [];
|
|
730
731
|
let processedCaveCount = 0;
|
|
731
732
|
let totalHashesGenerated = 0;
|
|
@@ -734,19 +735,15 @@ var HashManager = class {
|
|
|
734
735
|
if (hashesToInsert.length === 0) return;
|
|
735
736
|
await this.ctx.database.upsert("cave_hash", hashesToInsert);
|
|
736
737
|
totalHashesGenerated += hashesToInsert.length;
|
|
737
|
-
this.logger.info(`[${processedCaveCount}/${
|
|
738
|
+
this.logger.info(`[${processedCaveCount}/${cavesToProcess.length}] 正在导入 ${hashesToInsert.length} 条回声洞哈希...`);
|
|
738
739
|
hashesToInsert = [];
|
|
739
740
|
}, "flushBatch");
|
|
740
|
-
for (const cave2 of
|
|
741
|
+
for (const cave2 of cavesToProcess) {
|
|
741
742
|
processedCaveCount++;
|
|
742
743
|
try {
|
|
743
744
|
const newHashesForCave = await this.generateAllHashesForCave(cave2);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
if (!existingHashSet.has(uniqueKey)) {
|
|
747
|
-
hashesToInsert.push(hashObj);
|
|
748
|
-
existingHashSet.add(uniqueKey);
|
|
749
|
-
}
|
|
745
|
+
if (newHashesForCave.length > 0) {
|
|
746
|
+
hashesToInsert.push(...newHashesForCave);
|
|
750
747
|
}
|
|
751
748
|
if (hashesToInsert.length >= 100) await flushBatch();
|
|
752
749
|
} catch (error) {
|
|
@@ -755,9 +752,10 @@ var HashManager = class {
|
|
|
755
752
|
}
|
|
756
753
|
}
|
|
757
754
|
await flushBatch();
|
|
758
|
-
|
|
755
|
+
const successCount = processedCaveCount - errorCount;
|
|
756
|
+
return `已补全 ${successCount} 个回声洞的 ${totalHashesGenerated} 条哈希(失败 ${errorCount} 条)`;
|
|
759
757
|
} catch (error) {
|
|
760
|
-
this.logger.error("
|
|
758
|
+
this.logger.error("补全哈希失败:", error);
|
|
761
759
|
return `操作失败: ${error.message}`;
|
|
762
760
|
}
|
|
763
761
|
});
|
|
@@ -821,13 +819,13 @@ var HashManager = class {
|
|
|
821
819
|
if (requireAdmin(session, this.config)) return requireAdmin(session, this.config);
|
|
822
820
|
let cavesToProcess;
|
|
823
821
|
try {
|
|
822
|
+
await session.send("正在修复,请稍候...");
|
|
824
823
|
if (ids.length === 0) {
|
|
825
|
-
await session.send("正在修复,请稍候...");
|
|
826
824
|
cavesToProcess = await this.ctx.database.get("cave", { status: "active" });
|
|
827
825
|
} else {
|
|
828
826
|
cavesToProcess = await this.ctx.database.get("cave", { id: { $in: ids }, status: "active" });
|
|
829
827
|
}
|
|
830
|
-
if (!cavesToProcess.length) return "
|
|
828
|
+
if (!cavesToProcess.length) return "无可修复的回声洞";
|
|
831
829
|
let fixedFiles = 0;
|
|
832
830
|
let errorCount = 0;
|
|
833
831
|
const PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
@@ -1101,10 +1099,13 @@ var AIManager = class {
|
|
|
1101
1099
|
const formatContent = /* @__PURE__ */ __name((elements) => elements.filter((el) => el.type === "text").map((el) => el.content).join(" "), "formatContent");
|
|
1102
1100
|
const userMessage = {
|
|
1103
1101
|
role: "user",
|
|
1104
|
-
content:
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
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
|
+
}]
|
|
1108
1109
|
};
|
|
1109
1110
|
const response = await this.requestAI([userMessage], this.config.aiCheckPrompt, this.config.aiCheckSchema);
|
|
1110
1111
|
return {
|
|
@@ -1148,7 +1149,7 @@ var AIManager = class {
|
|
|
1148
1149
|
async getAnalysis(elements, mediaToSave, mediaBuffers) {
|
|
1149
1150
|
const userContent = [];
|
|
1150
1151
|
const combinedText = elements.filter((el) => el.type === "text" && el.content).map((el) => el.content).join("\n");
|
|
1151
|
-
if (combinedText.trim()) userContent.push({ type: "
|
|
1152
|
+
if (combinedText.trim()) userContent.push({ type: "input_text", text: combinedText });
|
|
1152
1153
|
const mediaMap = new Map(mediaBuffers?.map((m) => [m.fileName, m.buffer]));
|
|
1153
1154
|
const imageElements = elements.filter((el) => el.type === "image" && el.file);
|
|
1154
1155
|
for (const el of imageElements) {
|
|
@@ -1165,8 +1166,8 @@ var AIManager = class {
|
|
|
1165
1166
|
if (buffer) {
|
|
1166
1167
|
const mimeType = path3.extname(el.file).toLowerCase() === ".png" ? "image/png" : "image/jpeg";
|
|
1167
1168
|
userContent.push({
|
|
1168
|
-
type: "
|
|
1169
|
-
image_url:
|
|
1169
|
+
type: "input_image",
|
|
1170
|
+
image_url: `data:${mimeType};base64,${buffer.toString("base64")}`
|
|
1170
1171
|
});
|
|
1171
1172
|
}
|
|
1172
1173
|
} catch (error) {
|
|
@@ -1197,22 +1198,28 @@ var AIManager = class {
|
|
|
1197
1198
|
this.rateLimitResetTime = Date.now() + 6e4;
|
|
1198
1199
|
this.requestCount = 0;
|
|
1199
1200
|
}
|
|
1200
|
-
let schema
|
|
1201
|
-
|
|
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
|
+
}
|
|
1202
1208
|
const payload = {
|
|
1203
1209
|
model: this.config.aiModel,
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1210
|
+
input: [
|
|
1211
|
+
{ role: "system", content: systemPrompt },
|
|
1212
|
+
...messages
|
|
1213
|
+
],
|
|
1214
|
+
text: {
|
|
1215
|
+
format: {
|
|
1216
|
+
type: "json_schema",
|
|
1217
|
+
name: "extracted_data",
|
|
1218
|
+
schema
|
|
1211
1219
|
}
|
|
1212
|
-
}
|
|
1213
|
-
tool_choice: { type: "function", function: { name: toolName } }
|
|
1220
|
+
}
|
|
1214
1221
|
};
|
|
1215
|
-
const fullUrl = `${this.config.aiEndpoint.replace(/\/$/, "")}/
|
|
1222
|
+
const fullUrl = `${this.config.aiEndpoint.replace(/\/$/, "")}/responses`;
|
|
1216
1223
|
const headers = {
|
|
1217
1224
|
"Content-Type": "application/json",
|
|
1218
1225
|
"Authorization": `Bearer ${this.config.aiApiKey}`
|
|
@@ -1220,9 +1227,9 @@ var AIManager = class {
|
|
|
1220
1227
|
try {
|
|
1221
1228
|
this.requestCount++;
|
|
1222
1229
|
const response = await this.http.post(fullUrl, payload, { headers, timeout: 9e4 });
|
|
1223
|
-
const
|
|
1224
|
-
if (
|
|
1225
|
-
return JSON.parse(
|
|
1230
|
+
const responseText = response.output?.[0]?.content?.[0]?.text;
|
|
1231
|
+
if (responseText) {
|
|
1232
|
+
return JSON.parse(responseText);
|
|
1226
1233
|
} else {
|
|
1227
1234
|
this.logger.error("AI 响应格式不正确:", JSON.stringify(response));
|
|
1228
1235
|
throw new Error("AI 响应格式不正确");
|
|
@@ -1262,8 +1269,8 @@ var Config = import_koishi3.Schema.intersect([
|
|
|
1262
1269
|
import_koishi3.Schema.object({
|
|
1263
1270
|
enablePend: import_koishi3.Schema.boolean().default(false).description("启用审核"),
|
|
1264
1271
|
enableSimilarity: import_koishi3.Schema.boolean().default(false).description("启用查重"),
|
|
1265
|
-
textThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(
|
|
1266
|
-
imageThreshold: import_koishi3.Schema.number().min(0).max(100).step(0.01).default(
|
|
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("图片相似度阈值 (%)")
|
|
1267
1274
|
}).description("复核配置"),
|
|
1268
1275
|
import_koishi3.Schema.object({
|
|
1269
1276
|
enableAI: import_koishi3.Schema.boolean().default(false).description("启用 AI"),
|