halbot 1989.6.4 → 1989.6.6

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/bin/halbot.mjs ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { storage, utilitas } from 'utilitas';
4
+ import halbot from '../index.mjs';
5
+
6
+ const debug = utilitas.humanReadableBoolean(process.env['DEBUG']);
7
+ const log = content => utilitas.log(content, import.meta.url);
8
+
9
+ // Disabled for current version.
10
+ // const args = await (async (options) => {
11
+ // const { parseArgs } = await import('node:util');
12
+ // if (parseArgs) { // https://kgrz.io/node-has-native-arg-parsing.html
13
+ // const { values } = parseArgs({
14
+ // options: {
15
+ // // xxx: { type: 'string', short: 'x', default: '' }
16
+ // },
17
+ // ...options || {},
18
+ // });
19
+ // return values;
20
+ // }
21
+ // let args = {}; // simple fallback for node version < 19
22
+ // process.argv.map(arg => {
23
+ // const item = arg.replace(/^\-*([^=]*)=(.*)$/ig, '$1<,>$2').split('<,>');
24
+ // item.length > 1 && (args[item[0]] = item[1]);
25
+ // });
26
+ // return args;
27
+ // })();
28
+
29
+ try {
30
+ const { config } = await storage.getConfig(
31
+ ...debug ? [{ pack: './package.json' }] : [], // utilitas debug
32
+ );
33
+ await halbot(config);
34
+ } catch (err) { debug ? utilitas.throwError(err) : log(err); }
package/config.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "telegramToken": "// Telegram Bot API Token",
3
+ "chatGptKey": "// ChatGPT API Key",
4
+ "bingToken": "// Bing Usertoken from cookies",
5
+ "googleApiKey": "// Google Cloud API Key"
6
+ }
package/index.mjs CHANGED
@@ -0,0 +1,36 @@
1
+ import { bot, hal, speech, utilitas } from 'utilitas';
2
+
3
+ const skillPath = utilitas.__(import.meta.url, 'skills');
4
+
5
+ const init = async (options) => {
6
+ assert(options?.telegramToken, 'Telegram Bot API Token is required.', 400);
7
+ const [ai, _speech] = [{}, {}];
8
+ if (options?.googleApiKey) {
9
+ await speech.init({ apiKey: options?.googleApiKey, tts: true, stt: true });
10
+ Object.assign(_speech, { stt: speech.stt, tts: speech.tts });
11
+ }
12
+ if (options?.chatGptKey) {
13
+ ai['ChatGPT'] = await hal.init({
14
+ provider: 'CHATGPT', clientOptions: { apiKey: options.chatGptKey },
15
+ });
16
+ }
17
+ if (options?.bingToken) {
18
+ ai['Bing'] = await hal.init({
19
+ provider: 'BING', clientOptions: { userToken: options.bingToken },
20
+ });
21
+ }
22
+ assert(utilitas.countKeys(ai), 'No AI provider is configured.', 400);
23
+ return await bot.init({
24
+ ai, auth: options?.auth,
25
+ botToken: options?.telegramToken,
26
+ chatType: options?.chatType,
27
+ homeGroup: options?.homeGroup,
28
+ magicWord: options?.magicWord,
29
+ private: options?.private,
30
+ provider: 'telegram', speech: _speech,
31
+ skillPath: options?.skillPath || skillPath,
32
+ });
33
+ };
34
+
35
+ export default init;
36
+ export { bot, hal, speech, utilitas };
package/package.json CHANGED
@@ -1,11 +1,39 @@
1
1
  {
2
2
  "name": "halbot",
3
- "version": "1989.6.4",
4
- "description": "",
3
+ "description": "Just another ChatGPT/Bing Telegram bob.",
4
+ "version": "1989.6.6",
5
+ "private": false,
6
+ "homepage": "https://github.com/Leask/halbot",
7
+ "type": "module",
8
+ "engines": {
9
+ "node": ">=18.x"
10
+ },
5
11
  "main": "index.js",
12
+ "bin": {
13
+ "halbot": "bin/halbot.mjs"
14
+ },
6
15
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
16
+ "start": "node bin/halbot.mjs",
17
+ "debug": "node --inspect --trace-warnings debug.mjs",
18
+ "test": "node --inspect --trace-warnings test.mjs",
19
+ "updep": "npx npm-check-updates -u && npm install",
20
+ "gitsync": "( git commit -am \"Released @ `date`\" || true ) && git pull && git push",
21
+ "build": "npm run updep && ( git commit -am 'update dependencies' || true )",
22
+ "pub": "npm run build && npm run gitsync",
23
+ "beta": "npm publish --tag beta"
24
+ },
25
+ "author": "Leask Wong <i@leaskh.com>",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/Leask/halbot.git"
30
+ },
31
+ "dependencies": {
32
+ "@google-cloud/speech": "^5.4.0",
33
+ "@google-cloud/text-to-speech": "^4.2.1",
34
+ "@waylaidwanderer/chatgpt-api": "^1.28.10",
35
+ "telegraf": "^4.12.2",
36
+ "utilitas": "^1992.3.43"
8
37
  },
9
- "author": "",
10
- "license": "MIT"
38
+ "devDependencies": {}
11
39
  }
package/skills/ai.mjs ADDED
@@ -0,0 +1,70 @@
1
+ import { utilitas } from 'utilitas';
2
+
3
+ const onProgress = { onProgress: true };
4
+ const [YOU, BOT, LN2] = ['😸 You:', '🤖️ ', '\n\n'];
5
+ const [joinL1, joinL2] = [a => a.join('${LN2}---${LN2}'), a => a.join(LN2)];
6
+
7
+ const action = async (bot) => {
8
+ bot.use(async (ctx, next) => {
9
+ if (ctx.end || !ctx.text) { return await next(); }
10
+ const [multiAi, msgs, tts, pms] = [ctx.session.ai.size > 1, {}, {}, []];
11
+ let [lastMsg, lastSent] = ['', 0];
12
+ const packMsg = (options) => {
13
+ const packed = [...ctx.stt ? joinL2([YOU, ctx.stt]) : []];
14
+ const source = options?.tts ? tts : msgs;
15
+ for (let name of ctx.session.ai.size ? ctx.session.ai : [ctx.firstAi]) {
16
+ const defaultAi = name === ctx.firstAi;
17
+ packed.push(joinL2([
18
+ ...multiAi || !defaultAi || ctx.stt ? [`${BOT}${name}:`] : [],
19
+ options?.onProgress ? (
20
+ source[name] ? `${source[name].trim()} |` : '...'
21
+ ) : (source[name] || ''),
22
+ ]));
23
+ }
24
+ return joinL1(packed);
25
+ };
26
+ const ok = async (options) => {
27
+ const [curTime, curMsg] = [Date.now(), packMsg(options)];
28
+ if (options?.onProgress && (
29
+ curTime - lastSent < ctx.limit || lastMsg === curMsg
30
+ )) { return; }
31
+ [lastSent, lastMsg] = [curTime, curMsg];
32
+ return await ctx.ok(curMsg, options);
33
+ };
34
+ await ok(onProgress);
35
+ for (let name of ctx.session.ai.size ? ctx.session.ai : [ctx.firstAi]) {
36
+ if (utilitas.insensitiveCompare('/clear', ctx.text)) {
37
+ bot.ai[name].clear(ctx.chatId);
38
+ ctx.text = bot.hello;
39
+ }
40
+ pms.push((async () => {
41
+ try {
42
+ const resp = await bot.ai[name].send(
43
+ ctx.text, { session: ctx.chatId },
44
+ tkn => {
45
+ msgs[name] = `${(msgs[name] || '')}${tkn}`;
46
+ ok(onProgress);
47
+ }
48
+ );
49
+ msgs[name] = resp.responseRendered;
50
+ tts[name] = resp.spokenText;
51
+ } catch (err) {
52
+ msgs[name] = `[ERROR] ${err?.message || err}`;
53
+ tts[name] = msgs[name];
54
+ utilitas.log(err);
55
+ }
56
+ })());
57
+ }
58
+ await Promise.all(pms);
59
+ await ok();
60
+ ctx.tts = packMsg({ tts: true });
61
+ await next();
62
+ });
63
+ };
64
+
65
+ export const { run, priority, func } = {
66
+ run: true,
67
+ priority: 30,
68
+ name: 'ai',
69
+ func: action,
70
+ };
package/skills/cmd.mjs ADDED
@@ -0,0 +1,29 @@
1
+ import { utilitas } from 'utilitas';
2
+
3
+ const matchReg = /^\/([^\ ]*)(.*)$/ig;
4
+
5
+ const action = async (bot) => {
6
+ bot.use(async (ctx, next) => {
7
+ if (ctx.end || !ctx.text) { return await next(); }
8
+ ctx.session.ai || (ctx.session.ai = new Set());
9
+ const curAi = new Set();
10
+ ctx.cmd = ctx.text.split('\n')?.[0]?.replace(matchReg, '$1');
11
+ for (let name in bot.ai) {
12
+ ctx.firstAi || (ctx.firstAi = name);
13
+ (utilitas.insensitiveCompare(ctx.cmd, name) || ctx.cmd === '*')
14
+ && curAi.add(name);
15
+ }
16
+ curAi.size && (ctx.session.ai = curAi);
17
+ ctx.session.ai.size && (
18
+ ctx.text = ctx.text.replace(matchReg, '$2').trim() || bot.hello
19
+ );
20
+ await next();
21
+ });
22
+ };
23
+
24
+ export const { run, priority, func } = {
25
+ run: true,
26
+ priority: 10,
27
+ name: 'ai',
28
+ func: action,
29
+ };
@@ -0,0 +1,40 @@
1
+ const getTranslatePrompt = (lang) => // https://github.com/yetone/bob-plugin-openai-translator/blob/main/src/main.js
2
+ 'You are a translation engine that can only translate text and cannot interpret it.'
3
+ + ` Translate the following text into ${lang}: `;
4
+ const getPolishPrompt = () => // https://github.com/yetone/bob-plugin-openai-polisher/blob/main/src/main.js
5
+ 'Revise the following text to make them more clear, concise, and coherent.'
6
+ + ' Please note that you need to list the changes and briefly explain why: ';
7
+
8
+ const action = async (bot) => {
9
+ bot.use(async (ctx, next) => {
10
+ if (ctx.end || !ctx.text) { return await next(); }
11
+ switch (ctx.cmd) {
12
+ case '2en':
13
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getTranslatePrompt('English'));
14
+ break;
15
+ case '2zh':
16
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getTranslatePrompt('Traditional Chinese'));
17
+ break;
18
+ case '2zht':
19
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getTranslatePrompt('Traditional Chinese'));
20
+ break;
21
+ case '2zhs':
22
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getTranslatePrompt('Simplified Chinese'));
23
+ break;
24
+ case '2fr':
25
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getTranslatePrompt('French'));
26
+ break;
27
+ case 'p':
28
+ ctx.text = ctx.text.replace(`/${ctx.cmd}`, getPolishPrompt());
29
+ break;
30
+ }
31
+ await next();
32
+ });
33
+ };
34
+
35
+ export const { run, priority, func } = {
36
+ run: true,
37
+ priority: 20,
38
+ name: 'ai',
39
+ func: action,
40
+ };
File without changes