halbot 1993.2.112 → 1994.0.2

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.
Files changed (3) hide show
  1. package/README.md +36 -52
  2. package/index.mjs +40 -73
  3. package/package.json +9 -11
package/README.md CHANGED
@@ -3,7 +3,9 @@
3
3
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
4
4
  [![Node.js Package](https://github.com/Leask/halbot/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/Leask/halbot/actions/workflows/npm-publish.yml)
5
5
 
6
- Just another `ChatGPT` / `Gemini` / `Claude` / `Azure` / `Jina` / `Ollama` Telegram bot, which is simple design, easy to use, extendable and fun.
6
+ Just another AI powered Telegram bot, which is simple design, easy to use, extendable and fun.
7
+
8
+ ℹ️ In the latest version, we've moved away from directly integrating multiple SDKs and are now focusing on supporting `OpenAI-style` APIs. We recommend using `OpenRouter` for multi-model access, as it greatly simplifies configuration and usage complexity. This approach also provides more flexibility in selecting and switching between different AI models.
7
9
 
8
10
  Live demo, click to watch on YouTube:
9
11
 
@@ -26,16 +28,15 @@ alt="Halbot live demo" width="240" height="180" border="10" /></a>
26
28
  ## Features
27
29
 
28
30
  - [Telegram](https://telegram.org/) Bot (`Telegram Bot` token required)
31
+ - [OpenRouter](https://openrouter.ai/) (`OpenRouter` API Key required)
29
32
  - [ChatGPT](https://openai.com/blog/chatgpt) (`OpenAI` API key required)
30
- - [Gemini](https://ai.google.dev/gemini-api/docs) (Google `Gemini` API Key required)
31
- - [Claude](https://www.anthropic.com/api) (`Anthropic` or Google `Vextex` API Key required)
32
- - [Azure](https://azure.microsoft.com/en-us/solutions/ai) (`Azure` API Key required)
33
33
  - [Jina](https://jina.ai/api-dashboard/deepsearch) (`Jina` API Key required)
34
34
  - [Ollama](https://github.com/jmorganca/ollama) (Install `Ollama` and serve your model)
35
- - Speech-to-Text (`OpenAI` or `Google Cloud` API key required, or your own engine)
36
- - Text-to-Speech (`OpenAI` or `Google Cloud` API key required, or your own engine)
37
- - Text-to-Image by DALL·E or Imagen (`OpenAI` or Google `Gemini` API key required, or your own engine)
38
- - OCR/OBJECT_DETECT (`OpenAI` or Google `Gemini` API key required, or your own engine)
35
+ - Speech-to-Text (`OpenAI` or `Google` API key required, or your own engine)
36
+ - Text-to-Speech (`OpenAI` or `Google` API key required, or your own engine)
37
+ - Image generation by DALL·E or Imagen (`OpenAI` or `Google` API key required, or your own engine)
38
+ - Video generation by veo (`Google` API key required, or your own engine)
39
+ - OCR/OBJECT_DETECT (`OpenAI` or `Google` API key required, or your own engine)
39
40
  - DeepSearch (`Jina` API Key required)
40
41
  - Feeding webpage and [YouTube](https://www.youtube.com/) to enhance your prompt
41
42
  - Support Tools (Function Calls)
@@ -77,35 +78,29 @@ All supported configuration fields:
77
78
  // REQUIRED, string.
78
79
  "telegramToken": "[[Telegram Bot API Token]]",
79
80
 
81
+ // Set some of these fields if you need Openrouter's AI models.
82
+ // OPTIONAL, string.
83
+ "openrouterApiKey": "[[OpenRouter API Key]]",
84
+ // OPTIONAL, string, default: "*".
85
+ "openrouterModel": "[[Custom OpenRouter Model ID]]",
86
+ // OPTIONAL, integer.
87
+ "openrouterPriority": "[[Custom OpenRouter Priority]]",
88
+
80
89
  // Set some of these fields if you need OpenAI's ChatGPT, Whisper, Embedding features.
81
90
  // OPTIONAL, string.
82
91
  "openaiApiKey": "[[OpenAI API Key]]",
83
92
  // OPTIONAL, string.
84
93
  "openaiEndpoint": "[[Custom OpenAI API endpoint]]",
85
- // OPTIONAL, string, default: "gpt-3.5-turbo".
94
+ // OPTIONAL, string, default: [[latest gpt mainstream model]].
86
95
  "openaiModel": "[[Custom OpenAI Model ID]]",
87
96
  // OPTIONAL, integer.
88
97
  "openaiPriority": "[[Custom OpenAI Priority]]",
89
98
 
90
- // Set some of these fields if you need Google's Gemini, TTS, STT, OCR, OBJECT_DETECT, Embedding features.
99
+ // Set some of these fields if you need Google's search, imagen, veo, TTS, STT, OCR, OBJECT_DETECT, Embedding features.
91
100
  // OPTIONAL, string.
92
101
  "googleApiKey": "[[Google Cloud / Gemini API Key]]",
93
- // OPTIONAL, string, default: "gemini-pro-vision".
94
- "geminiModel": "[[Custom Gemini Model ID]]",
95
- // OPTIONAL, integer
96
- "geminiPriority": "[[Custom Gemini Priority]]",
97
-
98
- // Set some of these fields if you need Anthropic's Claude features.
99
- // OPTIONAL, string.
100
- "anthropicApiKey": "[[Anthropic API Key]]",
101
- // OPTIONAL, string.
102
- "anthropicCredentials": "[[Vertex Anthropic Credentials]]",
103
- // OPTIONAL, string.
104
- "anthropicProjectId": "[[Vertex Anthropic Project Id]]",
105
- // OPTIONAL, string, default: `latest claude model`.
106
- "anthropicModel": "[[Custom Anthropic Model ID]]",
107
- // OPTIONAL, integer.
108
- "anthropicPriority": "[[Custom Anthropic Priority]]",
102
+ // OPTIONAL, string, set if you need Google Search as a tool.
103
+ "googleCx": "[[Google Search Engine ID]]",
109
104
 
110
105
  // Set some of these fields if you need SiliconFlow's DeepSearch features.
111
106
  // OPTIONAL, string.
@@ -115,7 +110,7 @@ All supported configuration fields:
115
110
  // OPTIONAL, integer.
116
111
  "siliconflowPriority": "[[Custom SiliconFlow Priority]]",
117
112
 
118
- // Set some of these fields if you need Jina's DeepSearch features.
113
+ // Set some of these fields if you need Jina's DeepSearch, reader, search features.
119
114
  // OPTIONAL, string.
120
115
  "jinaApiKey": "[[Jina API Key]]",
121
116
  // OPTIONAL, string.
@@ -123,26 +118,6 @@ All supported configuration fields:
123
118
  // OPTIONAL, integer.
124
119
  "jinaPriority": "[[Custom Jina Priority]]",
125
120
 
126
- // Set some of these fields if you need Azure's AI features.
127
- // OPTIONAL, string.
128
- "azureApiKey": "[[Azure API Key]]",
129
- // OPTIONAL, string.
130
- "azureEndpoint": "[[Azure API Endpoint]]",
131
- // OPTIONAL, string.
132
- "azureModel": "[[Custom Azure Model ID]]",
133
- // OPTIONAL, integer.
134
- "azurePriority": "[[Custom Azure Priority]]",
135
-
136
- // Set some of these fields if you nee Azure OpenAI's AI features.
137
- // OPTIONAL, string.
138
- "azureOpenaiApiKey": "[[Azure OpenAI API Key]]",
139
- // OPTIONAL, string.
140
- "azureOpenaiEndpoint": "[[Azure OpenAI API Endpoint]]",
141
- // OPTIONAL, string.
142
- "azureOpenaiModel": "[[Custom Azure OpenAI Model ID]]",
143
- // OPTIONAL, integer.
144
- "azureOpenaiPriority": "[[Custom Azure OpenAI Priority]]",
145
-
146
121
  // Set some of these fields if you need Ollama features.
147
122
  // OPTIONAL, boolean.
148
123
  "ollamaEnabled": "[[Enable Ollama API]]",
@@ -153,10 +128,6 @@ All supported configuration fields:
153
128
  // OPTIONAL, integer.
154
129
  "ollamaPriority": "[[Custom Ollama Priority]]",
155
130
 
156
- // OPTIONAL, string.
157
- // Using this option along with `googleApiKey` to enable Google Search as a tool.
158
- "googleCx": "[[Google Search Engine ID]]",
159
-
160
131
  // OPTIONAL, undefined || array of string.
161
132
  // To open the bot to PUBLIC, DO NOT set this field;
162
133
  // To restrict the bot to PRIVATE, set chat/group/channel ids in this array.
@@ -231,7 +202,7 @@ In peace-of-mind:
231
202
  $ npx halbot
232
203
  ```
233
204
 
234
- `If you have multible AI engines configed, use '/chatgpt' or '/bing' to switch between them, or you can use '/*' to ask them all at the same time.`
205
+ Run `/help` in the chat to get help information.
235
206
 
236
207
  ## Integrate to your project
237
208
 
@@ -267,6 +238,10 @@ const config = {
267
238
  // ...
268
239
  },
269
240
 
241
+ // OPTIONAL, object.
242
+ // Your own embedding engine.
243
+ embedding: [[embeddingApi]],
244
+
270
245
  // OPTIONAL, object.
271
246
  // Your own speech-to-text and text-to-speech engine.
272
247
  speech: {
@@ -365,6 +340,15 @@ await halbot(config);
365
340
  - `halbot` uses [🤖 utilitas.bot](https://github.com/Leask/utilitas/blob/master/lib/bot.mjs) as a Telegram bot engine.
366
341
  - `halbot` uses [🤖 utilitas.alan](https://github.com/Leask/utilitas/blob/master/lib/alan.mjs) to communicate with the AI engines.
367
342
 
343
+ ## Related Issues:
344
+
345
+ Besure to upgrade jwa on node v25:
346
+ https://github.com/auth0/node-jsonwebtoken/issues/992
347
+
348
+ ```bash
349
+ $ npm upgrade jwa
350
+ ```
351
+
368
352
  ## Contact me
369
353
 
370
354
  <img width="320" alt="IMG_2289" src="https://user-images.githubusercontent.com/233022/232649734-ff356d76-1bd6-41b2-ad78-27b62e6a9020.JPG">
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { alan, bot, gen, web, speech, utilitas } from 'utilitas';
1
+ import { alan, bot, embedding, 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'));
@@ -6,100 +6,68 @@ const skillPath = utilitas.__(import.meta.url, 'skills');
6
6
 
7
7
  const init = async (options = {}) => {
8
8
  assert(options.telegramToken, 'Telegram Bot API Token is required.');
9
- const [pkg, _speech, speechOptions, vision] = [
10
- await utilitas.which(), options?.speech || {}, { tts: true, stt: true },
11
- {},
9
+ let [pkg, _speech, _embedding, speechOptions, vision, opts] = [
10
+ await utilitas.which(), options?.speech || {}, options?.embedding,
11
+ { tts: true, stt: true }, {}, null,
12
12
  ];
13
13
  const info = bot.lines([
14
14
  `[${hal.EMOJI_BOT} ${pkg.title}](${pkg.homepage})`, pkg.description
15
15
  ]);
16
- // init ai engines
17
16
  // use AI vision, AI stt if ChatGPT or Gemini is enabled
18
- if (options.openaiApiKey || options.googleApiKey) {
17
+ if (options.openrouterApiKey
18
+ || options.openaiApiKey || options.googleApiKey) {
19
19
  vision.read = alan.distillFile;
20
20
  vision.see = alan.distillFile;
21
21
  _speech?.stt || (_speech.stt = alan.distillFile);
22
22
  }
23
- // use openai embedding, dall-e, tts if openai is enabled
23
+ // use openai's dall-e, embedding, tts if openai is enabled
24
24
  if (options.openaiApiKey) {
25
- const apiKey = { apiKey: options.openaiApiKey, provider: 'OPENAI' };
26
- await alan.init({
27
- ...apiKey, model: options.openaiModel || '*',
28
- priority: options.openaiPriority, ...options
29
- });
30
- await gen.init(apiKey);
25
+ opts = { provider: 'OPENAI', apiKey: options.openaiApiKey };
26
+ await gen.init(opts);
27
+ if (!_embedding) {
28
+ await embedding.init(opts);
29
+ _embedding = embedding.embed;
30
+ }
31
31
  if (!_speech.tts) {
32
- await speech.init({ ...apiKey, ...speechOptions });
32
+ await speech.init({ ...opts, ...speechOptions });
33
33
  _speech.tts = speech.tts;
34
34
  }
35
35
  }
36
- // use gemini embedding if gemini is enabled and chatgpt is not enabled
37
- // use google tts if google api key is ready
36
+ // use google's imagen, veo, search if google is enabled
37
+ // use google's embedding, tts if google is enabled and ChatGPT is not
38
38
  if (options.googleApiKey) {
39
- const apiKey = { apiKey: options.googleApiKey, provider: 'GOOGLE' };
40
- await alan.init({
41
- ...apiKey, provider: 'GEMINI', model: options.geminiModel || '*',
42
- priority: options.geminiPriority, ...options
39
+ opts = { provider: 'GOOGLE', apiKey: options.googleApiKey };
40
+ await gen.init(opts);
41
+ options.googleCx && await web.initSearch({
42
+ ...opts, cx: options.googleCx,
43
43
  });
44
+ if (!_embedding) {
45
+ await embedding.init(opts);
46
+ _embedding = embedding.embed;
47
+ }
44
48
  if (!_speech.tts) {
45
- await speech.init({ ...apiKey, ...speechOptions });
49
+ await speech.init({ ...opts, ...speechOptions });
46
50
  _speech.tts = speech.tts;
47
51
  }
48
- options.googleCx && await web.initSearch({
49
- ...apiKey, cx: options.googleCx,
50
- });
51
52
  }
52
- const geminiGenReady = options.googleApiKey
53
- || (options.googleCredentials && options.googleProjectId);
54
- geminiGenReady && await gen.init({
55
- apiKey: options.googleApiKey, provider: 'GEMINI',
56
- credentials: options.googleCredentials,
57
- projectId: options.googleProjectId,
53
+ // init ai providers
54
+ options.openrouterApiKey && await alan.init({
55
+ provider: 'OPENROUTER', apiKey: options.openrouterApiKey,
56
+ model: options.openrouterModel || '*',
57
+ priority: options.openrouterPriority, ...options,
58
+ });
59
+ options.siliconflowApiKey && await alan.init({
60
+ provider: 'SILICONFLOW', apiKey: options.siliconflowApiKey,
61
+ model: options.siliconflowModel || '*',
62
+ priority: options.siliconflowPriority, ...options,
58
63
  });
59
- if (options.anthropicApiKey) {
60
- await alan.init({
61
- provider: 'ANTHROPIC', model: options.anthropicModel || '*',
62
- apiKey: options.anthropicApiKey,
63
- priority: options.anthropicPriority, ...options
64
- });
65
- }
66
- if (options.googleCredentials && options.googleProjectId) {
67
- await alan.init({
68
- provider: 'VERTEX ANTHROPIC', model: options.anthropicModel || '*',
69
- credentials: options.googleCredentials,
70
- projectId: options.googleProjectId,
71
- priority: options.anthropicPriority, ...options
72
- });
73
- }
74
- if (options.siliconflowApiKey) {
75
- await alan.init({
76
- provider: 'SILICONFLOW', model: options.siliconflowModel || '*',
77
- apiKey: options.siliconflowApiKey,
78
- priority: options.siliconflowPriority, ...options
79
- });
80
- }
81
64
  if (options.jinaApiKey) {
82
- const apiKey = { apiKey: options.jinaApiKey };
83
- await alan.init({
84
- provider: 'JINA', model: options.jinaModel || '*',
85
- ...apiKey, priority: options.jinaPriority, ...options
86
- });
87
- await web.initSearch({ provider: 'Jina', ...apiKey });
88
- }
89
- if (options.azureApiKey && options.azureEndpoint) {
90
- await alan.init({
91
- provider: 'AZURE', model: options.azureModel,
92
- apiKey: options.azureApiKey, priority: options.azurePriority,
93
- baseURL: options.azureEndpoint, ...options
94
- });
95
- }
96
- if (options.azureOpenaiApiKey && options.azureOpenaiEndpoint) {
65
+ opts = { provider: 'JINA', apiKey: options.jinaApiKey };
97
66
  await alan.init({
98
- provider: 'AZURE OPENAI', model: options.azureOpenaiModel,
99
- apiKey: options.azureOpenaiApiKey,
100
- priority: options.azureOpenaiPriority,
101
- endpoint: options.azureOpenaiEndpoint, ...options
67
+ ...opts, model: options.jinaModel || '*',
68
+ priority: options.jinaPriority, ...options
102
69
  });
70
+ await web.initSearch(opts);
103
71
  }
104
72
  if (options?.ollamaEnabled || options?.ollamaEndpoint) {
105
73
  await alan.init({
@@ -128,7 +96,6 @@ const init = async (options = {}) => {
128
96
  chatType: options?.chatType,
129
97
  cmds,
130
98
  database: options?.storage?.client && options?.storage,
131
- embedding: ais.find(x => x.embedding)?.embedding,
132
99
  supportedMimeTypes,
133
100
  hello: options?.hello,
134
101
  help: options?.help,
@@ -139,7 +106,7 @@ const init = async (options = {}) => {
139
106
  provider: 'telegram',
140
107
  session: options?.storage,
141
108
  skillPath: options?.skillPath || skillPath,
142
- speech: _speech, vision,
109
+ embedding: _embedding, speech: _speech, vision,
143
110
  });
144
111
  _hal._.lang = options?.lang || 'English';
145
112
  _hal._.gen = options?.gen
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "halbot",
3
3
  "description": "Just another `ChatGPT` / `Gemini` / `Claude` / `Azure` / `Jina` / `Ollama` Telegram bot, which is simple design, easy to use, extendable and fun.",
4
- "version": "1993.2.112",
4
+ "version": "1994.0.2",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/halbot",
7
7
  "type": "module",
8
8
  "engines": {
9
- "node": ">=19.x"
9
+ "node": ">=20.x"
10
10
  },
11
11
  "main": "index.mjs",
12
12
  "bin": {
@@ -29,29 +29,27 @@
29
29
  "url": "https://github.com/Leask/halbot.git"
30
30
  },
31
31
  "dependencies": {
32
- "@anthropic-ai/sdk": "^0.67.0",
33
- "@anthropic-ai/vertex-sdk": "^0.14.0",
34
32
  "@ffmpeg-installer/ffmpeg": "^1.1.0",
35
33
  "@ffprobe-installer/ffprobe": "^2.1.2",
36
34
  "@google-cloud/speech": "^7.2.1",
37
- "@google-cloud/text-to-speech": "^6.3.1",
35
+ "@google-cloud/text-to-speech": "^6.4.0",
38
36
  "@google-cloud/vision": "^5.3.4",
39
- "@google/genai": "^1.25.0",
37
+ "@google/genai": "^1.30.0",
40
38
  "@mozilla/readability": "^0.6.0",
41
39
  "fluent-ffmpeg": "^2.1.3",
42
- "ioredis": "^5.8.1",
40
+ "ioredis": "^5.8.2",
43
41
  "js-tiktoken": "^1.0.21",
44
- "jsdom": "^27.0.1",
42
+ "jsdom": "^27.2.0",
45
43
  "lorem-ipsum": "^2.0.8",
46
44
  "mime": "^4.1.0",
47
- "mysql2": "^3.15.2",
45
+ "mysql2": "^3.15.3",
48
46
  "office-text-extractor": "^3.0.3",
49
- "openai": "^6.5.0",
47
+ "openai": "^6.9.1",
50
48
  "pg": "^8.16.3",
51
49
  "pgvector": "^0.2.1",
52
50
  "telegraf": "^4.16.3",
53
51
  "tesseract.js": "^6.0.1",
54
- "utilitas": "^1999.1.93",
52
+ "utilitas": "^2000.3.14",
55
53
  "youtube-transcript": "^1.2.1"
56
54
  }
57
55
  }