koishi-plugin-satori-ai 1.3.7 → 1.3.9
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.d.ts +3 -2
- package/lib/index.js +218 -393
- package/lib/memory.d.ts +1 -1
- package/lib/types.d.ts +2 -3
- package/lib/userportrait.d.ts +2 -1
- package/lib/utils.d.ts +4 -1
- package/package.json +1 -1
- package/lib/gobang_ai.exe +0 -0
package/lib/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare class SAT extends Sat {
|
|
|
35
35
|
content: string;
|
|
36
36
|
error: boolean;
|
|
37
37
|
}>;
|
|
38
|
-
getChatResponse(user: User, messages: Sat.Msg[]): Promise<{
|
|
38
|
+
getChatResponse(user: User, messages: Sat.Msg[], prompt: string): Promise<{
|
|
39
39
|
content: string;
|
|
40
40
|
error: boolean;
|
|
41
41
|
}>;
|
|
@@ -47,9 +47,10 @@ export declare class SAT extends Sat {
|
|
|
47
47
|
getWarningList(session: Session): Promise<void>;
|
|
48
48
|
private clearSession;
|
|
49
49
|
private addCommonSense;
|
|
50
|
+
addGroupCommonSense(session: Session, content: string, groupId: string): Promise<string>;
|
|
50
51
|
private handleUserLevel;
|
|
51
52
|
private handleUserUsage;
|
|
52
|
-
handleRandomMiddleware(session: Session
|
|
53
|
+
handleRandomMiddleware(session: Session): Promise<string>;
|
|
53
54
|
handleNickNameMiddleware(session: Session, prompt: string): Promise<string>;
|
|
54
55
|
handleChannelMemoryManager(session: Session): Promise<void>;
|
|
55
56
|
}
|
package/lib/index.js
CHANGED
|
@@ -46,8 +46,8 @@ __export(src_exports, {
|
|
|
46
46
|
refreshPuppeteer: () => refreshPuppeteer
|
|
47
47
|
});
|
|
48
48
|
module.exports = __toCommonJS(src_exports);
|
|
49
|
-
var
|
|
50
|
-
var
|
|
49
|
+
var import_koishi13 = require("koishi");
|
|
50
|
+
var path6 = __toESM(require("path"));
|
|
51
51
|
|
|
52
52
|
// src/api.ts
|
|
53
53
|
var import_koishi2 = require("koishi");
|
|
@@ -258,25 +258,36 @@ function processPrompt(prompt) {
|
|
|
258
258
|
return prompt.trim();
|
|
259
259
|
}
|
|
260
260
|
__name(processPrompt, "processPrompt");
|
|
261
|
-
function filterResponse(prompt, words) {
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
261
|
+
function filterResponse(prompt, words, options) {
|
|
262
|
+
const applyBracketFilter = options?.applyBracketFilter ?? true;
|
|
263
|
+
const applyTagFilter = options?.applyTagFilter ?? true;
|
|
264
|
+
let working = prompt;
|
|
265
|
+
if (applyBracketFilter) {
|
|
266
|
+
const parts = working.split(/([(\[【《(][^))]*[)\]】》)])/g);
|
|
267
|
+
const filtered = parts.map((part) => {
|
|
268
|
+
if (part.startsWith("(") && part.endsWith(")") || part.startsWith("(") && part.endsWith(")") || part.startsWith("[") && part.endsWith("]") || part.startsWith("【") && part.endsWith("】") || part.startsWith("《") && part.endsWith("》")) {
|
|
269
|
+
return words.some((word) => part.includes(word)) ? "" : part;
|
|
270
|
+
}
|
|
271
|
+
return part;
|
|
272
|
+
}).join("");
|
|
273
|
+
working = filtered.replace(/\s+/g, "");
|
|
274
|
+
if (!working) {
|
|
275
|
+
working = prompt;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (!applyTagFilter) {
|
|
279
|
+
return working ? { content: working, error: false } : { content: "有点问题,请重置对话", error: true };
|
|
280
|
+
}
|
|
281
|
+
const answerRegex = /<p>((?!<\/?p>)[\s\S])*?<\/p>/g;
|
|
282
|
+
const answerRegex2 = /<doubaothinking>((?!<\/?doubaothinking>)[\s\S])*?<\/p>/g;
|
|
272
283
|
const answerRegex3 = /<doubaothinking>((?!<\/?doubaothinking>)[\s\S])*?<\/doubaothinking>/g;
|
|
273
284
|
const answerRegex4 = /<answer>((?!<\/?answer>)[\s\S])*?<\/answer>/g;
|
|
274
285
|
const answerRegex5 = /<doubaothinking>((?!<\/?doubaothinking>)[\s\S])*?<\/answer>/g;
|
|
275
|
-
const answerMatches =
|
|
276
|
-
const answerMatches2 =
|
|
277
|
-
const answerMatches3 =
|
|
278
|
-
const answerMatches4 =
|
|
279
|
-
const answerMatches5 =
|
|
286
|
+
const answerMatches = working.match(answerRegex);
|
|
287
|
+
const answerMatches2 = working.match(answerRegex2);
|
|
288
|
+
const answerMatches3 = working.match(answerRegex3);
|
|
289
|
+
const answerMatches4 = working.match(answerRegex4);
|
|
290
|
+
const answerMatches5 = working.match(answerRegex5);
|
|
280
291
|
const lastAnswer = answerMatches ? answerMatches[answerMatches.length - 1] : null;
|
|
281
292
|
const lastDoubao = answerMatches2 ? answerMatches2[answerMatches2.length - 1] : null;
|
|
282
293
|
const lastAnswer3 = answerMatches3 ? answerMatches3[answerMatches3.length - 1] : null;
|
|
@@ -347,6 +358,12 @@ function countCommonChars(str1, str2) {
|
|
|
347
358
|
const count2 = chars2.get(char) || 0;
|
|
348
359
|
commonCount += Math.min(count1, count2);
|
|
349
360
|
}
|
|
361
|
+
const countDigits = /* @__PURE__ */ __name((s) => (s.match(/\d/g) || []).length, "countDigits");
|
|
362
|
+
const digits1 = countDigits(str1);
|
|
363
|
+
const digits2 = countDigits(str2);
|
|
364
|
+
if (digits1 >= 3 || digits2 >= 3) {
|
|
365
|
+
return Math.max(commonCount, 2);
|
|
366
|
+
}
|
|
350
367
|
return commonCount;
|
|
351
368
|
}
|
|
352
369
|
__name(countCommonChars, "countCommonChars");
|
|
@@ -451,7 +468,7 @@ var APIClient = class {
|
|
|
451
468
|
if (i == this.config.maxRetryTimes) {
|
|
452
469
|
return this.handleAPIError(error);
|
|
453
470
|
}
|
|
454
|
-
await new Promise((
|
|
471
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.retry_delay_time || 5e3));
|
|
455
472
|
logger2.warn(`生成画像时API请求失败(${error}),重试(第${i}次)中...`);
|
|
456
473
|
continue;
|
|
457
474
|
}
|
|
@@ -508,7 +525,7 @@ var APIClient = class {
|
|
|
508
525
|
if (i == this.config.maxRetryTimes) {
|
|
509
526
|
return this.handleAPIError(error);
|
|
510
527
|
}
|
|
511
|
-
await new Promise((
|
|
528
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.retry_delay_time || 5e3));
|
|
512
529
|
logger2.warn(`API请求失败(${error}),重试(第${i}次)中...`);
|
|
513
530
|
continue;
|
|
514
531
|
}
|
|
@@ -582,7 +599,7 @@ var MemoryManager = class {
|
|
|
582
599
|
}
|
|
583
600
|
channelMemories = /* @__PURE__ */ new Map();
|
|
584
601
|
channelDialogues = /* @__PURE__ */ new Map();
|
|
585
|
-
charactersToRemove = ["的", "一", "是", "了", "什", "么", "我", "谁", "不", "人", "在", "他", "有", "这", "个", "上", "们", "来", "到", "时", "大", "地", "为", "子", "中", "你", "说", "生", "国", "年", "着", "就", "那", "和", "要", "她", "出", "也", "得", "里", "后", "自", "以", "会", "id="
|
|
602
|
+
charactersToRemove = ["的", "一", "是", "了", "什", "么", "我", "谁", "不", "人", "在", "他", "有", "这", "个", "上", "们", "来", "到", "时", "大", "地", "为", "子", "中", "你", "说", "生", "国", "年", "着", "就", "那", "和", "要", "她", "出", "也", "得", "里", "后", "自", "以", "会", "id="];
|
|
586
603
|
MAX_MEMORY_LENGTH = 5e3;
|
|
587
604
|
// 更新记忆
|
|
588
605
|
async updateMemories(session, prompt, config, response) {
|
|
@@ -617,7 +634,7 @@ var MemoryManager = class {
|
|
|
617
634
|
if (!this.config.channel_dialogues)
|
|
618
635
|
return "";
|
|
619
636
|
const Dialogue = this.channelDialogues[session.channelId]?.join("\n") || "";
|
|
620
|
-
const result = "
|
|
637
|
+
const result = "以下是群聊内最近的包括所有人的聊天记录,当当前对话涉及其中内容时你可以参考这些信息,但是要注意分辨发言人是谁:{\n" + Dialogue + "\n}\n";
|
|
621
638
|
return result;
|
|
622
639
|
}
|
|
623
640
|
// 括号引号过滤
|
|
@@ -712,11 +729,14 @@ var MemoryManager = class {
|
|
|
712
729
|
async searchMemories(session, prompt, type = "user") {
|
|
713
730
|
const filePathMap = {
|
|
714
731
|
"user": this.getUserMemoryPath(session.userId),
|
|
715
|
-
"common": path2.join(this.config.dataDir, "common_sense.txt")
|
|
732
|
+
"common": path2.join(this.config.dataDir, "common_sense.txt"),
|
|
733
|
+
"group": path2.join(this.config.dataDir, "group_sense", `${session.channelId}.txt`)
|
|
716
734
|
};
|
|
717
735
|
const topNMap = {
|
|
718
736
|
"user": this.config.dailogues_topN,
|
|
719
|
-
"common": this.config.common_topN
|
|
737
|
+
"common": this.config.common_topN,
|
|
738
|
+
"group": this.config.common_topN
|
|
739
|
+
// 群常识和常识使用同样的topN
|
|
720
740
|
};
|
|
721
741
|
const filePath = filePathMap[type];
|
|
722
742
|
if (!fs2.existsSync(filePath)) {
|
|
@@ -753,7 +773,8 @@ var MemoryManager = class {
|
|
|
753
773
|
formatMatches(matched, type, topN = 5) {
|
|
754
774
|
const prefixMap = {
|
|
755
775
|
"common": "这是你可能用到的信息:",
|
|
756
|
-
"user": "以下是较久之前用户说过的话和对话时间:"
|
|
776
|
+
"user": "以下是较久之前用户说过的话和对话时间:",
|
|
777
|
+
"group": "以下是本群聊你可能需要知道的信息:"
|
|
757
778
|
};
|
|
758
779
|
const time = `时段:${getTimeOfDay((/* @__PURE__ */ new Date()).getHours())}`;
|
|
759
780
|
const date = `当前日期和时间:${(/* @__PURE__ */ new Date()).toLocaleString()} ${time}`;
|
|
@@ -766,11 +787,17 @@ ${date}
|
|
|
766
787
|
}
|
|
767
788
|
`;
|
|
768
789
|
return result;
|
|
769
|
-
} else {
|
|
790
|
+
} else if (type === "user") {
|
|
770
791
|
matched.forEach((entry) => entry.content = entry.content + (entry.role === "user" ? "(未记录时间)" : entry.role));
|
|
771
792
|
const result = `${prefixMap[type]}{
|
|
772
793
|
${matched.map((entry) => entry.content).join("\n")}
|
|
773
794
|
}
|
|
795
|
+
`;
|
|
796
|
+
return result;
|
|
797
|
+
} else if (type === "group") {
|
|
798
|
+
const result = `${prefixMap[type]}{
|
|
799
|
+
${matched.map((entry) => entry.content).join("\n")}
|
|
800
|
+
}
|
|
774
801
|
`;
|
|
775
802
|
return result;
|
|
776
803
|
}
|
|
@@ -919,6 +946,8 @@ async function handleFavorabilitySystem(ctx, session, config) {
|
|
|
919
946
|
}
|
|
920
947
|
__name(handleFavorabilitySystem, "handleFavorabilitySystem");
|
|
921
948
|
function getFavorabilityLevel(user, config) {
|
|
949
|
+
if (user.favorability >= config.favorability_div_3 && user?.items["镇定贴"]?.count > 0 && user?.items["镇定贴"]?.description && user?.items["镇定贴"]?.description == "on")
|
|
950
|
+
return "朋友";
|
|
922
951
|
if (user?.items["订婚戒指"]?.count > 0 && user?.items["订婚戒指"]?.description && user?.items["订婚戒指"]?.description == "已使用")
|
|
923
952
|
return "夫妻";
|
|
924
953
|
if (user.favorability < config.favorability_div_1)
|
|
@@ -1068,7 +1097,7 @@ function createMiddleware(ctx, sat, config) {
|
|
|
1068
1097
|
return await handleNickNameMessage(sat, session);
|
|
1069
1098
|
}
|
|
1070
1099
|
if (shouldRandomTrigger(session, config)) {
|
|
1071
|
-
return await sat.handleRandomMiddleware(session
|
|
1100
|
+
return await sat.handleRandomMiddleware(session);
|
|
1072
1101
|
}
|
|
1073
1102
|
return next();
|
|
1074
1103
|
};
|
|
@@ -1139,6 +1168,7 @@ var Sat = class extends import_koishi5.Service {
|
|
|
1139
1168
|
import_koishi5.Schema.transform(String, (value) => [value])
|
|
1140
1169
|
]).default([]).role("secret").description("深度思考模型api_key"),
|
|
1141
1170
|
appointModel: import_koishi5.Schema.string().default("deepseek-reasoner").description("深度思考模型"),
|
|
1171
|
+
enhanceReasoningProtection: import_koishi5.Schema.boolean().default(true).description("是否增强思维链保护(开启后会强制输出内容带有限制标签,极大防止思维链溢出问题)"),
|
|
1142
1172
|
not_reasoner_LLM_URL: import_koishi5.Schema.string().default("https://api.deepseek.com").description("非深度思考模型请求地址"),
|
|
1143
1173
|
not_reasoner_LLM: import_koishi5.Schema.string().default("deepseek-chat").description("非深度思考模型(用于节省成本"),
|
|
1144
1174
|
not_reasoner_LLM_key: import_koishi5.Schema.union([
|
|
@@ -1182,7 +1212,7 @@ var Sat = class extends import_koishi5.Service {
|
|
|
1182
1212
|
dataDir: import_koishi5.Schema.string().default("./data/satori_ai").description("聊天记录保存位置(长期记忆)"),
|
|
1183
1213
|
memory_block_words: import_koishi5.Schema.array(String).default(["好感"]).description("记忆屏蔽词"),
|
|
1184
1214
|
remember_min_length: import_koishi5.Schema.number().description("触发保存到记忆的长度").default(20),
|
|
1185
|
-
common_topN: import_koishi5.Schema.number().default(5).description("
|
|
1215
|
+
common_topN: import_koishi5.Schema.number().default(5).description("群常识、常识记忆检索最大匹配数"),
|
|
1186
1216
|
dailogues_topN: import_koishi5.Schema.number().default(5).description("对话记忆检索最大匹配数"),
|
|
1187
1217
|
enable_fixed_dialogues: import_koishi5.Schema.boolean().default(false).description("是否启用固定对话(在dataDir中的fixed_dialogues.json修改)")
|
|
1188
1218
|
}).description("记忆设置"),
|
|
@@ -1197,6 +1227,7 @@ var Sat = class extends import_koishi5.Service {
|
|
|
1197
1227
|
duplicateDialogueCheck: import_koishi5.Schema.boolean().default(true).description("是否检查重复对话"),
|
|
1198
1228
|
enable_online_user_check: import_koishi5.Schema.boolean().default(true).description("在未回答而再次提问时是否提示用户有未完成的对话"),
|
|
1199
1229
|
random_min_tokens: import_koishi5.Schema.number().default(20).description("随机触发对话的最小长度"),
|
|
1230
|
+
enable_random_without_favorability: import_koishi5.Schema.boolean().default(true).description("是否启用随机触发对话无视高好感度(即使用户好感度很高也会最多视为朋友)"),
|
|
1200
1231
|
randnum: import_koishi5.Schema.number().role("slider").min(0).max(1).step(0.01).default(0).description("在群聊中随机触发对话的概率,如需关闭可设置为 0"),
|
|
1201
1232
|
sentences_divide: import_koishi5.Schema.boolean().default(true).description("是否分句发送"),
|
|
1202
1233
|
min_sentences_length: import_koishi5.Schema.number().default(10).description("每个分句的最小长度"),
|
|
@@ -1255,9 +1286,6 @@ var Sat = class extends import_koishi5.Service {
|
|
|
1255
1286
|
import_koishi5.Schema.object({
|
|
1256
1287
|
enable_game: import_koishi5.Schema.boolean().default(false).description("是否开启游戏模块"),
|
|
1257
1288
|
game_block_channel: import_koishi5.Schema.array(String).description("不提供游戏的频道id"),
|
|
1258
|
-
enable_gobang: import_koishi5.Schema.boolean().default(false).description("是否开启五子棋游戏(需要puppeteer支持)"),
|
|
1259
|
-
channel_id_for_gobang: import_koishi5.Schema.array(String).description("启用五子棋的游戏频道id(不建议太多,第一个会被公示)"),
|
|
1260
|
-
cd_for_gobang: import_koishi5.Schema.number().default(3600).description("每人五子棋游戏cd时间(秒)"),
|
|
1261
1289
|
enable_OneTouch: import_koishi5.Schema.boolean().default(false).description("是否开启一碰一游戏(需要puppeteer支持)"),
|
|
1262
1290
|
cd_for_OneTouch: import_koishi5.Schema.number().default(600).description("每人一碰一游戏cd时间(秒)"),
|
|
1263
1291
|
enable_fencing: import_koishi5.Schema.boolean().default(false).description("是否开启击剑游戏(无效,开发中)")
|
|
@@ -1309,7 +1337,7 @@ var UserPortraitManager = class {
|
|
|
1309
1337
|
});
|
|
1310
1338
|
fs5.writeFileSync(memoryPath, JSON.stringify(replacedContent, null, 2));
|
|
1311
1339
|
const validEntries = replacedContent.filter((entry) => entry.role !== "user").map((entry) => {
|
|
1312
|
-
const timeMatch = entry.role.match(/对话日期和时间:(\d{
|
|
1340
|
+
const timeMatch = entry.role.match(/对话日期和时间:(\d{1,2}\/\d{1,2}\/\d{4}), (\d{1,2}:\d{2}:\d{2} [AP]M)/);
|
|
1313
1341
|
if (!timeMatch)
|
|
1314
1342
|
return null;
|
|
1315
1343
|
return {
|
|
@@ -1323,11 +1351,11 @@ var UserPortraitManager = class {
|
|
|
1323
1351
|
return validEntries.slice(0, maxEntries).map((entry) => `${entry.content}${entry.role}`);
|
|
1324
1352
|
}
|
|
1325
1353
|
// 生成提示词模板
|
|
1326
|
-
|
|
1354
|
+
buildFirstMessage(level, history, user) {
|
|
1327
1355
|
return [{
|
|
1328
1356
|
role: "user",
|
|
1329
|
-
content:
|
|
1330
|
-
1.
|
|
1357
|
+
content: `你是一个角色扮演智能体工作流中的一环,请根据以下信息生成户画像。可选内容包括:
|
|
1358
|
+
1. 基本信息(性别、年龄、生日等)
|
|
1331
1359
|
2. 生活习惯(作息等)
|
|
1332
1360
|
3. 反感点(如有)
|
|
1333
1361
|
4. 对AI的期望(从对话历史中推断)
|
|
@@ -1335,21 +1363,47 @@ var UserPortraitManager = class {
|
|
|
1335
1363
|
|
|
1336
1364
|
用户名:${user.usersname}
|
|
1337
1365
|
你与用户的关系:${level}
|
|
1338
|
-
历史画像:
|
|
1339
|
-
${existingPortrait ? "无" : existingPortrait}
|
|
1340
|
-
|
|
1341
1366
|
近期的用户发言记录:
|
|
1342
1367
|
${history}
|
|
1343
1368
|
|
|
1344
1369
|
注意事项:
|
|
1370
|
+
·没有涉及到的信息注为无
|
|
1345
1371
|
·用户一定是人类,其他情况是角色扮演
|
|
1346
|
-
·根据发言修正历史画像内容,但是历史画像中与发言无关的部分必须保留
|
|
1347
1372
|
·尤其注意用户说“记住”的部分,可能是用户希望记录的信息
|
|
1348
1373
|
·因为在角色扮演中,用户可能会说出不符合事实的信息,需要根据事实推断,避免盲目相信或主观臆测
|
|
1349
1374
|
·使用尽可能简洁的表达
|
|
1350
1375
|
·保留不确定性的表述(如"可能"、"似乎"、"用户自称")
|
|
1351
1376
|
·保持中立和客观,避免带有个人情感色彩的描述,不要添加评价或建议
|
|
1352
1377
|
·仅给出画像内容,不要添加额外的描述、建议、评价、注解等任何内容
|
|
1378
|
+
·不使用markdown等标记语言,直接书写即可`
|
|
1379
|
+
}];
|
|
1380
|
+
}
|
|
1381
|
+
buildSecondMessage(level, NewPortrait, existingPortrait, user) {
|
|
1382
|
+
return [{
|
|
1383
|
+
role: "user",
|
|
1384
|
+
content: `你是一个角色扮演智能体工作流中的一环,请根据以下信息合并用户画像。内容包括:
|
|
1385
|
+
1. 基本信息(性别、年龄、生日等,不要遗漏或改动已有的信息)
|
|
1386
|
+
2. 生活习惯(作息等)
|
|
1387
|
+
3. 反感点(如有)
|
|
1388
|
+
4. 对AI的期望(从对话历史中推断)
|
|
1389
|
+
5. 用户希望记住的信息(如有)
|
|
1390
|
+
|
|
1391
|
+
用户名:${user.usersname}
|
|
1392
|
+
你与用户的关系:${level}
|
|
1393
|
+
已有画像:
|
|
1394
|
+
${existingPortrait ? "无" : existingPortrait}
|
|
1395
|
+
|
|
1396
|
+
新补充信息:
|
|
1397
|
+
${NewPortrait}
|
|
1398
|
+
|
|
1399
|
+
注意事项:
|
|
1400
|
+
·用户一定是人类,其他情况是角色扮演
|
|
1401
|
+
·根据已有画像,补充新信息,避免重复,并且不要遗漏你认为重要信息
|
|
1402
|
+
·你认为不太重要的信息可以删除
|
|
1403
|
+
·使用尽可能简洁的表达
|
|
1404
|
+
·保留不确定性的表述(如"可能"、"似乎"、"用户自称")
|
|
1405
|
+
·保持中立和客观,避免带有个人情感色彩的描述,不要添加评价或建议
|
|
1406
|
+
·仅给出画像内容,不要添加额外的描述、建议、评价、注解等任何内容
|
|
1353
1407
|
·不使用markdown等标记语言,直接书写即可`
|
|
1354
1408
|
}];
|
|
1355
1409
|
}
|
|
@@ -1364,10 +1418,12 @@ ${history}
|
|
|
1364
1418
|
const dialogues = await this.getDialogues(user);
|
|
1365
1419
|
const existing = this.readPortrait(user.userid);
|
|
1366
1420
|
const userlevel = getFavorabilityLevel(user, this.getFavorabilityConfig());
|
|
1367
|
-
const messages = this.buildMessage(userlevel, dialogues.join("\n"), existing, user);
|
|
1368
1421
|
logger5.info(`用户 ${user.userid} 画像生成中...`);
|
|
1369
1422
|
try {
|
|
1370
|
-
const
|
|
1423
|
+
const FirstMessages = this.buildFirstMessage(userlevel, dialogues.join("\n"), user);
|
|
1424
|
+
const NewPortrait = await apiClient.generateUserPortrait(user, FirstMessages);
|
|
1425
|
+
const SecondMessages = this.buildSecondMessage(userlevel, NewPortrait.content, existing, user);
|
|
1426
|
+
const response = await apiClient.generateUserPortrait(user, SecondMessages);
|
|
1371
1427
|
if (response && !response.error) {
|
|
1372
1428
|
this.savePortrait(user, response.content);
|
|
1373
1429
|
if (user.usage > this.config.portrait_usage - 1)
|
|
@@ -1647,9 +1703,9 @@ ${this.config.mood_prompt_2}
|
|
|
1647
1703
|
};
|
|
1648
1704
|
|
|
1649
1705
|
// src/game.ts
|
|
1650
|
-
var
|
|
1706
|
+
var import_koishi11 = require("koishi");
|
|
1651
1707
|
|
|
1652
|
-
// src/
|
|
1708
|
+
// src/gamefencing.ts
|
|
1653
1709
|
var import_koishi9 = require("koishi");
|
|
1654
1710
|
|
|
1655
1711
|
// src/abstractGame.ts
|
|
@@ -1753,270 +1809,8 @@ var abstractGame = class {
|
|
|
1753
1809
|
}
|
|
1754
1810
|
};
|
|
1755
1811
|
|
|
1756
|
-
// src/gamegobang.ts
|
|
1757
|
-
var import_child_process = require("child_process");
|
|
1758
|
-
var path6 = __toESM(require("path"));
|
|
1759
|
-
var logger8 = new import_koishi9.Logger("satori-game-gobang");
|
|
1760
|
-
var BOARD_SIZE = 14;
|
|
1761
|
-
var inspireSearchLength = 10;
|
|
1762
|
-
var Coordinate = class {
|
|
1763
|
-
static {
|
|
1764
|
-
__name(this, "Coordinate");
|
|
1765
|
-
}
|
|
1766
|
-
x;
|
|
1767
|
-
y;
|
|
1768
|
-
score;
|
|
1769
|
-
constructor(a = 0, b = 0, s = 0) {
|
|
1770
|
-
this.x = a;
|
|
1771
|
-
this.y = b;
|
|
1772
|
-
this.score = s;
|
|
1773
|
-
}
|
|
1774
|
-
};
|
|
1775
|
-
async function wrapInHTML(str) {
|
|
1776
|
-
if (!puppeteer) {
|
|
1777
|
-
logger8.warn("puppeteer未就绪");
|
|
1778
|
-
return "出现错误,请联系管理员";
|
|
1779
|
-
}
|
|
1780
|
-
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
1781
|
-
<style>
|
|
1782
|
-
body {
|
|
1783
|
-
padding: 10px;
|
|
1784
|
-
display: inline-block;
|
|
1785
|
-
}
|
|
1786
|
-
</style>
|
|
1787
|
-
</html>`);
|
|
1788
|
-
}
|
|
1789
|
-
__name(wrapInHTML, "wrapInHTML");
|
|
1790
|
-
var goBangSingleGame = class extends abstractGameSingleGame {
|
|
1791
|
-
static {
|
|
1792
|
-
__name(this, "goBangSingleGame");
|
|
1793
|
-
}
|
|
1794
|
-
playerFlag;
|
|
1795
|
-
// 玩家棋子颜色(1: 黑棋,2: 白棋)
|
|
1796
|
-
winningFlag = 4 /* pending */;
|
|
1797
|
-
// 当前胜负状态
|
|
1798
|
-
level;
|
|
1799
|
-
// AI 难度等级
|
|
1800
|
-
board = [];
|
|
1801
|
-
// BOARD_SIZExBOARD_SIZE 棋盘状态
|
|
1802
|
-
lastScore = 0;
|
|
1803
|
-
// 上次评分
|
|
1804
|
-
turnsCount = 0;
|
|
1805
|
-
// 回合数
|
|
1806
|
-
constructor(disposeListener, session) {
|
|
1807
|
-
super(disposeListener, session);
|
|
1808
|
-
}
|
|
1809
|
-
// 初始化棋盘,随机决定玩家先手
|
|
1810
|
-
startGame = () => {
|
|
1811
|
-
super.startGame();
|
|
1812
|
-
this.board = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
|
|
1813
|
-
this.turnsCount = 0;
|
|
1814
|
-
this.playerFlag = Math.round(Math.random()) + 1;
|
|
1815
|
-
const getCornerCoordinate = /* @__PURE__ */ __name((i) => {
|
|
1816
|
-
const quarter = i < 0.5 ? 0.2 : 0.7;
|
|
1817
|
-
const base = Math.round(BOARD_SIZE * quarter);
|
|
1818
|
-
return base;
|
|
1819
|
-
}, "getCornerCoordinate");
|
|
1820
|
-
for (let i = 0; i <= 1; i++) {
|
|
1821
|
-
for (let j = 0; j <= 1; j++) {
|
|
1822
|
-
const randomX = getCornerCoordinate(i) + 1 - 2 * i;
|
|
1823
|
-
const randomY = getCornerCoordinate(j);
|
|
1824
|
-
const player = Math.round(Math.random()) + 1;
|
|
1825
|
-
this.board[randomX][randomY] = player;
|
|
1826
|
-
this.board[randomX + i * 2 - 1][randomY - j * 2 + 1] = 3 - player;
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
if (this.playerFlag === 1) {
|
|
1830
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2] = 1;
|
|
1831
|
-
this.board[BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 2;
|
|
1832
|
-
return wrapInHTML("游戏开始,你随机到了先手(黑)\n输入两个数字以下棋,先行后列,例如:“0 13”\n" + this.printBoard());
|
|
1833
|
-
} else {
|
|
1834
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2] = 1;
|
|
1835
|
-
this.board[BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 2;
|
|
1836
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 1;
|
|
1837
|
-
return wrapInHTML("游戏开始,你随机到了后手(白)\n输入两个数字以下棋,先行后列,例如:“0 13”\n" + this.printBoard());
|
|
1838
|
-
}
|
|
1839
|
-
};
|
|
1840
|
-
// 结束游戏,返回结果
|
|
1841
|
-
endGame = async () => {
|
|
1842
|
-
super.endGame();
|
|
1843
|
-
let bonusLevel = this.level;
|
|
1844
|
-
if (this.winningFlag === 1 /* win */ && this.playerFlag === 1) {
|
|
1845
|
-
bonusLevel -= 1;
|
|
1846
|
-
} else if (this.winningFlag === 2 /* lose */ && this.playerFlag === 1) {
|
|
1847
|
-
bonusLevel += 1;
|
|
1848
|
-
}
|
|
1849
|
-
return { message: `${bonusLevel}`, win: this.winningFlag, gameName: "五子棋", playerID: this.session.userId };
|
|
1850
|
-
};
|
|
1851
|
-
/**
|
|
1852
|
-
* 处理玩家输入(落子坐标)
|
|
1853
|
-
* @param str 输入内容,格式为 "x y"
|
|
1854
|
-
*/
|
|
1855
|
-
async processInput(str) {
|
|
1856
|
-
const [x, y] = str.split(" ").map((a) => {
|
|
1857
|
-
return parseInt(a);
|
|
1858
|
-
});
|
|
1859
|
-
if (isNaN(x) || isNaN(y))
|
|
1860
|
-
return;
|
|
1861
|
-
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE)
|
|
1862
|
-
return "坐标超出范围了";
|
|
1863
|
-
if (this.board[x][y] !== 0)
|
|
1864
|
-
return "这个位置已经有棋子了,别想耍赖";
|
|
1865
|
-
if (this.winningFlag !== 4 /* pending */)
|
|
1866
|
-
return "游戏已结束";
|
|
1867
|
-
this.lastActionTime = Date.now();
|
|
1868
|
-
this.board[x][y] = this.playerFlag;
|
|
1869
|
-
logger8.info(`level: ${this.level}, player: x: ${x}, y: ${y}`);
|
|
1870
|
-
if (this.checkWin(x, y))
|
|
1871
|
-
return wrapInHTML(this.printBoard() + "\n游戏已结束,发送结束游戏退出");
|
|
1872
|
-
const starttime = Date.now();
|
|
1873
|
-
const aiMove = this.getAIMove();
|
|
1874
|
-
const endtime = Date.now();
|
|
1875
|
-
if (aiMove.x === -1 || aiMove.y === -1) {
|
|
1876
|
-
this.winningFlag = 3 /* draw */;
|
|
1877
|
-
return "计算失败,视为平局,发送结束游戏退出";
|
|
1878
|
-
}
|
|
1879
|
-
if (this.turnsCount > 50) {
|
|
1880
|
-
this.winningFlag = 3 /* draw */;
|
|
1881
|
-
return "平局,发送结束游戏退出";
|
|
1882
|
-
}
|
|
1883
|
-
logger8.info(`AI 落子坐标: ${aiMove.x} ${aiMove.y},得分: ${aiMove.score},AI 落子耗时: ${endtime - starttime}ms`);
|
|
1884
|
-
this.board[aiMove.x][aiMove.y] = 3 - this.playerFlag;
|
|
1885
|
-
if (this.turnsCount > 5) {
|
|
1886
|
-
setTimeout(() => {
|
|
1887
|
-
this.session.send(this.generateChat(aiMove.score));
|
|
1888
|
-
}, 1e3);
|
|
1889
|
-
}
|
|
1890
|
-
this.lastScore = aiMove.score;
|
|
1891
|
-
this.turnsCount++;
|
|
1892
|
-
if (this.checkWin(aiMove.x, aiMove.y))
|
|
1893
|
-
return wrapInHTML(this.printBoard() + "\n游戏已结束,发送结束游戏退出");
|
|
1894
|
-
return wrapInHTML(this.printBoard() + "\n我这一步下在这里哦(" + aiMove.x + " " + aiMove.y + " 用时" + (endtime - starttime) + "ms)");
|
|
1895
|
-
}
|
|
1896
|
-
getAIMove() {
|
|
1897
|
-
try {
|
|
1898
|
-
const boardStr = this.board.map((row) => row.join(" ")).join(" ");
|
|
1899
|
-
const exePath = path6.resolve(__dirname, "../lib/gobang_ai.exe");
|
|
1900
|
-
const level = this.turnsCount > 3 ? this.level : Math.min(5, this.level);
|
|
1901
|
-
const stdout = (0, import_child_process.execSync)(
|
|
1902
|
-
`"${exePath}" "${boardStr}" ${this.playerFlag} ${level} ${inspireSearchLength}`,
|
|
1903
|
-
{ timeout: 18e5 }
|
|
1904
|
-
// 设置1800秒超时
|
|
1905
|
-
).toString().trim();
|
|
1906
|
-
const [x, y, score] = stdout.split(" ").map(Number);
|
|
1907
|
-
return new Coordinate(x, y, score);
|
|
1908
|
-
} catch (error) {
|
|
1909
|
-
logger8.error(`AI计算失败: ${error}`);
|
|
1910
|
-
}
|
|
1911
|
-
return new Coordinate(-1, -1, -1);
|
|
1912
|
-
}
|
|
1913
|
-
// 检查是否连成五子
|
|
1914
|
-
checkWin(x, y) {
|
|
1915
|
-
const directions = [[1, 0], [0, 1], [1, 1], [1, -1]];
|
|
1916
|
-
for (const [dx, dy] of directions) {
|
|
1917
|
-
let count = 1;
|
|
1918
|
-
for (let i = 1; i < 5; i++) {
|
|
1919
|
-
if (this.checkDirection(x, y, dx, dy, i))
|
|
1920
|
-
count++;
|
|
1921
|
-
else
|
|
1922
|
-
break;
|
|
1923
|
-
}
|
|
1924
|
-
for (let i = 1; i < 5; i++) {
|
|
1925
|
-
if (this.checkDirection(x, y, -dx, -dy, i))
|
|
1926
|
-
count++;
|
|
1927
|
-
else
|
|
1928
|
-
break;
|
|
1929
|
-
}
|
|
1930
|
-
if (count >= 5) {
|
|
1931
|
-
this.winningFlag = this.board[x][y] === this.playerFlag ? 1 /* win */ : 2 /* lose */;
|
|
1932
|
-
return true;
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
return false;
|
|
1936
|
-
}
|
|
1937
|
-
// 辅助方法:检查指定方向是否有连续棋子
|
|
1938
|
-
checkDirection(x, y, dx, dy, step) {
|
|
1939
|
-
const nx = x + dx * step, ny = y + dy * step;
|
|
1940
|
-
return nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && this.board[nx][ny] === this.board[x][y];
|
|
1941
|
-
}
|
|
1942
|
-
// 生成带表情符号的棋盘字符串
|
|
1943
|
-
printBoard() {
|
|
1944
|
-
const numberEmojis = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🔢", "🔢", "🔢", "🔢"];
|
|
1945
|
-
let res = "🟨" + numberEmojis.slice(0, BOARD_SIZE).join("") + "🟨\n";
|
|
1946
|
-
for (let i = 0; i < BOARD_SIZE; i++) {
|
|
1947
|
-
res += numberEmojis[i];
|
|
1948
|
-
for (let j = 0; j < BOARD_SIZE; j++) {
|
|
1949
|
-
res += this.board[i][j] === 0 ? "🟨" : this.board[i][j] === 1 ? "⚫" : "⚪";
|
|
1950
|
-
}
|
|
1951
|
-
res += numberEmojis[i];
|
|
1952
|
-
res += "\n";
|
|
1953
|
-
}
|
|
1954
|
-
res += "🟨" + numberEmojis.slice(0, BOARD_SIZE).join("") + "🟨\n";
|
|
1955
|
-
return res;
|
|
1956
|
-
}
|
|
1957
|
-
generateChat(Score) {
|
|
1958
|
-
if (this.lastScore < 5e6 && Score > 5e6 && this.level > 3) {
|
|
1959
|
-
return "我觉得你要输了哦~";
|
|
1960
|
-
}
|
|
1961
|
-
if (this.lastScore < 1e6 && Score > 1e6) {
|
|
1962
|
-
return "只能下在这里了~";
|
|
1963
|
-
}
|
|
1964
|
-
if (4e3 <= Score && Score < 1e4) {
|
|
1965
|
-
return "这招怎么样?";
|
|
1966
|
-
}
|
|
1967
|
-
if (2e3 <= Score && Score < 4e3 && Math.random() < 0.5) {
|
|
1968
|
-
return {
|
|
1969
|
-
0: "有点意思哦~",
|
|
1970
|
-
1: "真是焦灼的局面",
|
|
1971
|
-
2: "势均力敌呢~",
|
|
1972
|
-
3: "你在想什么呢?",
|
|
1973
|
-
4: "走这里会不会太冒险了?"
|
|
1974
|
-
}[Math.floor(Math.random() * 5)];
|
|
1975
|
-
}
|
|
1976
|
-
if (Score < -1e6) {
|
|
1977
|
-
return "好猛烈的攻击啊~";
|
|
1978
|
-
}
|
|
1979
|
-
if (Score < 0 && Math.random() < 0.5) {
|
|
1980
|
-
return "你还真是厉害呢~";
|
|
1981
|
-
}
|
|
1982
|
-
if (Score < 100) {
|
|
1983
|
-
return "出乎意料的一手啊";
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
};
|
|
1987
|
-
var goBang = class extends abstractGame {
|
|
1988
|
-
static {
|
|
1989
|
-
__name(this, "goBang");
|
|
1990
|
-
}
|
|
1991
|
-
constructor() {
|
|
1992
|
-
super(goBangSingleGame);
|
|
1993
|
-
}
|
|
1994
|
-
// 启动游戏时可传入难度参数
|
|
1995
|
-
async startGame(session, ctx, args) {
|
|
1996
|
-
let level;
|
|
1997
|
-
if (!isNaN(parseInt(args[0])))
|
|
1998
|
-
level = parseInt(args[0]);
|
|
1999
|
-
else {
|
|
2000
|
-
setTimeout(() => {
|
|
2001
|
-
session.send("未输入难度等级(2-6),默认设为3");
|
|
2002
|
-
}, 500);
|
|
2003
|
-
level = 3;
|
|
2004
|
-
}
|
|
2005
|
-
if (level < 2 || level > 6) {
|
|
2006
|
-
level = level < 2 ? 2 : 6;
|
|
2007
|
-
setTimeout(() => {
|
|
2008
|
-
session.send("难度等级必须在2到6之间,已调整为" + level);
|
|
2009
|
-
}, 500);
|
|
2010
|
-
}
|
|
2011
|
-
const game = await super.startGame(session, ctx, args);
|
|
2012
|
-
game.level = level;
|
|
2013
|
-
return game;
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2016
|
-
|
|
2017
1812
|
// src/gamefencing.ts
|
|
2018
|
-
var
|
|
2019
|
-
var logger9 = new import_koishi10.Logger("satori-game-fencing");
|
|
1813
|
+
var logger8 = new import_koishi9.Logger("satori-game-fencing");
|
|
2020
1814
|
var fencingSingleGame = class _fencingSingleGame extends abstractGameSingleGame {
|
|
2021
1815
|
static {
|
|
2022
1816
|
__name(this, "fencingSingleGame");
|
|
@@ -2198,8 +1992,8 @@ var fencing = class extends abstractGame {
|
|
|
2198
1992
|
};
|
|
2199
1993
|
|
|
2200
1994
|
// src/gameOneTouch.ts
|
|
2201
|
-
var
|
|
2202
|
-
var
|
|
1995
|
+
var import_koishi10 = require("koishi");
|
|
1996
|
+
var logger9 = new import_koishi10.Logger("satori-game-onetouch");
|
|
2203
1997
|
var SKILL_MAP = {
|
|
2204
1998
|
// 基础技能
|
|
2205
1999
|
"-1": {},
|
|
@@ -2290,7 +2084,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2290
2084
|
hp: this.baseHP,
|
|
2291
2085
|
status: 0 /* Normal */
|
|
2292
2086
|
};
|
|
2293
|
-
return await
|
|
2087
|
+
return await wrapInHTML(`游戏开始!
|
|
2294
2088
|
对方的手势:左${this.ai.left} 右${this.ai.right}
|
|
2295
2089
|
你的手势:左${this.player.left} 右${this.player.right}
|
|
2296
2090
|
输入格式"左 右"选择要触碰的手
|
|
@@ -2340,9 +2134,9 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2340
2134
|
}
|
|
2341
2135
|
async processInput(input) {
|
|
2342
2136
|
if (input === "游戏规则")
|
|
2343
|
-
return await
|
|
2137
|
+
return await wrapInHTML(this.instuction);
|
|
2344
2138
|
if (input === "技能列表")
|
|
2345
|
-
return await
|
|
2139
|
+
return await wrapInHTML(this.skillList);
|
|
2346
2140
|
if (this.turnCount === 0)
|
|
2347
2141
|
this.initState(this.level);
|
|
2348
2142
|
this.turnCount++;
|
|
@@ -2383,7 +2177,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2383
2177
|
statusIcon(this.player.vulnerablility, "💔"),
|
|
2384
2178
|
this.player.status === 1 /* Stunned */ ? "💫 眩晕" : ""
|
|
2385
2179
|
].filter(Boolean).join(" | ");
|
|
2386
|
-
return
|
|
2180
|
+
return wrapInHTML(`▶️你的行动:${result}
|
|
2387
2181
|
|
|
2388
2182
|
▶️我的行动:${aiResult}
|
|
2389
2183
|
|
|
@@ -2768,7 +2562,7 @@ ${bonusMessage}` : "");
|
|
|
2768
2562
|
bestMove = move;
|
|
2769
2563
|
}
|
|
2770
2564
|
}
|
|
2771
|
-
|
|
2565
|
+
logger9.info(`AI选择的动作:${bestMove[0]}碰${bestMove[1]}, 分数:${bestScore}`);
|
|
2772
2566
|
if (this.turnCount > 5)
|
|
2773
2567
|
this.session.sendQueued(this.generateChat(bestScore), 1e3);
|
|
2774
2568
|
this.lastScore = bestScore;
|
|
@@ -2994,9 +2788,9 @@ var OneTouchGame = class extends abstractGame {
|
|
|
2994
2788
|
return game;
|
|
2995
2789
|
}
|
|
2996
2790
|
};
|
|
2997
|
-
async function
|
|
2791
|
+
async function wrapInHTML(str) {
|
|
2998
2792
|
if (!puppeteer) {
|
|
2999
|
-
|
|
2793
|
+
logger9.warn("puppeteer未就绪");
|
|
3000
2794
|
return "出现错误,请联系管理员";
|
|
3001
2795
|
}
|
|
3002
2796
|
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
@@ -3008,15 +2802,15 @@ async function wrapInHTML2(str) {
|
|
|
3008
2802
|
</style>
|
|
3009
2803
|
</html>`);
|
|
3010
2804
|
}
|
|
3011
|
-
__name(
|
|
2805
|
+
__name(wrapInHTML, "wrapInHTML");
|
|
3012
2806
|
|
|
3013
2807
|
// src/game.ts
|
|
3014
|
-
var
|
|
2808
|
+
var logger10 = new import_koishi11.Logger("satori-game");
|
|
3015
2809
|
var Game = class {
|
|
3016
2810
|
static {
|
|
3017
2811
|
__name(this, "Game");
|
|
3018
2812
|
}
|
|
3019
|
-
GAMES = ["
|
|
2813
|
+
GAMES = ["一碰一"];
|
|
3020
2814
|
// 支持的游戏列表
|
|
3021
2815
|
channelGames = /* @__PURE__ */ new Map();
|
|
3022
2816
|
// 频道ID到游戏名称的映射
|
|
@@ -3030,9 +2824,6 @@ var Game = class {
|
|
|
3030
2824
|
this.context = ctx;
|
|
3031
2825
|
this.config = cfg;
|
|
3032
2826
|
this.sat = sat;
|
|
3033
|
-
if (this.config.enable_gobang) {
|
|
3034
|
-
this.availableGames.set("五子棋", new goBang());
|
|
3035
|
-
}
|
|
3036
2827
|
if (this.config.enable_fencing) {
|
|
3037
2828
|
this.availableGames.set("击剑", new fencing());
|
|
3038
2829
|
}
|
|
@@ -3051,8 +2842,6 @@ var Game = class {
|
|
|
3051
2842
|
}
|
|
3052
2843
|
// 启动指定游戏
|
|
3053
2844
|
async startGame(session, gameName, args) {
|
|
3054
|
-
if (this.config.game_block_channel.includes(session.channelId))
|
|
3055
|
-
return "本群不支持游戏哦" + (this.config.channel_id_for_gobang[0] ? ",想玩请加群" + this.config.channel_id_for_gobang[0] : "");
|
|
3056
2845
|
if (this.channelGames.get(session.channelId))
|
|
3057
2846
|
return "当前频道已经有游戏在进行中";
|
|
3058
2847
|
if (gameName == "")
|
|
@@ -3062,9 +2851,6 @@ var Game = class {
|
|
|
3062
2851
|
const game = this.availableGames.get(gameName);
|
|
3063
2852
|
if (!game)
|
|
3064
2853
|
return "没有这个游戏哦";
|
|
3065
|
-
if (gameName === "五子棋" && !this.config.channel_id_for_gobang.includes(session.channelId)) {
|
|
3066
|
-
return "本群不支持五子棋哦,想玩请加群" + this.config.channel_id_for_gobang[0];
|
|
3067
|
-
}
|
|
3068
2854
|
const user = await ensureUserExists(this.context, session.userId, session.username);
|
|
3069
2855
|
const lastUsage = this.userUsage.get(`${session.userId}-${gameName}`);
|
|
3070
2856
|
if (lastUsage && user.userlevel < 4) {
|
|
@@ -3079,7 +2865,7 @@ var Game = class {
|
|
|
3079
2865
|
refreshPuppeteer(this.context);
|
|
3080
2866
|
game.startGame(session, this.context, args);
|
|
3081
2867
|
this.channelGames.set(session.channelId, gameName);
|
|
3082
|
-
|
|
2868
|
+
logger10.info(`游戏${gameName}已开始于${session.channelId}`);
|
|
3083
2869
|
}
|
|
3084
2870
|
// 结束当前游戏
|
|
3085
2871
|
async endGame(session) {
|
|
@@ -3088,7 +2874,7 @@ var Game = class {
|
|
|
3088
2874
|
return "当前频道没有游戏在进行中";
|
|
3089
2875
|
if (await this.availableGames.get(gameName).endGame(session, this.context)) {
|
|
3090
2876
|
this.channelGames.delete(session.channelId);
|
|
3091
|
-
|
|
2877
|
+
logger10.info(`${session.channelId}的游戏已结束`);
|
|
3092
2878
|
}
|
|
3093
2879
|
}
|
|
3094
2880
|
async chat(session, gameName, prompt) {
|
|
@@ -3101,8 +2887,6 @@ var Game = class {
|
|
|
3101
2887
|
}
|
|
3102
2888
|
getGameCd(gameName) {
|
|
3103
2889
|
switch (gameName) {
|
|
3104
|
-
case "五子棋":
|
|
3105
|
-
return this.config.cd_for_gobang;
|
|
3106
2890
|
case "一碰一":
|
|
3107
2891
|
return this.config.cd_for_OneTouch;
|
|
3108
2892
|
default:
|
|
@@ -3114,7 +2898,7 @@ var Game = class {
|
|
|
3114
2898
|
this.GAMES.forEach((game) => {
|
|
3115
2899
|
list += game + "\n";
|
|
3116
2900
|
});
|
|
3117
|
-
|
|
2901
|
+
logger10.info(list);
|
|
3118
2902
|
return list;
|
|
3119
2903
|
}
|
|
3120
2904
|
async resultJudge(result, ctx, session) {
|
|
@@ -3160,8 +2944,8 @@ var Game = class {
|
|
|
3160
2944
|
};
|
|
3161
2945
|
|
|
3162
2946
|
// src/broadcast.ts
|
|
3163
|
-
var
|
|
3164
|
-
var
|
|
2947
|
+
var import_koishi12 = require("koishi");
|
|
2948
|
+
var logger11 = new import_koishi12.Logger("satori-ai-broadcast");
|
|
3165
2949
|
var BroadcastManager = class {
|
|
3166
2950
|
static {
|
|
3167
2951
|
__name(this, "BroadcastManager");
|
|
@@ -3191,16 +2975,16 @@ var BroadcastManager = class {
|
|
|
3191
2975
|
const id = `broadcast-${this.idCounter++}`;
|
|
3192
2976
|
const broadcast = new broadcastMessage(this.ctx, this.config, message, img);
|
|
3193
2977
|
this.broadcastMessages.set(id, broadcast);
|
|
3194
|
-
|
|
2978
|
+
logger11.info(`广播已创建 ID: ${id}`);
|
|
3195
2979
|
return `广播已创建 ID: ${id}`;
|
|
3196
2980
|
}
|
|
3197
2981
|
async deleteBroadcast(id) {
|
|
3198
2982
|
if (this.broadcastMessages.has(id)) {
|
|
3199
2983
|
this.broadcastMessages.delete(id);
|
|
3200
|
-
|
|
2984
|
+
logger11.info(`广播已删除 ID: ${id}`);
|
|
3201
2985
|
return "已删除广播:" + id;
|
|
3202
2986
|
} else {
|
|
3203
|
-
|
|
2987
|
+
logger11.warn(`未找到广播 ID: ${id}`);
|
|
3204
2988
|
return "未找到该广播";
|
|
3205
2989
|
}
|
|
3206
2990
|
}
|
|
@@ -3208,7 +2992,7 @@ var BroadcastManager = class {
|
|
|
3208
2992
|
for (const [id, broadcast] of this.broadcastMessages.entries()) {
|
|
3209
2993
|
if (broadcast.setTime.getTime() + 1e3 * 60 * this.config.waiting_time < Date.now()) {
|
|
3210
2994
|
this.broadcastMessages.delete(id);
|
|
3211
|
-
|
|
2995
|
+
logger11.info(`广播已过期 ID: ${id}`);
|
|
3212
2996
|
continue;
|
|
3213
2997
|
}
|
|
3214
2998
|
await broadcast.sendMessage(session);
|
|
@@ -3236,7 +3020,7 @@ ${alreadySentChannels}
|
|
|
3236
3020
|
}
|
|
3237
3021
|
}
|
|
3238
3022
|
const result = list.length > 0 ? list.join("\n") : null;
|
|
3239
|
-
return result ?
|
|
3023
|
+
return result ? wrapInHTML2(result) : null;
|
|
3240
3024
|
}
|
|
3241
3025
|
};
|
|
3242
3026
|
var broadcastMessage = class {
|
|
@@ -3267,13 +3051,13 @@ var broadcastMessage = class {
|
|
|
3267
3051
|
try {
|
|
3268
3052
|
this.alreadySentChannels.add(channelId);
|
|
3269
3053
|
if (this.img) {
|
|
3270
|
-
session.send(await
|
|
3054
|
+
session.send(await wrapInHTML2(this.message));
|
|
3271
3055
|
} else {
|
|
3272
3056
|
session.send(this.message);
|
|
3273
3057
|
}
|
|
3274
|
-
|
|
3058
|
+
logger11.info(`向群 ${channelId} 广播: ${this.message}`);
|
|
3275
3059
|
} catch (error) {
|
|
3276
|
-
|
|
3060
|
+
logger11.error(`广播失败 ${channelId}: ${error}`);
|
|
3277
3061
|
}
|
|
3278
3062
|
}
|
|
3279
3063
|
getAlreadySentChannels() {
|
|
@@ -3281,9 +3065,9 @@ var broadcastMessage = class {
|
|
|
3281
3065
|
return alreadySentChannels.length > 0 ? alreadySentChannels.join("\n") : "无";
|
|
3282
3066
|
}
|
|
3283
3067
|
};
|
|
3284
|
-
async function
|
|
3068
|
+
async function wrapInHTML2(str) {
|
|
3285
3069
|
if (!puppeteer) {
|
|
3286
|
-
|
|
3070
|
+
logger11.warn("puppeteer未就绪");
|
|
3287
3071
|
return str;
|
|
3288
3072
|
}
|
|
3289
3073
|
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
@@ -3295,16 +3079,17 @@ async function wrapInHTML3(str) {
|
|
|
3295
3079
|
</style>
|
|
3296
3080
|
</html>`);
|
|
3297
3081
|
}
|
|
3298
|
-
__name(
|
|
3082
|
+
__name(wrapInHTML2, "wrapInHTML");
|
|
3299
3083
|
|
|
3300
3084
|
// src/index.tsx
|
|
3301
|
-
var
|
|
3085
|
+
var logger12 = new import_koishi13.Logger("satori-ai");
|
|
3086
|
+
var randomPrompt = "根据群聊内最近的包括所有人的聊天记录,锐评一下群聊中的话题";
|
|
3302
3087
|
var puppeteer = null;
|
|
3303
3088
|
function refreshPuppeteer(ctx) {
|
|
3304
3089
|
if (ctx.puppeteer) {
|
|
3305
3090
|
puppeteer = ctx.puppeteer;
|
|
3306
3091
|
} else {
|
|
3307
|
-
|
|
3092
|
+
logger12.warn("puppeteer未就绪");
|
|
3308
3093
|
}
|
|
3309
3094
|
}
|
|
3310
3095
|
__name(refreshPuppeteer, "refreshPuppeteer");
|
|
@@ -3433,7 +3218,8 @@ var SAT = class extends Sat {
|
|
|
3433
3218
|
registerCommands(ctx) {
|
|
3434
3219
|
ctx.command("sat <text:text>", { authority: this.config.authority }).alias(...this.config.alias).action(async ({ session }, prompt) => this.handleSatCommand(session, prompt));
|
|
3435
3220
|
ctx.command("sat.clear", "清空会话").option("global", "-g").action(({ session, options }) => this.clearSession(session, options.global));
|
|
3436
|
-
ctx.command("sat.common_sense <text:text>", "添加常识").action(async ({ session }, prompt) => this.addCommonSense(session, prompt));
|
|
3221
|
+
ctx.command("sat.common_sense <text:text>", "添加常识", { authority: 4 }).alias("添加常识").action(async ({ session }, prompt) => this.addCommonSense(session, prompt));
|
|
3222
|
+
ctx.command("sat.group_sense <text:text>", "添加群常识", { authority: 3 }).alias("添加群常识").option("id", "-i <id:string>", { authority: 3 }).action(async ({ session, options }, prompt) => this.addGroupCommonSense(session, prompt, options.id));
|
|
3437
3223
|
ctx.command("sat.update_user_level", "更新用户等级", { authority: 2 }).alias("更新用户").option("id", "-i <id:string>", { authority: 4 }).option("level", "-l <level:number>", { authority: 4 }).action(async ({ session, options }) => this.handleUserLevel(session, options));
|
|
3438
3224
|
ctx.command("sat.user_usage", "查看用户使用次数").alias("查询次数").action(async ({ session }) => this.handleUserUsage(session));
|
|
3439
3225
|
ctx.command("sat.add_output_censor <text:text>", "添加输出敏感词", { authority: 4 }).alias("添加输出屏蔽词").action(async ({ session }, word) => addOutputCensor(session, word, this.config.dataDir));
|
|
@@ -3492,9 +3278,9 @@ var SAT = class extends Sat {
|
|
|
3492
3278
|
const messages = generateAuxiliaryPrompt(prompt, response.content, user, this.getFavorabilityConfig());
|
|
3493
3279
|
const result = await this.apiClient.auxiliaryChat(messages);
|
|
3494
3280
|
if (result.error) {
|
|
3495
|
-
|
|
3281
|
+
logger12.error(`辅助判断失败:${result.content}`);
|
|
3496
3282
|
} else {
|
|
3497
|
-
|
|
3283
|
+
logger12.info(`辅助判断:${result.content}`);
|
|
3498
3284
|
return handleAuxiliaryResult(this.ctx, session, this.getFavorabilityConfig(), result.content);
|
|
3499
3285
|
}
|
|
3500
3286
|
}
|
|
@@ -3581,81 +3367,111 @@ var SAT = class extends Sat {
|
|
|
3581
3367
|
await inputContentCheck(this.ctx, censored, session.userId, this.getFavorabilityConfig(), session, this.moodManager);
|
|
3582
3368
|
}
|
|
3583
3369
|
if (this.config.log_ask_response)
|
|
3584
|
-
|
|
3370
|
+
logger12.info(`用户 ${session.username}:${processedPrompt}`);
|
|
3585
3371
|
return censored;
|
|
3586
3372
|
}
|
|
3587
3373
|
// 生成回复
|
|
3588
3374
|
async generateResponse(session, prompt) {
|
|
3589
3375
|
if (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
|
|
3590
|
-
|
|
3376
|
+
logger12.info(`频道 ${session.channelId} 并发数过高(${this.getChannelParallelCount(session)}),${session.username}等待中...`);
|
|
3591
3377
|
}
|
|
3592
3378
|
while (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
|
|
3593
3379
|
this.updateChannelParallelCount(session, -1);
|
|
3594
|
-
await new Promise((
|
|
3380
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3));
|
|
3595
3381
|
this.updateChannelParallelCount(session, 1);
|
|
3596
3382
|
}
|
|
3597
3383
|
const messages = await this.buildMessages(session, prompt);
|
|
3598
|
-
|
|
3384
|
+
logger12.info(`频道 ${session.channelId} 处理:${session.userId},剩余${this.getChannelParallelCount(session)}并发`);
|
|
3599
3385
|
const user = await getUser(this.ctx, session.userId);
|
|
3600
|
-
let response = await this.getChatResponse(user, messages);
|
|
3386
|
+
let response = await this.getChatResponse(user, messages, prompt);
|
|
3601
3387
|
if (response.error)
|
|
3602
|
-
response = await this.getChatResponse(user, messages);
|
|
3388
|
+
response = await this.getChatResponse(user, messages, prompt);
|
|
3603
3389
|
if (response.error)
|
|
3604
3390
|
updateUserUsage(this.ctx, user, -1);
|
|
3605
3391
|
return response;
|
|
3606
3392
|
}
|
|
3607
3393
|
// 获取聊天回复
|
|
3608
|
-
async getChatResponse(user, messages) {
|
|
3394
|
+
async getChatResponse(user, messages, prompt) {
|
|
3395
|
+
const hasTicket = user?.items?.["地灵殿通行证"]?.description && user.items["地灵殿通行证"].description === "on";
|
|
3396
|
+
const maxLength = hasTicket ? user?.items?.["地灵殿通行证"]?.metadata?.use_not_reasoner_LLM_length : this.config.use_not_reasoner_LLM_length;
|
|
3397
|
+
const useNoReasoner = prompt.length <= maxLength && this.config.enable_reasoner_like;
|
|
3609
3398
|
let response = await this.apiClient.chat(user, messages);
|
|
3610
3399
|
if (this.config.log_ask_response) {
|
|
3611
3400
|
if (this.config.enable_favorability && this.config.enable_mood)
|
|
3612
|
-
|
|
3401
|
+
logger12.info(`Satori AI:(心情值:${this.moodManager.getMoodValue(user.userid)})${response.content}`);
|
|
3613
3402
|
else
|
|
3614
|
-
|
|
3403
|
+
logger12.info(`Satori AI:${response.content}`);
|
|
3404
|
+
}
|
|
3405
|
+
if (!response.error) {
|
|
3406
|
+
response = filterResponse(response.content, this.config.reasoner_filter_word.split("-"), {
|
|
3407
|
+
applyBracketFilter: this.config.reasoner_filter,
|
|
3408
|
+
applyTagFilter: useNoReasoner || this.config.enhanceReasoningProtection
|
|
3409
|
+
});
|
|
3615
3410
|
}
|
|
3616
|
-
if (this.config.reasoner_filter && !response.error)
|
|
3617
|
-
response = filterResponse(response.content, this.config.reasoner_filter_word.split("-"));
|
|
3618
3411
|
return response;
|
|
3619
3412
|
}
|
|
3620
3413
|
// 构建消息
|
|
3621
3414
|
async buildMessages(session, prompt) {
|
|
3622
3415
|
const messages = [];
|
|
3623
|
-
const
|
|
3416
|
+
const user = await ensureUserExists(this.ctx, session.userId, session.username);
|
|
3417
|
+
const hasTicket = user?.items?.["地灵殿通行证"]?.description && user.items["地灵殿通行证"].description === "on";
|
|
3418
|
+
const maxLength = hasTicket ? user?.items?.["地灵殿通行证"]?.metadata?.use_not_reasoner_LLM_length : this.config.use_not_reasoner_LLM_length;
|
|
3419
|
+
const useNoReasoner = prompt.length <= maxLength && this.config.enable_reasoner_like;
|
|
3420
|
+
const exampleWithoutReasoner = `<think>
|
|
3624
3421
|
好的,我会尽量做到的
|
|
3625
3422
|
</think>
|
|
3626
3423
|
<p>已明确对话要求</p>`;
|
|
3424
|
+
const exampleWithTag = `<p>已明确对话要求</p>`;
|
|
3425
|
+
const exampleWithoutTag = `已明确对话要求`;
|
|
3426
|
+
const example = useNoReasoner ? exampleWithoutReasoner : this.config.enhanceReasoningProtection ? exampleWithTag : exampleWithoutTag;
|
|
3627
3427
|
if (this.config.no_system_prompt) {
|
|
3628
3428
|
messages.push({ role: "user", content: await this.buildSystemPrompt(session, prompt) });
|
|
3629
3429
|
messages.push({ role: "assistant", content: example });
|
|
3630
3430
|
} else {
|
|
3631
3431
|
messages.push({ role: "system", content: await this.buildSystemPrompt(session, prompt) });
|
|
3632
3432
|
}
|
|
3633
|
-
|
|
3634
|
-
|
|
3433
|
+
if (prompt != randomPrompt) {
|
|
3434
|
+
const userMemory = this.memoryManager.getChannelContext(this.config.personal_memory ? session.userId : session.channelId);
|
|
3435
|
+
messages.push(...userMemory);
|
|
3436
|
+
}
|
|
3635
3437
|
messages.push({ role: "user", content: prompt });
|
|
3636
3438
|
let payload = messages.map((msg) => msg.role + ":" + msg.content).join("\n");
|
|
3637
3439
|
if (this.config.log_system_prompt)
|
|
3638
|
-
|
|
3440
|
+
logger12.info(`系统提示:
|
|
3639
3441
|
${payload}`);
|
|
3640
3442
|
return messages;
|
|
3641
3443
|
}
|
|
3642
3444
|
// 构建系统提示
|
|
3643
3445
|
async buildSystemPrompt(session, prompt) {
|
|
3644
3446
|
const commonSense = await this.memoryManager.searchMemories(session, prompt, "common");
|
|
3447
|
+
const groupSense = await this.memoryManager.searchMemories(session, prompt, "group");
|
|
3645
3448
|
const channelDialogue = await this.memoryManager.getChannelDialogue(session);
|
|
3646
3449
|
const userMemory = await this.memoryManager.searchMemories(session, prompt);
|
|
3647
3450
|
const user = await getUser(this.ctx, session.userId);
|
|
3648
3451
|
const moodLevel = this.moodManager.getMoodLevel(user.userid);
|
|
3649
3452
|
let systemPrompt = "";
|
|
3453
|
+
if (prompt == randomPrompt) {
|
|
3454
|
+
systemPrompt += "#首先明确一些参考信息\n";
|
|
3455
|
+
systemPrompt += "\n##" + channelDialogue;
|
|
3456
|
+
systemPrompt += this.getThinkingPrompt(user, prompt);
|
|
3457
|
+
systemPrompt += this.config.prompt;
|
|
3458
|
+
if (this.config.enhanceReasoningProtection) {
|
|
3459
|
+
systemPrompt += `
|
|
3460
|
+
#注意:你最终的回复内容必须使用“<p>”开头,使用“</p>”结尾
|
|
3461
|
+
`;
|
|
3462
|
+
if (this.config.no_system_prompt)
|
|
3463
|
+
systemPrompt += "\n#如果你明白以上内容,请回复“<p>已明确对话要求</p>”";
|
|
3464
|
+
}
|
|
3465
|
+
return systemPrompt;
|
|
3466
|
+
}
|
|
3650
3467
|
systemPrompt += "#首先明确一些参考信息\n";
|
|
3651
3468
|
systemPrompt += "\n##" + commonSense;
|
|
3469
|
+
systemPrompt += "\n##" + groupSense;
|
|
3652
3470
|
systemPrompt += "\n##" + channelDialogue;
|
|
3653
3471
|
systemPrompt += "\n##" + userMemory;
|
|
3654
3472
|
if (moodLevel == "normal" || moodLevel == "happy")
|
|
3655
3473
|
systemPrompt += "\n##" + this.portraitManager.getUserPortrait(session);
|
|
3656
|
-
systemPrompt += "\n#参考信息到此为止,接下来是思考要求\n";
|
|
3657
3474
|
systemPrompt += this.getThinkingPrompt(user, prompt);
|
|
3658
|
-
systemPrompt += "\n#接下来是对话要求,以下要求仅对最终的回复内容生效,不限制思考过程\n";
|
|
3659
3475
|
systemPrompt += this.config.prompt;
|
|
3660
3476
|
if (user?.items?.["觉的衣柜"]?.count && (moodLevel == "normal" || moodLevel == "happy")) {
|
|
3661
3477
|
const clothes = user?.items?.["觉的衣柜"]?.metadata?.clothes;
|
|
@@ -3683,23 +3499,31 @@ ${payload}`);
|
|
|
3683
3499
|
if (nickName)
|
|
3684
3500
|
systemPrompt += `, 昵称是:${nickName},称呼用户时请优先使用昵称
|
|
3685
3501
|
`;
|
|
3686
|
-
|
|
3502
|
+
if (this.config.enhanceReasoningProtection) {
|
|
3503
|
+
systemPrompt += `
|
|
3687
3504
|
#注意:你最终的回复内容必须使用“<p>”开头,使用“</p>”结尾
|
|
3688
3505
|
`;
|
|
3689
|
-
|
|
3690
|
-
|
|
3506
|
+
if (this.config.no_system_prompt)
|
|
3507
|
+
systemPrompt += "\n#如果你明白以上内容,请回复“<p>已明确对话要求</p>”";
|
|
3508
|
+
}
|
|
3691
3509
|
return systemPrompt;
|
|
3692
3510
|
}
|
|
3693
3511
|
// 思考提示
|
|
3694
3512
|
getThinkingPrompt(user, prompt) {
|
|
3695
3513
|
const reasonerPrompt = this.config.reasoner_prompt;
|
|
3696
|
-
const promptForNoReasoner =
|
|
3514
|
+
const promptForNoReasoner = `
|
|
3515
|
+
#参考信息到此为止,接下来是思考要求
|
|
3516
|
+
#请你在回复时先进行分析思考,并且模仿思维链的模式输出思考内容,${reasonerPrompt};
|
|
3697
3517
|
#你在思考时必须以 "<think>" 开头, "</think>" 结尾。仔细揣摩用户意图,**完整输出思考内容后**再输出正式的回复内容;
|
|
3698
|
-
#注意:你的正式回复内容必须使用“<p
|
|
3699
|
-
|
|
3700
|
-
const promptForReasoner = `#你在思考时必须以 "嗯" 开头。仔细揣摩用户意图,思考结束后返回符合要求的回复。
|
|
3701
|
-
#注意:你的回复内容必须使用“<p>”开头,使用“</p>”结尾
|
|
3518
|
+
#注意:你的正式回复内容必须使用“<p>”开头,在输出全部回复后使用“</p>”结尾(即输出且仅输出一对标签),并且无论如何都要把标签输出完整
|
|
3519
|
+
#接下来是对话要求,以下要求仅对最终的回复内容生效,不限制思考过程
|
|
3702
3520
|
`;
|
|
3521
|
+
const promptForReasoner = this.config.enhanceReasoningProtection ? `
|
|
3522
|
+
#参考信息到此为止,接下来是思考要求
|
|
3523
|
+
#你在思考时必须以 "嗯" 开头。仔细揣摩用户意图,思考结束后返回符合要求的回复。
|
|
3524
|
+
#注意:你的回复内容必须使用“<p>”开头,在输出全部回复后使用“</p>”结尾(即输出且仅输出一对标签)
|
|
3525
|
+
#接下来是对话要求,以下要求仅对最终的回复内容生效,不限制思考过程
|
|
3526
|
+
` : "";
|
|
3703
3527
|
const hasTicket = user?.items?.["地灵殿通行证"]?.description && user.items["地灵殿通行证"].description === "on";
|
|
3704
3528
|
const maxLength = hasTicket ? user?.items?.["地灵殿通行证"]?.metadata?.use_not_reasoner_LLM_length : this.config.use_not_reasoner_LLM_length;
|
|
3705
3529
|
const useNoReasoner = prompt.length <= maxLength;
|
|
@@ -3740,10 +3564,10 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3740
3564
|
response = `@${session.username} ` + response;
|
|
3741
3565
|
}
|
|
3742
3566
|
if (this.config.sentences_divide && response.length > 10) {
|
|
3743
|
-
const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) =>
|
|
3567
|
+
const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) => import_koishi13.h.text(text));
|
|
3744
3568
|
for (const sentence of sentences) {
|
|
3745
3569
|
await session.send(sentence);
|
|
3746
|
-
await new Promise((
|
|
3570
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.time_interval));
|
|
3747
3571
|
}
|
|
3748
3572
|
return null;
|
|
3749
3573
|
}
|
|
@@ -3753,7 +3577,7 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3753
3577
|
if (!this.config.enable_warning)
|
|
3754
3578
|
return;
|
|
3755
3579
|
if (auxiliaryResult.includes("好感↓")) {
|
|
3756
|
-
|
|
3580
|
+
logger12.info(`在群${session.channelId}中,${session.username}骚扰我!`);
|
|
3757
3581
|
this.usersToWarn.set(session.channelId, session.username);
|
|
3758
3582
|
}
|
|
3759
3583
|
}
|
|
@@ -3793,13 +3617,25 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3793
3617
|
async addCommonSense(session, content) {
|
|
3794
3618
|
if (!content)
|
|
3795
3619
|
return session.text("commands.sat.common_sense.messages.no-prompt");
|
|
3796
|
-
const filePath =
|
|
3620
|
+
const filePath = path6.join(this.config.dataDir, "common_sense.txt");
|
|
3797
3621
|
await this.memoryManager.saveLongTermMemory(session, [{
|
|
3798
3622
|
role: "user",
|
|
3799
3623
|
content: content.replace(/\"/g, "'").trim()
|
|
3800
3624
|
}], filePath);
|
|
3801
3625
|
return session.text("commands.sat.common_sense.messages.succeed", [content]);
|
|
3802
3626
|
}
|
|
3627
|
+
// 添加群常识
|
|
3628
|
+
async addGroupCommonSense(session, content, groupId) {
|
|
3629
|
+
if (!content)
|
|
3630
|
+
return session.text("commands.sat.common_sense.messages.no-prompt");
|
|
3631
|
+
const id = groupId || session.channelId;
|
|
3632
|
+
const filePath = path6.join(this.config.dataDir, `group_sense`, `${id}.txt`);
|
|
3633
|
+
await this.memoryManager.saveLongTermMemory(session, [{
|
|
3634
|
+
role: "user",
|
|
3635
|
+
content: content.replace(/\"/g, "'").trim()
|
|
3636
|
+
}], filePath);
|
|
3637
|
+
return session.text("commands.sat.common_sense.messages.succeed", [`群${id}中:` + content]);
|
|
3638
|
+
}
|
|
3803
3639
|
// 更新用户等级
|
|
3804
3640
|
async handleUserLevel(session, options) {
|
|
3805
3641
|
const userId = options.id || session.userId;
|
|
@@ -3828,21 +3664,10 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3828
3664
|
return result;
|
|
3829
3665
|
}
|
|
3830
3666
|
// 随机中间件转接
|
|
3831
|
-
async handleRandomMiddleware(session
|
|
3832
|
-
|
|
3833
|
-
const
|
|
3834
|
-
|
|
3835
|
-
return null;
|
|
3836
|
-
if (await this.checkUserDialogueCount(session, user, 0))
|
|
3837
|
-
return null;
|
|
3838
|
-
if (await this.checkFavorabilityBlock(session))
|
|
3839
|
-
return null;
|
|
3840
|
-
let censored = processedPrompt;
|
|
3841
|
-
if (this.ctx.censor)
|
|
3842
|
-
censored = await this.ctx.censor.transform(processedPrompt, session);
|
|
3843
|
-
if (censored.includes("**"))
|
|
3844
|
-
return null;
|
|
3845
|
-
return this.handleSatCommand(session, prompt);
|
|
3667
|
+
async handleRandomMiddleware(session) {
|
|
3668
|
+
await this.updateChannelParallelCount(session, 1);
|
|
3669
|
+
const response = await this.generateResponse(session, randomPrompt);
|
|
3670
|
+
return await this.formatResponse(session, response.content, null);
|
|
3846
3671
|
}
|
|
3847
3672
|
// 昵称中间件转接
|
|
3848
3673
|
async handleNickNameMiddleware(session, prompt) {
|
package/lib/memory.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class MemoryManager {
|
|
|
23
23
|
clearAllMemories(): void;
|
|
24
24
|
getChannelMemory(channelId: string): MemoryEntry[];
|
|
25
25
|
saveLongTermMemory(session: Session, dialogues: MemoryEntry[], filePath?: string): Promise<void>;
|
|
26
|
-
searchMemories(session: Session, prompt: string, type?: 'user' | 'common'): Promise<string>;
|
|
26
|
+
searchMemories(session: Session, prompt: string, type?: 'user' | 'common' | 'group'): Promise<string>;
|
|
27
27
|
private findBestMatches;
|
|
28
28
|
private calculateMatchScore;
|
|
29
29
|
private formatMatches;
|
package/lib/types.d.ts
CHANGED
|
@@ -148,6 +148,7 @@ export declare namespace Sat {
|
|
|
148
148
|
baseURL: string;
|
|
149
149
|
key: string[];
|
|
150
150
|
appointModel: string;
|
|
151
|
+
enhanceReasoningProtection: boolean;
|
|
151
152
|
not_reasoner_LLM_URL: string;
|
|
152
153
|
not_reasoner_LLM: string;
|
|
153
154
|
not_reasoner_LLM_key: string[];
|
|
@@ -191,6 +192,7 @@ export declare namespace Sat {
|
|
|
191
192
|
duplicateDialogueCheck: boolean;
|
|
192
193
|
enable_online_user_check: boolean;
|
|
193
194
|
random_min_tokens: number;
|
|
195
|
+
enable_random_without_favorability: boolean;
|
|
194
196
|
randnum: number;
|
|
195
197
|
sentences_divide: boolean;
|
|
196
198
|
min_sentences_length: number;
|
|
@@ -244,9 +246,6 @@ export declare namespace Sat {
|
|
|
244
246
|
waiting_time: number;
|
|
245
247
|
enable_game: boolean;
|
|
246
248
|
game_block_channel: string[];
|
|
247
|
-
enable_gobang: boolean;
|
|
248
|
-
channel_id_for_gobang: string[];
|
|
249
|
-
cd_for_gobang: number;
|
|
250
249
|
enable_fencing: boolean;
|
|
251
250
|
enable_OneTouch: boolean;
|
|
252
251
|
cd_for_OneTouch: number;
|
package/lib/userportrait.d.ts
CHANGED
|
@@ -9,7 +9,8 @@ export declare class UserPortraitManager {
|
|
|
9
9
|
hasPortrait(userId: string): boolean;
|
|
10
10
|
readPortrait(userId: string): string;
|
|
11
11
|
private getDialogues;
|
|
12
|
-
private
|
|
12
|
+
private buildFirstMessage;
|
|
13
|
+
private buildSecondMessage;
|
|
13
14
|
generatePortrait(session: Session, user: User, apiClient: APIClient): Promise<void>;
|
|
14
15
|
private savePortrait;
|
|
15
16
|
private ensurePortraitFile;
|
package/lib/utils.d.ts
CHANGED
|
@@ -23,7 +23,10 @@ export declare function processPrompt(prompt: string): string;
|
|
|
23
23
|
* @param words 需要过滤的关键词
|
|
24
24
|
* @returns 处理后的字符串,删除含有关键词的部分
|
|
25
25
|
*/
|
|
26
|
-
export declare function filterResponse(prompt: string, words: string[]
|
|
26
|
+
export declare function filterResponse(prompt: string, words: string[], options?: {
|
|
27
|
+
applyBracketFilter?: boolean;
|
|
28
|
+
applyTagFilter?: boolean;
|
|
29
|
+
}): {
|
|
27
30
|
content: string;
|
|
28
31
|
error: boolean;
|
|
29
32
|
};
|
package/package.json
CHANGED
package/lib/gobang_ai.exe
DELETED
|
Binary file
|