koishi-plugin-satori-ai 1.3.6 → 1.3.8
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 +147 -358
- package/lib/types.d.ts +0 -3
- package/lib/userportrait.d.ts +2 -1
- package/package.json +1 -1
- package/lib/gobang_ai.exe +0 -0
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");
|
|
@@ -284,11 +284,11 @@ function filterResponse(prompt, words) {
|
|
|
284
284
|
const lastAnswer5 = answerMatches5 ? answerMatches5[answerMatches5.length - 1] : null;
|
|
285
285
|
const answerContent = lastAnswer || lastDoubao || lastAnswer3 || lastAnswer4 || lastAnswer5;
|
|
286
286
|
if (!answerContent) {
|
|
287
|
-
return { content: "
|
|
287
|
+
return { content: "有点问题,请重置对话", error: true };
|
|
288
288
|
}
|
|
289
289
|
const regex = /<p>|<\/p>|<doubaothinking>|<\/doubaothinking>|<\/p|<answer>|<\/answer>|<br>|<\/br>|<br\/>/g;
|
|
290
290
|
const cleanedContent = answerContent.replace(regex, "");
|
|
291
|
-
return cleanedContent ? { content: cleanedContent, error: false } : { content: "
|
|
291
|
+
return cleanedContent ? { content: cleanedContent, error: false } : { content: "有点问题,请重置对话", error: true };
|
|
292
292
|
}
|
|
293
293
|
__name(filterResponse, "filterResponse");
|
|
294
294
|
function addOutputCensor(session, word, baseURL) {
|
|
@@ -311,6 +311,51 @@ async function updateUserPWithTicket(ctx, user, adjustment) {
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
__name(updateUserPWithTicket, "updateUserPWithTicket");
|
|
314
|
+
function findLongestCommonSubstring(str1, str2) {
|
|
315
|
+
if (!str1 || !str2)
|
|
316
|
+
return 0;
|
|
317
|
+
const m = str1.length;
|
|
318
|
+
const n = str2.length;
|
|
319
|
+
const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
|
|
320
|
+
let maxLength = 0;
|
|
321
|
+
for (let i = 1; i <= m; i++) {
|
|
322
|
+
for (let j = 1; j <= n; j++) {
|
|
323
|
+
if (str1[i - 1] === str2[j - 1]) {
|
|
324
|
+
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
325
|
+
maxLength = Math.max(maxLength, dp[i][j]);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return maxLength;
|
|
330
|
+
}
|
|
331
|
+
__name(findLongestCommonSubstring, "findLongestCommonSubstring");
|
|
332
|
+
function countCommonChars(str1, str2) {
|
|
333
|
+
const chars1 = /* @__PURE__ */ new Map();
|
|
334
|
+
const chars2 = /* @__PURE__ */ new Map();
|
|
335
|
+
for (const char of str1) {
|
|
336
|
+
if (/[\u4e00-\u9fff]/.test(char)) {
|
|
337
|
+
chars1.set(char, (chars1.get(char) || 0) + 1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
for (const char of str2) {
|
|
341
|
+
if (/[\u4e00-\u9fff]/.test(char)) {
|
|
342
|
+
chars2.set(char, (chars2.get(char) || 0) + 1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
let commonCount = 0;
|
|
346
|
+
for (const [char, count1] of chars1) {
|
|
347
|
+
const count2 = chars2.get(char) || 0;
|
|
348
|
+
commonCount += Math.min(count1, count2);
|
|
349
|
+
}
|
|
350
|
+
const countDigits = /* @__PURE__ */ __name((s) => (s.match(/\d/g) || []).length, "countDigits");
|
|
351
|
+
const digits1 = countDigits(str1);
|
|
352
|
+
const digits2 = countDigits(str2);
|
|
353
|
+
if (digits1 >= 3 || digits2 >= 3) {
|
|
354
|
+
return Math.max(commonCount, 2);
|
|
355
|
+
}
|
|
356
|
+
return commonCount;
|
|
357
|
+
}
|
|
358
|
+
__name(countCommonChars, "countCommonChars");
|
|
314
359
|
|
|
315
360
|
// src/api.ts
|
|
316
361
|
var logger2 = new import_koishi2.Logger("satori-api");
|
|
@@ -412,7 +457,7 @@ var APIClient = class {
|
|
|
412
457
|
if (i == this.config.maxRetryTimes) {
|
|
413
458
|
return this.handleAPIError(error);
|
|
414
459
|
}
|
|
415
|
-
await new Promise((
|
|
460
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.retry_delay_time || 5e3));
|
|
416
461
|
logger2.warn(`生成画像时API请求失败(${error}),重试(第${i}次)中...`);
|
|
417
462
|
continue;
|
|
418
463
|
}
|
|
@@ -469,7 +514,7 @@ var APIClient = class {
|
|
|
469
514
|
if (i == this.config.maxRetryTimes) {
|
|
470
515
|
return this.handleAPIError(error);
|
|
471
516
|
}
|
|
472
|
-
await new Promise((
|
|
517
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.retry_delay_time || 5e3));
|
|
473
518
|
logger2.warn(`API请求失败(${error}),重试(第${i}次)中...`);
|
|
474
519
|
continue;
|
|
475
520
|
}
|
|
@@ -543,7 +588,7 @@ var MemoryManager = class {
|
|
|
543
588
|
}
|
|
544
589
|
channelMemories = /* @__PURE__ */ new Map();
|
|
545
590
|
channelDialogues = /* @__PURE__ */ new Map();
|
|
546
|
-
charactersToRemove = ["的", "一", "是", "了", "什", "么", "我", "谁", "不", "人", "在", "他", "有", "这", "个", "上", "们", "来", "到", "时", "大", "地", "为", "子", "中", "你", "说", "生", "国", "年", "着", "就", "那", "和", "要", "她", "出", "也", "得", "里", "后", "自", "以", "会", "id="
|
|
591
|
+
charactersToRemove = ["的", "一", "是", "了", "什", "么", "我", "谁", "不", "人", "在", "他", "有", "这", "个", "上", "们", "来", "到", "时", "大", "地", "为", "子", "中", "你", "说", "生", "国", "年", "着", "就", "那", "和", "要", "她", "出", "也", "得", "里", "后", "自", "以", "会", "id="];
|
|
547
592
|
MAX_MEMORY_LENGTH = 5e3;
|
|
548
593
|
// 更新记忆
|
|
549
594
|
async updateMemories(session, prompt, config, response) {
|
|
@@ -578,7 +623,7 @@ var MemoryManager = class {
|
|
|
578
623
|
if (!this.config.channel_dialogues)
|
|
579
624
|
return "";
|
|
580
625
|
const Dialogue = this.channelDialogues[session.channelId]?.join("\n") || "";
|
|
581
|
-
const result = "
|
|
626
|
+
const result = "以下是群聊内最近的包括所有人的聊天记录,当当前对话涉及其中内容时你可以参考这些信息,但是要注意分辨发言人是谁:{\n" + Dialogue + "\n}\n";
|
|
582
627
|
return result;
|
|
583
628
|
}
|
|
584
629
|
// 括号引号过滤
|
|
@@ -702,22 +747,12 @@ var MemoryManager = class {
|
|
|
702
747
|
calculateMatchScore(content, keywords) {
|
|
703
748
|
if (keywords.length === 0)
|
|
704
749
|
return { score: 0, count: 0 };
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
const
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
let count = 0;
|
|
712
|
-
matches.forEach((match) => {
|
|
713
|
-
const chineseCount = (match.match(chineseRegex) || []).length;
|
|
714
|
-
const englishCount = match.length - chineseCount;
|
|
715
|
-
count += chineseCount * 2 + englishCount;
|
|
716
|
-
});
|
|
717
|
-
const totalChinese = (content.match(chineseRegex) || []).length;
|
|
718
|
-
const totalEnglish = content.length - totalChinese;
|
|
719
|
-
const totalWeight = totalChinese * 2 + totalEnglish;
|
|
720
|
-
const ratio = totalWeight > 0 ? count / totalWeight : 0;
|
|
750
|
+
const regex = new RegExp(`[${this.charactersToRemove.join("")}]`, "g");
|
|
751
|
+
content = content.replace(regex, "");
|
|
752
|
+
const Keyword = keywords.map((k) => escapeRegExp(k)).join("");
|
|
753
|
+
const length = findLongestCommonSubstring(content, Keyword);
|
|
754
|
+
const count = countCommonChars(content, Keyword);
|
|
755
|
+
const ratio = (length * length + count) / content.length;
|
|
721
756
|
return { score: ratio, count };
|
|
722
757
|
}
|
|
723
758
|
// 格式化匹配结果
|
|
@@ -732,7 +767,8 @@ var MemoryManager = class {
|
|
|
732
767
|
matched = matched.slice(0, topN < matched.length ? topN : matched.length);
|
|
733
768
|
if (type === "common") {
|
|
734
769
|
const result = `${prefixMap[type]}{
|
|
735
|
-
${matched.map((entry) => entry.content).join("\n")}
|
|
770
|
+
${matched.map((entry) => entry.content).join("\n")}
|
|
771
|
+
${date}
|
|
736
772
|
}
|
|
737
773
|
`;
|
|
738
774
|
return result;
|
|
@@ -1225,9 +1261,6 @@ var Sat = class extends import_koishi5.Service {
|
|
|
1225
1261
|
import_koishi5.Schema.object({
|
|
1226
1262
|
enable_game: import_koishi5.Schema.boolean().default(false).description("是否开启游戏模块"),
|
|
1227
1263
|
game_block_channel: import_koishi5.Schema.array(String).description("不提供游戏的频道id"),
|
|
1228
|
-
enable_gobang: import_koishi5.Schema.boolean().default(false).description("是否开启五子棋游戏(需要puppeteer支持)"),
|
|
1229
|
-
channel_id_for_gobang: import_koishi5.Schema.array(String).description("启用五子棋的游戏频道id(不建议太多,第一个会被公示)"),
|
|
1230
|
-
cd_for_gobang: import_koishi5.Schema.number().default(3600).description("每人五子棋游戏cd时间(秒)"),
|
|
1231
1264
|
enable_OneTouch: import_koishi5.Schema.boolean().default(false).description("是否开启一碰一游戏(需要puppeteer支持)"),
|
|
1232
1265
|
cd_for_OneTouch: import_koishi5.Schema.number().default(600).description("每人一碰一游戏cd时间(秒)"),
|
|
1233
1266
|
enable_fencing: import_koishi5.Schema.boolean().default(false).description("是否开启击剑游戏(无效,开发中)")
|
|
@@ -1279,7 +1312,7 @@ var UserPortraitManager = class {
|
|
|
1279
1312
|
});
|
|
1280
1313
|
fs5.writeFileSync(memoryPath, JSON.stringify(replacedContent, null, 2));
|
|
1281
1314
|
const validEntries = replacedContent.filter((entry) => entry.role !== "user").map((entry) => {
|
|
1282
|
-
const timeMatch = entry.role.match(/对话日期和时间:(\d{
|
|
1315
|
+
const timeMatch = entry.role.match(/对话日期和时间:(\d{1,2}\/\d{1,2}\/\d{4}), (\d{1,2}:\d{2}:\d{2} [AP]M)/);
|
|
1283
1316
|
if (!timeMatch)
|
|
1284
1317
|
return null;
|
|
1285
1318
|
return {
|
|
@@ -1293,11 +1326,11 @@ var UserPortraitManager = class {
|
|
|
1293
1326
|
return validEntries.slice(0, maxEntries).map((entry) => `${entry.content}${entry.role}`);
|
|
1294
1327
|
}
|
|
1295
1328
|
// 生成提示词模板
|
|
1296
|
-
|
|
1329
|
+
buildFirstMessage(level, history, user) {
|
|
1297
1330
|
return [{
|
|
1298
1331
|
role: "user",
|
|
1299
|
-
content:
|
|
1300
|
-
1.
|
|
1332
|
+
content: `你是一个角色扮演智能体工作流中的一环,请根据以下信息生成户画像。可选内容包括:
|
|
1333
|
+
1. 基本信息(性别、年龄、生日等)
|
|
1301
1334
|
2. 生活习惯(作息等)
|
|
1302
1335
|
3. 反感点(如有)
|
|
1303
1336
|
4. 对AI的期望(从对话历史中推断)
|
|
@@ -1305,21 +1338,47 @@ var UserPortraitManager = class {
|
|
|
1305
1338
|
|
|
1306
1339
|
用户名:${user.usersname}
|
|
1307
1340
|
你与用户的关系:${level}
|
|
1308
|
-
历史画像:
|
|
1309
|
-
${existingPortrait ? "无" : existingPortrait}
|
|
1310
|
-
|
|
1311
1341
|
近期的用户发言记录:
|
|
1312
1342
|
${history}
|
|
1313
1343
|
|
|
1314
1344
|
注意事项:
|
|
1345
|
+
·没有涉及到的信息注为无
|
|
1315
1346
|
·用户一定是人类,其他情况是角色扮演
|
|
1316
|
-
·根据发言修正历史画像内容,但是历史画像中与发言无关的部分必须保留
|
|
1317
1347
|
·尤其注意用户说“记住”的部分,可能是用户希望记录的信息
|
|
1318
1348
|
·因为在角色扮演中,用户可能会说出不符合事实的信息,需要根据事实推断,避免盲目相信或主观臆测
|
|
1319
1349
|
·使用尽可能简洁的表达
|
|
1320
1350
|
·保留不确定性的表述(如"可能"、"似乎"、"用户自称")
|
|
1321
1351
|
·保持中立和客观,避免带有个人情感色彩的描述,不要添加评价或建议
|
|
1322
1352
|
·仅给出画像内容,不要添加额外的描述、建议、评价、注解等任何内容
|
|
1353
|
+
·不使用markdown等标记语言,直接书写即可`
|
|
1354
|
+
}];
|
|
1355
|
+
}
|
|
1356
|
+
buildSecondMessage(level, NewPortrait, existingPortrait, user) {
|
|
1357
|
+
return [{
|
|
1358
|
+
role: "user",
|
|
1359
|
+
content: `你是一个角色扮演智能体工作流中的一环,请根据以下信息合并用户画像。内容包括:
|
|
1360
|
+
1. 基本信息(性别、年龄、生日等,不要遗漏或改动已有的信息)
|
|
1361
|
+
2. 生活习惯(作息等)
|
|
1362
|
+
3. 反感点(如有)
|
|
1363
|
+
4. 对AI的期望(从对话历史中推断)
|
|
1364
|
+
5. 用户希望记住的信息(如有)
|
|
1365
|
+
|
|
1366
|
+
用户名:${user.usersname}
|
|
1367
|
+
你与用户的关系:${level}
|
|
1368
|
+
已有画像:
|
|
1369
|
+
${existingPortrait ? "无" : existingPortrait}
|
|
1370
|
+
|
|
1371
|
+
新补充信息:
|
|
1372
|
+
${NewPortrait}
|
|
1373
|
+
|
|
1374
|
+
注意事项:
|
|
1375
|
+
·用户一定是人类,其他情况是角色扮演
|
|
1376
|
+
·根据已有画像,补充新信息,避免重复,并且不要遗漏你认为重要信息
|
|
1377
|
+
·你认为不太重要的信息可以删除
|
|
1378
|
+
·使用尽可能简洁的表达
|
|
1379
|
+
·保留不确定性的表述(如"可能"、"似乎"、"用户自称")
|
|
1380
|
+
·保持中立和客观,避免带有个人情感色彩的描述,不要添加评价或建议
|
|
1381
|
+
·仅给出画像内容,不要添加额外的描述、建议、评价、注解等任何内容
|
|
1323
1382
|
·不使用markdown等标记语言,直接书写即可`
|
|
1324
1383
|
}];
|
|
1325
1384
|
}
|
|
@@ -1334,10 +1393,12 @@ ${history}
|
|
|
1334
1393
|
const dialogues = await this.getDialogues(user);
|
|
1335
1394
|
const existing = this.readPortrait(user.userid);
|
|
1336
1395
|
const userlevel = getFavorabilityLevel(user, this.getFavorabilityConfig());
|
|
1337
|
-
const messages = this.buildMessage(userlevel, dialogues.join("\n"), existing, user);
|
|
1338
1396
|
logger5.info(`用户 ${user.userid} 画像生成中...`);
|
|
1339
1397
|
try {
|
|
1340
|
-
const
|
|
1398
|
+
const FirstMessages = this.buildFirstMessage(userlevel, dialogues.join("\n"), user);
|
|
1399
|
+
const NewPortrait = await apiClient.generateUserPortrait(user, FirstMessages);
|
|
1400
|
+
const SecondMessages = this.buildSecondMessage(userlevel, NewPortrait.content, existing, user);
|
|
1401
|
+
const response = await apiClient.generateUserPortrait(user, SecondMessages);
|
|
1341
1402
|
if (response && !response.error) {
|
|
1342
1403
|
this.savePortrait(user, response.content);
|
|
1343
1404
|
if (user.usage > this.config.portrait_usage - 1)
|
|
@@ -1617,9 +1678,9 @@ ${this.config.mood_prompt_2}
|
|
|
1617
1678
|
};
|
|
1618
1679
|
|
|
1619
1680
|
// src/game.ts
|
|
1620
|
-
var
|
|
1681
|
+
var import_koishi11 = require("koishi");
|
|
1621
1682
|
|
|
1622
|
-
// src/
|
|
1683
|
+
// src/gamefencing.ts
|
|
1623
1684
|
var import_koishi9 = require("koishi");
|
|
1624
1685
|
|
|
1625
1686
|
// src/abstractGame.ts
|
|
@@ -1723,270 +1784,8 @@ var abstractGame = class {
|
|
|
1723
1784
|
}
|
|
1724
1785
|
};
|
|
1725
1786
|
|
|
1726
|
-
// src/gamegobang.ts
|
|
1727
|
-
var import_child_process = require("child_process");
|
|
1728
|
-
var path6 = __toESM(require("path"));
|
|
1729
|
-
var logger8 = new import_koishi9.Logger("satori-game-gobang");
|
|
1730
|
-
var BOARD_SIZE = 14;
|
|
1731
|
-
var inspireSearchLength = 10;
|
|
1732
|
-
var Coordinate = class {
|
|
1733
|
-
static {
|
|
1734
|
-
__name(this, "Coordinate");
|
|
1735
|
-
}
|
|
1736
|
-
x;
|
|
1737
|
-
y;
|
|
1738
|
-
score;
|
|
1739
|
-
constructor(a = 0, b = 0, s = 0) {
|
|
1740
|
-
this.x = a;
|
|
1741
|
-
this.y = b;
|
|
1742
|
-
this.score = s;
|
|
1743
|
-
}
|
|
1744
|
-
};
|
|
1745
|
-
async function wrapInHTML(str) {
|
|
1746
|
-
if (!puppeteer) {
|
|
1747
|
-
logger8.warn("puppeteer未就绪");
|
|
1748
|
-
return "出现错误,请联系管理员";
|
|
1749
|
-
}
|
|
1750
|
-
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
1751
|
-
<style>
|
|
1752
|
-
body {
|
|
1753
|
-
padding: 10px;
|
|
1754
|
-
display: inline-block;
|
|
1755
|
-
}
|
|
1756
|
-
</style>
|
|
1757
|
-
</html>`);
|
|
1758
|
-
}
|
|
1759
|
-
__name(wrapInHTML, "wrapInHTML");
|
|
1760
|
-
var goBangSingleGame = class extends abstractGameSingleGame {
|
|
1761
|
-
static {
|
|
1762
|
-
__name(this, "goBangSingleGame");
|
|
1763
|
-
}
|
|
1764
|
-
playerFlag;
|
|
1765
|
-
// 玩家棋子颜色(1: 黑棋,2: 白棋)
|
|
1766
|
-
winningFlag = 4 /* pending */;
|
|
1767
|
-
// 当前胜负状态
|
|
1768
|
-
level;
|
|
1769
|
-
// AI 难度等级
|
|
1770
|
-
board = [];
|
|
1771
|
-
// BOARD_SIZExBOARD_SIZE 棋盘状态
|
|
1772
|
-
lastScore = 0;
|
|
1773
|
-
// 上次评分
|
|
1774
|
-
turnsCount = 0;
|
|
1775
|
-
// 回合数
|
|
1776
|
-
constructor(disposeListener, session) {
|
|
1777
|
-
super(disposeListener, session);
|
|
1778
|
-
}
|
|
1779
|
-
// 初始化棋盘,随机决定玩家先手
|
|
1780
|
-
startGame = () => {
|
|
1781
|
-
super.startGame();
|
|
1782
|
-
this.board = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
|
|
1783
|
-
this.turnsCount = 0;
|
|
1784
|
-
this.playerFlag = Math.round(Math.random()) + 1;
|
|
1785
|
-
const getCornerCoordinate = /* @__PURE__ */ __name((i) => {
|
|
1786
|
-
const quarter = i < 0.5 ? 0.2 : 0.7;
|
|
1787
|
-
const base = Math.round(BOARD_SIZE * quarter);
|
|
1788
|
-
return base;
|
|
1789
|
-
}, "getCornerCoordinate");
|
|
1790
|
-
for (let i = 0; i <= 1; i++) {
|
|
1791
|
-
for (let j = 0; j <= 1; j++) {
|
|
1792
|
-
const randomX = getCornerCoordinate(i) + 1 - 2 * i;
|
|
1793
|
-
const randomY = getCornerCoordinate(j);
|
|
1794
|
-
const player = Math.round(Math.random()) + 1;
|
|
1795
|
-
this.board[randomX][randomY] = player;
|
|
1796
|
-
this.board[randomX + i * 2 - 1][randomY - j * 2 + 1] = 3 - player;
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
if (this.playerFlag === 1) {
|
|
1800
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2] = 1;
|
|
1801
|
-
this.board[BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 2;
|
|
1802
|
-
return wrapInHTML("游戏开始,你随机到了先手(黑)\n输入两个数字以下棋,先行后列,例如:“0 13”\n" + this.printBoard());
|
|
1803
|
-
} else {
|
|
1804
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2] = 1;
|
|
1805
|
-
this.board[BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 2;
|
|
1806
|
-
this.board[BOARD_SIZE / 2][BOARD_SIZE / 2 + (Math.round(Math.random()) ? -1 : 1)] = 1;
|
|
1807
|
-
return wrapInHTML("游戏开始,你随机到了后手(白)\n输入两个数字以下棋,先行后列,例如:“0 13”\n" + this.printBoard());
|
|
1808
|
-
}
|
|
1809
|
-
};
|
|
1810
|
-
// 结束游戏,返回结果
|
|
1811
|
-
endGame = async () => {
|
|
1812
|
-
super.endGame();
|
|
1813
|
-
let bonusLevel = this.level;
|
|
1814
|
-
if (this.winningFlag === 1 /* win */ && this.playerFlag === 1) {
|
|
1815
|
-
bonusLevel -= 1;
|
|
1816
|
-
} else if (this.winningFlag === 2 /* lose */ && this.playerFlag === 1) {
|
|
1817
|
-
bonusLevel += 1;
|
|
1818
|
-
}
|
|
1819
|
-
return { message: `${bonusLevel}`, win: this.winningFlag, gameName: "五子棋", playerID: this.session.userId };
|
|
1820
|
-
};
|
|
1821
|
-
/**
|
|
1822
|
-
* 处理玩家输入(落子坐标)
|
|
1823
|
-
* @param str 输入内容,格式为 "x y"
|
|
1824
|
-
*/
|
|
1825
|
-
async processInput(str) {
|
|
1826
|
-
const [x, y] = str.split(" ").map((a) => {
|
|
1827
|
-
return parseInt(a);
|
|
1828
|
-
});
|
|
1829
|
-
if (isNaN(x) || isNaN(y))
|
|
1830
|
-
return;
|
|
1831
|
-
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE)
|
|
1832
|
-
return "坐标超出范围了";
|
|
1833
|
-
if (this.board[x][y] !== 0)
|
|
1834
|
-
return "这个位置已经有棋子了,别想耍赖";
|
|
1835
|
-
if (this.winningFlag !== 4 /* pending */)
|
|
1836
|
-
return "游戏已结束";
|
|
1837
|
-
this.lastActionTime = Date.now();
|
|
1838
|
-
this.board[x][y] = this.playerFlag;
|
|
1839
|
-
logger8.info(`level: ${this.level}, player: x: ${x}, y: ${y}`);
|
|
1840
|
-
if (this.checkWin(x, y))
|
|
1841
|
-
return wrapInHTML(this.printBoard() + "\n游戏已结束,发送结束游戏退出");
|
|
1842
|
-
const starttime = Date.now();
|
|
1843
|
-
const aiMove = this.getAIMove();
|
|
1844
|
-
const endtime = Date.now();
|
|
1845
|
-
if (aiMove.x === -1 || aiMove.y === -1) {
|
|
1846
|
-
this.winningFlag = 3 /* draw */;
|
|
1847
|
-
return "计算失败,视为平局,发送结束游戏退出";
|
|
1848
|
-
}
|
|
1849
|
-
if (this.turnsCount > 50) {
|
|
1850
|
-
this.winningFlag = 3 /* draw */;
|
|
1851
|
-
return "平局,发送结束游戏退出";
|
|
1852
|
-
}
|
|
1853
|
-
logger8.info(`AI 落子坐标: ${aiMove.x} ${aiMove.y},得分: ${aiMove.score},AI 落子耗时: ${endtime - starttime}ms`);
|
|
1854
|
-
this.board[aiMove.x][aiMove.y] = 3 - this.playerFlag;
|
|
1855
|
-
if (this.turnsCount > 5) {
|
|
1856
|
-
setTimeout(() => {
|
|
1857
|
-
this.session.send(this.generateChat(aiMove.score));
|
|
1858
|
-
}, 1e3);
|
|
1859
|
-
}
|
|
1860
|
-
this.lastScore = aiMove.score;
|
|
1861
|
-
this.turnsCount++;
|
|
1862
|
-
if (this.checkWin(aiMove.x, aiMove.y))
|
|
1863
|
-
return wrapInHTML(this.printBoard() + "\n游戏已结束,发送结束游戏退出");
|
|
1864
|
-
return wrapInHTML(this.printBoard() + "\n我这一步下在这里哦(" + aiMove.x + " " + aiMove.y + " 用时" + (endtime - starttime) + "ms)");
|
|
1865
|
-
}
|
|
1866
|
-
getAIMove() {
|
|
1867
|
-
try {
|
|
1868
|
-
const boardStr = this.board.map((row) => row.join(" ")).join(" ");
|
|
1869
|
-
const exePath = path6.resolve(__dirname, "../lib/gobang_ai.exe");
|
|
1870
|
-
const level = this.turnsCount > 3 ? this.level : Math.min(5, this.level);
|
|
1871
|
-
const stdout = (0, import_child_process.execSync)(
|
|
1872
|
-
`"${exePath}" "${boardStr}" ${this.playerFlag} ${level} ${inspireSearchLength}`,
|
|
1873
|
-
{ timeout: 18e5 }
|
|
1874
|
-
// 设置1800秒超时
|
|
1875
|
-
).toString().trim();
|
|
1876
|
-
const [x, y, score] = stdout.split(" ").map(Number);
|
|
1877
|
-
return new Coordinate(x, y, score);
|
|
1878
|
-
} catch (error) {
|
|
1879
|
-
logger8.error(`AI计算失败: ${error}`);
|
|
1880
|
-
}
|
|
1881
|
-
return new Coordinate(-1, -1, -1);
|
|
1882
|
-
}
|
|
1883
|
-
// 检查是否连成五子
|
|
1884
|
-
checkWin(x, y) {
|
|
1885
|
-
const directions = [[1, 0], [0, 1], [1, 1], [1, -1]];
|
|
1886
|
-
for (const [dx, dy] of directions) {
|
|
1887
|
-
let count = 1;
|
|
1888
|
-
for (let i = 1; i < 5; i++) {
|
|
1889
|
-
if (this.checkDirection(x, y, dx, dy, i))
|
|
1890
|
-
count++;
|
|
1891
|
-
else
|
|
1892
|
-
break;
|
|
1893
|
-
}
|
|
1894
|
-
for (let i = 1; i < 5; i++) {
|
|
1895
|
-
if (this.checkDirection(x, y, -dx, -dy, i))
|
|
1896
|
-
count++;
|
|
1897
|
-
else
|
|
1898
|
-
break;
|
|
1899
|
-
}
|
|
1900
|
-
if (count >= 5) {
|
|
1901
|
-
this.winningFlag = this.board[x][y] === this.playerFlag ? 1 /* win */ : 2 /* lose */;
|
|
1902
|
-
return true;
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
return false;
|
|
1906
|
-
}
|
|
1907
|
-
// 辅助方法:检查指定方向是否有连续棋子
|
|
1908
|
-
checkDirection(x, y, dx, dy, step) {
|
|
1909
|
-
const nx = x + dx * step, ny = y + dy * step;
|
|
1910
|
-
return nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && this.board[nx][ny] === this.board[x][y];
|
|
1911
|
-
}
|
|
1912
|
-
// 生成带表情符号的棋盘字符串
|
|
1913
|
-
printBoard() {
|
|
1914
|
-
const numberEmojis = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🔢", "🔢", "🔢", "🔢"];
|
|
1915
|
-
let res = "🟨" + numberEmojis.slice(0, BOARD_SIZE).join("") + "🟨\n";
|
|
1916
|
-
for (let i = 0; i < BOARD_SIZE; i++) {
|
|
1917
|
-
res += numberEmojis[i];
|
|
1918
|
-
for (let j = 0; j < BOARD_SIZE; j++) {
|
|
1919
|
-
res += this.board[i][j] === 0 ? "🟨" : this.board[i][j] === 1 ? "⚫" : "⚪";
|
|
1920
|
-
}
|
|
1921
|
-
res += numberEmojis[i];
|
|
1922
|
-
res += "\n";
|
|
1923
|
-
}
|
|
1924
|
-
res += "🟨" + numberEmojis.slice(0, BOARD_SIZE).join("") + "🟨\n";
|
|
1925
|
-
return res;
|
|
1926
|
-
}
|
|
1927
|
-
generateChat(Score) {
|
|
1928
|
-
if (this.lastScore < 5e6 && Score > 5e6 && this.level > 3) {
|
|
1929
|
-
return "我觉得你要输了哦~";
|
|
1930
|
-
}
|
|
1931
|
-
if (this.lastScore < 1e6 && Score > 1e6) {
|
|
1932
|
-
return "只能下在这里了~";
|
|
1933
|
-
}
|
|
1934
|
-
if (4e3 <= Score && Score < 1e4) {
|
|
1935
|
-
return "这招怎么样?";
|
|
1936
|
-
}
|
|
1937
|
-
if (2e3 <= Score && Score < 4e3 && Math.random() < 0.5) {
|
|
1938
|
-
return {
|
|
1939
|
-
0: "有点意思哦~",
|
|
1940
|
-
1: "真是焦灼的局面",
|
|
1941
|
-
2: "势均力敌呢~",
|
|
1942
|
-
3: "你在想什么呢?",
|
|
1943
|
-
4: "走这里会不会太冒险了?"
|
|
1944
|
-
}[Math.floor(Math.random() * 5)];
|
|
1945
|
-
}
|
|
1946
|
-
if (Score < -1e6) {
|
|
1947
|
-
return "好猛烈的攻击啊~";
|
|
1948
|
-
}
|
|
1949
|
-
if (Score < 0 && Math.random() < 0.5) {
|
|
1950
|
-
return "你还真是厉害呢~";
|
|
1951
|
-
}
|
|
1952
|
-
if (Score < 100) {
|
|
1953
|
-
return "出乎意料的一手啊";
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
};
|
|
1957
|
-
var goBang = class extends abstractGame {
|
|
1958
|
-
static {
|
|
1959
|
-
__name(this, "goBang");
|
|
1960
|
-
}
|
|
1961
|
-
constructor() {
|
|
1962
|
-
super(goBangSingleGame);
|
|
1963
|
-
}
|
|
1964
|
-
// 启动游戏时可传入难度参数
|
|
1965
|
-
async startGame(session, ctx, args) {
|
|
1966
|
-
let level;
|
|
1967
|
-
if (!isNaN(parseInt(args[0])))
|
|
1968
|
-
level = parseInt(args[0]);
|
|
1969
|
-
else {
|
|
1970
|
-
setTimeout(() => {
|
|
1971
|
-
session.send("未输入难度等级(2-6),默认设为3");
|
|
1972
|
-
}, 500);
|
|
1973
|
-
level = 3;
|
|
1974
|
-
}
|
|
1975
|
-
if (level < 2 || level > 6) {
|
|
1976
|
-
level = level < 2 ? 2 : 6;
|
|
1977
|
-
setTimeout(() => {
|
|
1978
|
-
session.send("难度等级必须在2到6之间,已调整为" + level);
|
|
1979
|
-
}, 500);
|
|
1980
|
-
}
|
|
1981
|
-
const game = await super.startGame(session, ctx, args);
|
|
1982
|
-
game.level = level;
|
|
1983
|
-
return game;
|
|
1984
|
-
}
|
|
1985
|
-
};
|
|
1986
|
-
|
|
1987
1787
|
// src/gamefencing.ts
|
|
1988
|
-
var
|
|
1989
|
-
var logger9 = new import_koishi10.Logger("satori-game-fencing");
|
|
1788
|
+
var logger8 = new import_koishi9.Logger("satori-game-fencing");
|
|
1990
1789
|
var fencingSingleGame = class _fencingSingleGame extends abstractGameSingleGame {
|
|
1991
1790
|
static {
|
|
1992
1791
|
__name(this, "fencingSingleGame");
|
|
@@ -2168,8 +1967,8 @@ var fencing = class extends abstractGame {
|
|
|
2168
1967
|
};
|
|
2169
1968
|
|
|
2170
1969
|
// src/gameOneTouch.ts
|
|
2171
|
-
var
|
|
2172
|
-
var
|
|
1970
|
+
var import_koishi10 = require("koishi");
|
|
1971
|
+
var logger9 = new import_koishi10.Logger("satori-game-onetouch");
|
|
2173
1972
|
var SKILL_MAP = {
|
|
2174
1973
|
// 基础技能
|
|
2175
1974
|
"-1": {},
|
|
@@ -2260,7 +2059,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2260
2059
|
hp: this.baseHP,
|
|
2261
2060
|
status: 0 /* Normal */
|
|
2262
2061
|
};
|
|
2263
|
-
return await
|
|
2062
|
+
return await wrapInHTML(`游戏开始!
|
|
2264
2063
|
对方的手势:左${this.ai.left} 右${this.ai.right}
|
|
2265
2064
|
你的手势:左${this.player.left} 右${this.player.right}
|
|
2266
2065
|
输入格式"左 右"选择要触碰的手
|
|
@@ -2310,9 +2109,9 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2310
2109
|
}
|
|
2311
2110
|
async processInput(input) {
|
|
2312
2111
|
if (input === "游戏规则")
|
|
2313
|
-
return await
|
|
2112
|
+
return await wrapInHTML(this.instuction);
|
|
2314
2113
|
if (input === "技能列表")
|
|
2315
|
-
return await
|
|
2114
|
+
return await wrapInHTML(this.skillList);
|
|
2316
2115
|
if (this.turnCount === 0)
|
|
2317
2116
|
this.initState(this.level);
|
|
2318
2117
|
this.turnCount++;
|
|
@@ -2353,7 +2152,7 @@ var OneTouchSingleGame = class extends abstractGameSingleGame {
|
|
|
2353
2152
|
statusIcon(this.player.vulnerablility, "💔"),
|
|
2354
2153
|
this.player.status === 1 /* Stunned */ ? "💫 眩晕" : ""
|
|
2355
2154
|
].filter(Boolean).join(" | ");
|
|
2356
|
-
return
|
|
2155
|
+
return wrapInHTML(`▶️你的行动:${result}
|
|
2357
2156
|
|
|
2358
2157
|
▶️我的行动:${aiResult}
|
|
2359
2158
|
|
|
@@ -2738,7 +2537,7 @@ ${bonusMessage}` : "");
|
|
|
2738
2537
|
bestMove = move;
|
|
2739
2538
|
}
|
|
2740
2539
|
}
|
|
2741
|
-
|
|
2540
|
+
logger9.info(`AI选择的动作:${bestMove[0]}碰${bestMove[1]}, 分数:${bestScore}`);
|
|
2742
2541
|
if (this.turnCount > 5)
|
|
2743
2542
|
this.session.sendQueued(this.generateChat(bestScore), 1e3);
|
|
2744
2543
|
this.lastScore = bestScore;
|
|
@@ -2964,9 +2763,9 @@ var OneTouchGame = class extends abstractGame {
|
|
|
2964
2763
|
return game;
|
|
2965
2764
|
}
|
|
2966
2765
|
};
|
|
2967
|
-
async function
|
|
2766
|
+
async function wrapInHTML(str) {
|
|
2968
2767
|
if (!puppeteer) {
|
|
2969
|
-
|
|
2768
|
+
logger9.warn("puppeteer未就绪");
|
|
2970
2769
|
return "出现错误,请联系管理员";
|
|
2971
2770
|
}
|
|
2972
2771
|
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
@@ -2978,15 +2777,15 @@ async function wrapInHTML2(str) {
|
|
|
2978
2777
|
</style>
|
|
2979
2778
|
</html>`);
|
|
2980
2779
|
}
|
|
2981
|
-
__name(
|
|
2780
|
+
__name(wrapInHTML, "wrapInHTML");
|
|
2982
2781
|
|
|
2983
2782
|
// src/game.ts
|
|
2984
|
-
var
|
|
2783
|
+
var logger10 = new import_koishi11.Logger("satori-game");
|
|
2985
2784
|
var Game = class {
|
|
2986
2785
|
static {
|
|
2987
2786
|
__name(this, "Game");
|
|
2988
2787
|
}
|
|
2989
|
-
GAMES = ["
|
|
2788
|
+
GAMES = ["一碰一"];
|
|
2990
2789
|
// 支持的游戏列表
|
|
2991
2790
|
channelGames = /* @__PURE__ */ new Map();
|
|
2992
2791
|
// 频道ID到游戏名称的映射
|
|
@@ -3000,9 +2799,6 @@ var Game = class {
|
|
|
3000
2799
|
this.context = ctx;
|
|
3001
2800
|
this.config = cfg;
|
|
3002
2801
|
this.sat = sat;
|
|
3003
|
-
if (this.config.enable_gobang) {
|
|
3004
|
-
this.availableGames.set("五子棋", new goBang());
|
|
3005
|
-
}
|
|
3006
2802
|
if (this.config.enable_fencing) {
|
|
3007
2803
|
this.availableGames.set("击剑", new fencing());
|
|
3008
2804
|
}
|
|
@@ -3021,8 +2817,6 @@ var Game = class {
|
|
|
3021
2817
|
}
|
|
3022
2818
|
// 启动指定游戏
|
|
3023
2819
|
async startGame(session, gameName, args) {
|
|
3024
|
-
if (this.config.game_block_channel.includes(session.channelId))
|
|
3025
|
-
return "本群不支持游戏哦" + (this.config.channel_id_for_gobang[0] ? ",想玩请加群" + this.config.channel_id_for_gobang[0] : "");
|
|
3026
2820
|
if (this.channelGames.get(session.channelId))
|
|
3027
2821
|
return "当前频道已经有游戏在进行中";
|
|
3028
2822
|
if (gameName == "")
|
|
@@ -3032,9 +2826,6 @@ var Game = class {
|
|
|
3032
2826
|
const game = this.availableGames.get(gameName);
|
|
3033
2827
|
if (!game)
|
|
3034
2828
|
return "没有这个游戏哦";
|
|
3035
|
-
if (gameName === "五子棋" && !this.config.channel_id_for_gobang.includes(session.channelId)) {
|
|
3036
|
-
return "本群不支持五子棋哦,想玩请加群" + this.config.channel_id_for_gobang[0];
|
|
3037
|
-
}
|
|
3038
2829
|
const user = await ensureUserExists(this.context, session.userId, session.username);
|
|
3039
2830
|
const lastUsage = this.userUsage.get(`${session.userId}-${gameName}`);
|
|
3040
2831
|
if (lastUsage && user.userlevel < 4) {
|
|
@@ -3049,7 +2840,7 @@ var Game = class {
|
|
|
3049
2840
|
refreshPuppeteer(this.context);
|
|
3050
2841
|
game.startGame(session, this.context, args);
|
|
3051
2842
|
this.channelGames.set(session.channelId, gameName);
|
|
3052
|
-
|
|
2843
|
+
logger10.info(`游戏${gameName}已开始于${session.channelId}`);
|
|
3053
2844
|
}
|
|
3054
2845
|
// 结束当前游戏
|
|
3055
2846
|
async endGame(session) {
|
|
@@ -3058,7 +2849,7 @@ var Game = class {
|
|
|
3058
2849
|
return "当前频道没有游戏在进行中";
|
|
3059
2850
|
if (await this.availableGames.get(gameName).endGame(session, this.context)) {
|
|
3060
2851
|
this.channelGames.delete(session.channelId);
|
|
3061
|
-
|
|
2852
|
+
logger10.info(`${session.channelId}的游戏已结束`);
|
|
3062
2853
|
}
|
|
3063
2854
|
}
|
|
3064
2855
|
async chat(session, gameName, prompt) {
|
|
@@ -3071,8 +2862,6 @@ var Game = class {
|
|
|
3071
2862
|
}
|
|
3072
2863
|
getGameCd(gameName) {
|
|
3073
2864
|
switch (gameName) {
|
|
3074
|
-
case "五子棋":
|
|
3075
|
-
return this.config.cd_for_gobang;
|
|
3076
2865
|
case "一碰一":
|
|
3077
2866
|
return this.config.cd_for_OneTouch;
|
|
3078
2867
|
default:
|
|
@@ -3084,7 +2873,7 @@ var Game = class {
|
|
|
3084
2873
|
this.GAMES.forEach((game) => {
|
|
3085
2874
|
list += game + "\n";
|
|
3086
2875
|
});
|
|
3087
|
-
|
|
2876
|
+
logger10.info(list);
|
|
3088
2877
|
return list;
|
|
3089
2878
|
}
|
|
3090
2879
|
async resultJudge(result, ctx, session) {
|
|
@@ -3130,8 +2919,8 @@ var Game = class {
|
|
|
3130
2919
|
};
|
|
3131
2920
|
|
|
3132
2921
|
// src/broadcast.ts
|
|
3133
|
-
var
|
|
3134
|
-
var
|
|
2922
|
+
var import_koishi12 = require("koishi");
|
|
2923
|
+
var logger11 = new import_koishi12.Logger("satori-ai-broadcast");
|
|
3135
2924
|
var BroadcastManager = class {
|
|
3136
2925
|
static {
|
|
3137
2926
|
__name(this, "BroadcastManager");
|
|
@@ -3161,16 +2950,16 @@ var BroadcastManager = class {
|
|
|
3161
2950
|
const id = `broadcast-${this.idCounter++}`;
|
|
3162
2951
|
const broadcast = new broadcastMessage(this.ctx, this.config, message, img);
|
|
3163
2952
|
this.broadcastMessages.set(id, broadcast);
|
|
3164
|
-
|
|
2953
|
+
logger11.info(`广播已创建 ID: ${id}`);
|
|
3165
2954
|
return `广播已创建 ID: ${id}`;
|
|
3166
2955
|
}
|
|
3167
2956
|
async deleteBroadcast(id) {
|
|
3168
2957
|
if (this.broadcastMessages.has(id)) {
|
|
3169
2958
|
this.broadcastMessages.delete(id);
|
|
3170
|
-
|
|
2959
|
+
logger11.info(`广播已删除 ID: ${id}`);
|
|
3171
2960
|
return "已删除广播:" + id;
|
|
3172
2961
|
} else {
|
|
3173
|
-
|
|
2962
|
+
logger11.warn(`未找到广播 ID: ${id}`);
|
|
3174
2963
|
return "未找到该广播";
|
|
3175
2964
|
}
|
|
3176
2965
|
}
|
|
@@ -3178,7 +2967,7 @@ var BroadcastManager = class {
|
|
|
3178
2967
|
for (const [id, broadcast] of this.broadcastMessages.entries()) {
|
|
3179
2968
|
if (broadcast.setTime.getTime() + 1e3 * 60 * this.config.waiting_time < Date.now()) {
|
|
3180
2969
|
this.broadcastMessages.delete(id);
|
|
3181
|
-
|
|
2970
|
+
logger11.info(`广播已过期 ID: ${id}`);
|
|
3182
2971
|
continue;
|
|
3183
2972
|
}
|
|
3184
2973
|
await broadcast.sendMessage(session);
|
|
@@ -3206,7 +2995,7 @@ ${alreadySentChannels}
|
|
|
3206
2995
|
}
|
|
3207
2996
|
}
|
|
3208
2997
|
const result = list.length > 0 ? list.join("\n") : null;
|
|
3209
|
-
return result ?
|
|
2998
|
+
return result ? wrapInHTML2(result) : null;
|
|
3210
2999
|
}
|
|
3211
3000
|
};
|
|
3212
3001
|
var broadcastMessage = class {
|
|
@@ -3237,13 +3026,13 @@ var broadcastMessage = class {
|
|
|
3237
3026
|
try {
|
|
3238
3027
|
this.alreadySentChannels.add(channelId);
|
|
3239
3028
|
if (this.img) {
|
|
3240
|
-
session.send(await
|
|
3029
|
+
session.send(await wrapInHTML2(this.message));
|
|
3241
3030
|
} else {
|
|
3242
3031
|
session.send(this.message);
|
|
3243
3032
|
}
|
|
3244
|
-
|
|
3033
|
+
logger11.info(`向群 ${channelId} 广播: ${this.message}`);
|
|
3245
3034
|
} catch (error) {
|
|
3246
|
-
|
|
3035
|
+
logger11.error(`广播失败 ${channelId}: ${error}`);
|
|
3247
3036
|
}
|
|
3248
3037
|
}
|
|
3249
3038
|
getAlreadySentChannels() {
|
|
@@ -3251,9 +3040,9 @@ var broadcastMessage = class {
|
|
|
3251
3040
|
return alreadySentChannels.length > 0 ? alreadySentChannels.join("\n") : "无";
|
|
3252
3041
|
}
|
|
3253
3042
|
};
|
|
3254
|
-
async function
|
|
3043
|
+
async function wrapInHTML2(str) {
|
|
3255
3044
|
if (!puppeteer) {
|
|
3256
|
-
|
|
3045
|
+
logger11.warn("puppeteer未就绪");
|
|
3257
3046
|
return str;
|
|
3258
3047
|
}
|
|
3259
3048
|
return puppeteer.render(`<html><body>${str.replaceAll(/\n/g, "<BR>")}</body>
|
|
@@ -3265,16 +3054,16 @@ async function wrapInHTML3(str) {
|
|
|
3265
3054
|
</style>
|
|
3266
3055
|
</html>`);
|
|
3267
3056
|
}
|
|
3268
|
-
__name(
|
|
3057
|
+
__name(wrapInHTML2, "wrapInHTML");
|
|
3269
3058
|
|
|
3270
3059
|
// src/index.tsx
|
|
3271
|
-
var
|
|
3060
|
+
var logger12 = new import_koishi13.Logger("satori-ai");
|
|
3272
3061
|
var puppeteer = null;
|
|
3273
3062
|
function refreshPuppeteer(ctx) {
|
|
3274
3063
|
if (ctx.puppeteer) {
|
|
3275
3064
|
puppeteer = ctx.puppeteer;
|
|
3276
3065
|
} else {
|
|
3277
|
-
|
|
3066
|
+
logger12.warn("puppeteer未就绪");
|
|
3278
3067
|
}
|
|
3279
3068
|
}
|
|
3280
3069
|
__name(refreshPuppeteer, "refreshPuppeteer");
|
|
@@ -3462,9 +3251,9 @@ var SAT = class extends Sat {
|
|
|
3462
3251
|
const messages = generateAuxiliaryPrompt(prompt, response.content, user, this.getFavorabilityConfig());
|
|
3463
3252
|
const result = await this.apiClient.auxiliaryChat(messages);
|
|
3464
3253
|
if (result.error) {
|
|
3465
|
-
|
|
3254
|
+
logger12.error(`辅助判断失败:${result.content}`);
|
|
3466
3255
|
} else {
|
|
3467
|
-
|
|
3256
|
+
logger12.info(`辅助判断:${result.content}`);
|
|
3468
3257
|
return handleAuxiliaryResult(this.ctx, session, this.getFavorabilityConfig(), result.content);
|
|
3469
3258
|
}
|
|
3470
3259
|
}
|
|
@@ -3551,21 +3340,21 @@ var SAT = class extends Sat {
|
|
|
3551
3340
|
await inputContentCheck(this.ctx, censored, session.userId, this.getFavorabilityConfig(), session, this.moodManager);
|
|
3552
3341
|
}
|
|
3553
3342
|
if (this.config.log_ask_response)
|
|
3554
|
-
|
|
3343
|
+
logger12.info(`用户 ${session.username}:${processedPrompt}`);
|
|
3555
3344
|
return censored;
|
|
3556
3345
|
}
|
|
3557
3346
|
// 生成回复
|
|
3558
3347
|
async generateResponse(session, prompt) {
|
|
3559
3348
|
if (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
|
|
3560
|
-
|
|
3349
|
+
logger12.info(`频道 ${session.channelId} 并发数过高(${this.getChannelParallelCount(session)}),${session.username}等待中...`);
|
|
3561
3350
|
}
|
|
3562
3351
|
while (this.getChannelParallelCount(session) > this.config.max_parallel_count) {
|
|
3563
3352
|
this.updateChannelParallelCount(session, -1);
|
|
3564
|
-
await new Promise((
|
|
3353
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1e3));
|
|
3565
3354
|
this.updateChannelParallelCount(session, 1);
|
|
3566
3355
|
}
|
|
3567
3356
|
const messages = await this.buildMessages(session, prompt);
|
|
3568
|
-
|
|
3357
|
+
logger12.info(`频道 ${session.channelId} 处理:${session.userId},剩余${this.getChannelParallelCount(session)}并发`);
|
|
3569
3358
|
const user = await getUser(this.ctx, session.userId);
|
|
3570
3359
|
let response = await this.getChatResponse(user, messages);
|
|
3571
3360
|
if (response.error)
|
|
@@ -3579,9 +3368,9 @@ var SAT = class extends Sat {
|
|
|
3579
3368
|
let response = await this.apiClient.chat(user, messages);
|
|
3580
3369
|
if (this.config.log_ask_response) {
|
|
3581
3370
|
if (this.config.enable_favorability && this.config.enable_mood)
|
|
3582
|
-
|
|
3371
|
+
logger12.info(`Satori AI:(心情值:${this.moodManager.getMoodValue(user.userid)})${response.content}`);
|
|
3583
3372
|
else
|
|
3584
|
-
|
|
3373
|
+
logger12.info(`Satori AI:${response.content}`);
|
|
3585
3374
|
}
|
|
3586
3375
|
if (this.config.reasoner_filter && !response.error)
|
|
3587
3376
|
response = filterResponse(response.content, this.config.reasoner_filter_word.split("-"));
|
|
@@ -3605,7 +3394,7 @@ var SAT = class extends Sat {
|
|
|
3605
3394
|
messages.push({ role: "user", content: prompt });
|
|
3606
3395
|
let payload = messages.map((msg) => msg.role + ":" + msg.content).join("\n");
|
|
3607
3396
|
if (this.config.log_system_prompt)
|
|
3608
|
-
|
|
3397
|
+
logger12.info(`系统提示:
|
|
3609
3398
|
${payload}`);
|
|
3610
3399
|
return messages;
|
|
3611
3400
|
}
|
|
@@ -3664,7 +3453,7 @@ ${payload}`);
|
|
|
3664
3453
|
getThinkingPrompt(user, prompt) {
|
|
3665
3454
|
const reasonerPrompt = this.config.reasoner_prompt;
|
|
3666
3455
|
const promptForNoReasoner = `#请你在回复时先进行分析思考,并且模仿思维链的模式输出思考内容,${reasonerPrompt};
|
|
3667
|
-
#你在思考时必须以 "<think>" 开头, "</think>"
|
|
3456
|
+
#你在思考时必须以 "<think>" 开头, "</think>" 结尾。仔细揣摩用户意图,**完整输出思考内容后**再输出正式的回复内容;
|
|
3668
3457
|
#注意:你的正式回复内容必须使用“<p>”开头,使用“</p>”结尾,并且无论如何都要把标签输出完整
|
|
3669
3458
|
`;
|
|
3670
3459
|
const promptForReasoner = `#你在思考时必须以 "嗯" 开头。仔细揣摩用户意图,思考结束后返回符合要求的回复。
|
|
@@ -3710,10 +3499,10 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3710
3499
|
response = `@${session.username} ` + response;
|
|
3711
3500
|
}
|
|
3712
3501
|
if (this.config.sentences_divide && response.length > 10) {
|
|
3713
|
-
const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) =>
|
|
3502
|
+
const sentences = splitSentences(response, this.config.min_sentences_length, this.config.max_sentences_length).map((text) => import_koishi13.h.text(text));
|
|
3714
3503
|
for (const sentence of sentences) {
|
|
3715
3504
|
await session.send(sentence);
|
|
3716
|
-
await new Promise((
|
|
3505
|
+
await new Promise((resolve2) => setTimeout(resolve2, this.config.time_interval));
|
|
3717
3506
|
}
|
|
3718
3507
|
return null;
|
|
3719
3508
|
}
|
|
@@ -3723,7 +3512,7 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3723
3512
|
if (!this.config.enable_warning)
|
|
3724
3513
|
return;
|
|
3725
3514
|
if (auxiliaryResult.includes("好感↓")) {
|
|
3726
|
-
|
|
3515
|
+
logger12.info(`在群${session.channelId}中,${session.username}骚扰我!`);
|
|
3727
3516
|
this.usersToWarn.set(session.channelId, session.username);
|
|
3728
3517
|
}
|
|
3729
3518
|
}
|
|
@@ -3763,10 +3552,10 @@ ${useNoReasoner ? promptForNoReasoner : promptForReasoner}
|
|
|
3763
3552
|
async addCommonSense(session, content) {
|
|
3764
3553
|
if (!content)
|
|
3765
3554
|
return session.text("commands.sat.common_sense.messages.no-prompt");
|
|
3766
|
-
const filePath =
|
|
3555
|
+
const filePath = path6.join(this.config.dataDir, "common_sense.txt");
|
|
3767
3556
|
await this.memoryManager.saveLongTermMemory(session, [{
|
|
3768
3557
|
role: "user",
|
|
3769
|
-
content
|
|
3558
|
+
content: content.replace(/\"/g, "'").trim()
|
|
3770
3559
|
}], filePath);
|
|
3771
3560
|
return session.text("commands.sat.common_sense.messages.succeed", [content]);
|
|
3772
3561
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -244,9 +244,6 @@ export declare namespace Sat {
|
|
|
244
244
|
waiting_time: number;
|
|
245
245
|
enable_game: boolean;
|
|
246
246
|
game_block_channel: string[];
|
|
247
|
-
enable_gobang: boolean;
|
|
248
|
-
channel_id_for_gobang: string[];
|
|
249
|
-
cd_for_gobang: number;
|
|
250
247
|
enable_fencing: boolean;
|
|
251
248
|
enable_OneTouch: boolean;
|
|
252
249
|
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/package.json
CHANGED
package/lib/gobang_ai.exe
DELETED
|
Binary file
|