diff --git a/package-lock.json b/package-lock.json index 7d56a7e5..2ca049d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,11 @@ "license": "MIT", "dependencies": { "@elastic/elasticsearch": "^8.9.0", + "@google-cloud/text-to-speech": "^5.0.1", "@grammyjs/auto-chat-action": "^0.1.1", "@grammyjs/auto-retry": "^1.1.1", "@grammyjs/conversations": "^1.1.2", + "@grammyjs/files": "^1.0.4", "@grammyjs/menu": "^1.2.1", "@grammyjs/ratelimiter": "^1.2.0", "@grammyjs/runner": "^2.0.3", @@ -29,7 +31,7 @@ "express-async-handler": "^1.2.0", "form-data": "^4.0.0", "gpt-tokenizer": "^2.1.1", - "grammy": "^1.17.1", + "grammy": "^1.18.3", "jsqr": "^1.4.0", "litllm": "^3.0.0", "lokijs": "^1.5.12", @@ -2911,6 +2913,17 @@ "@ethersproject/strings": "^5.7.0" } }, + "node_modules/@google-cloud/text-to-speech": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/text-to-speech/-/text-to-speech-5.0.1.tgz", + "integrity": "sha512-ERuxvrgIT4On+7bq5Q4ZapYU6qvHhsjPwuXapoff+82VmGjgqgNL+ICMRRq4BbDGai3R68StF3lsSPb2X5OtNw==", + "dependencies": { + "google-gax": "^4.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@grammyjs/auto-chat-action": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@grammyjs/auto-chat-action/-/auto-chat-action-0.1.1.tgz", @@ -2943,6 +2956,17 @@ "grammy": "^1.10.0" } }, + "node_modules/@grammyjs/files": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@grammyjs/files/-/files-1.0.4.tgz", + "integrity": "sha512-GT7JWRH9cs5kIrBtUGwMwVEhb1w7Vtnc93UT3zM/HYigmeVd93wWaIqyuSYsZq1VIB+9CSk0oz+ZsnxK83z7tg==", + "engines": { + "node": "^12.20.0 || >=14.13.1" + }, + "peerDependencies": { + "grammy": "^1.3.0" + } + }, "node_modules/@grammyjs/menu": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@grammyjs/menu/-/menu-1.2.1.tgz", @@ -2974,9 +2998,100 @@ } }, "node_modules/@grammyjs/types": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-3.1.2.tgz", - "integrity": "sha512-AsSkTUfZCfSEIacUBOQ94qLbZZy3UofkschWv4uBJKEHjuEfGnjeZZgiwhDfTDjmpmW+MbcasvS+FEfD2jiSLw==" + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-3.2.2.tgz", + "integrity": "sha512-ycKdX7sfjtrKUzKmzQeDrHdsIetcuu8Wbz7WDZtOj2PmJrYGYbC40R7O2v7vhncmQNKUgu8YSvADPKCmnTb73Q==" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.3.tgz", + "integrity": "sha512-b8iWtdrYIeT5fdZdS4Br/6h/kuk0PW5EVBUGk1amSbrpL8DlktJD43CdcCWwRdd6+jgwHhADSbL9CsNnm6EUPA==", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@grpc/proto-loader/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", @@ -3682,6 +3797,60 @@ "node": ">=14" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@scure/base": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", @@ -4250,6 +4419,11 @@ "@types/node": "*" } }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -5865,6 +6039,11 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -7361,6 +7540,14 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8759,6 +8946,55 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/gaxios": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz", + "integrity": "sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.0.0.tgz", + "integrity": "sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -8941,6 +9177,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/google-auth-library": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.0.0.tgz", + "integrity": "sha512-IQGjgQoVUAfOk6khqTVMLvWx26R+yPw9uLyb1MNyMQpdKiKt0Fd9sp4NWoINjyGHR8S3iw12hMTYK7O8J07c6Q==", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.0.0", + "gcp-metadata": "^6.0.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-gax": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.0.4.tgz", + "integrity": "sha512-Yoey/ABON2HaTUIRUt5tTQAvwQ6E/2etSyFXwHNVcYtIiYDpKix7G4oorZdkp17gFiYovzRCRhRZYrfdCgRK9Q==", + "dependencies": { + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.0", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "google-auth-library": "^9.0.0", + "node-fetch": "^2.6.1", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^2.0.0", + "protobufjs": "7.2.5", + "retry-request": "^6.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8992,14 +9277,14 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/grammy": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.17.1.tgz", - "integrity": "sha512-ba1xsEVMoEjvTZNhOvSYt/dgoIFbMKYnFKHw3iioKYbQMCBsoX+FbO5hRse+sxhNwQzkDmiUtzAcK5elpEJg2w==", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.18.3.tgz", + "integrity": "sha512-XnqFeADCXzq90zgGG8Ah8iOdoSf2PjpHf5ki09DMSbkg2KC7MraOHO2DAtlEjGxjqDQeGnHIHOktMWB0mj82VQ==", "dependencies": { - "@grammyjs/types": "3.1.2", + "@grammyjs/types": "3.2.2", "abort-controller": "^3.0.0", "debug": "^4.3.4", - "node-fetch": "^2.6.11" + "node-fetch": "^2.7.0" }, "engines": { "node": "^12.20.0 || >=14.13.1" @@ -9011,6 +9296,18 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gtoken": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", + "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -9759,7 +10056,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -10625,6 +10921,14 @@ "node": ">=4" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -10704,6 +11008,25 @@ "node": "*" } }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keccak": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", @@ -10820,6 +11143,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -10860,6 +11188,11 @@ "resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.12.tgz", "integrity": "sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==" }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -11467,9 +11800,9 @@ "integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==" }, "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -11732,6 +12065,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -12652,6 +12993,40 @@ "node": ">= 6" } }, + "node_modules/proto3-json-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.0.tgz", + "integrity": "sha512-FB/YaNrpiPkyQNSNPilpn8qn0KdEfkgmJ9JP93PQyF/U4bAiXY5BiUdDhiDO4S48uSQ6AesklgVlrKiqZPzegw==", + "dependencies": { + "protobufjs": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -13157,6 +13532,18 @@ "node": ">= 4" } }, + "node_modules/retry-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-6.0.0.tgz", + "integrity": "sha512-24kaFMd3wCnT3n4uPnsQh90ZSV8OISpfTFXJ00Wi+/oD2OPrp63EQ8hznk6rhxdlpwx2QBhQSDz2Fg46ki852g==", + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", diff --git a/package.json b/package.json index 6d242436..feec2173 100644 --- a/package.json +++ b/package.json @@ -74,9 +74,11 @@ }, "dependencies": { "@elastic/elasticsearch": "^8.9.0", + "@google-cloud/text-to-speech": "^5.0.1", "@grammyjs/auto-chat-action": "^0.1.1", "@grammyjs/auto-retry": "^1.1.1", "@grammyjs/conversations": "^1.1.2", + "@grammyjs/files": "^1.0.4", "@grammyjs/menu": "^1.2.1", "@grammyjs/ratelimiter": "^1.2.0", "@grammyjs/runner": "^2.0.3", @@ -93,7 +95,7 @@ "express-async-handler": "^1.2.0", "form-data": "^4.0.0", "gpt-tokenizer": "^2.1.1", - "grammy": "^1.17.1", + "grammy": "^1.18.3", "jsqr": "^1.4.0", "litllm": "^3.0.0", "lokijs": "^1.5.12", diff --git a/src/bot.ts b/src/bot.ts index 1c86ccb8..2f9a9272 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -49,6 +49,8 @@ import * as Sentry from '@sentry/node' import * as Events from 'events' import { ProfilingIntegration } from '@sentry/profiling-node' import { ES } from './es' +import { hydrateFiles } from '@grammyjs/files' +import { VoiceTranslateBot } from './modules/voice-translate' Events.EventEmitter.defaultMaxListeners = 30 @@ -61,6 +63,7 @@ const logger = pino({ }) export const bot = new Bot(config.telegramBotAuthToken) +bot.api.config.use(hydrateFiles(bot.token)) bot.api.config.use(autoRetry()) bot.use( @@ -212,6 +215,7 @@ const translateBot = new TranslateBot() const llmsBot = new LlmsBot(payments) const documentBot = new DocumentHandler() const telegramPayments = new TelegramPayments(payments) +const voiceTranslateBot = new VoiceTranslateBot(payments) bot.on('message:new_chat_members:me', async (ctx) => { try { @@ -321,6 +325,7 @@ const writeCommandLog = async ( const PayableBots: Record = { qrCodeBot: { bot: qrCodeBot }, sdImagesBot: { bot: sdImagesBot }, + voiceTranslate: { bot: voiceTranslateBot }, voiceMemo: { bot: voiceMemo }, documentBot: { bot: documentBot }, translateBot: { bot: translateBot }, diff --git a/src/config.ts b/src/config.ts index c50deff8..b0f0eb51 100644 --- a/src/config.ts +++ b/src/config.ts @@ -148,5 +148,5 @@ export default { password: process.env.ES_PASSWORD ?? '', index: process.env.ES_INDEX }, - deepL: { apikey: process.env.DEEPL_API_KEY ?? '' } + gc: { credentials: process.env.GC_CREDENTIALS ?? '' } } diff --git a/src/modules/open-ai/api/openAi.ts b/src/modules/open-ai/api/openAi.ts index a2285d82..49d2abd8 100644 --- a/src/modules/open-ai/api/openAi.ts +++ b/src/modules/open-ai/api/openAi.ts @@ -17,6 +17,7 @@ import { type DalleGPTModel, DalleGPTModels } from '../types' +import type fs from 'fs' const openai = new OpenAI({ apiKey: config.openAiKey }) @@ -245,3 +246,12 @@ export function getGrammy429Error (): GrammyError { { parameters: { retry_after: 33 } } ) } + +export async function speechToText (readStream: fs.ReadStream): Promise { + const result = await openai.audio.transcriptions.create({ + file: readStream, + model: 'whisper-1' + }) + + return result.text +} diff --git a/src/modules/types.ts b/src/modules/types.ts index 295ff5e2..f47bc514 100644 --- a/src/modules/types.ts +++ b/src/modules/types.ts @@ -11,6 +11,7 @@ import { import { type AutoChatActionFlavor } from '@grammyjs/auto-chat-action' import { type ParseMode } from 'grammy/types' import { type InlineKeyboardMarkup } from 'grammy/out/types' +import type { FileFlavor } from '@grammyjs/files' export interface ImageGenSessionData { numImages: number @@ -99,10 +100,10 @@ export interface BotSessionData { analytics: Analytics } -export type BotContext = Context & +export type BotContext = FileFlavor & ConversationFlavor & -AutoChatActionFlavor +AutoChatActionFlavor> export type CustomContext = Filter export type OnMessageContext = CustomContext<'message'> diff --git a/src/modules/voice-translate/client.ts b/src/modules/voice-translate/client.ts new file mode 100644 index 00000000..3ce130c2 --- /dev/null +++ b/src/modules/voice-translate/client.ts @@ -0,0 +1,17 @@ +import GcTextToSpeech from '@google-cloud/text-to-speech' +import config from '../../config' + +const credentials = JSON.parse(Buffer.from(config.gc.credentials, 'base64').toString('utf-8')) +const client = new GcTextToSpeech.TextToSpeechClient({ credentials }) + +export async function textToSpeech (text: string): Promise { + const ssml = `${text}` + + const [response] = await client.synthesizeSpeech({ + input: { ssml }, + voice: { languageCode: 'en-US', ssmlGender: 'MALE' }, + audioConfig: { audioEncoding: 'MP3' } + }) + + return response.audioContent +} diff --git a/src/modules/voice-translate/index.ts b/src/modules/voice-translate/index.ts new file mode 100644 index 00000000..38541331 --- /dev/null +++ b/src/modules/voice-translate/index.ts @@ -0,0 +1,77 @@ +import fs from 'fs' +import pino from 'pino' +import { InputFile } from 'grammy' +import type { Logger } from 'pino' +import { textToSpeech } from './client' +import type { BotPayments } from '../payment' +import { speechToText } from '../open-ai/api/openAi' +import type { OnMessageContext, PayableBot } from '../types' + +export class VoiceTranslateBot implements PayableBot { + private readonly payments: BotPayments + + private readonly logger: Logger + + constructor (payments: BotPayments) { + this.payments = payments + this.logger = pino({ + name: 'VoiceTranslate', + transport: { + target: 'pino-pretty', + options: { colorize: true } + } + }) + } + + public isSupportedEvent (ctx: OnMessageContext): boolean { + const { voice, audio } = ctx.update.message + + return (!!voice || !!audio) + } + + public getEstimatedPrice (ctx: OnMessageContext): number { + return 0 + } + + public async onEvent (ctx: OnMessageContext): Promise { + const { voice, audio } = ctx.update.message + + if (!(!!voice || !!audio)) { + return + } + + const message = await ctx.reply('Waite a moment...') + + if (!ctx.chat?.id) { + throw Error('chat id is undefined') + } + + const file = await ctx.getFile() + const path = await file.download() + + let ext = 'ogg' + + if (file.file_path) { + ext = file.file_path.split('.').pop() ?? ext + } + + const filename = path + '.' + ext + fs.renameSync(path, filename) + + const resultText = await speechToText(fs.createReadStream(filename)) + fs.rmSync(filename) + + const voiceResult = await textToSpeech(resultText) + + if (!voiceResult) { + await ctx.reply('voice generation error') + return + } + + await ctx.api.editMessageText(ctx.chat.id, message.message_id, resultText) + + const inputFile = new InputFile(voiceResult) + + await ctx.replyWithVoice(inputFile) + } +}