halbot 1991.2.18 → 1991.2.20
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/index.mjs +1 -1
- package/package.json +3 -3
- package/skills/-8845_session.mjs +131 -9
- package/skills/50_prompt.mjs +0 -1
- package/skills/60_prepare.mjs +1 -1
- package/skills/70_chat.mjs +4 -4
package/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { alan, bot,
|
|
1
|
+
import { alan, bot, image, shot, speech, utilitas, vision } from 'utilitas';
|
|
2
2
|
import { parse } from 'csv-parse/sync';
|
|
3
3
|
|
|
4
4
|
await utilitas.locate(utilitas.__(import.meta.url, 'package.json'));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halbot",
|
|
3
3
|
"description": "Just another `ChatGPT` / `Gemini` / `Mistral (by ollama)` Telegram bob, which is simple design, easy to use, extendable and fun.",
|
|
4
|
-
"version": "1991.2.
|
|
4
|
+
"version": "1991.2.20",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/Leask/halbot",
|
|
7
7
|
"type": "module",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"mysql2": "^3.10.3",
|
|
47
47
|
"office-text-extractor": "^3.0.3",
|
|
48
48
|
"ollama": "^0.5.6",
|
|
49
|
-
"openai": "^4.53.
|
|
49
|
+
"openai": "^4.53.2",
|
|
50
50
|
"pg": "^8.12.0",
|
|
51
51
|
"pgvector": "^0.2.0",
|
|
52
52
|
"telegraf": "^4.16.3",
|
|
53
53
|
"tesseract.js": "^5.1.0",
|
|
54
|
-
"utilitas": "^1996.1.
|
|
54
|
+
"utilitas": "^1996.1.34",
|
|
55
55
|
"youtube-transcript": "^1.2.1"
|
|
56
56
|
}
|
|
57
57
|
}
|
package/skills/-8845_session.mjs
CHANGED
|
@@ -1,25 +1,140 @@
|
|
|
1
|
-
import { alan } from 'utilitas';
|
|
1
|
+
import { alan, bot, uoid, utilitas } from 'utilitas';
|
|
2
|
+
|
|
3
|
+
const EMIJI_FINISH = '☑️';
|
|
4
|
+
|
|
5
|
+
// moved to help and configs
|
|
6
|
+
const keyboards = [[
|
|
7
|
+
{ text: '/clear this thread 🆑' },
|
|
8
|
+
{ text: '/clearall threads 🔄' }
|
|
9
|
+
], [
|
|
10
|
+
{ text: '/end this thread ❎' },
|
|
11
|
+
{ text: '/list threads 🧵' },
|
|
12
|
+
{ text: '/new thread ✨' },
|
|
13
|
+
], [
|
|
14
|
+
{ text: '/help 🛟' },
|
|
15
|
+
{ text: '/ttsoff 🔇' },
|
|
16
|
+
{ text: '/ttson 🔊' },
|
|
17
|
+
]];
|
|
2
18
|
|
|
3
19
|
const action = async (ctx, next) => {
|
|
4
|
-
|
|
20
|
+
// reset session storage
|
|
21
|
+
const resetSession = () => ctx.session.sessionId = uoid.create({
|
|
22
|
+
type: `ALAN_SESSION_${ctx.chatId}`, security: true,
|
|
23
|
+
});
|
|
24
|
+
const resetSessions = () => ctx.session.sessions = [];
|
|
25
|
+
const resetContext = context => ctx.session.context = context || {};
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
ctx.session.sessionId || resetSession();
|
|
28
|
+
ctx.session.sessions || resetSessions();
|
|
5
29
|
ctx.session.context || resetContext();
|
|
6
|
-
|
|
30
|
+
// load functions
|
|
31
|
+
const switchSession = async () => {
|
|
32
|
+
let resp;
|
|
33
|
+
for (const session of ctx.session.sessions) {
|
|
34
|
+
if (session.id === ctx.session.sessionId) {
|
|
35
|
+
ctx.session.sessionId = session.id;
|
|
36
|
+
ctx.session.context = session.context;
|
|
37
|
+
session.touchedAt = now;
|
|
38
|
+
resp = session;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!resp) {
|
|
43
|
+
ctx.session.sessions.push(resp = {
|
|
44
|
+
id: resetSession(),
|
|
45
|
+
createdAt: now, touchedAt: now, context: {},
|
|
46
|
+
});
|
|
47
|
+
await ctx.clear();
|
|
48
|
+
}
|
|
49
|
+
ctx.carry = { sessionId: ctx.session.sessionId };
|
|
50
|
+
return resp;
|
|
51
|
+
};
|
|
52
|
+
const defauleTitle = i => (ctx.session.sessions[i]?.context?.cmd
|
|
53
|
+
? `\`${ctx.session.sessions[i].context.cmd}\` ` : 'Untitled thread '
|
|
54
|
+
) + `(${new Date(ctx.session.sessions[i].createdAt).toLocaleString()})`;
|
|
55
|
+
const getLabel = i => ctx.session.sessions[i].label || defauleTitle(i);
|
|
56
|
+
const findSession = id => {
|
|
57
|
+
for (let i = 0; i < ctx.session.sessions.length; i++) {
|
|
58
|
+
if (ctx.session.sessions[i].id === utilitas.trim(id)) {
|
|
59
|
+
return i;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
7
63
|
ctx.clear = async context => {
|
|
8
64
|
await alan.resetSession(
|
|
9
|
-
ctx.
|
|
65
|
+
ctx.session.sessionId,
|
|
66
|
+
// { systemPrompt: context?.prompt } // @todo: switch to real system prompt
|
|
10
67
|
);
|
|
11
68
|
resetContext(context);
|
|
69
|
+
const id = findSession(ctx.session.sessionId);
|
|
70
|
+
ctx.cmd.ignored = true;
|
|
71
|
+
ctx.session.sessions?.[id] && (
|
|
72
|
+
ctx.session.sessions[id].context = ctx.session.context
|
|
73
|
+
);
|
|
12
74
|
ctx.hello(context?.prompt);
|
|
13
75
|
};
|
|
76
|
+
const ok = async (message, options) => await ctx.ok(message, {
|
|
77
|
+
...options || {}, ...options?.buttons ? {} : { keyboards }
|
|
78
|
+
});
|
|
79
|
+
// handle commands
|
|
80
|
+
const sendList = async (names, lastMsgId) => {
|
|
81
|
+
lastMsgId = lastMsgId || ctx.update?.callback_query?.message?.message_id;
|
|
82
|
+
const message = `🧵 Thread${ctx.session.sessions.length > 0 ? 's' : ''}:`;
|
|
83
|
+
const buttons = ctx.session.sessions.map((x, i) => {
|
|
84
|
+
names?.[x.id]
|
|
85
|
+
&& (ctx.session.sessions[i].label = names[x.id])
|
|
86
|
+
&& (ctx.session.sessions[i].labelUpdatedAt = now);
|
|
87
|
+
return {
|
|
88
|
+
label: `${ctx.session.sessions[i].id === ctx.session.sessionId
|
|
89
|
+
? `${EMIJI_FINISH} ` : ''}${getLabel(i)}`,
|
|
90
|
+
text: `/switch ${x.id}`,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
return await ok(message, { lastMessageId: lastMsgId, buttons });
|
|
94
|
+
};
|
|
95
|
+
const switched = async preTitle => await ok(
|
|
96
|
+
`${preTitle ? `❎ Thread ended: \`${preTitle}\`.\n\n` : ''}` +
|
|
97
|
+
`${EMIJI_FINISH} Thread switched: \`${getLabel(findSession(ctx.session.sessionId))}\`.`
|
|
98
|
+
);
|
|
14
99
|
switch (ctx.cmd?.cmd) {
|
|
15
|
-
case 'clear':
|
|
16
|
-
|
|
17
|
-
|
|
100
|
+
case 'clear': await ctx.clear(); break;
|
|
101
|
+
case 'clearall': resetSessions(); break;
|
|
102
|
+
case 'new': resetSession(); break;
|
|
103
|
+
case 'list':
|
|
104
|
+
const resp = await sendList();
|
|
105
|
+
utilitas.ignoreErrFunc(async () => {
|
|
106
|
+
const sNames = await alan.analyzeSessions(
|
|
107
|
+
ctx.session.sessions.filter(
|
|
108
|
+
x => (x.labelUpdatedAt || 0) < x.touchedAt
|
|
109
|
+
).map(x => x.id), { ignoreRequest: bot.HELLO }
|
|
110
|
+
);
|
|
111
|
+
return await sendList(sNames, resp[0]?.message_id);
|
|
112
|
+
});
|
|
113
|
+
return resp;
|
|
114
|
+
case 'end':
|
|
115
|
+
const id = findSession(
|
|
116
|
+
ctx.cmd.args.startsWith('ALAN_SESSION_')
|
|
117
|
+
&& utilitas.trim(ctx.cmd.args) || ctx.session.sessionId
|
|
118
|
+
);
|
|
119
|
+
let preTitle = '';
|
|
120
|
+
ctx.session.sessions?.[id] && (preTitle = getLabel(id))
|
|
121
|
+
&& (ctx.session.sessions.splice(id, 1));
|
|
122
|
+
const sorted = ctx.session.sessions.slice().sort(
|
|
123
|
+
(x, y) => y.touchedAt - x.touchedAt
|
|
124
|
+
);
|
|
125
|
+
ctx.session.sessionId = sorted?.[0]?.id;
|
|
126
|
+
await switchSession();
|
|
127
|
+
return await switched(preTitle);
|
|
128
|
+
case 'switch':
|
|
129
|
+
ctx.session.sessionId = utilitas.trim(ctx.cmd.args);
|
|
130
|
+
await switchSession();
|
|
131
|
+
return await sendList();
|
|
18
132
|
case 'factory':
|
|
19
133
|
case 'reset':
|
|
20
|
-
await alan.resetSession(ctx.
|
|
134
|
+
await alan.resetSession(ctx.session.sessionId);
|
|
21
135
|
break;
|
|
22
136
|
}
|
|
137
|
+
await switchSession();
|
|
23
138
|
await next();
|
|
24
139
|
};
|
|
25
140
|
|
|
@@ -29,5 +144,12 @@ export const { name, run, priority, func, help, cmds, cmdx } = {
|
|
|
29
144
|
priority: -8845,
|
|
30
145
|
func: action,
|
|
31
146
|
help: '',
|
|
32
|
-
cmdx: {
|
|
147
|
+
cmdx: {
|
|
148
|
+
new: 'Add a session.',
|
|
149
|
+
end: 'Delete a session.',
|
|
150
|
+
switch: 'Switch to a session.',
|
|
151
|
+
clear: 'Clear current AI conversation session and start a new one.',
|
|
152
|
+
clearall: 'Clear all AI conversation sessions.',
|
|
153
|
+
list: 'List all AI conversation sessions.',
|
|
154
|
+
},
|
|
33
155
|
};
|
package/skills/50_prompt.mjs
CHANGED
|
@@ -73,7 +73,6 @@ export const { name, run, priority, func, help, cmds, cmdx } = {
|
|
|
73
73
|
del: 'Delete a custom prompt: /del `COMMAND`.',
|
|
74
74
|
acplist: `List prompts from ${ACP}.`,
|
|
75
75
|
acpdetail: `Show details of ${ACP}.`,
|
|
76
|
-
clear: 'Clear current AI conversation session and start a new one.',
|
|
77
76
|
},
|
|
78
77
|
cmdx: {},
|
|
79
78
|
};
|
package/skills/60_prepare.mjs
CHANGED
|
@@ -10,7 +10,7 @@ const action = async (ctx, next) => {
|
|
|
10
10
|
ctx.avatar = '🔘'; ctx.result = utilitas.trim(ctx.txt);
|
|
11
11
|
} else if (ctx.m?.poll) {
|
|
12
12
|
ctx.avatar = '📊';
|
|
13
|
-
} else if (ctx.cmd?.cmd && ctx.cmd?.
|
|
13
|
+
} else if (ctx.cmd?.cmd && !ctx.cmd?.ignored) {
|
|
14
14
|
ctx.avatar = '🚀'; ctx.result = utilitas.trim(ctx.txt);
|
|
15
15
|
} else {
|
|
16
16
|
ctx.avatar = '😸';
|
package/skills/70_chat.mjs
CHANGED
|
@@ -33,10 +33,10 @@ const action = async (ctx, next) => {
|
|
|
33
33
|
)) { return; }
|
|
34
34
|
[lastSent, lastMsg] = [curTime, curMsg];
|
|
35
35
|
const cmd = ctx.session.context?.cmd;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
return await ctx.ok(curMsg, { md: true, ...options || {}
|
|
36
|
+
options?.final && cmd && (extra.buttons = [{
|
|
37
|
+
label: `❎ End context: \`${cmd}\``, text: '/clear',
|
|
38
|
+
}]);
|
|
39
|
+
return await ctx.ok(curMsg, { md: true, ...extra, ...options || {} });
|
|
40
40
|
};
|
|
41
41
|
await ok(onProgress);
|
|
42
42
|
for (let n of ctx.selectedAi) {
|