koishi-plugin-hhs-huatu 0.2.1 → 0.2.2
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 +180 -20
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1152,6 +1152,59 @@ function parseForbidden(input) {
|
|
|
1152
1152
|
}
|
|
1153
1153
|
__name(parseForbidden, "parseForbidden");
|
|
1154
1154
|
var backslash = /@@__BACKSLASH__@@/g;
|
|
1155
|
+
function cleanUndesiredParameter(undesired) {
|
|
1156
|
+
const optionPatterns = [
|
|
1157
|
+
/-K\s+["']?[^"']*["']?/g,
|
|
1158
|
+
// -K 选项
|
|
1159
|
+
/-m\s+\w+/g,
|
|
1160
|
+
// -m 选项
|
|
1161
|
+
/-s\s+\w+/g,
|
|
1162
|
+
// -s 选项
|
|
1163
|
+
/-r\s+[\w\d]+/g,
|
|
1164
|
+
// -r 选项
|
|
1165
|
+
/-o\s+\w+/g,
|
|
1166
|
+
// -o 选项
|
|
1167
|
+
/-O\s*/g,
|
|
1168
|
+
// -O 选项
|
|
1169
|
+
/-x\s+\d+/g,
|
|
1170
|
+
// -x 选项
|
|
1171
|
+
/-t\s+\d+/g,
|
|
1172
|
+
// -t 选项
|
|
1173
|
+
/-c\s+[\d.]+/g,
|
|
1174
|
+
// -c 选项
|
|
1175
|
+
/-R\s+[\d.]+/g,
|
|
1176
|
+
// -R 选项
|
|
1177
|
+
/-n\s+[\d.]+/g,
|
|
1178
|
+
// -n 选项
|
|
1179
|
+
/-N\s+[\d.]+/g,
|
|
1180
|
+
// -N 选项
|
|
1181
|
+
/-H\s*/g,
|
|
1182
|
+
// -H 选项
|
|
1183
|
+
/-S\s*/g,
|
|
1184
|
+
// -S 选项
|
|
1185
|
+
/-d\s*/g,
|
|
1186
|
+
// -d 选项
|
|
1187
|
+
/-C\s+\w+/g,
|
|
1188
|
+
// -C 选项
|
|
1189
|
+
/-D\s*/g,
|
|
1190
|
+
// -D 选项
|
|
1191
|
+
/-T\s*/g,
|
|
1192
|
+
// -T 选项
|
|
1193
|
+
/-i\s+\d+/g,
|
|
1194
|
+
// -i 选项
|
|
1195
|
+
/-b\s+\d+/g,
|
|
1196
|
+
// -b 选项
|
|
1197
|
+
/-I\s*/g
|
|
1198
|
+
// -I 选项
|
|
1199
|
+
];
|
|
1200
|
+
let cleaned = undesired.trim();
|
|
1201
|
+
for (const pattern of optionPatterns) {
|
|
1202
|
+
cleaned = cleaned.replace(pattern, "").trim();
|
|
1203
|
+
}
|
|
1204
|
+
cleaned = cleaned.replace(/^["']|["']$/g, "").trim();
|
|
1205
|
+
return cleaned;
|
|
1206
|
+
}
|
|
1207
|
+
__name(cleanUndesiredParameter, "cleanUndesiredParameter");
|
|
1155
1208
|
function parseInput(session, input, config, override, undesired) {
|
|
1156
1209
|
if (!input) {
|
|
1157
1210
|
return [
|
|
@@ -1167,8 +1220,21 @@ function parseInput(session, input, config, override, undesired) {
|
|
|
1167
1220
|
}
|
|
1168
1221
|
const negative = [];
|
|
1169
1222
|
const placement = session.resolve(config.placement);
|
|
1170
|
-
const appendToList = /* @__PURE__ */ __name((words, input2 = "") => {
|
|
1171
|
-
|
|
1223
|
+
const appendToList = /* @__PURE__ */ __name((words, input2 = "", isNegative = false) => {
|
|
1224
|
+
let tags;
|
|
1225
|
+
if (isNegative) {
|
|
1226
|
+
if (input2.includes(",")) {
|
|
1227
|
+
tags = input2.split(/,\s*/g);
|
|
1228
|
+
} else {
|
|
1229
|
+
tags = [input2.trim()];
|
|
1230
|
+
}
|
|
1231
|
+
} else {
|
|
1232
|
+
if (input2.includes(",")) {
|
|
1233
|
+
tags = input2.split(/,\s*/g);
|
|
1234
|
+
} else {
|
|
1235
|
+
tags = input2.split(/\s+/g).filter((tag) => tag.trim());
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1172
1238
|
if (placement === "before") tags.reverse();
|
|
1173
1239
|
for (let tag of tags) {
|
|
1174
1240
|
tag = tag.trim();
|
|
@@ -1184,10 +1250,13 @@ function parseInput(session, input, config, override, undesired) {
|
|
|
1184
1250
|
const capture = input.match(/(,\s*|\s+)(-u\s+|--undesired\s+|negative prompts?:\s*)([\s\S]+)/m);
|
|
1185
1251
|
if (capture?.[3]) {
|
|
1186
1252
|
input = input.slice(0, capture.index).trim();
|
|
1187
|
-
appendToList(negative, capture[3]);
|
|
1253
|
+
appendToList(negative, capture[3], true);
|
|
1188
1254
|
}
|
|
1189
1255
|
if (undesired) {
|
|
1190
|
-
|
|
1256
|
+
const cleanedUndesired = cleanUndesiredParameter(undesired);
|
|
1257
|
+
if (cleanedUndesired) {
|
|
1258
|
+
appendToList(negative, cleanedUndesired, true);
|
|
1259
|
+
}
|
|
1191
1260
|
}
|
|
1192
1261
|
const forbidden = parseForbidden(session.resolve(config.forbidden));
|
|
1193
1262
|
const positive = input.split(/,\s*/g).filter((word) => {
|
|
@@ -1205,15 +1274,30 @@ function parseInput(session, input, config, override, undesired) {
|
|
|
1205
1274
|
if (/^<.+>$/.test(word)) return word.replace(/ /g, "_");
|
|
1206
1275
|
return config.lowerCase ? word.toLowerCase() : word;
|
|
1207
1276
|
});
|
|
1208
|
-
|
|
1277
|
+
const processedNegative = negative.filter((word) => {
|
|
1278
|
+
word = word.toLowerCase().replace(/[\x00-\x7f]/g, (s) => s.replace(/[^0-9a-zA-Z]/, " ")).replace(/\s+/, " ").trim();
|
|
1279
|
+
if (!word) return false;
|
|
1280
|
+
for (const { pattern, strict } of forbidden) {
|
|
1281
|
+
if (strict && word.split(/\W+/g).includes(pattern)) {
|
|
1282
|
+
return false;
|
|
1283
|
+
} else if (!strict && word.includes(pattern)) {
|
|
1284
|
+
return false;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
return true;
|
|
1288
|
+
}).map((word) => {
|
|
1289
|
+
if (/^<.+>$/.test(word)) return word.replace(/ /g, "_");
|
|
1290
|
+
return config.lowerCase ? word.toLowerCase() : word;
|
|
1291
|
+
});
|
|
1292
|
+
if (Math.max(getWordCount(positive), getWordCount(processedNegative)) > (session.resolve(config.maxWords) || Infinity)) {
|
|
1209
1293
|
return [".too-many-words"];
|
|
1210
1294
|
}
|
|
1211
1295
|
if (!override) {
|
|
1212
|
-
appendToList(positive, session.resolve(config.basePrompt));
|
|
1213
|
-
appendToList(
|
|
1214
|
-
if (config.defaultPromptSw) appendToList(positive, session.resolve(config.defaultPrompt));
|
|
1296
|
+
appendToList(positive, session.resolve(config.basePrompt), false);
|
|
1297
|
+
appendToList(processedNegative, session.resolve(config.negativePrompt), true);
|
|
1298
|
+
if (config.defaultPromptSw) appendToList(positive, session.resolve(config.defaultPrompt), false);
|
|
1215
1299
|
}
|
|
1216
|
-
return [null, positive.join(", "),
|
|
1300
|
+
return [null, positive.join(", "), processedNegative.join(", ")];
|
|
1217
1301
|
}
|
|
1218
1302
|
__name(parseInput, "parseInput");
|
|
1219
1303
|
function getWordCount(words) {
|
|
@@ -1247,7 +1331,9 @@ var STRATEGIES = {
|
|
|
1247
1331
|
formData
|
|
1248
1332
|
);
|
|
1249
1333
|
const nsfw = response.data.results[0].entities[0].classes.nsfw;
|
|
1250
|
-
|
|
1334
|
+
if (config.debugLog) {
|
|
1335
|
+
logger.info(`api4ai图片审核结果:${nsfw}`);
|
|
1336
|
+
}
|
|
1251
1337
|
return {
|
|
1252
1338
|
pass: nsfw <= config.api4ai.nsfwThreshold,
|
|
1253
1339
|
score: nsfw,
|
|
@@ -1267,11 +1353,15 @@ var STRATEGIES = {
|
|
|
1267
1353
|
});
|
|
1268
1354
|
const bucket = config.bucket || "default-1250000000";
|
|
1269
1355
|
const region = config.region?.toLowerCase() || "ap-chengdu";
|
|
1270
|
-
|
|
1356
|
+
if (config.debugLog) {
|
|
1357
|
+
logger.info(`腾讯云图片审核请求参数: Region=${region}, Bucket=${bucket}, BizType=${config.bizType}`);
|
|
1358
|
+
}
|
|
1271
1359
|
try {
|
|
1272
1360
|
const imageBase64 = Buffer.from(buffer).toString("base64");
|
|
1273
1361
|
const url = `https://${bucket}.ci.${region}.myqcloud.com/image/auditing`;
|
|
1274
|
-
|
|
1362
|
+
if (config.debugLog) {
|
|
1363
|
+
logger.info(`腾讯云图片审核请求URL: ${url}`);
|
|
1364
|
+
}
|
|
1275
1365
|
const requestData = {
|
|
1276
1366
|
Input: {
|
|
1277
1367
|
Content: imageBase64
|
|
@@ -1301,13 +1391,17 @@ var STRATEGIES = {
|
|
|
1301
1391
|
}
|
|
1302
1392
|
);
|
|
1303
1393
|
});
|
|
1304
|
-
|
|
1394
|
+
if (config.debugLog) {
|
|
1395
|
+
logger.info(`腾讯云图片审核响应:`, JSON.stringify(response));
|
|
1396
|
+
}
|
|
1305
1397
|
const result = response.JobsDetail || response.Response && response.Response.JobsDetail;
|
|
1306
1398
|
if (!result) {
|
|
1307
1399
|
throw new Error("审核结果解析失败,未找到JobsDetail字段");
|
|
1308
1400
|
}
|
|
1309
1401
|
const label = result.Label;
|
|
1310
|
-
|
|
1402
|
+
if (config.debugLog) {
|
|
1403
|
+
logger.info(`腾讯云图片审核结果: Label=${label}`);
|
|
1404
|
+
}
|
|
1311
1405
|
return {
|
|
1312
1406
|
pass: label === "Normal",
|
|
1313
1407
|
score: label === "Normal" ? 0 : 1,
|
|
@@ -1325,7 +1419,9 @@ var STRATEGIES = {
|
|
|
1325
1419
|
if (error.statusCode) {
|
|
1326
1420
|
errorMessage += ` (状态码: ${error.statusCode})`;
|
|
1327
1421
|
}
|
|
1328
|
-
|
|
1422
|
+
if (config.debugLog) {
|
|
1423
|
+
logger.error(`腾讯云图片审核失败详情:`, JSON.stringify(error, Object.getOwnPropertyNames(error)));
|
|
1424
|
+
}
|
|
1329
1425
|
}
|
|
1330
1426
|
logger.error(`腾讯云图片审核失败: ${errorMessage}`);
|
|
1331
1427
|
throw new Error(errorMessage);
|
|
@@ -1346,7 +1442,9 @@ async function auditImage(ctx, data, config) {
|
|
|
1346
1442
|
buffer = Buffer.from(data);
|
|
1347
1443
|
}
|
|
1348
1444
|
const imageSizeKB = Math.round(buffer.length / 1024);
|
|
1349
|
-
|
|
1445
|
+
if (config.debugLog) {
|
|
1446
|
+
ctx.logger.debug(`图片大小: ${imageSizeKB}KB`);
|
|
1447
|
+
}
|
|
1350
1448
|
const maxSizeKB = config.imageAudit?.maxSizeKB || 4096;
|
|
1351
1449
|
if (imageSizeKB > maxSizeKB) {
|
|
1352
1450
|
ctx.logger.warn(`图片大小(${imageSizeKB}KB)超过限制(${maxSizeKB}KB),可能影响审核性能`);
|
|
@@ -1376,7 +1474,9 @@ async function auditImage(ctx, data, config) {
|
|
|
1376
1474
|
if (!result.processingTime) {
|
|
1377
1475
|
result.processingTime = totalProcessingTime;
|
|
1378
1476
|
}
|
|
1379
|
-
|
|
1477
|
+
if (config.debugLog) {
|
|
1478
|
+
ctx.logger.debug(`图片审核完成,总耗时: ${totalProcessingTime}ms`);
|
|
1479
|
+
}
|
|
1380
1480
|
return result;
|
|
1381
1481
|
} catch (error) {
|
|
1382
1482
|
let errorMessage = "审核失败";
|
|
@@ -1390,7 +1490,7 @@ async function auditImage(ctx, data, config) {
|
|
|
1390
1490
|
if (error.statusCode) {
|
|
1391
1491
|
errorMessage += ` (状态码: ${error.statusCode})`;
|
|
1392
1492
|
}
|
|
1393
|
-
if (config.
|
|
1493
|
+
if (config.debugLog) {
|
|
1394
1494
|
ctx.logger.error(`图片审核失败详情:`, JSON.stringify(error, Object.getOwnPropertyNames(error)));
|
|
1395
1495
|
} else {
|
|
1396
1496
|
ctx.logger.error(`图片审核失败: ${errorMessage}`);
|
|
@@ -1480,6 +1580,56 @@ var inject = {
|
|
|
1480
1580
|
required: ["http"],
|
|
1481
1581
|
optional: ["translator"]
|
|
1482
1582
|
};
|
|
1583
|
+
function extractOptionsFromUndesired(undesired) {
|
|
1584
|
+
const extractedOptions = {};
|
|
1585
|
+
let cleanedUndesired = undesired.trim();
|
|
1586
|
+
const optionPatterns = [
|
|
1587
|
+
// 带引号的选项(优先级最高)
|
|
1588
|
+
{ pattern: /-K\s+["']([^"']*)["']/g, key: "chars" },
|
|
1589
|
+
{ pattern: /-m\s+["']([^"']*)["']/g, key: "model" },
|
|
1590
|
+
{ pattern: /-s\s+["']([^"']*)["']/g, key: "sampler" },
|
|
1591
|
+
{ pattern: /-r\s+["']([^"']*)["']/g, key: "resolution" },
|
|
1592
|
+
{ pattern: /-o\s+["']([^"']*)["']/g, key: "output" },
|
|
1593
|
+
{ pattern: /-C\s+["']([^"']*)["']/g, key: "scheduler" },
|
|
1594
|
+
// 不带引号的选项
|
|
1595
|
+
{ pattern: /-K\s+(\S+)/g, key: "chars" },
|
|
1596
|
+
{ pattern: /-m\s+(\w+)/g, key: "model" },
|
|
1597
|
+
{ pattern: /-s\s+(\w+)/g, key: "sampler" },
|
|
1598
|
+
{ pattern: /-r\s+([\w\d]+)/g, key: "resolution" },
|
|
1599
|
+
{ pattern: /-o\s+(\w+)/g, key: "output" },
|
|
1600
|
+
{ pattern: /-O\s*/g, key: "override", value: true },
|
|
1601
|
+
{ pattern: /-x\s+(\d+)/g, key: "seed" },
|
|
1602
|
+
{ pattern: /-t\s+(\d+)/g, key: "steps" },
|
|
1603
|
+
{ pattern: /-c\s+([\d.]+)/g, key: "scale" },
|
|
1604
|
+
{ pattern: /-R\s+([\d.]+)/g, key: "rescale" },
|
|
1605
|
+
{ pattern: /-n\s+([\d.]+)/g, key: "noise" },
|
|
1606
|
+
{ pattern: /-N\s+([\d.]+)/g, key: "strength" },
|
|
1607
|
+
{ pattern: /-H\s*/g, key: "hiresFix", value: true },
|
|
1608
|
+
{ pattern: /-S\s*/g, key: "smea", value: true },
|
|
1609
|
+
{ pattern: /-d\s*/g, key: "smeaDyn", value: true },
|
|
1610
|
+
{ pattern: /-C\s+(\w+)/g, key: "scheduler" },
|
|
1611
|
+
{ pattern: /-D\s*/g, key: "decrisper", value: true },
|
|
1612
|
+
{ pattern: /-T\s*/g, key: "noTranslator", value: true },
|
|
1613
|
+
{ pattern: /-i\s+(\d+)/g, key: "iterations" },
|
|
1614
|
+
{ pattern: /-b\s+(\d+)/g, key: "batch" },
|
|
1615
|
+
{ pattern: /-I\s*/g, key: "ignoreSpace", value: true }
|
|
1616
|
+
];
|
|
1617
|
+
for (const { pattern, key, value } of optionPatterns) {
|
|
1618
|
+
const matches = [...cleanedUndesired.matchAll(pattern)];
|
|
1619
|
+
for (const match of matches) {
|
|
1620
|
+
if (value !== void 0) {
|
|
1621
|
+
extractedOptions[key] = value;
|
|
1622
|
+
} else if (match[1]) {
|
|
1623
|
+
extractedOptions[key] = match[1];
|
|
1624
|
+
}
|
|
1625
|
+
cleanedUndesired = cleanedUndesired.replace(match[0], "").trim();
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
cleanedUndesired = cleanedUndesired.replace(/\s+/g, " ").trim();
|
|
1629
|
+
cleanedUndesired = cleanedUndesired.replace(/^["']|["']$/g, "").trim();
|
|
1630
|
+
return { cleanedUndesired, extractedOptions };
|
|
1631
|
+
}
|
|
1632
|
+
__name(extractOptionsFromUndesired, "extractOptionsFromUndesired");
|
|
1483
1633
|
function apply(ctx, config) {
|
|
1484
1634
|
const userTasks = /* @__PURE__ */ Object.create(null);
|
|
1485
1635
|
const userCooldowns = /* @__PURE__ */ Object.create(null);
|
|
@@ -2636,8 +2786,18 @@ function apply(ctx, config) {
|
|
|
2636
2786
|
const cmd = ctx.command("novelai [prompts...]").alias("nai").alias("imagine").alias("nai4", { options: { model: "nai-v4-full", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4c", { options: { model: "nai-v4-curated-preview", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4-5c", { options: { model: "nai-v4-5-curated", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4-5", { options: { model: "nai-v4-5-full", sampler: "k_euler_a", iterations: 1, batch: 1 } }).userFields(["authority"]).shortcut("imagine", { i18n: true, fuzzy: true }).shortcut("enhance", { i18n: true, fuzzy: true, options: { enhance: true } }).option("enhance", "-e", { hidden: some(restricted, thirdParty, noImage) }).option("model", "-m <model>", { type: models, hidden: thirdParty }).option("resolution", "-r <resolution>", { type: resolution2 }).option("output", "-o", { type: ["minimal", "default", "verbose"] }).option("override", "-O", { hidden: restricted }).option("sampler", "-s <sampler>").option("seed", "-x <seed:number>").option("steps", "-t <step>", { type: step, hidden: restricted }).option("scale", "-c <scale:number>").option("rescale", "-R <rescale:number>").option("noise", "-n <noise:number>", { hidden: some(restricted, thirdParty) }).option("strength", "-N <strength:number>", { hidden: restricted }).option("hiresFix", "-H", { hidden: /* @__PURE__ */ __name(() => config.type !== "sd-webui", "hidden") }).option("hiresFixSteps", "<step>", { type: step, hidden: /* @__PURE__ */ __name(() => config.type !== "sd-webui", "hidden") }).option("smea", "-S", { hidden: /* @__PURE__ */ __name(() => config.model !== "nai-v3", "hidden") }).option("smeaDyn", "-d", { hidden: /* @__PURE__ */ __name(() => config.model !== "nai-v3", "hidden") }).option("scheduler", "-C <scheduler:string>", {
|
|
2637
2787
|
hidden: /* @__PURE__ */ __name(() => config.type === "naifu", "hidden"),
|
|
2638
2788
|
type: ["token", "login"].includes(config.type) ? scheduler.nai : config.type === "sd-webui" ? scheduler.sd : config.type === "stable-horde" ? scheduler.horde : []
|
|
2639
|
-
}).option("decrisper", "-D", { hidden: thirdParty }).option("undesired", "-u <undesired>").option("noTranslator", "-T", { hidden: /* @__PURE__ */ __name(() => !ctx.translator || !config.translator, "hidden") }).option("iterations", "-i <iterations:posint>", { fallback: 1, hidden: /* @__PURE__ */ __name(() => config.maxIterations <= 1, "hidden") }).option("batch", "-b <batch:option>", { fallback: 1, hidden: /* @__PURE__ */ __name(() => config.maxIterations <= 1, "hidden") }).option("chars", "-K <chars>").option("ignoreSpace", "-I", { hidden: true }).action(async ({ session, options: options2, name: name2 }, ...prompts) => {
|
|
2640
|
-
|
|
2789
|
+
}).option("decrisper", "-D", { hidden: thirdParty }).option("undesired", "-u <undesired:text>").option("noTranslator", "-T", { hidden: /* @__PURE__ */ __name(() => !ctx.translator || !config.translator, "hidden") }).option("iterations", "-i <iterations:posint>", { fallback: 1, hidden: /* @__PURE__ */ __name(() => config.maxIterations <= 1, "hidden") }).option("batch", "-b <batch:option>", { fallback: 1, hidden: /* @__PURE__ */ __name(() => config.maxIterations <= 1, "hidden") }).option("chars", "-K <chars>").option("ignoreSpace", "-I", { hidden: true }).action(async ({ session, options: options2, name: name2 }, ...prompts) => {
|
|
2790
|
+
let input = prompts.join(" ");
|
|
2791
|
+
if (options2.undesired) {
|
|
2792
|
+
const { cleanedUndesired, extractedOptions } = extractOptionsFromUndesired(options2.undesired);
|
|
2793
|
+
options2.undesired = cleanedUndesired;
|
|
2794
|
+
Object.assign(options2, extractedOptions);
|
|
2795
|
+
if (config.debugLog) {
|
|
2796
|
+
ctx.logger.info(`[Undesired Debug] 原始 undesired: ${options2.undesired}`);
|
|
2797
|
+
ctx.logger.info(`[Undesired Debug] 清理后 undesired: ${cleanedUndesired}`);
|
|
2798
|
+
ctx.logger.info(`[Undesired Debug] 提取的选项: ${JSON.stringify(extractedOptions)}`);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2641
2801
|
if (config.debugLog) {
|
|
2642
2802
|
ctx.logger.info(`[Characters Debug] 接收到的 prompts 数组: ${JSON.stringify(prompts)}`);
|
|
2643
2803
|
ctx.logger.info(`[Characters Debug] 接收到的 input: ${input}`);
|