halbot 1990.1.121 → 1990.1.122

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
@@ -67,7 +67,7 @@ All supported configuration fields:
67
67
  // REQUIRED, string.
68
68
  "telegramToken": "[[Telegram Bot API Token]]",
69
69
 
70
- // Set some of these fields if you need ChatGPT features.
70
+ // Set some of these fields if you need ChatGPT, Whisper, Embedding features.
71
71
  // OPTIONAL, string.
72
72
  "openaiApiKey": "[[OpenAI API Key]]",
73
73
  // OPTIONAL, string.
@@ -104,7 +104,7 @@ All supported configuration fields:
104
104
  "mistralPriority": "[[Custom Mistral Priority]]",
105
105
 
106
106
  // OPTIONAL, string.
107
- // Set this field if you need TTS/STT/OCR/OBJECT_DETECT features.
107
+ // Set this field if you need Google's TTS/STT/OCR/OBJECT_DETECT/Embedding.
108
108
  "googleApiKey": "[[Google Cloud API Key]]",
109
109
 
110
110
  // OPTIONAL, undefined || array of string.
@@ -138,20 +138,32 @@ All supported configuration fields:
138
138
  "help": "[[help information]]",
139
139
 
140
140
  // OPTIONAL, object.
141
- // Sessions/conversations storage, support MariaDB/MySQL and Redis for now.
141
+ // Sessions/conversations storage.
142
+ // support PostgreSQL, MariaDB/MySQL and Redis for now.
142
143
  // If omitted, the bot will use memory storage and sync to this file.
143
- // Example: (Compatibility: https://github.com/sidorares/node-mysql2)
144
+ // Example: (Compatibility: https://node-postgres.com/apis/pool)
144
145
  "storage": {
145
- "type": "[["MARIADB" || "MYSQL"]]",
146
+ "provider": "POSTGRESQL",
146
147
  "host": "[[DATABASE HOST]]",
147
148
  "database": "[[DATABASE NAME]]",
148
149
  "user": "[[DATABASE USER]]",
149
150
  "password": "[[DATABASE PASSWORD]]",
151
+ "vector": true, // REQUIRED
152
+ ...[[OTHER DATABASE OPTIONS]],
153
+ },
154
+ // OR: (Compatibility: https://github.com/sidorares/node-mysql2)
155
+ "storage": {
156
+ "provider": "[["MARIADB" || "MYSQL"]]",
157
+ "host": "[[DATABASE HOST]]",
158
+ "database": "[[DATABASE NAME]]",
159
+ "user": "[[DATABASE USER]]",
160
+ "password": "[[DATABASE PASSWORD]]",
161
+ "charset": "utf8mb4", // REQUIRED
150
162
  ...[[OTHER DATABASE OPTIONS]],
151
163
  },
152
164
  // OR: (Compatibility: https://github.com/luin/ioredis)
