halbot 1993.2.23 → 1993.2.25

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 CHANGED
@@ -91,12 +91,6 @@ All supported configuration fields:
91
91
  // OPTIONAL, integer, default: 1.
92
92
  "chatGptPriority": "[[Custom ChatGPT Priority]]",
93
93
 
94
- // Set some of these fields if you need to use custom ChatGPT API.
95
- // OPTIONAL, string.
96
- "chatGptApiKey": "[[Custom ChatGPT API Key]]",
97
- // OPTIONAL, string.
98
- "chatGptEndpoint": "[[Custom ChatGPT API endpoint]]",
99
-
100
94
  // Set some of these fields if you need Anthropic's Claude features.
101
95
  // OPTIONAL, string.
102
96
  "claudeApiKey": "[[Anthropic API Key]]",
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { alan, bot, image, shot, speech, utilitas, vision } from 'utilitas';
1
+ import { alan, bot, image, shot, speech, utilitas } from 'utilitas';
2
2
  import { parse } from 'csv-parse/sync';
3
3
 
4
4
  await utilitas.locate(utilitas.__(import.meta.url, 'package.json'));
@@ -29,40 +29,51 @@ const fetchPrompts = async () => {
29
29
 
30
30
  const init = async (options) => {
31
31
  assert(options?.telegramToken, 'Telegram Bot API Token is required.');
32
- const [pkg, ai, _speech, speechOptions, engines]
33
- = [await utilitas.which(), {}, {}, { tts: true, stt: true }, {}];
32
+ const [pkg, ai, _speech, speechOptions, engines, vision]
33
+ = [await utilitas.which(), {}, {}, { tts: true, stt: true }, {}, {}];
34
34
  const info = bot.lines([
35
35
  `[${bot.EMOJI_BOT} ${pkg.title}](${pkg.homepage})`, pkg.description
36
36
  ]);
37
37
  let embedding;
38
38
  // init ai engines
39
- if (options?.openaiApiKey || options?.chatGptApiKey) {
40
- await alan.init({
41
- provider: 'OPENAI',
42
- apiKey: options?.openaiApiKey || options?.chatGptApiKey,
43
- ...options || {},
44
- });
39
+ // use AI vision, AI stt if ChatGPT or Gemini is enabled
40
+ if (options?.openaiApiKey || options?.googleApiKey) {
41
+ vision.read = alan.distillFile;
42
+ vision.see = alan.distillFile;
43
+ _speech.stt = alan.distillFile;
44
+ }
45
+ // use openai embedding, dall-e, tts if openai is enabled
46
+ if (options?.openaiApiKey) {
47
+ const apiKey = { apiKey: options.openaiApiKey };
48
+ await alan.init({ provider: 'OPENAI', ...apiKey, ...options || {} });
45
49
  ai['ChatGPT'] = {
46
50
  engine: 'CHATGPT', priority: options?.chatGptPriority || 0,
47
- };
48
- engines['CHATGPT'] = {
49
- // only support custom model while prompting
50
- model: options?.chatGptModel,
51
- };
51
+ }; // only support custom model while prompting:
52
+ engines['CHATGPT'] = { model: options?.chatGptModel, };
53
+ embedding = alan.createOpenAIEmbedding;
54
+ await image.init(apiKey);
55
+ await speech.init({ ...apiKey, provider: 'OPENAI', ...speechOptions });
56
+ _speech.tts = speech.tts;
52
57
  }
58
+ // use gemini embedding if gemini is enabled and chatgpt is not enabled
59
+ // use google tts if google api key is ready
53
60
  if (options?.googleApiKey) {
54
- await alan.init({
55
- provider: 'GEMINI', apiKey: options?.googleApiKey,
56
- model: options?.geminiModel, // only support custom model while initiating
57
- ...options || {},
61
+ const apiKey = { apiKey: options.googleApiKey };
62
+ await alan.init({ // only support custom model while initiating:
63
+ provider: 'GEMINI', ...apiKey,
64
+ model: options?.geminiModel, ...options || {},
58
65
  });
59
66
  ai['Gemini'] = {
60
67
  engine: 'GEMINI', priority: options?.geminiPriority || 1,
61
- };
62
- engines['GEMINI'] = {
63
- // save for reference not for prompting
64
- model: options?.geminiModel,
65
- };
68
+ }; // save for reference not for prompting:
69
+ engines['GEMINI'] = { model: options?.geminiModel };
70
+ embedding || (embedding = alan.createGeminiEmbedding);
71
+ if (!_speech.tts) {
72
+ await speech.init({
73
+ ...apiKey, provider: 'GOOGLE', ...speechOptions,
74
+ });
75
+ _speech.tts = speech.tts;
76
+ }
66
77
  }
67
78
  if (options?.claudeApiKey) {
68
79
  await alan.init({
@@ -71,11 +82,8 @@ const init = async (options) => {
71
82
  });
72
83
  ai['Claude'] = {
73
84
  engine: 'CLAUDE', priority: options?.claudePriority || 2,
74
- };
75
- engines['CLAUDE'] = {
76
- // only support custom model while prompting
77
- model: options?.claudeModel,
78
- };
85
+ }; // only support custom model while prompting:
86
+ engines['CLAUDE'] = { model: options?.claudeModel };
79
87
  }
80
88
  if (options?.ollamaEnabled || options?.ollamaEndpoint) {
81
89
  await alan.init({
@@ -92,27 +100,12 @@ const init = async (options) => {
92
100
  assert(utilitas.countKeys(ai), 'No AI provider is configured.');
93
101
  await alan.initChat({ engines, sessions: options?.storage });
94
102
  for (const i in ai) { ai[i].model = engines[ai[i].engine].model; }
95
- // init image, speech, embedding engines
96
- if (options?.openaiApiKey) {
97
- const apiKey = { apiKey: options.openaiApiKey };
98
- await image.init(apiKey);
99
- await speech.init({ ...apiKey, provider: 'OPENAI', ...speechOptions });
100
- embedding = alan.createOpenAIEmbedding;
101
- } else if (options?.googleApiKey) {
102
- const apiKey = { apiKey: options.googleApiKey };
103
- await speech.init({ ...apiKey, provider: 'GOOGLE', ...speechOptions });
104
- embedding = alan.createGeminiEmbedding;
105
- }
106
- // init vision / audio engine
103
+ // config multimodal engines
107
104
  const supportedMimeTypes = new Set(Object.values(engines).map(
108
105
  x => alan.MODELS[x.model]
109
106
  ).map(x => [
110
107
  ...x.supportedMimeTypes || [], ...x.supportedAudioTypes || [],
111
108
  ]).flat().map(x => x.toLowerCase()));
112
- if (options?.googleApiKey) {
113
- const apiKey = { apiKey: options.googleApiKey };
114
- await vision.init(apiKey);
115
- }
116
109
  // init bot
117
110
  const _bot = await bot.init({
118
111
  args: options?.args,
@@ -131,8 +124,7 @@ const init = async (options) => {
131
124
  botProvider: 'telegram',
132
125
  session: options?.storage,
133
126
  skillPath: options?.skillPath || skillPath,
134
- speech: (options?.openaiApiKey || options?.googleApiKey) && speech,
135
- vision: options?.googleApiKey && vision,
127
+ speech: _speech, vision,
136
128
  });
137
129
  _bot._.ai = ai; // Should be an array of a map of AIs.
138
130
  _bot._.lang = options?.lang || 'English';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "halbot",
3
3
  "description": "Just another `ChatGPT` / `Gemini` / `Ollama` Telegram bob, which is simple design, easy to use, extendable and fun.",
4
- "version": "1993.2.23",
4
+ "version": "1993.2.25",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/halbot",
7
7
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  "csv-parse": "^5.6.0",
41
41
  "fluent-ffmpeg": "^2.1.3",
42
42
  "ioredis": "^5.4.2",
43
- "js-tiktoken": "^1.0.16",
43
+ "js-tiktoken": "^1.0.17",
44
44
  "jsdom": "^26.0.0",
45
45
  "lorem-ipsum": "^2.0.8",
46
46
  "mime": "^4.0.6",
@@ -52,7 +52,7 @@
52
52
  "pgvector": "^0.2.0",
53
53
  "telegraf": "^4.16.3",
54
54
  "tesseract.js": "^6.0.0",
55
- "utilitas": "^1998.2.6",
55
+ "utilitas": "^1998.2.13",
56
56
  "youtube-transcript": "^1.2.1"
57
57
  }
58
58
  }
@@ -1,5 +1,21 @@
1
1
  import { alan, bot, utilitas } from 'utilitas';
2
2
 
3
+ const checkUnsupportedMimeType = async ctx => {
4
+ ctx.carry.attachments = [];
5
+ for (const x of ctx.collected.filter(x => x.type === 'PROMPT')) {
6
+ let notSupported = false;
7
+ ctx.selectedAi.map(y => {
8
+ if (![
9
+ ...alan.MODELS[ctx._.ai[y].model]?.supportedMimeTypes || [],
10
+ ...alan.MODELS[ctx._.ai[y].model]?.supportedAudioTypes || [],
11
+ ].includes(y?.content?.mime_type)) { notSupported = true; }
12
+ });
13
+ notSupported ? await x.content.analyze() : ctx.carry.attachments.push({
14
+ ...x.content, analyze: undefined,
15
+ });
16
+ }
17
+ };
18
+
3
19
  const action = async (ctx, next) => {
4
20
  // avatar
5
21
  if (ctx.result) {
@@ -16,9 +32,7 @@ const action = async (ctx, next) => {
16
32
  ctx.avatar = '😸';
17
33
  }
18
34
  // prompt
19
- ctx.carry.attachments = ctx.collected.filter(
20
- x => x.type === 'PROMPT'
21
- ).map(x => x.content);
35
+ await checkUnsupportedMimeType(ctx);
22
36
  const maxInputTokens = alan.getMaxChatPromptLimit()
23
37
  - alan.ATTACHMENT_TOKEN_COST * ctx.carry.attachments.length;
24
38
  const additionInfo = ctx.collected.filter(
@@ -28,7 +42,7 @@ const action = async (ctx, next) => {
28
42
  while (await alan.countTokens(
29
43
  `${ctx.prompt}${additionInfo?.[0] || ''}`
30
44
  ) < maxInputTokens && additionInfo.length) {
31
- ctx.prompt += ` ${additionInfo.shift()}`;
45
+ ctx.prompt += `${additionInfo.shift()} `;
32
46
  }
33
47
  ctx.prompt = utilitas.trim(ctx.prompt);
34
48
  additionInfo.filter(x => x).length && (ctx.prompt += '...');