koishi-plugin-cocoyyy-console 1.2.1 → 1.2.2-alpha.1
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
CHANGED
|
@@ -381,19 +381,62 @@ function loadGroupFunctionLimitConfig(config) {
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
__name(loadGroupFunctionLimitConfig, "loadGroupFunctionLimitConfig");
|
|
384
|
+
function getEffectiveMenuListForGuild(guildId) {
|
|
385
|
+
if (!groupFunctionLimitConfig || groupFunctionLimitConfig.length === 0) {
|
|
386
|
+
return [];
|
|
387
|
+
}
|
|
388
|
+
const explicit = groupFunctionLimitConfig.find(
|
|
389
|
+
(item) => String(item.group_id) === String(guildId)
|
|
390
|
+
);
|
|
391
|
+
if (explicit) {
|
|
392
|
+
return Array.isArray(explicit.menu_list) ? explicit.menu_list : [];
|
|
393
|
+
}
|
|
394
|
+
const defaultEntry = groupFunctionLimitConfig.find(
|
|
395
|
+
(item) => String(item.group_id) === "#"
|
|
396
|
+
);
|
|
397
|
+
if (defaultEntry) {
|
|
398
|
+
return Array.isArray(defaultEntry.menu_list) ? defaultEntry.menu_list : [];
|
|
399
|
+
}
|
|
400
|
+
return [];
|
|
401
|
+
}
|
|
402
|
+
__name(getEffectiveMenuListForGuild, "getEffectiveMenuListForGuild");
|
|
403
|
+
function isFunctionAllowedForGuild(guildId, menuNumber) {
|
|
404
|
+
if (!groupFunctionLimitConfig || groupFunctionLimitConfig.length === 0) {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
if (guildId === void 0 || guildId === null) {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
return getEffectiveMenuListForGuild(guildId).includes(menuNumber);
|
|
411
|
+
}
|
|
412
|
+
__name(isFunctionAllowedForGuild, "isFunctionAllowedForGuild");
|
|
413
|
+
function getAllowedMenuNumbersForGuild(guildId) {
|
|
414
|
+
if (!groupFunctionLimitConfig || groupFunctionLimitConfig.length === 0) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
if (guildId === void 0 || guildId === null) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
const allMenus = menuList ?? [];
|
|
421
|
+
if (allMenus.length === 0) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
const validNumbers = new Set(allMenus.map((item) => item.number));
|
|
425
|
+
return getEffectiveMenuListForGuild(guildId).filter((n) => validNumbers.has(n));
|
|
426
|
+
}
|
|
427
|
+
__name(getAllowedMenuNumbersForGuild, "getAllowedMenuNumbersForGuild");
|
|
384
428
|
function getCtxForFunction(ctx, menuNumber) {
|
|
385
429
|
if (!groupFunctionLimitConfig || groupFunctionLimitConfig.length === 0) {
|
|
386
430
|
return ctx;
|
|
387
431
|
}
|
|
388
|
-
const
|
|
389
|
-
const defaultAllowed = defaultEntry ? defaultEntry.menu_list.includes(menuNumber) : false;
|
|
432
|
+
const defaultAllowed = isFunctionAllowedForGuild("#", menuNumber) ?? false;
|
|
390
433
|
const explicitGroups = groupFunctionLimitConfig.filter((item) => String(item.group_id) !== "#");
|
|
391
434
|
if (defaultAllowed) {
|
|
392
|
-
const excludedIds = explicitGroups.filter((item) => !item.
|
|
435
|
+
const excludedIds = explicitGroups.filter((item) => !getEffectiveMenuListForGuild(item.group_id).includes(menuNumber)).map((item) => String(item.group_id));
|
|
393
436
|
if (excludedIds.length === 0) return ctx;
|
|
394
437
|
return ctx.exclude((session) => !!session.guildId && excludedIds.includes(session.guildId));
|
|
395
438
|
} else {
|
|
396
|
-
const includedIds = explicitGroups.filter((item) => item.
|
|
439
|
+
const includedIds = explicitGroups.filter((item) => getEffectiveMenuListForGuild(item.group_id).includes(menuNumber)).map((item) => String(item.group_id));
|
|
397
440
|
if (includedIds.length === 0) {
|
|
398
441
|
logger.info(`[getCtxForFunction Info]: 功能 ${menuNumber} 在所有群组中均未启用,跳过注册`);
|
|
399
442
|
return null;
|
|
@@ -402,38 +445,16 @@ function getCtxForFunction(ctx, menuNumber) {
|
|
|
402
445
|
}
|
|
403
446
|
}
|
|
404
447
|
__name(getCtxForFunction, "getCtxForFunction");
|
|
405
|
-
function getGroupFunctionLimitConfig() {
|
|
406
|
-
return groupFunctionLimitConfig;
|
|
407
|
-
}
|
|
408
|
-
__name(getGroupFunctionLimitConfig, "getGroupFunctionLimitConfig");
|
|
409
448
|
function getMenuList() {
|
|
410
449
|
return menuList;
|
|
411
450
|
}
|
|
412
451
|
__name(getMenuList, "getMenuList");
|
|
413
452
|
|
|
414
453
|
// src/services/menu_service.ts
|
|
415
|
-
function getAllowedMenuNumbersForGuild(guildId) {
|
|
416
|
-
const groupList = getGroupFunctionLimitConfig();
|
|
417
|
-
if (!groupList || groupList.length === 0) return null;
|
|
418
|
-
if (guildId === void 0 || guildId === null) return null;
|
|
419
|
-
const allMenus = getMenuList() ?? [];
|
|
420
|
-
if (!allMenus || allMenus.length === 0) return null;
|
|
421
|
-
const match = groupList.find(
|
|
422
|
-
(item) => String(item.group_id) === String(guildId)
|
|
423
|
-
);
|
|
424
|
-
if (!match) return null;
|
|
425
|
-
if (!Array.isArray(match.menu_list)) return null;
|
|
426
|
-
const menuByNumber = /* @__PURE__ */ new Map();
|
|
427
|
-
for (const item of allMenus) {
|
|
428
|
-
menuByNumber.set(item.number, item.number);
|
|
429
|
-
}
|
|
430
|
-
return match.menu_list.map((menuNum) => Number(menuByNumber.get(menuNum)));
|
|
431
|
-
}
|
|
432
|
-
__name(getAllowedMenuNumbersForGuild, "getAllowedMenuNumbersForGuild");
|
|
433
454
|
function isCommandAllowedForGuild(commandNumber, guildId) {
|
|
434
|
-
const allowed =
|
|
435
|
-
if (
|
|
436
|
-
return allowed
|
|
455
|
+
const allowed = isFunctionAllowedForGuild(guildId, commandNumber);
|
|
456
|
+
if (allowed === null) return true;
|
|
457
|
+
return allowed;
|
|
437
458
|
}
|
|
438
459
|
__name(isCommandAllowedForGuild, "isCommandAllowedForGuild");
|
|
439
460
|
function buildFuncMenu(menuTitle, featureName, commandList2) {
|
|
@@ -444,7 +465,7 @@ ${menuTitle}:
|
|
|
444
465
|
}
|
|
445
466
|
__name(buildFuncMenu, "buildFuncMenu");
|
|
446
467
|
function getMenuListByCommand(command = null, functionConfig, session) {
|
|
447
|
-
const guildId = session?.
|
|
468
|
+
const guildId = session?.guildId;
|
|
448
469
|
const allMenus = getMenuList() ?? [];
|
|
449
470
|
if (allMenus.length === 0) return "当前没有可用的功能,请联系管理员配置功能";
|
|
450
471
|
const menuByNumber = /* @__PURE__ */ new Map();
|
|
@@ -517,7 +538,7 @@ function getMenuListByCommand(command = null, functionConfig, session) {
|
|
|
517
538
|
return buildFuncMenu("禁漫下载功能菜单", "禁漫下载功能", jmFuncMenuList);
|
|
518
539
|
default:
|
|
519
540
|
const allowedMenuNumbers = getAllowedMenuNumbersForGuild(guildId);
|
|
520
|
-
const finalMenuList = allowedMenuNumbers ? allMenus.filter((item) => allowedMenuNumbers.includes(item.number))
|
|
541
|
+
const finalMenuList = allowedMenuNumbers === null ? allMenus : allMenus.filter((item) => allowedMenuNumbers.includes(item.number));
|
|
521
542
|
return `[所有命令都需要@bot]
|
|
522
543
|
当前可用功能列表:
|
|
523
544
|
${finalMenuList.map((item) => item.name + ": " + item.description).join("\n ")}
|
|
@@ -1760,6 +1781,68 @@ function extractImageAndText(content) {
|
|
|
1760
1781
|
return { imageUrls, text };
|
|
1761
1782
|
}
|
|
1762
1783
|
__name(extractImageAndText, "extractImageAndText");
|
|
1784
|
+
function extractFromForwardChildren(children) {
|
|
1785
|
+
const allTexts = [];
|
|
1786
|
+
const allImageUrls = [];
|
|
1787
|
+
for (const msgEl of children) {
|
|
1788
|
+
if (msgEl.type !== "message") continue;
|
|
1789
|
+
const msgChildren = msgEl.children ?? [];
|
|
1790
|
+
const authorEl = msgChildren.find((c) => c.type === "author");
|
|
1791
|
+
const senderName = authorEl?.attrs?.name ?? String(authorEl?.attrs?.id ?? "未知");
|
|
1792
|
+
const msgTexts = [];
|
|
1793
|
+
for (const child of msgChildren) {
|
|
1794
|
+
if (child.type === "text") {
|
|
1795
|
+
const t = child.attrs?.content ?? "";
|
|
1796
|
+
if (t) msgTexts.push(t);
|
|
1797
|
+
} else if (child.type === "img" || child.type === "image") {
|
|
1798
|
+
const url = child.attrs?.src ?? child.attrs?.url ?? "";
|
|
1799
|
+
if (url) allImageUrls.push(url);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
if (msgTexts.length > 0) {
|
|
1803
|
+
allTexts.push(`[${senderName}]: ${msgTexts.join("")}`);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
return { imageUrls: allImageUrls, text: allTexts.join("\n") };
|
|
1807
|
+
}
|
|
1808
|
+
__name(extractFromForwardChildren, "extractFromForwardChildren");
|
|
1809
|
+
async function fetchForwardMessages(session, forwardId) {
|
|
1810
|
+
try {
|
|
1811
|
+
const result = await session.bot.internal.getForwardMsg({ id: forwardId });
|
|
1812
|
+
const messages = result?.messages ?? [];
|
|
1813
|
+
const allTexts = [];
|
|
1814
|
+
const allImageUrls = [];
|
|
1815
|
+
for (const msg of messages) {
|
|
1816
|
+
const sender = msg?.sender?.nickname ?? String(msg?.sender?.user_id ?? "未知");
|
|
1817
|
+
const segments = msg?.message ?? msg?.content ?? [];
|
|
1818
|
+
const msgTexts = [];
|
|
1819
|
+
for (const seg of segments) {
|
|
1820
|
+
if (seg.type === "text") {
|
|
1821
|
+
const t = seg.data?.text ?? "";
|
|
1822
|
+
if (t) msgTexts.push(t);
|
|
1823
|
+
} else if (seg.type === "image") {
|
|
1824
|
+
const url = seg.data?.url ?? seg.data?.file ?? "";
|
|
1825
|
+
if (url) allImageUrls.push(url);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
if (msgTexts.length > 0) {
|
|
1829
|
+
allTexts.push(`[${sender}]: ${msgTexts.join("")}`);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return { imageUrls: allImageUrls, text: allTexts.join("\n") };
|
|
1833
|
+
} catch (e) {
|
|
1834
|
+
logger.error("[fetchForwardMessages Error]: 获取转发消息失败: " + e);
|
|
1835
|
+
return { imageUrls: [], text: "" };
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
__name(fetchForwardMessages, "fetchForwardMessages");
|
|
1839
|
+
function extractForwardId(elements, content) {
|
|
1840
|
+
const forwardEl = elements.find((el) => el.type === "forward");
|
|
1841
|
+
if (forwardEl?.attrs?.id) return String(forwardEl.attrs.id);
|
|
1842
|
+
const match = content.match(/<forward\b[^>]*\bid=["']?([^"'\s>/]+)["']?/i);
|
|
1843
|
+
return match?.[1] ?? null;
|
|
1844
|
+
}
|
|
1845
|
+
__name(extractForwardId, "extractForwardId");
|
|
1763
1846
|
async function checkShitOrNot(session, parttern_msg, config) {
|
|
1764
1847
|
chatHistory = [];
|
|
1765
1848
|
chatHistory.push({ role: "system", content: [{ type: "text", text: parttern_msg }] });
|
|
@@ -1784,6 +1867,59 @@ async function checkShitOrNot(session, parttern_msg, config) {
|
|
|
1784
1867
|
return resp2;
|
|
1785
1868
|
}
|
|
1786
1869
|
__name(checkShitOrNot, "checkShitOrNot");
|
|
1870
|
+
async function checkShitOrNot_v2(session, parttern_msg, config) {
|
|
1871
|
+
chatHistory = [];
|
|
1872
|
+
chatHistory.push({ role: "system", content: [{ type: "text", text: parttern_msg }] });
|
|
1873
|
+
const quoteContent = session.quote.content;
|
|
1874
|
+
const quoteElements = session.quote.elements ?? [];
|
|
1875
|
+
logger.info("[checkShitOrNot_v2 Info]: 引用消息内容: " + quoteContent);
|
|
1876
|
+
let imageUrls = [];
|
|
1877
|
+
let text = "";
|
|
1878
|
+
let isForward = false;
|
|
1879
|
+
const forwardId = extractForwardId(quoteElements, quoteContent);
|
|
1880
|
+
if (forwardId) {
|
|
1881
|
+
isForward = true;
|
|
1882
|
+
logger.info("[checkShitOrNot_v2 Info]: 检测到转发聊天记录,ID: " + forwardId);
|
|
1883
|
+
const forwardEl = quoteElements.find((el) => el.type === "forward");
|
|
1884
|
+
const forwardChildren = forwardEl?.children ?? [];
|
|
1885
|
+
if (forwardChildren.length > 0) {
|
|
1886
|
+
const extracted = extractFromForwardChildren(forwardChildren);
|
|
1887
|
+
imageUrls = extracted.imageUrls;
|
|
1888
|
+
text = extracted.text;
|
|
1889
|
+
logger.info("[checkShitOrNot_v2 Info]: 从 children 提取转发内容,共 " + forwardChildren.length + " 条");
|
|
1890
|
+
}
|
|
1891
|
+
if (!text && imageUrls.length === 0) {
|
|
1892
|
+
logger.info("[checkShitOrNot_v2 Info]: children 为空,尝试通过 NapCat API 拉取转发消息");
|
|
1893
|
+
const extracted = await fetchForwardMessages(session, forwardId);
|
|
1894
|
+
imageUrls = extracted.imageUrls;
|
|
1895
|
+
text = extracted.text;
|
|
1896
|
+
}
|
|
1897
|
+
} else {
|
|
1898
|
+
const extracted = extractImageAndText(quoteContent);
|
|
1899
|
+
imageUrls = extracted.imageUrls;
|
|
1900
|
+
text = extracted.text;
|
|
1901
|
+
}
|
|
1902
|
+
if (!text && imageUrls.length === 0) {
|
|
1903
|
+
logger.warn("[checkShitOrNot_v2 Warn]: 引用消息中未发现文本或图片");
|
|
1904
|
+
return isForward ? "转发聊天记录中未发现可分析的文本或图片" : "引用消息中未发现文本或图片";
|
|
1905
|
+
}
|
|
1906
|
+
logger.info("[checkShitOrNot_v2 Info]: 提取图片 URL: " + imageUrls.join(", "));
|
|
1907
|
+
const displayText = isForward ? `以下是转发聊天记录的内容:
|
|
1908
|
+
|
|
1909
|
+
${text}` : text;
|
|
1910
|
+
const targetContent = [
|
|
1911
|
+
...displayText ? [{ type: "text", text: displayText }] : [],
|
|
1912
|
+
...imageUrls.map((url) => ({ type: "image_url", image_url: { url } }))
|
|
1913
|
+
];
|
|
1914
|
+
chatHistory.push({ role: "user", content: targetContent });
|
|
1915
|
+
const { err: err2, resp: resp2 } = await callOpenRouter(config.api_url, config.api_key, config.api_model, chatHistory);
|
|
1916
|
+
if (err2 != null) {
|
|
1917
|
+
logger.error("[checkShitOrNot_v2 Error]: " + err2);
|
|
1918
|
+
return null;
|
|
1919
|
+
}
|
|
1920
|
+
return resp2;
|
|
1921
|
+
}
|
|
1922
|
+
__name(checkShitOrNot_v2, "checkShitOrNot_v2");
|
|
1787
1923
|
|
|
1788
1924
|
// src/services/son_func/shit_or_not_command.ts
|
|
1789
1925
|
var local_config = null;
|
|
@@ -1830,6 +1966,26 @@ son判断模式列表:
|
|
|
1830
1966
|
think_flag = false;
|
|
1831
1967
|
}
|
|
1832
1968
|
});
|
|
1969
|
+
ctx.command("sonv2 <参数>", "判定是否为史").action(async ({ session }, ...args) => {
|
|
1970
|
+
if (!dev_mode) {
|
|
1971
|
+
if (!is_at_bot_quote(session)) return "请提供正确格式,如: [引用消息] @bot son [判断模式]";
|
|
1972
|
+
}
|
|
1973
|
+
if (think_flag) return "请等待思考结果";
|
|
1974
|
+
const parttern = args?.[0];
|
|
1975
|
+
if (!parttern) return "请提供正确判断模式,如: [引用消息] @bot son [判断模式]";
|
|
1976
|
+
if (!local_config) return "未加载配置文件,请查看日志";
|
|
1977
|
+
const parttern_msg = local_config.shit_or_not?.prompts[parttern];
|
|
1978
|
+
if (!parttern_msg) return "未找到判断模式,请查看日志";
|
|
1979
|
+
await session.send("已收到,正在品鉴中...");
|
|
1980
|
+
think_flag = true;
|
|
1981
|
+
try {
|
|
1982
|
+
let exec = await checkShitOrNot_v2(session, parttern_msg, ai_config);
|
|
1983
|
+
if (exec == null) return "品鉴失败,请查看日志";
|
|
1984
|
+
return exec;
|
|
1985
|
+
} finally {
|
|
1986
|
+
think_flag = false;
|
|
1987
|
+
}
|
|
1988
|
+
});
|
|
1833
1989
|
}
|
|
1834
1990
|
__name(registerShitOrNotCommands, "registerShitOrNotCommands");
|
|
1835
1991
|
function extractAtId(content) {
|
|
@@ -11,6 +11,16 @@ type MenuList = {
|
|
|
11
11
|
description: string;
|
|
12
12
|
};
|
|
13
13
|
declare function loadGroupFunctionLimitConfig(config: my_config.GroupFunctionLimitConfig): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* 判断指定群聊是否允许使用某功能编号。
|
|
16
|
+
* 返回 null 表示未加载功能限制配置(不做限制)。
|
|
17
|
+
*/
|
|
18
|
+
declare function isFunctionAllowedForGuild(guildId: string | number | undefined, menuNumber: number): boolean | null;
|
|
19
|
+
/**
|
|
20
|
+
* 返回指定群聊允许使用的功能编号列表。
|
|
21
|
+
* 返回 null 表示未加载功能限制配置(不做限制)。
|
|
22
|
+
*/
|
|
23
|
+
declare function getAllowedMenuNumbersForGuild(guildId: string | number | undefined): number[] | null;
|
|
14
24
|
/**
|
|
15
25
|
* 根据 groupFuncLimit.json 的 groupList 配置,为指定功能编号返回对应的 Koishi Context:
|
|
16
26
|
*
|
|
@@ -21,7 +31,7 @@ declare function loadGroupFunctionLimitConfig(config: my_config.GroupFunctionLim
|
|
|
21
31
|
* - 若未加载功能限制配置:直接返回原始 ctx(不加限制)
|
|
22
32
|
*/
|
|
23
33
|
declare function getCtxForFunction(ctx: Context, menuNumber: number): Context | null;
|
|
24
|
-
export { groupFunctionLimitConfig, loadGroupFunctionLimitConfig, getCtxForFunction, };
|
|
34
|
+
export { groupFunctionLimitConfig, loadGroupFunctionLimitConfig, getCtxForFunction, isFunctionAllowedForGuild, getAllowedMenuNumbersForGuild, };
|
|
25
35
|
declare function getGroupFunctionLimitConfig(): GroupFunctionLimitItem[];
|
|
26
36
|
declare function getMenuList(): MenuList[];
|
|
27
37
|
export { getGroupFunctionLimitConfig, getMenuList, };
|
|
@@ -2,4 +2,5 @@ import { Session } from 'koishi';
|
|
|
2
2
|
import { AiAPIConfig } from '../../config/config';
|
|
3
3
|
declare function ocrImage(buffer: Buffer): Promise<string>;
|
|
4
4
|
declare function checkShitOrNot(session: Session, parttern_msg: string, config: AiAPIConfig): Promise<string>;
|
|
5
|
-
|
|
5
|
+
declare function checkShitOrNot_v2(session: Session, parttern_msg: string, config: AiAPIConfig): Promise<string>;
|
|
6
|
+
export { checkShitOrNot, checkShitOrNot_v2, ocrImage };
|