halbot 1993.2.88 → 1993.2.90

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { alan, bot, image, web, speech, utilitas } from 'utilitas';
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 image.init(apiKey);
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.anthropicCredentials && options.anthropicProjectId) {
62
+ if (options.googleCredentials && options.googleProjectId) {
57
63
  await alan.init({
58
64
  provider: 'VERTEX ANTHROPIC', model: options.anthropicModel || '*',
59
- credentials: options.anthropicCredentials,
60
- projectId: options.anthropicProjectId,
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._.image = options?.openaiApiKey && image;
139
+ _hal._.gen = options?.gen
140
+ || (options?.openaiApiKey || geminiGenReady ? gen : null);
134
141
  return _hal;
135
142
  };
136
143
 
package/lib/hal.mjs CHANGED
@@ -20,6 +20,7 @@ const isMarkdownError = e => e?.description?.includes?.("can't parse entities");
20
20
  const getFile = async (id, op) => (await web.get(await getFileUrl(id), op)).content;
21
21
  const compact = (str, op) => utilitas.ensureString(str, { ...op || {}, compact: true });
22
22
  const compactLimit = (str, op) => compact(str, { ...op || {}, limit: 140 });
23
+ const getKey = s => s?.toLowerCase?.()?.startsWith?.('http') ? 'url' : 'source';
23
24
  const SEARCH_LIMIT = 10;
24
25
 
25
26
  const [ // https://limits.tginfo.me/en
@@ -362,18 +363,26 @@ const subconscious = [{
362
363
  ctx.complete = async (options) => await ctx.ok('☑️', options);
363
364
  ctx.json = async (obj, options) => await ctx.ok(json(obj), options);
364
365
  ctx.list = async (list, options) => await ctx.ok(uList(list), options);
365
- ctx.media = async (fnc, src, options) => ctx.done.push(await ctx[fnc]({
366
- [src?.toLowerCase?.()?.startsWith?.('http') ? 'url' : 'source']: src
367
- }, getExtra(ctx, options)));
368
- ctx.audio = async (sr, op) => await ctx.media('replyWithAudio', sr, op);
369
- ctx.image = async (sr, op) => await ctx.media('replyWithPhoto', sr, op);
370
- ctx.sendConfig = async (obj, options, _ctx) => await ctx.ok(utilitas.prettyJson(
371
- obj, { code: true, md: true }
372
- ), options);
366
+ ctx.replyWith = async (func, src, options) => ctx.done.push(
367
+ await ctx[func]({ [getKey(src)]: src }, getExtra(ctx, options))
368
+ );
369
+ ctx.audio = async (s, o) => await ctx.replyWith('replyWithAudio', s, o);
370
+ ctx.image = async (s, o) => await ctx.replyWith('replyWithPhoto', s, o);
371
+ ctx.video = async (s, o) => await ctx.replyWith('replyWithVideo', s, o);
372
+ ctx.media = async (srs, options) => await ctx.done.push(
373
+ await ctx.replyWithMediaGroup(srs.map(x => ({
374
+ type: x.type || 'photo', media: { [getKey(x.src)]: x.src },
375
+ })), getExtra(ctx, options))
376
+ );
377
+ ctx.sendConfig = async (obj, options, _ctx) => await ctx.ok(
378
+ utilitas.prettyJson(obj, { code: true, md: true }), options
379
+ );
373
380
  ctx.speech = async (cnt, options) => {
374
381
  let file;
375
382
  if (Buffer.isBuffer(cnt)) {
376
- file = await storage.convert(cnt, { input: storage.BUFFER, expected: storage.FILE });
383
+ file = await storage.convert(cnt, {
384
+ input: storage.BUFFER, expected: storage.FILE,
385
+ });
377
386
  } else if (cnt.length <= speech.OPENAI_TTS_MAX_LENGTH) {
378
387
  file = await utilitas.ignoreErrFunc(async () => await ctx._.speech.tts(
379
388
  cnt, { expected: 'file' }
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.88",
4
+ "version": "1993.2.90",
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.10.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",
@@ -51,7 +51,7 @@
51
51
  "pgvector": "^0.2.0",
52
52
  "telegraf": "^4.16.3",
53
53
  "tesseract.js": "^6.0.1",
54
- "utilitas": "^1999.1.53",
54
+ "utilitas": "^1999.1.60",
55
55
  "youtube-transcript": "^1.2.1"
56
56
  }
57
57
  }
@@ -1,29 +1,32 @@
1
1
  import { bot } from '../index.mjs';
2
2
 
3
+ const GEMINI = 'GEMINI';
4
+ const types = { image: 'photo', video: 'video' };
5
+
3
6
  const action = async (ctx, next) => {
4
- let provider = '';
7
+ let [provider, func] = [GEMINI, 'image'];
5
8
  switch (ctx.cmd.cmd) {
6
9
  case 'gptimage': provider = 'OPENAI'; break;
7
- case 'dream': case 'imagen': default: provider = 'GEMINI';
10
+ case 'fantasy': func = 'video';
8
11
  }
9
12
  if (!ctx.cmd.args) {
10
13
  return await ctx.ok('Please input your prompt.');
11
14
  }
12
- let [objMsg, images] = [(await ctx.ok('💭'))[0], null]; //tts = null
15
+ let [objMsg, output] = [(await ctx.ok('💭'))[0], null]; //tts = null
13
16
  try {
14
- images = await ctx._.image.generate(ctx.cmd.args, {
17
+ output = (await ctx._.gen[func](ctx.cmd.args, {
15
18
  provider, expected: 'FILE'
16
- });
19
+ })) || [];
17
20
  } catch (err) {
18
- return await ctx.er(err.message || 'Error generating image.',
21
+ return await ctx.er(err.message || `Error generating ${func}.`,
19
22
  { lastMessageId: objMsg.message_id });
20
23
  }
21
24
  await ctx.deleteMessage(objMsg.message_id);
22
- for (let image of images || []) {
23
- // tts = image.tts || '';
24
- await ctx.image(image.data, { caption: image.caption || '' });
25
- await ctx.timeout();
26
- }
25
+ await ctx.media(
26
+ output.map(x => ({ type: types[func], src: x.data })),
27
+ { caption: output[0]?.caption || '' }
28
+ );
29
+ // tts = output.tts || '';
27
30
  // await ctx.shouldSpeech(tts);
28
31
  };
29
32
 
@@ -35,13 +38,16 @@ export const { name, run, priority, func, cmds, help } = {
35
38
  help: bot.lines([
36
39
  '¶ Use Google `Imagen` (default) or OpenAI `GPT Image` to generate images.',
37
40
  'Example 1: /dream a cat in a rocket',
41
+ '¶ Use Google `Veo` to generate videos.',
42
+ 'Example 2: /fantasy two cats are kissing each other',
38
43
  '¶ Use `Imagen` to generate images.',
39
- 'Example 2: /imagen a cat in a car',
44
+ 'Example 3: /imagen a cat in a car',
40
45
  '¶ Use `GPT Image` to generate images.',
41
- 'Example: /gptimage a cat on a bike',
46
+ 'Example 4: /gptimage a cat on a bike',
42
47
  ]),
43
48
  cmds: {
44
49
  dream: 'Generate images with default model: /dream `PROMPT`',
50
+ fantasy: 'Generate videos with `Veo`: /fantasy `PROMPT`',
45
51
  imagen: 'Generate images with `Imagen`: /imagen `PROMPT`',
46
52
  gptimage: 'Generate images with `GPT Image`: /gptimage `PROMPT`',
47
53
  },