153
165
  "storage": {
154
- "type": "REDIS",
166
+ "provider": "REDIS",
155
167
  "host": "[[REDIS HOST]]",
156
168
  "password": "[[REDIS PASSWORD]]",
157
169
  ...[[OTHER REDIS OPTIONS]],
package/bin/halbot.mjs CHANGED
@@ -10,6 +10,7 @@ const _getConfig = async () => await _storage.getConfig();
10
10
  const getConfig = async key => (await _getConfig())?.config?.[key];
11
11
 
12
12
  let storage = {
13
+ provider: 'FILE',
13
14
  get: async key => (await getConfig(MEMORY))?.[key],
14
15
  set: async (k, v) => await _storage.setConfig({ [MEMORY]: { [k]: v } }),
15
16
  };
@@ -17,14 +18,14 @@ let storage = {
17
18
  try {
18
19
  const { filename, config } = await _getConfig();
19
20
  assert(utilitas.countKeys(config), `Error loading config from ${filename}.`);
20
- const sessionType = utilitas.trim(config.storage?.provider, { case: 'UP' });
21
- switch (sessionType) {
22
- case 'MARIADB': case 'MYSQL':
21
+ const provider = utilitas.trim(config.storage?.provider, { case: 'UP' });
22
+ switch (provider) {
23
+ case 'MARIADB': case 'MYSQL': case 'POSTGRESQL':
23
24
  await dbio.init(config.storage);
24
- storage = await memory.init();
25
+ storage = { ...await memory.init(), provider, client: dbio };
25
26
  break;
26
27
  case 'REDIS':
27
- storage = await cache.init(config.storage);
28
+ storage = { ...await cache.init(config.storage), provider };
28
29
  break;
29
30
  default:
30
31
  config.storage && utilitas.throwError('Invalid storage config.');
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { alan, bot, image, shot, speech, utilitas, vision } from 'utilitas';
1
+ import { alan, bot, dbio, image, shot, speech, utilitas, vision } from 'utilitas';
2
2
  import { parse } from 'csv-parse/sync';
3
3
 
4
4
  await utilitas.locate(utilitas.__(import.meta.url, 'package.json'));
@@ -34,13 +34,11 @@ const init = async (options) => {
34
34
  const info = bot.lines([
35
35
  `[${bot.EMOJI_BOT} ${pkg.title}](${pkg.homepage})`, pkg.description
36
36
  ]);
37
+ let embedding;
37
38
  // init ai engines
38
39
  if (options?.openaiApiKey || options?.chatGptApiKey) {
39
- const apiKey = { apiKey: options?.chatGptApiKey || options?.openaiApiKey };
40
- await alan.init({
41
- provider: 'openai', ...apiKey,
42
- baseURL: options?.chatGptEndpoint || options?.openaiEndpoint,
43
- });
40
+ const apiKey = { apiKey: options?.openaiApiKey || options?.chatGptApiKey };
41
+ await alan.init({ provider: 'openai', ...apiKey, ...options });
44
42
  ai['ChatGPT'] = {
45
43
  engine: 'CHATGPT', priority: options?.chatGptPriority || 0,
46
44
  };
@@ -79,14 +77,16 @@ const init = async (options) => {
79
77
  }
80
78
  assert(utilitas.countKeys(ai), 'No AI provider is configured.');
81
79
  await alan.initChat({ engines, sessions: options?.storage });
82
- // init image, speech engines
80
+ // init image, speech, embedding engines
83
81
  if (options?.openaiApiKey) {
84
82
  const apiKey = { apiKey: options.openaiApiKey };
85
83
  await image.init(apiKey);
86
84
  await speech.init({ ...apiKey, provider: 'OPENAI', ...speechOptions });
85
+ embedding = alan.createOpenAIEmbedding;
87
86
  } else if (options?.googleApiKey) {
88
87
  const apiKey = { apiKey: options.googleApiKey };
89
88
  await speech.init({ ...apiKey, provider: 'GOOGLE', ...speechOptions });
89
+ embedding = alan.createVertexEmbedding;
90
90
  }
91
91
  // init vision engine
92
92
  const supportedMimeTypes = new Set(Object.values(engines).map(
@@ -103,6 +103,8 @@ const init = async (options) => {
103
103
  botToken: options?.telegramToken,
104
104
  chatType: options?.chatType,
105
105
  cmds: options?.cmds,
106
+ database: options?.storage?.client && options?.storage,
107
+ embedding, supportedMimeTypes,
106
108
  hello: options?.hello,
107
109
  help: options?.help,
108
110
  homeGroup: options?.homeGroup,
@@ -114,7 +116,6 @@ const init = async (options) => {
114
116
  skillPath: options?.skillPath || skillPath,
115
117
  speech: (options?.openaiApiKey || options?.googleApiKey) && speech,
116
118
  vision: options?.googleApiKey && vision,
117
- supportedMimeTypes,
118
119
  });
119
120
  _bot._.ai = ai; // Should be an array of a map of AIs.
120
121
  _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/Bing Chat Telegram bob, which is simple design, easy to use, extendable and fun.",
4
- "version": "1990.1.121",
4
+ "version": "1990.1.122",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/Leask/halbot",
7
7
  "type": "module",
@@ -21,7 +21,7 @@ const action = async (ctx, next) => {
21
21
  x => String.isString(x.content)
22
22
  ).map(x => x.content).join('\n').split(' ').filter(x => x);
23
23
  ctx.prompt = (ctx.text || '') + '\n\n';
24
- while (alan.countTokens(ctx.prompt) < maxInputTokens
24
+ while (await alan.countTokens(ctx.prompt) < maxInputTokens
25
25
  && additionInfo.length) {
26
26
  ctx.prompt += ` ${additionInfo.shift()}`;
27
27
  }
@@ -52,9 +52,6 @@ const action = async (ctx, next) => {
52
52
  tts[n] = ctx.selectedAi.length === 1
53
53
  && !msgs[n].split('\n').some(x => /^```/.test(x))
54
54
  ? resp.spoken : '';
55
- // extra.buttons = resp?.suggestedResponses?.map?.(label => ({
56
- // label, text: `/bing@${ctx.botInfo.username} ${label}`,
57
- // }));
58
55
  return resp;
59
56
  } catch (err) {
60
57
  msgs[n] = err?.message || err;