dsh-feini 0.1.5 → 0.1.6
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/package.json +1 -1
- package/src/bridge.mjs +2 -1
- package/src/guess-plan.mjs +79 -0
package/package.json
CHANGED
package/src/bridge.mjs
CHANGED
|
@@ -37,6 +37,7 @@ import { lastAssistant } from './last-assistant.mjs';
|
|
|
37
37
|
import { takeInterest, addInterest, removeInterest, interestsLine, INTEREST_RULE } from './interests.mjs';
|
|
38
38
|
import { startInterestReview } from './review.mjs';
|
|
39
39
|
import { seaLine } from './sea.mjs';
|
|
40
|
+
import { planHint } from './guess-plan.mjs';
|
|
40
41
|
import { takeGuess, addGuess, resolveGuess, guessesLine, GUESS_RULE } from './guess.mjs';
|
|
41
42
|
import { ANGER_RULE, angerLine, offend, coaxed, looksLikeCoax } from './anger.mjs';
|
|
42
43
|
import { getBalance, BALANCE_RULE } from './balance.mjs';
|
|
@@ -1127,7 +1128,7 @@ async function respond(bot, userId, text, images, quoted, replyToId = 0) {
|
|
|
1127
1128
|
? []
|
|
1128
1129
|
: getHistory(config.memoryPath, config.bucket.entry, config.bucket.pet, config.historyRounds);
|
|
1129
1130
|
const messages = [
|
|
1130
|
-
{ role: 'system', content: buildSystem(text) + awayNote + correctionLine(text) + searchNote + recentFacts(config.memoryPath, config.bucket.entry, config.bucket.pet) },
|
|
1131
|
+
{ role: 'system', content: buildSystem(text) + awayNote + correctionLine(text) + planHint(seaFile, text) + searchNote + recentFacts(config.memoryPath, config.bucket.entry, config.bucket.pet) },
|
|
1131
1132
|
...history,
|
|
1132
1133
|
{ role: 'user', content },
|
|
1133
1134
|
];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「你猜我在干啥」:先翻他昨天说过的行程,翻不到再按习惯猜。
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独一个模块:这段逻辑要能单独测(拿真的 me.json 喂它),
|
|
5
|
+
* 塞在 bridge.mjs 里一导入就把桥跑起来了,没法测。
|
|
6
|
+
*
|
|
7
|
+
* 检索顺序按他定的来:
|
|
8
|
+
* 1. 最近几天他说过的安排(明天/今天/约/说好 + 去/吃/见…),优先他自己说的;
|
|
9
|
+
* 2. 没翻到就让她按习惯猜(作息、最近在玩什么、爱吃什么)。
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
|
|
13
|
+
const PLAN_RE = /(明天|今天|后天|约好|说好|打算)/;
|
|
14
|
+
const VERB_RE = /(去|吃|见|回|上班|上课|开会|出门)/;
|
|
15
|
+
const NOT_PLAN_RE = /(猜猜|你猜|猜一下|猜我|哼|再说一遍|还记得|记得我|有没有给你说|给你说过)/;
|
|
16
|
+
|
|
17
|
+
/** 像不像「哪天要去干嘛」:短句 + 时间词 + 动作词,别把一整段聊天当成行程 */
|
|
18
|
+
function looksLikePlan(t) {
|
|
19
|
+
if (!t || t.length < 4 || t.length > 70) return false;
|
|
20
|
+
if (!PLAN_RE.test(t) || !VERB_RE.test(t)) return false;
|
|
21
|
+
if (NOT_PLAN_RE.test(t)) return false;
|
|
22
|
+
// 「今天」「明天」后面紧跟着动作,才像安排
|
|
23
|
+
return /(明天|今天|后天|约好|说好|打算)[^。!?;;]{0,18}(去|吃|见|回|上班|上课|开会|出门)/.test(t);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 最近几天里「像安排」的话,他自己说的排前面,然后按新到旧 */
|
|
27
|
+
export function recentPlans(seaFile, { days = 5, limit = 4 } = {}) {
|
|
28
|
+
let data = {};
|
|
29
|
+
try {
|
|
30
|
+
data = JSON.parse(fs.readFileSync(seaFile, 'utf8'));
|
|
31
|
+
} catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const since = Date.now() - days * 86400000;
|
|
35
|
+
const list = [];
|
|
36
|
+
for (const m of data.messages || []) {
|
|
37
|
+
const at = Number(m.at) || 0;
|
|
38
|
+
const t = String(m.text || '');
|
|
39
|
+
if (at < since || !looksLikePlan(t)) continue;
|
|
40
|
+
list.push({ text: t, at, isOwner: !!m.isOwner });
|
|
41
|
+
}
|
|
42
|
+
for (const lt of data.longTerm || []) {
|
|
43
|
+
const t = String(lt.text || '');
|
|
44
|
+
const at = Number(lt.lastMentionAt || lt.createdAt) || 0;
|
|
45
|
+
if (at < since || !looksLikePlan(t)) continue;
|
|
46
|
+
list.push({ text: t, at, isOwner: true });
|
|
47
|
+
}
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
return list
|
|
50
|
+
.sort((a, b) => (b.isOwner ? 1 : 0) - (a.isOwner ? 1 : 0) || b.at - a.at)
|
|
51
|
+
.filter((x) => {
|
|
52
|
+
const k = x.text.slice(0, 24);
|
|
53
|
+
if (seen.has(k)) return false;
|
|
54
|
+
seen.add(k);
|
|
55
|
+
return true;
|
|
56
|
+
})
|
|
57
|
+
.slice(0, limit);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 拼给 system 的一段;他不是在让猜就返回空 */
|
|
61
|
+
export function planHint(seaFile, text) {
|
|
62
|
+
const t = String(text || '');
|
|
63
|
+
if (!/(猜猜|你猜|猜一下|猜我|猜猜看)/.test(t)) return '';
|
|
64
|
+
const plans = recentPlans(seaFile);
|
|
65
|
+
if (plans.length) {
|
|
66
|
+
const rows = plans
|
|
67
|
+
.map((p) => `${p.at ? new Date(p.at).toLocaleDateString('zh-CN') + ' ' : ''}${p.text.slice(0, 80)}`)
|
|
68
|
+
.join(';');
|
|
69
|
+
return (
|
|
70
|
+
`\n\n【他在让你猜·先看行程】最近他说过的安排:${rows}。` +
|
|
71
|
+
'先按这些安排加上现在的时间点来猜(昨天说今天要去哪、几点做什么),' +
|
|
72
|
+
'对不上再用他的习惯猜(作息、最近在玩什么、爱吃什么)。用一两句说出来,别列清单。'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return (
|
|
76
|
+
'\n\n【他在让你猜·没查到行程】海里没捞到他最近几天的明确安排,那就按他的习惯猜:' +
|
|
77
|
+
'这个点平时在干嘛、最近在玩什么、爱吃什么。猜一两个就好;他不认就让他给个提示,别硬猜。'
|
|
78
|
+
);
|
|
79
|
+
}
|