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.
Files changed (2) hide show
  1. package/lib/index.js +180 -20
  2. 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
- const tags = input2.split(/,\s*/g);
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
- appendToList(negative, undesired);
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
- if (Math.max(getWordCount(positive), getWordCount(negative)) > (session.resolve(config.maxWords) || Infinity)) {
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(negative, session.resolve(config.negativePrompt));
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(", "), negative.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
- logger.info(`api4ai图片审核结果:${nsfw}`);
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
- logger.info(`腾讯云图片审核请求参数: Region=${region}, Bucket=${bucket}, BizType=${config.bizType}`);
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
- logger.info(`腾讯云图片审核请求URL: ${url}`);
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
- logger.info(`腾讯云图片审核响应:`, JSON.stringify(response));
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
- logger.info(`腾讯云图片审核结果: Label=${label}`);
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
- logger.error(`腾讯云图片审核失败详情:`, JSON.stringify(error, Object.getOwnPropertyNames(error)));
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
- ctx.logger.debug(`图片大小: ${imageSizeKB}KB`);
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
- ctx.logger.debug(`图片审核完成,总耗时: ${totalProcessingTime}ms`);
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.imageAudit?.debug) {
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
- const input = prompts.join(" ");
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}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-hhs-huatu",
3
3
  "description": "Generate images by diffusion models",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [