halbot 1990.1.107 → 1990.1.108
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/bin/halbot.mjs +1 -2
- package/index.mjs +25 -12
- package/package.json +7 -6
- package/skills/-8845_session.mjs +33 -0
- package/skills/10_engine.mjs +2 -39
- package/skills/20_instant.mjs +20 -8
- package/skills/50_prompt.mjs +1 -4
- package/skills/60_prepare.mjs +3 -6
- package/skills/70_chat.mjs +18 -16
package/bin/halbot.mjs
CHANGED
|
@@ -17,8 +17,7 @@ let storage = {
|
|
|
17
17
|
try {
|
|
18
18
|
const { filename, config } = await _getConfig();
|
|
19
19
|
assert(utilitas.countKeys(config), `Error loading config from ${filename}.`);
|
|
20
|
-
const sessionType = utilitas.trim(config.storage?.
|
|
21
|
-
if (config.storage?.type) { delete config.storage.type; }
|
|
20
|
+
const sessionType = utilitas.trim(config.storage?.provider, { case: 'UP' });
|
|
22
21
|
switch (sessionType) {
|
|
23
22
|
case 'MARIADB': case 'MYSQL':
|
|
24
23
|
await dbio.init(config.storage);
|
package/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { alan, bot, image, shot, speech, utilitas, vision } from 'utilitas';
|
|
2
2
|
import { parse } from 'csv-parse/sync';
|
|
3
|
+
import { end } from 'utilitas/lib/event.mjs';
|
|
3
4
|
|
|
4
5
|
await utilitas.locate(utilitas.__(import.meta.url, 'package.json'));
|
|
5
6
|
const log = content => utilitas.log(content, 'halbot');
|
|
@@ -29,19 +30,18 @@ const fetchPrompts = async () => {
|
|
|
29
30
|
|
|
30
31
|
const init = async (options) => {
|
|
31
32
|
assert(options?.telegramToken, 'Telegram Bot API Token is required.');
|
|
32
|
-
const [pkg, ai, _speech, speechOptions]
|
|
33
|
-
= [await utilitas.which(), {}, {}, { tts: true, stt: true }];
|
|
33
|
+
const [pkg, ai, _speech, speechOptions, engines]
|
|
34
|
+
= [await utilitas.which(), {}, {}, { tts: true, stt: true }, {}];
|
|
34
35
|
const info = bot.lines([
|
|
35
36
|
`[${bot.EMOJI_BOT} ${pkg.title}](${pkg.homepage})`, pkg.description
|
|
36
37
|
]);
|
|
37
|
-
const cacheOptions = options?.storage ? { store: options.storage } : null;
|
|
38
38
|
if (options?.openaiApiKey) {
|
|
39
39
|
const apiKey = { apiKey: options.openaiApiKey };
|
|
40
|
-
|
|
41
|
-
provider: 'CHATGPT', clientOptions: apiKey, cacheOptions,
|
|
42
|
-
});
|
|
40
|
+
await alan.init({ provider: 'openai', ...apiKey });
|
|
43
41
|
await speech.init({ ...apiKey, provider: 'OPENAI', ...speechOptions });
|
|
44
42
|
await image.init(apiKey);
|
|
43
|
+
ai['ChatGPT'] = { engine: 'CHATGPT' };
|
|
44
|
+
engines['CHATGPT'] = {};
|
|
45
45
|
}
|
|
46
46
|
if (options?.googleApiKey) {
|
|
47
47
|
const apiKey = { apiKey: options.googleApiKey };
|
|
@@ -50,12 +50,25 @@ const init = async (options) => {
|
|
|
50
50
|
...apiKey, provider: 'GOOGLE', ...speechOptions,
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
-
if (options?.
|
|
54
|
-
|
|
55
|
-
provider: '
|
|
56
|
-
|
|
53
|
+
if (options?.googleCredentials && options?.googleProject) {
|
|
54
|
+
await alan.init({
|
|
55
|
+
provider: 'VERTEX',
|
|
56
|
+
credentials: options.googleCredentials,
|
|
57
|
+
project: options.googleProject,
|
|
58
|
+
});
|
|
59
|
+
ai['Gemini'] = { engine: 'VERTEX' };
|
|
60
|
+
engines['VERTEX'] = {};
|
|
61
|
+
}
|
|
62
|
+
if (options?.mistralEnabled || options?.mistralEndpoint) {
|
|
63
|
+
await alan.init({
|
|
64
|
+
provider: 'OLLAMA',
|
|
65
|
+
endpoint: options?.mistralEndpoint,
|
|
66
|
+
model: options?.mistralModel,
|
|
57
67
|
});
|
|
68
|
+
ai['Mistral'] = { engine: 'OLLAMA' };
|
|
69
|
+
engines['OLLAMA'] = {};
|
|
58
70
|
}
|
|
71
|
+
await alan.initChat({ engines, sessions: options?.storage });
|
|
59
72
|
assert(utilitas.countKeys(ai), 'No AI provider is configured.');
|
|
60
73
|
const _bot = await bot.init({
|
|
61
74
|
args: options?.args,
|
|
@@ -83,4 +96,4 @@ const init = async (options) => {
|
|
|
83
96
|
};
|
|
84
97
|
|
|
85
98
|
export default init;
|
|
86
|
-
export {
|
|
99
|
+
export { alan, bot, init, speech, utilitas };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halbot",
|
|
3
3
|
"description": "Just another ChatGPT/Bing Chat Telegram bob, which is simple design, easy to use, extendable and fun.",
|
|
4
|
-
"version": "1990.1.
|
|
4
|
+
"version": "1990.1.108",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/Leask/halbot",
|
|
7
7
|
"type": "module",
|
|
@@ -31,21 +31,22 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
33
33
|
"@ffprobe-installer/ffprobe": "^2.1.2",
|
|
34
|
+
"@google-cloud/aiplatform": "^3.9.0",
|
|
34
35
|
"@google-cloud/speech": "^6.1.0",
|
|
35
36
|
"@google-cloud/text-to-speech": "^5.0.1",
|
|
37
|
+
"@google-cloud/vertexai": "^0.1.3",
|
|
36
38
|
"@google-cloud/vision": "^4.0.2",
|
|
37
|
-
"@mozilla/readability": "^0.
|
|
38
|
-
"@waylaidwanderer/chatgpt-api": "^1.37.3",
|
|
39
|
+
"@mozilla/readability": "^0.5.0",
|
|
39
40
|
"csv-parse": "^5.5.3",
|
|
40
41
|
"fluent-ffmpeg": "^2.1.2",
|
|
41
42
|
"ioredis": "^5.3.2",
|
|
42
43
|
"jsdom": "^23.0.1",
|
|
43
44
|
"mysql2": "^3.6.5",
|
|
44
45
|
"office-text-extractor": "^3.0.2",
|
|
45
|
-
"openai": "^4.
|
|
46
|
+
"openai": "^4.24.1",
|
|
46
47
|
"telegraf": "^4.15.3",
|
|
47
|
-
"tesseract.js": "^5.0.
|
|
48
|
-
"utilitas": "^1995.2.
|
|
48
|
+
"tesseract.js": "^5.0.4",
|
|
49
|
+
"utilitas": "^1995.2.42",
|
|
49
50
|
"youtube-transcript": "^1.0.6"
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { alan } from 'utilitas';
|
|
2
|
+
|
|
3
|
+
const action = async (ctx, next) => {
|
|
4
|
+
const resetContext = context => ctx.session.context = context || {}
|
|
5
|
+
ctx.session.context || resetContext();
|
|
6
|
+
ctx.carry = { sessionId: `ALAN_SESSION_${ctx.chatId}` };
|
|
7
|
+
ctx.clear = async context => {
|
|
8
|
+
await alan.resetSession(
|
|
9
|
+
ctx.carry.sessionId, // { systemPrompt: context?.prompt } @todo! // switch to real system prompt
|
|
10
|
+
);
|
|
11
|
+
resetContext(context);
|
|
12
|
+
ctx.hello(context?.prompt);
|
|
13
|
+
};
|
|
14
|
+
switch (ctx.cmd?.cmd) {
|
|
15
|
+
case 'clear':
|
|
16
|
+
await ctx.clear();
|
|
17
|
+
break;
|
|
18
|
+
case 'factory':
|
|
19
|
+
case 'reset':
|
|
20
|
+
await alan.resetSession(ctx.carry.sessionId);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
await next();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const { name, run, priority, func, help, cmds, cmdx } = {
|
|
27
|
+
name: 'session',
|
|
28
|
+
run: true,
|
|
29
|
+
priority: -8845,
|
|
30
|
+
func: action,
|
|
31
|
+
help: '',
|
|
32
|
+
cmdx: {},
|
|
33
|
+
};
|
package/skills/10_engine.mjs
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { bot, utilitas } from 'utilitas';
|
|
2
2
|
|
|
3
|
-
const balanced = 'balanced';
|
|
4
|
-
const bingTones = [balanced, 'creative', 'precise'];
|
|
5
|
-
|
|
6
3
|
let configuredAi;
|
|
7
4
|
|
|
8
5
|
const action = async (ctx, next) => {
|
|
9
|
-
ctx.session.context || (ctx.session.context = {});
|
|
10
|
-
ctx.session.latest || (ctx.session.latest = {});
|
|
11
6
|
ctx.isDefaultAi = name => name === ctx.firstAi;
|
|
12
|
-
ctx.clear = context => (ctx.selectedAi || []).map(n => {
|
|
13
|
-
ctx._.ai[n].clear(ctx.chatId);
|
|
14
|
-
delete ctx.session.context[n];
|
|
15
|
-
delete ctx.session.latest[n];
|
|
16
|
-
context && (ctx.session.context[n] = context);
|
|
17
|
-
}) && ctx.hello(context?.prompt);
|
|
18
7
|
ctx.firstAi = (configuredAi = Object.keys(ctx._.ai))[0];
|
|
19
8
|
switch (ctx.session.config?.ai) {
|
|
20
9
|
case '': ctx.selectedAi = [ctx.firstAi]; break;
|
|
@@ -34,12 +23,6 @@ const validateAi = val => {
|
|
|
34
23
|
utilitas.throwError('No AI engine matched.');
|
|
35
24
|
};
|
|
36
25
|
|
|
37
|
-
const validateTone = val => {
|
|
38
|
-
val = utilitas.trim(val, { case: 'LOW' });
|
|
39
|
-
assert([...bingTones, ''].includes(val), 'Unsupported tone-style.');
|
|
40
|
-
return val;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
26
|
export const { name, run, priority, func, help, args } = {
|
|
44
27
|
name: 'Engine',
|
|
45
28
|
run: true,
|
|
@@ -54,26 +37,15 @@ export const { name, run, priority, func, help, args } = {
|
|
|
54
37
|
'¶ Tweak enhanced output rendering.',
|
|
55
38
|
'Example 1: /set --render on',
|
|
56
39
|
'Example 2: /set --render off',
|
|
57
|
-
// '¶ Select between [OpenAI models](https://platform.openai.com/docs/models).',
|
|
58
|
-
// "Tip !!!4!!!: Set `gptmodel=''` to use default OpenAI model.",
|
|
59
|
-
// 'Popular models:',
|
|
60
|
-
// '- [gpt-4](https://platform.openai.com/docs/models/gpt-4): 8192 tokens, trained Sep 2021.',
|
|
61
|
-
// '- [gpt-4-32k](https://platform.openai.com/docs/models/gpt-4): 32768 tokens, trained Sep 2021.',
|
|
62
|
-
// '- [gpt-3.5-turbo](https://platform.openai.com/docs/models/gpt-3-5): 4096 tokens, trained Sep 2021.',
|
|
63
|
-
// '- [text-davinci-003](https://platform.openai.com/docs/models/gpt-3-5): 4097 tokens, trained Sep 2021.',
|
|
64
|
-
// '- [text-davinci-002](https://platform.openai.com/docs/models/gpt-3-5): 4097 tokens, trained Sep 2021.',
|
|
65
|
-
// '- [code-davinci-002](https://platform.openai.com/docs/models/gpt-3-5): 8001 tokens, trained Sep 2021 (Coding Optimized).',
|
|
66
|
-
'¶ Set tone-style for Bing.',
|
|
67
|
-
"Tip 4: Set `tone=''` to use default tone-style.",
|
|
68
40
|
]),
|
|
69
41
|
args: {
|
|
70
42
|
hello: {
|
|
71
|
-
type: 'string', short: 's', default: 'You are
|
|
43
|
+
type: 'string', short: 's', default: 'You are a helpful assistant.',
|
|
72
44
|
desc: "Change initial prompt: /set --hello 'Bonjour!'",
|
|
73
45
|
},
|
|
74
46
|
ai: {
|
|
75
47
|
type: 'string', short: 'a', default: '',
|
|
76
|
-
desc: "`(ChatGPT,
|
|
48
|
+
desc: "`(ChatGPT, Gemini, Mistral, @)` Select AI engine.",
|
|
77
49
|
validate: validateAi,
|
|
78
50
|
},
|
|
79
51
|
render: {
|
|
@@ -81,14 +53,5 @@ export const { name, run, priority, func, help, args } = {
|
|
|
81
53
|
desc: `\`(${bot.BINARY_STRINGS.join(', ')})\` Enable/Disable enhanced output rendering.`,
|
|
82
54
|
validate: utilitas.humanReadableBoolean,
|
|
83
55
|
},
|
|
84
|
-
// gptmodel: {
|
|
85
|
-
// type: 'string', short: 'g', default: 'gpt-3.5-turbo',
|
|
86
|
-
// desc: 'Set OpenAI model: /set --gptmodel=`MODEL`.',
|
|
87
|
-
// },
|
|
88
|
-
tone: {
|
|
89
|
-
type: 'string', short: 't', default: balanced,
|
|
90
|
-
desc: `\`(${bingTones.join(', ')})\` Set tone-style for Bing.`,
|
|
91
|
-
validate: validateTone,
|
|
92
|
-
},
|
|
93
56
|
},
|
|
94
57
|
};
|
package/skills/20_instant.mjs
CHANGED
|
@@ -8,16 +8,27 @@ const action = async (ctx, next) => {
|
|
|
8
8
|
ctx.multiAi = ctx.selectedAi.length > 1;
|
|
9
9
|
ctx.hello(ctx.cmd.args);
|
|
10
10
|
break;
|
|
11
|
-
case 'bing':
|
|
12
|
-
assert(utilitas.insensitiveHas(allAi, 'bing'), 'Bing is not available.');
|
|
13
|
-
ctx.selectedAi = ['Bing'];
|
|
14
|
-
ctx.hello(ctx.cmd.args);
|
|
15
|
-
break;
|
|
16
11
|
case 'chatgpt':
|
|
17
|
-
|
|
12
|
+
if (!utilitas.insensitiveHas(allAi, 'chatgpt')) {
|
|
13
|
+
return await ctx.er('ChatGPT is not available.');
|
|
14
|
+
}
|
|
18
15
|
ctx.selectedAi = ['ChatGPT'];
|
|
19
16
|
ctx.hello(ctx.cmd.args);
|
|
20
17
|
break;
|
|
18
|
+
case 'gemini':
|
|
19
|
+
if (!utilitas.insensitiveHas(allAi, 'gemini')) {
|
|
20
|
+
return await ctx.er('Gemini is not available.');
|
|
21
|
+
}
|
|
22
|
+
ctx.selectedAi = ['Gemini'];
|
|
23
|
+
ctx.hello(ctx.cmd.args);
|
|
24
|
+
break;
|
|
25
|
+
case 'mistral':
|
|
26
|
+
if (!utilitas.insensitiveHas(allAi, 'mistral')) {
|
|
27
|
+
return await ctx.er('Mistral is not available.');
|
|
28
|
+
}
|
|
29
|
+
ctx.selectedAi = ['Mistral'];
|
|
30
|
+
ctx.hello(ctx.cmd.args);
|
|
31
|
+
break;
|
|
21
32
|
}
|
|
22
33
|
await next();
|
|
23
34
|
};
|
|
@@ -32,7 +43,8 @@ export const { name, run, priority, func, help, cmds } = {
|
|
|
32
43
|
]),
|
|
33
44
|
cmds: {
|
|
34
45
|
all: 'Use all AI engines simultaneously: /all Say hello to all AIs!',
|
|
35
|
-
chatgpt: 'Use ChatGPT temporary: /chatgpt Say hello to ChatGPT!',
|
|
36
|
-
|
|
46
|
+
chatgpt: 'Use ⚛️ ChatGPT temporary: /chatgpt Say hello to ChatGPT!',
|
|
47
|
+
gemini: 'Use ♊️ Gemini temporary: /gemini Say hello to Gemini!',
|
|
48
|
+
mistral: 'Use Ⓜ️ Mistral temporary: /mistral Say hello to Mistral!',
|
|
37
49
|
},
|
|
38
50
|
};
|
package/skills/50_prompt.mjs
CHANGED
|
@@ -48,13 +48,10 @@ const action = async (ctx, next) => {
|
|
|
48
48
|
])
|
|
49
49
|
));
|
|
50
50
|
return await ctx.ok(details || 'Data not found.');
|
|
51
|
-
case 'clear':
|
|
52
|
-
ctx.clear();
|
|
53
|
-
break;
|
|
54
51
|
default:
|
|
55
52
|
const prompt = ctx.session.prompts?.[cmd] || ctx._.prompts?.[cmd]?.prompt;
|
|
56
53
|
!ctx.context && prompt && (ctx.context = { cmd, prompt });
|
|
57
|
-
ctx.context && ctx.clear(ctx.context);
|
|
54
|
+
ctx.context && await ctx.clear(ctx.context);
|
|
58
55
|
}
|
|
59
56
|
await next();
|
|
60
57
|
};
|
package/skills/60_prepare.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { alan, bot, utilitas } from 'utilitas';
|
|
2
2
|
|
|
3
3
|
const action = async (ctx, next) => {
|
|
4
4
|
// avatar
|
|
@@ -16,21 +16,18 @@ const action = async (ctx, next) => {
|
|
|
16
16
|
ctx.avatar = '😸';
|
|
17
17
|
}
|
|
18
18
|
// prompt
|
|
19
|
+
const maxInputTokens = alan.getMaxChatPromptLimit();
|
|
19
20
|
const additionInfo = ctx.collected.length ? ctx.collected.map(
|
|
20
21
|
x => x.content
|
|
21
22
|
).join('\n').split(' ') : [];
|
|
22
23
|
ctx.prompt = (ctx.text || '') + '\n\n';
|
|
23
|
-
while (
|
|
24
|
+
while (alan.countTokens(ctx.prompt) < maxInputTokens
|
|
24
25
|
&& additionInfo.length) {
|
|
25
26
|
ctx.prompt += ` ${additionInfo.shift()}`;
|
|
26
27
|
}
|
|
27
28
|
ctx.prompt = utilitas.trim(ctx.prompt);
|
|
28
29
|
additionInfo.filter(x => x).length && (ctx.prompt += '...');
|
|
29
30
|
// next
|
|
30
|
-
ctx.carry = {
|
|
31
|
-
sessionId: ctx.chatId,
|
|
32
|
-
toneStyle: ctx.session.config?.tone,
|
|
33
|
-
};
|
|
34
31
|
await next();
|
|
35
32
|
};
|
|
36
33
|
|
package/skills/70_chat.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { bot, utilitas } from 'utilitas';
|
|
1
|
+
import { alan, bot, utilitas } from 'utilitas';
|
|
2
2
|
|
|
3
3
|
const onProgress = { onProgress: true };
|
|
4
|
-
const [BOT, LN2] = [`${bot.EMOJI_BOT} `, '\n\n'];
|
|
5
4
|
const [joinL1, joinL2] = [a => a.join(LN2), a => a.join(LN2)];
|
|
6
|
-
const enrich = name => name === '
|
|
5
|
+
const enrich = name => name === 'VERTEX' ? 'Gemini' : name;
|
|
7
6
|
const log = content => utilitas.log(content, import.meta.url);
|
|
7
|
+
const [BOT, BOTS, LN2]
|
|
8
|
+
= [`${bot.EMOJI_BOT} `, { ChatGPT: '⚛️', Gemini: '♊️', Mistral: 'Ⓜ️' }, '\n\n'];
|
|
8
9
|
|
|
9
10
|
const action = async (ctx, next) => {
|
|
10
11
|
if (!ctx.prompt) { return await next(); }
|
|
@@ -17,12 +18,12 @@ const action = async (ctx, next) => {
|
|
|
17
18
|
const pure = [];
|
|
18
19
|
ctx.selectedAi.map(n => {
|
|
19
20
|
const content = source[n] || '';
|
|
20
|
-
const cmd = ctx.session.context
|
|
21
|
+
const cmd = ctx.session.context?.cmd;
|
|
21
22
|
const context = cmd && ` > \`${cmd}\` (exit by /clear)` || '';
|
|
22
23
|
pure.push(content);
|
|
23
24
|
packed.push(joinL2([
|
|
24
25
|
...ctx.multiAi || !ctx.isDefaultAi(n) || said || context
|
|
25
|
-
? [`${
|
|
26
|
+
? [`${BOTS[n]} ${enrich(n)}${context}:`] : [], content,
|
|
26
27
|
]));
|
|
27
28
|
});
|
|
28
29
|
return options?.tts && !pure.join('').trim().length ? '' : joinL1(packed);
|
|
@@ -39,19 +40,20 @@ const action = async (ctx, next) => {
|
|
|
39
40
|
for (let n of ctx.selectedAi) {
|
|
40
41
|
pms.push((async () => {
|
|
41
42
|
try {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const resp = await alan.talk(ctx.prompt, {
|
|
44
|
+
engine: ctx._.ai[n].engine, ...ctx.carry,
|
|
45
|
+
stream: async r => {
|
|
46
|
+
msgs[n] = r[0].text;
|
|
47
|
+
await ok(onProgress);
|
|
48
|
+
},
|
|
47
49
|
});
|
|
48
50
|
msgs[n] = ctx.session.config?.render === false
|
|
49
|
-
?
|
|
50
|
-
tts[n] = msgs[n].split('\n').some(x => /^```/.test(x)) ? '' :
|
|
51
|
-
extra.buttons =
|
|
52
|
-
|
|
53
|
-
}));
|
|
54
|
-
return
|
|
51
|
+
? resp.text : resp.rendered;
|
|
52
|
+
tts[n] = msgs[n].split('\n').some(x => /^```/.test(x)) ? '' : resp.spoken;
|
|
53
|
+
// extra.buttons = resp?.suggestedResponses?.map?.(label => ({
|
|
54
|
+
// label, text: `/bing@${ctx.botInfo.username} ${label}`,
|
|
55
|
+
// }));
|
|
56
|
+
return resp;
|
|
55
57
|
} catch (err) {
|
|
56
58
|
msgs[n] = err?.message || err;
|
|
57
59
|
tts[n] = msgs[n];
|