halbot 1993.2.112 → 1994.1.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.
- package/README.md +36 -52
- package/index.mjs +40 -73
- package/package.json +10 -12
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
[](./LICENSE)
|
|
4
4
|
[](https://github.com/Leask/halbot/actions/workflows/npm-publish.yml)
|
|
5
5
|
|
|
6
|
-
Just another
|
|
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
|
|
36
|
-
- Text-to-Speech (`OpenAI` or `Google
|
|
37
|
-
-
|
|
38
|
-
-
|
|
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:
|
|
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
|
|
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,
|
|
94
|
-
"
|
|
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
|
-
`
|
|
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
|
-
|
|
10
|
-
await utilitas.which(), options?.speech || {},
|
|
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.
|
|
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
|
|
23
|
+
// use openai's dall-e, embedding, tts if openai is enabled
|
|
24
24
|
if (options.openaiApiKey) {
|
|
25
|
-
|
|
26
|
-
await
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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({ ...
|
|
32
|
+
await speech.init({ ...opts, ...speechOptions });
|
|
33
33
|
_speech.tts = speech.tts;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
// use
|
|
37
|
-
// use google tts if google
|
|
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
|
-
|
|
40
|
-
await
|
|
41
|
-
|
|
42
|
-
|
|
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({ ...
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
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
|
-
"description": "Just another
|
|
4
|
-
"version": "
|
|
3
|
+
"description": "Just another AI powered Telegram bot, which is simple design, easy to use, extendable and fun.",
|
|
4
|
+
"version": "1994.1.2",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/Leask/halbot",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
|
-
"node": ">=
|
|
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.
|
|
35
|
+
"@google-cloud/text-to-speech": "^6.4.0",
|
|
38
36
|
"@google-cloud/vision": "^5.3.4",
|
|
39
|
-
"@google/genai": "^1.
|
|
37
|
+
"@google/genai": "^1.30.0",
|
|
40
38
|
"@mozilla/readability": "^0.6.0",
|
|
41
39
|
"fluent-ffmpeg": "^2.1.3",
|
|
42
|
-
"ioredis": "^5.8.
|
|
40
|
+
"ioredis": "^5.8.2",
|
|
43
41
|
"js-tiktoken": "^1.0.21",
|
|
44
|
-
"jsdom": "^27.0
|
|
42
|
+
"jsdom": "^27.2.0",
|
|
45
43
|
"lorem-ipsum": "^2.0.8",
|
|
46
44
|
"mime": "^4.1.0",
|
|
47
|
-
"mysql2": "^3.15.
|
|
45
|
+
"mysql2": "^3.15.3",
|
|
48
46
|
"office-text-extractor": "^3.0.3",
|
|
49
|
-
"openai": "^6.
|
|
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": "^
|
|
52
|
+
"utilitas": "^2000.3.14",
|
|
55
53
|
"youtube-transcript": "^1.2.1"
|
|
56
54
|
}
|
|
57
55
|
}
|