halbot 1993.2.89 → 1993.2.91
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 +14 -7
- package/lib/hal.mjs +29 -18
- package/package.json +4 -4
- package/skills/40_dream.mjs +29 -16
package/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { alan, bot,
|
|
1
|
+
import { alan, bot, gen, web, speech, utilitas } from 'utilitas';
|
|
2
2
|
import * as hal from './lib/hal.mjs';
|
|
3
3
|
|
|
4
4
|
await utilitas.locate(utilitas.__(import.meta.url, 'package.json'));
|
|
@@ -25,7 +25,7 @@ const init = async (options = {}) => {
|
|
|
25
25
|
...apiKey, model: options.openaiModel || '*',
|
|
26
26
|
priority: options.openaiPriority, ...options
|
|
27
27
|
});
|
|
28
|
-
await
|
|
28
|
+
await gen.init(apiKey);
|
|
29
29
|
await speech.init({ ...apiKey, ...speechOptions });
|
|
30
30
|
_speech.tts = speech.tts;
|
|
31
31
|
}
|
|
@@ -37,7 +37,6 @@ const init = async (options = {}) => {
|
|
|
37
37
|
...apiKey, provider: 'GEMINI', model: options.geminiModel || '*',
|
|
38
38
|
priority: options.geminiPriority, ...options
|
|
39
39
|
});
|
|
40
|
-
await image.init({ ...apiKey, provider: 'GEMINI' });
|
|
41
40
|
if (!_speech.tts) {
|
|
42
41
|
await speech.init({ ...apiKey, ...speechOptions });
|
|
43
42
|
_speech.tts = speech.tts;
|
|
@@ -46,6 +45,13 @@ const init = async (options = {}) => {
|
|
|
46
45
|
...apiKey, cx: options.googleCx,
|
|
47
46
|
});
|
|
48
47
|
}
|
|
48
|
+
const geminiGenReady = options.googleApiKey
|
|
49
|
+
|| (options.googleCredentials && options.googleProjectId);
|
|
50
|
+
geminiGenReady && await gen.init({
|
|
51
|
+
apiKey: options.googleApiKey, provider: 'GEMINI',
|
|
52
|
+
credentials: options.googleCredentials,
|
|
53
|
+
projectId: options.googleProjectId,
|
|
54
|
+
});
|
|
49
55
|
if (options.anthropicApiKey) {
|
|
50
56
|
await alan.init({
|
|
51
57
|
provider: 'ANTHROPIC', model: options.anthropicModel || '*',
|
|
@@ -53,11 +59,11 @@ const init = async (options = {}) => {
|
|
|
53
59
|
priority: options.anthropicPriority, ...options
|
|
54
60
|
});
|
|
55
61
|
}
|
|
56
|
-
if (options.
|
|
62
|
+
if (options.googleCredentials && options.googleProjectId) {
|
|
57
63
|
await alan.init({
|
|
58
64
|
provider: 'VERTEX ANTHROPIC', model: options.anthropicModel || '*',
|
|
59
|
-
credentials: options.
|
|
60
|
-
projectId: options.
|
|
65
|
+
credentials: options.googleCredentials,
|
|
66
|
+
projectId: options.googleProjectId,
|
|
61
67
|
priority: options.anthropicPriority, ...options
|
|
62
68
|
});
|
|
63
69
|
}
|
|
@@ -130,7 +136,8 @@ const init = async (options = {}) => {
|
|
|
130
136
|
speech: _speech, vision,
|
|
131
137
|
});
|
|
132
138
|
_hal._.lang = options?.lang || 'English';
|
|
133
|
-
_hal._.
|
|
139
|
+
_hal._.gen = options?.gen
|
|
140
|
+
|| (options?.openaiApiKey || geminiGenReady ? gen : null);
|
|
134
141
|
return _hal;
|
|
135
142
|
};
|
|
136
143
|
|
package/lib/hal.mjs
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
alan, bot, callosum, dbio, storage, uoid, utilitas, web,
|
|
3
|
-
} from 'utilitas';
|
|
4
|
-
|
|
5
1
|
import { basename, join } from 'path';
|
|
2
|
+
import { bot, callosum, dbio, storage, uoid, utilitas, web } from 'utilitas';
|
|
6
3
|
import { parseArgs as _parseArgs } from 'node:util';
|
|
7
4
|
import { readdirSync } from 'fs';
|
|
8
5
|
|
|
@@ -20,6 +17,7 @@ const isMarkdownError = e => e?.description?.includes?.("can't parse entities");
|
|
|
20
17
|
const getFile = async (id, op) => (await web.get(await getFileUrl(id), op)).content;
|
|
21
18
|
const compact = (str, op) => utilitas.ensureString(str, { ...op || {}, compact: true });
|
|
22
19
|
const compactLimit = (str, op) => compact(str, { ...op || {}, limit: 140 });
|
|
20
|
+
const getKey = s => s?.toLowerCase?.()?.startsWith?.('http') ? 'url' : 'source';
|
|
23
21
|
const SEARCH_LIMIT = 10;
|
|
24
22
|
|
|
25
23
|
const [ // https://limits.tginfo.me/en
|
|
@@ -362,18 +360,26 @@ const subconscious = [{
|
|
|
362
360
|
ctx.complete = async (options) => await ctx.ok('☑️', options);
|
|
363
361
|
ctx.json = async (obj, options) => await ctx.ok(json(obj), options);
|
|
364
362
|
ctx.list = async (list, options) => await ctx.ok(uList(list), options);
|
|
365
|
-
ctx.
|
|
366
|
-
[
|
|
367
|
-
|
|
368
|
-
ctx.audio = async (
|
|
369
|
-
ctx.image = async (
|
|
370
|
-
ctx.
|
|
371
|
-
|
|
372
|
-
|
|
363
|
+
ctx.replyWith = async (func, src, options) => ctx.done.push(
|
|
364
|
+
await ctx[func]({ [getKey(src)]: src }, getExtra(ctx, options))
|
|
365
|
+
);
|
|
366
|
+
ctx.audio = async (s, o) => await ctx.replyWith('replyWithAudio', s, o);
|
|
367
|
+
ctx.image = async (s, o) => await ctx.replyWith('replyWithPhoto', s, o);
|
|
368
|
+
ctx.video = async (s, o) => await ctx.replyWith('replyWithVideo', s, o);
|
|
369
|
+
ctx.media = async (srs, options) => await ctx.done.push(
|
|
370
|
+
await ctx.replyWithMediaGroup(srs.map(x => ({
|
|
371
|
+
type: x.type || 'photo', media: { [getKey(x.src)]: x.src },
|
|
372
|
+
})), getExtra(ctx, options))
|
|
373
|
+
);
|
|
374
|
+
ctx.sendConfig = async (obj, options, _ctx) => await ctx.ok(
|
|
375
|
+
utilitas.prettyJson(obj, { code: true, md: true }), options
|
|
376
|
+
);
|
|
373
377
|
ctx.speech = async (cnt, options) => {
|
|
374
378
|
let file;
|
|
375
379
|
if (Buffer.isBuffer(cnt)) {
|
|
376
|
-
file = await storage.convert(cnt, {
|
|
380
|
+
file = await storage.convert(cnt, {
|
|
381
|
+
input: storage.BUFFER, expected: storage.FILE,
|
|
382
|
+
});
|
|
377
383
|
} else if (cnt.length <= speech.OPENAI_TTS_MAX_LENGTH) {
|
|
378
384
|
file = await utilitas.ignoreErrFunc(async () => await ctx._.speech.tts(
|
|
379
385
|
cnt, { expected: 'file' }
|
|
@@ -603,7 +609,11 @@ const subconscious = [{
|
|
|
603
609
|
const analyze = async () => {
|
|
604
610
|
const resp = await utilitas.ignoreErrFunc(async () => {
|
|
605
611
|
[
|
|
606
|
-
|
|
612
|
+
storage.MIME_MP3, storage.MIME_MPEGA,
|
|
613
|
+
storage.MIME_MP4, storage.MIME_MPEG,
|
|
614
|
+
storage.MIME_MPGA, storage.MIME_M4A,
|
|
615
|
+
storage.MIME_WAV, storage.MIME_WEBM,
|
|
616
|
+
storage.MIME_OGG,
|
|
607
617
|
].includes(audio.mime_type) || (
|
|
608
618
|
file = await media.convertAudioTo16kNanoPcmWave(
|
|
609
619
|
file, { input: storage.BUFFER, expected: storage.BUFFER }
|
|
@@ -614,9 +624,9 @@ const subconscious = [{
|
|
|
614
624
|
log(`STT: '${resp}'`);
|
|
615
625
|
ctx.collect(resp);
|
|
616
626
|
};
|
|
617
|
-
if (hal._.supportedMimeTypes.has(
|
|
627
|
+
if (hal._.supportedMimeTypes.has(MIME_WAV)) {
|
|
618
628
|
ctx.collect({
|
|
619
|
-
mime_type:
|
|
629
|
+
mime_type: MIME_WAV, url, analyze,
|
|
620
630
|
data: await media.convertAudioTo16kNanoPcmWave(file, {
|
|
621
631
|
input: storage.BUFFER, expected: storage.BASE64,
|
|
622
632
|
}),
|
|
@@ -727,9 +737,10 @@ const subconscious = [{
|
|
|
727
737
|
if (m.photo?.[m.photo?.length - 1]) {
|
|
728
738
|
const p = m.photo[m.photo.length - 1];
|
|
729
739
|
files.push({
|
|
730
|
-
asPrompt: hal._.supportedMimeTypes.has(
|
|
740
|
+
asPrompt: hal._.supportedMimeTypes.has(storage.MIME_JPEG),
|
|
731
741
|
file_name: `${p.file_id}.jpg`, fileId: p.file_id,
|
|
732
|
-
mime_type:
|
|
742
|
+
mime_type: storage.MIME_JPEG, type: 'PHOTO',
|
|
743
|
+
ocrFunc: ctx._.vision?.see,
|
|
733
744
|
});
|
|
734
745
|
}
|
|
735
746
|
if (m.video_note) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halbot",
|
|
3
3
|
"description": "Just another `ChatGPT` / `Gemini` / `Claude` / `Azure` / `Jina` / `Ollama` Telegram bob, which is simple design, easy to use, extendable and fun.",
|
|
4
|
-
"version": "1993.2.
|
|
4
|
+
"version": "1993.2.91",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/Leask/halbot",
|
|
7
7
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@google-cloud/speech": "^7.0.1",
|
|
37
37
|
"@google-cloud/text-to-speech": "^6.0.1",
|
|
38
38
|
"@google-cloud/vision": "^5.1.0",
|
|
39
|
-
"@google/genai": "^0.
|
|
39
|
+
"@google/genai": "^0.12.0",
|
|
40
40
|
"@mozilla/readability": "^0.6.0",
|
|
41
41
|
"fluent-ffmpeg": "^2.1.3",
|
|
42
42
|
"ioredis": "^5.6.1",
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
"mime": "^4.0.7",
|
|
47
47
|
"mysql2": "^3.14.1",
|
|
48
48
|
"office-text-extractor": "^3.0.3",
|
|
49
|
-
"openai": "^4.
|
|
49
|
+
"openai": "^4.97.0",
|
|
50
50
|
"pg": "^8.15.6",
|
|
51
51
|
"pgvector": "^0.2.0",
|
|
52
52
|
"telegraf": "^4.16.3",
|
|
53
53
|
"tesseract.js": "^6.0.1",
|
|
54
|
-
"utilitas": "^1999.1.
|
|
54
|
+
"utilitas": "^1999.1.61",
|
|
55
55
|
"youtube-transcript": "^1.2.1"
|
|
56
56
|
}
|
|
57
57
|
}
|
package/skills/40_dream.mjs
CHANGED
|
@@ -1,29 +1,39 @@
|
|
|
1
|
-
import { bot } from '../index.mjs';
|
|
1
|
+
import { bot, storage } from '../index.mjs';
|
|
2
|
+
|
|
3
|
+
const GEMINI = 'GEMINI';
|
|
4
|
+
const types = { image: 'photo', video: 'video' };
|
|
2
5
|
|
|
3
6
|
const action = async (ctx, next) => {
|
|
4
|
-
let provider = '';
|
|
7
|
+
let [provider, func, reference] = [GEMINI, 'image', null];
|
|
5
8
|
switch (ctx.cmd.cmd) {
|
|
6
|
-
case '
|
|
7
|
-
case '
|
|
9
|
+
case 'fantasy': func = 'video'; break;
|
|
10
|
+
case 'gptimage':
|
|
11
|
+
provider = 'OPENAI';
|
|
12
|
+
reference = ctx.collected.filter(x => [
|
|
13
|
+
storage.MIME_JPEG, storage.MIME_PNG, storage.MIME_WEBP
|
|
14
|
+
].includes(x?.content?.mime_type)).slice(0, 16).map(
|
|
15
|
+
x => x?.content?.data
|
|
16
|
+
);
|
|
8
17
|
}
|
|
9
18
|
if (!ctx.cmd.args) {
|
|
10
19
|
return await ctx.ok('Please input your prompt.');
|
|
11
20
|
}
|
|
12
|
-
let [objMsg,
|
|
21
|
+
let [objMsg, output] = [(await ctx.ok('💭'))[0], null]; //tts = null
|
|
13
22
|
try {
|
|
14
|
-
|
|
15
|
-
provider, expected: 'FILE'
|
|
16
|
-
|
|
23
|
+
output = (await ctx._.gen[func](ctx.cmd.args, {
|
|
24
|
+
provider, expected: 'FILE',
|
|
25
|
+
...reference?.length ? { reference, input: 'BASE64' } : {},
|
|
26
|
+
})) || [];
|
|
17
27
|
} catch (err) {
|
|
18
|
-
return await ctx.er(err.message ||
|
|
28
|
+
return await ctx.er(err.message || `Error generating ${func}.`,
|
|
19
29
|
{ lastMessageId: objMsg.message_id });
|
|
20
30
|
}
|
|
21
31
|
await ctx.deleteMessage(objMsg.message_id);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
await ctx.media(
|
|
33
|
+
output.map(x => ({ type: types[func], src: x.data })),
|
|
34
|
+
{ caption: output[0]?.caption || '' }
|
|
35
|
+
);
|
|
36
|
+
// tts = output.tts || '';
|
|
27
37
|
// await ctx.shouldSpeech(tts);
|
|
28
38
|
};
|
|
29
39
|
|
|
@@ -35,13 +45,16 @@ export const { name, run, priority, func, cmds, help } = {
|
|
|
35
45
|
help: bot.lines([
|
|
36
46
|
'¶ Use Google `Imagen` (default) or OpenAI `GPT Image` to generate images.',
|
|
37
47
|
'Example 1: /dream a cat in a rocket',
|
|
48
|
+
'¶ Use Google `Veo` to generate videos.',
|
|
49
|
+
'Example 2: /fantasy two cats are kissing each other',
|
|
38
50
|
'¶ Use `Imagen` to generate images.',
|
|
39
|
-
'Example
|
|
51
|
+
'Example 3: /imagen a cat in a car',
|
|
40
52
|
'¶ Use `GPT Image` to generate images.',
|
|
41
|
-
'Example: /gptimage a cat on a bike',
|
|
53
|
+
'Example 4: /gptimage a cat on a bike',
|
|
42
54
|
]),
|
|
43
55
|
cmds: {
|
|
44
56
|
dream: 'Generate images with default model: /dream `PROMPT`',
|
|
57
|
+
fantasy: 'Generate videos with `Veo`: /fantasy `PROMPT`',
|
|
45
58
|
imagen: 'Generate images with `Imagen`: /imagen `PROMPT`',
|
|
46
59
|
gptimage: 'Generate images with `GPT Image`: /gptimage `PROMPT`',
|
|
47
60
|
},
|