bump libs
migrate to typescript 6 remove ytdl feature
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": false,
|
||||||
"es2021": true
|
"es2021": true
|
||||||
},
|
},
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "tg-chat-bot",
|
"name": "tg-chat-bot",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^1.50.1",
|
"@google/genai": "^1.51.0",
|
||||||
"@libsql/client": "^0.17.3",
|
"@libsql/client": "^0.17.3",
|
||||||
"@mistralai/mistralai": "^2.2.1",
|
"@mistralai/mistralai": "^2.2.1",
|
||||||
"@napi-rs/canvas": "^0.1.100",
|
"@napi-rs/canvas": "^0.1.100",
|
||||||
@@ -24,8 +24,7 @@
|
|||||||
"systeminformation": "^5.31.5",
|
"systeminformation": "^5.31.5",
|
||||||
"twemoji": "^14.0.2",
|
"twemoji": "^14.0.2",
|
||||||
"typescript-telegram-bot-api": "^0.14.0",
|
"typescript-telegram-bot-api": "^0.14.0",
|
||||||
"youtubei.js": "^17.0.1",
|
"zod": "^4.4.1",
|
||||||
"zod": "^4.3.6",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.13",
|
||||||
@@ -34,10 +33,10 @@
|
|||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
||||||
"@typescript-eslint/parser": "^8.59.1",
|
"@typescript-eslint/parser": "^8.59.1",
|
||||||
"drizzle-kit": "^1.0.0-beta.22",
|
"drizzle-kit": "^1.0.0-rc.1",
|
||||||
"eslint": "^10.2.1",
|
"eslint": "^10.2.1",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^6.0.3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -46,8 +45,6 @@
|
|||||||
|
|
||||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
||||||
|
|
||||||
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.11.0", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
|
|
||||||
|
|
||||||
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
|
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
|
||||||
|
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
|
"@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
|
||||||
@@ -118,7 +115,7 @@
|
|||||||
|
|
||||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="],
|
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="],
|
||||||
|
|
||||||
"@google/genai": ["@google/genai@1.50.1", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-YbkX7H9+1Pt8wOt7DDREy8XSoiL6fRDzZQRyaVBarFf8MR3zHGqVdvM4cLbDXqPhxqvegZShgfxb8kw9C7YhAQ=="],
|
"@google/genai": ["@google/genai@1.51.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "p-retry": "^4.6.2", "protobufjs": "^7.5.4", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.2" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-vTZZF3CSimN7cn2zsLpW2p5WF0eZa5Gz69ITMPCNHpPrDlAstOfGifSfi0p/s9Z9400f7xJRkgvkQNrcM7pJ6w=="],
|
||||||
|
|
||||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||||
|
|
||||||
@@ -406,7 +403,7 @@
|
|||||||
|
|
||||||
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
|
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
|
||||||
|
|
||||||
"drizzle-kit": ["drizzle-kit@1.0.0-beta.9-e89174b", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "tsx": "^4.20.6" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-Xrw3k8E2CbSZr+kqe3k5W4oxd2fbEyczjKtyGIkAq0x9Wqpa/VtAT6Mkh83sIzqG4OSN7lOoUafsDxSE/AR7RA=="],
|
"drizzle-kit": ["drizzle-kit@1.0.0-rc.1", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "get-tsconfig": "^4.13.6", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-eDvXzRhke7OwvmN7AciGOU1E2y17MKNhghGciyw1RbmmkuD/2KDXLn3rFRZcDBmfj6CQSEnyvbU+7Fqrn2JQyA=="],
|
||||||
|
|
||||||
"drizzle-orm": ["drizzle-orm@1.0.0-beta.22", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/mssql", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mssql", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-F+DZyVIvH0oVKa/w08Cle1xfoH+pc+htIXHG/frnMLG72aby9NYYr9oc+9XvghnoO4umxFItduz0OMmQJMnenw=="],
|
"drizzle-orm": ["drizzle-orm@1.0.0-beta.22", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/mssql", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mssql", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-F+DZyVIvH0oVKa/w08Cle1xfoH+pc+htIXHG/frnMLG72aby9NYYr9oc+9XvghnoO4umxFItduz0OMmQJMnenw=="],
|
||||||
|
|
||||||
@@ -520,7 +517,7 @@
|
|||||||
|
|
||||||
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||||
|
|
||||||
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
|
"get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="],
|
||||||
|
|
||||||
"get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
|
"get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
|
||||||
|
|
||||||
@@ -580,6 +577,8 @@
|
|||||||
|
|
||||||
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||||
|
|
||||||
|
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||||
|
|
||||||
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
|
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
|
||||||
|
|
||||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||||
@@ -626,8 +625,6 @@
|
|||||||
|
|
||||||
"merge-deep": ["merge-deep@3.0.3", "", { "dependencies": { "arr-union": "^3.1.0", "clone-deep": "^0.2.4", "kind-of": "^3.0.2" } }, "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA=="],
|
"merge-deep": ["merge-deep@3.0.3", "", { "dependencies": { "arr-union": "^3.1.0", "clone-deep": "^0.2.4", "kind-of": "^3.0.2" } }, "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA=="],
|
||||||
|
|
||||||
"meriyah": ["meriyah@6.1.4", "", {}, "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ=="],
|
|
||||||
|
|
||||||
"mime-db": ["mime-db@1.46.0", "", {}, "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="],
|
"mime-db": ["mime-db@1.46.0", "", {}, "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="],
|
||||||
|
|
||||||
"mime-types": ["mime-types@2.1.29", "", { "dependencies": { "mime-db": "1.46.0" } }, "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ=="],
|
"mime-types": ["mime-types@2.1.29", "", { "dependencies": { "mime-db": "1.46.0" } }, "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ=="],
|
||||||
@@ -794,7 +791,7 @@
|
|||||||
|
|
||||||
"typed-query-selector": ["typed-query-selector@2.12.1", "", {}, "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA=="],
|
"typed-query-selector": ["typed-query-selector@2.12.1", "", {}, "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
||||||
|
|
||||||
"typescript-telegram-bot-api": ["typescript-telegram-bot-api@0.14.0", "", { "dependencies": { "axios": "^1.7.7", "form-data": "^4.0.1" } }, "sha512-PjigN50TxenH5LjPLqiZopyNizy3tObh3bdLmKwPBo+rW7zUt7iNzJKcNnX7FkMZUmJ2DBvnZ+W+L4oQNwU7eQ=="],
|
"typescript-telegram-bot-api": ["typescript-telegram-bot-api@0.14.0", "", { "dependencies": { "axios": "^1.7.7", "form-data": "^4.0.1" } }, "sha512-PjigN50TxenH5LjPLqiZopyNizy3tObh3bdLmKwPBo+rW7zUt7iNzJKcNnX7FkMZUmJ2DBvnZ+W+L4oQNwU7eQ=="],
|
||||||
|
|
||||||
@@ -834,9 +831,7 @@
|
|||||||
|
|
||||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||||
|
|
||||||
"youtubei.js": ["youtubei.js@17.0.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "meriyah": "^6.1.4" } }, "sha512-1lO4b8UqMDzE0oh2qEGzbBOd4UYRdxn/4PdpRM7BGTHxM6ddsEsKZTu90jp8V9FHVgC2h1UirQyqoqLiKwl+Zg=="],
|
"zod": ["zod@4.4.1", "", {}, "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q=="],
|
||||||
|
|
||||||
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
|
||||||
|
|
||||||
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
|
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
|
||||||
|
|
||||||
@@ -850,6 +845,8 @@
|
|||||||
|
|
||||||
"@libsql/isomorphic-ws/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
"@libsql/isomorphic-ws/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||||
|
|
||||||
|
"@mistralai/mistralai/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||||
|
|
||||||
"@puppeteer/browsers/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
"@puppeteer/browsers/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||||
|
|
||||||
"@puppeteer/browsers/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
"@puppeteer/browsers/yargs": ["yargs@17.7.2", "", { "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" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||||
@@ -902,6 +899,8 @@
|
|||||||
|
|
||||||
"tsx/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
"tsx/esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
||||||
|
|
||||||
|
"tsx/get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
|
||||||
|
|
||||||
"yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="],
|
"yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="],
|
||||||
|
|
||||||
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
"@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||||
|
|||||||
Generated
+677
-1162
File diff suppressed because it is too large
Load Diff
+4
-5
@@ -8,7 +8,7 @@
|
|||||||
"bun:start": "bun run dist/index.js"
|
"bun:start": "bun run dist/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^1.50.1",
|
"@google/genai": "^1.51.0",
|
||||||
"@libsql/client": "^0.17.3",
|
"@libsql/client": "^0.17.3",
|
||||||
"@mistralai/mistralai": "^2.2.1",
|
"@mistralai/mistralai": "^2.2.1",
|
||||||
"@napi-rs/canvas": "^0.1.100",
|
"@napi-rs/canvas": "^0.1.100",
|
||||||
@@ -27,8 +27,7 @@
|
|||||||
"systeminformation": "^5.31.5",
|
"systeminformation": "^5.31.5",
|
||||||
"twemoji": "^14.0.2",
|
"twemoji": "^14.0.2",
|
||||||
"typescript-telegram-bot-api": "^0.14.0",
|
"typescript-telegram-bot-api": "^0.14.0",
|
||||||
"youtubei.js": "^17.0.1",
|
"zod": "^4.4.1"
|
||||||
"zod": "^4.3.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.13",
|
||||||
@@ -37,9 +36,9 @@
|
|||||||
"@types/fluent-ffmpeg": "^2.1.28",
|
"@types/fluent-ffmpeg": "^2.1.28",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
||||||
"@typescript-eslint/parser": "^8.59.1",
|
"@typescript-eslint/parser": "^8.59.1",
|
||||||
"drizzle-kit": "^1.0.0-beta.22",
|
"drizzle-kit": "^1.0.0-rc.1",
|
||||||
"eslint": "^10.2.1",
|
"eslint": "^10.2.1",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^6.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export abstract class CallbackCommand {
|
|||||||
|
|
||||||
abstract text: string;
|
abstract text: string;
|
||||||
abstract data: string;
|
abstract data: string;
|
||||||
requirements?: Requirements = null;
|
requirements?: Requirements | null = null;
|
||||||
|
|
||||||
abstract execute(query: CallbackQuery): Promise<void>;
|
abstract execute(query: CallbackQuery): Promise<void>;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -9,7 +9,7 @@ export abstract class Command {
|
|||||||
command?: string | string[];
|
command?: string | string[];
|
||||||
argsMode: ArgsMode = "none";
|
argsMode: ArgsMode = "none";
|
||||||
|
|
||||||
requirements?: Requirements = null;
|
requirements?: Requirements | null = null;
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export abstract class Command {
|
|||||||
|
|
||||||
abstract execute(
|
abstract execute(
|
||||||
msg: Message,
|
msg: Message,
|
||||||
match?: RegExpExecArray
|
match?: RegExpExecArray | null
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export class Requirements {
|
|||||||
requirements: Requirement[] = [];
|
requirements: Requirement[] = [];
|
||||||
|
|
||||||
private constructor(requirements?: Requirement[]) {
|
private constructor(requirements?: Requirement[]) {
|
||||||
this.requirements = requirements;
|
this.requirements = requirements || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Build(...requirements: Requirement[]): Requirements {
|
static Build(...requirements: Requirement[]): Requirements {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {CallbackCommand} from "../base/callback-command";
|
|||||||
export class Cancel extends CallbackCommand {
|
export class Cancel extends CallbackCommand {
|
||||||
|
|
||||||
text = "❌ Отменить";
|
text = "❌ Отменить";
|
||||||
data = null;
|
data = "";
|
||||||
|
|
||||||
constructor(text?: string, data?: string) {
|
constructor(text?: string, data?: string) {
|
||||||
super();
|
super();
|
||||||
@@ -13,7 +13,7 @@ export class Cancel extends CallbackCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static withData(data?: string): Cancel {
|
static withData(data?: string): Cancel {
|
||||||
return new Cancel(null, data);
|
return new Cancel("", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import {CallbackCommand} from "../base/callback-command";
|
|
||||||
import {CallbackQuery} from "typescript-telegram-bot-api";
|
|
||||||
import {Requirements} from "../base/requirements";
|
|
||||||
import {Requirement} from "../base/requirement";
|
|
||||||
import {commands} from "../index";
|
|
||||||
import {YouTubeDownload} from "../commands/youtube-download";
|
|
||||||
|
|
||||||
const downloadText = " 📥 Скачать";
|
|
||||||
const getFromCacheText = "📥 Загрузить из кэша";
|
|
||||||
|
|
||||||
export class DownloadYtVideo extends CallbackCommand {
|
|
||||||
data = "/ytdl";
|
|
||||||
text = " 📥 Скачать";
|
|
||||||
|
|
||||||
requirements = Requirements.Build(Requirement.SAME_USER);
|
|
||||||
|
|
||||||
constructor(text?: string, data?: string) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.text = text || this.text;
|
|
||||||
this.data = data || this.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static withData(inCache?: boolean, data?: string): DownloadYtVideo {
|
|
||||||
return new DownloadYtVideo(inCache ? getFromCacheText : downloadText, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(query: CallbackQuery): Promise<void> {
|
|
||||||
const videoId = query.data.split(" ")[1];
|
|
||||||
if (!videoId) return;
|
|
||||||
|
|
||||||
const yt = commands.find(c => c instanceof YouTubeDownload);
|
|
||||||
if (!yt) return;
|
|
||||||
await yt.downloadYouTubeVideo(query.message, {videoId: videoId});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,8 @@ export class OllamaCancel extends CallbackCommand {
|
|||||||
requirements = Requirements.Build(Requirement.SAME_USER);
|
requirements = Requirements.Build(Requirement.SAME_USER);
|
||||||
|
|
||||||
async execute(query: CallbackQuery): Promise<void> {
|
async execute(query: CallbackQuery): Promise<void> {
|
||||||
|
if (!query.message || !query.data) return;
|
||||||
|
|
||||||
const chatId = query.message.chat.id;
|
const chatId = query.message.chat.id;
|
||||||
const fromId = query.from.id;
|
const fromId = query.from.id;
|
||||||
const messageId = query.message.message_id;
|
const messageId = query.message.message_id;
|
||||||
@@ -44,7 +46,7 @@ export class OllamaCancel extends CallbackCommand {
|
|||||||
|
|
||||||
let content: string | null = null;
|
let content: string | null = null;
|
||||||
|
|
||||||
if (msg?.text?.trim()?.length > 0) {
|
if (msg?.text?.trim()?.length) {
|
||||||
content = msg?.text.trim();
|
content = msg?.text.trim();
|
||||||
if (content.length + Environment.ollamaCancelledText.length > 4096) {
|
if (content.length + Environment.ollamaCancelledText.length > 4096) {
|
||||||
content = content.substring(0, 4096 - Environment.ollamaCancelledText.length - 2) + "\n";
|
content = content.substring(0, 4096 - Environment.ollamaCancelledText.length - 2) + "\n";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class TryAgain extends CallbackCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static withData(data?: string): TryAgain {
|
static withData(data?: string): TryAgain {
|
||||||
return new TryAgain(null, data);
|
return new TryAgain("", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import {CallbackCommand} from "../base/callback-command";
|
|
||||||
import {CallbackQuery} from "typescript-telegram-bot-api";
|
|
||||||
import {processYouTubeLink} from "../util/utils";
|
|
||||||
|
|
||||||
export class YtInfo extends CallbackCommand {
|
|
||||||
data = "/ytinfo";
|
|
||||||
text: string;
|
|
||||||
|
|
||||||
async execute(query: CallbackQuery): Promise<void> {
|
|
||||||
const videoId = query.data.split(" ")[1];
|
|
||||||
if (!videoId) return;
|
|
||||||
|
|
||||||
await processYouTubeLink(query.message, null, videoId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,7 @@ export class AdminsAdd extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const id = msg.reply_to_message.from.id;
|
const id = msg.reply_to_message.from.id;
|
||||||
const text = fullName(msg.reply_to_message.from);
|
const text = fullName(msg.reply_to_message.from);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class AdminsRemove extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const id = msg.reply_to_message.from.id;
|
const id = msg.reply_to_message.from.id;
|
||||||
const text = fullName(msg.reply_to_message.from);
|
const text = fullName(msg.reply_to_message.from);
|
||||||
|
|||||||
+2
-2
@@ -13,7 +13,7 @@ export class Ae extends Command {
|
|||||||
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
async execute(msg: Message, params?: RegExpExecArray) {
|
async execute(msg: Message, params?: RegExpExecArray) {
|
||||||
const match = params?.[3];
|
const match = params?.[3] || "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let e = eval(match);
|
let e = eval(match);
|
||||||
@@ -21,7 +21,7 @@ export class Ae extends Command {
|
|||||||
e = ((typeof e == "string") ? e : JSON.stringify(e));
|
e = ((typeof e == "string") ? e : JSON.stringify(e));
|
||||||
|
|
||||||
await oldSendMessage(msg, e).catch(async () => await errorPlaceholder(msg));
|
await oldSendMessage(msg, e).catch(async () => await errorPlaceholder(msg));
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
const text = e.message.toString();
|
const text = e.message.toString();
|
||||||
|
|
||||||
if (text.includes("is not defined")) {
|
if (text.includes("is not defined")) {
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ export class Ban extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.from || ! msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const user = msg.reply_to_message.from;
|
const user = msg.reply_to_message.from;
|
||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class Choice extends Command {
|
|||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
|
|
||||||
const payload = match[3];
|
const payload = match?.[3] || "";
|
||||||
|
|
||||||
const re =
|
const re =
|
||||||
/\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^,]+?))\s*(?:,|$)/g;
|
/\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^,]+?))\s*(?:,|$)/g;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export class Dice extends Command {
|
|||||||
description = "Sends random or specific dice";
|
description = "Sends random or specific dice";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
const split = msg.text.split("/dice ");
|
const split = msg.text?.split("/dice ");
|
||||||
const secondPart = split[1]?.trim();
|
const secondPart = split?.[1]?.trim() || "";
|
||||||
const emojiIndex = emojis.indexOf(secondPart);
|
const emojiIndex = emojis.indexOf(secondPart);
|
||||||
const emojiToDice: DiceEmoji = (emojiIndex >= 0 ? emojis[emojiIndex] : randomValue(emojis)) as DiceEmoji;
|
const emojiToDice: DiceEmoji = (emojiIndex >= 0 ? emojis[emojiIndex] : randomValue(emojis)) as DiceEmoji;
|
||||||
|
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ export class Distort extends Command {
|
|||||||
|
|
||||||
const inputBuf = await downloadTelegramFile(file.file_path);
|
const inputBuf = await downloadTelegramFile(file.file_path);
|
||||||
|
|
||||||
const outBuf = await waveDistortSharp(inputBuf, amp, wavelength);
|
const outBuf = await waveDistortSharp(<Buffer>inputBuf, amp, wavelength);
|
||||||
|
|
||||||
await bot.sendPhoto({
|
await bot.sendPhoto({
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
photo: outBuf,
|
photo: outBuf,
|
||||||
caption: `Искажение готово ✅ (amp=${amp}, wavelength=${wavelength})`,
|
caption: `Искажение готово ✅ (amp=${amp}, wavelength=${wavelength})`,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
await oldReplyToMessage(
|
await oldReplyToMessage(
|
||||||
msg, `Не получилось исказить изображение: ${e?.message ?? String(e)}`
|
msg, `Не получилось исказить изображение: ${e?.message ?? String(e)}`
|
||||||
).catch(logError);
|
).catch(logError);
|
||||||
|
|||||||
+22
-17
@@ -4,7 +4,7 @@ import {bot, googleAi} from "../index";
|
|||||||
import {MessageStore} from "../common/message-store";
|
import {MessageStore} from "../common/message-store";
|
||||||
import {Requirements} from "../base/requirements";
|
import {Requirements} from "../base/requirements";
|
||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {ApiError} from "@google/genai";
|
|
||||||
import {
|
import {
|
||||||
collectReplyChainText,
|
collectReplyChainText,
|
||||||
escapeMarkdownV2Text,
|
escapeMarkdownV2Text,
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
startIntervalEditor
|
startIntervalEditor
|
||||||
} from "../util/utils";
|
} from "../util/utils";
|
||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
|
import {ApiError} from "@google/genai";
|
||||||
|
|
||||||
export class GeminiChat extends ChatCommand {
|
export class GeminiChat extends ChatCommand {
|
||||||
command = "gemini";
|
command = "gemini";
|
||||||
@@ -26,11 +27,11 @@ export class GeminiChat extends ChatCommand {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeGemini(msg, match?.[3]);
|
return this.executeGemini(msg, match?.[3] || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeGemini(msg: Message, text: string): Promise<void> {
|
async executeGemini(msg: Message, text: string): Promise<void> {
|
||||||
if (!text || text.trim().length === 0) return;
|
if (!text || !text.trim().length) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ export class GeminiChat extends ChatCommand {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ export class GeminiChat extends ChatCommand {
|
|||||||
|
|
||||||
const stream = await googleAi.interactions.create({
|
const stream = await googleAi.interactions.create({
|
||||||
model: Environment.GEMINI_MODEL,
|
model: Environment.GEMINI_MODEL,
|
||||||
input: input,
|
input: input as any,
|
||||||
stream: true
|
stream: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ export class GeminiChat extends ChatCommand {
|
|||||||
await bot.editMessageText(
|
await bot.editMessageText(
|
||||||
{
|
{
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: waitMessage.message_id,
|
message_id: <number>waitMessage?.message_id,
|
||||||
text: escapeMarkdownV2Text(text),
|
text: escapeMarkdownV2Text(text),
|
||||||
parse_mode: "MarkdownV2"
|
parse_mode: "MarkdownV2"
|
||||||
}
|
}
|
||||||
@@ -117,9 +118,11 @@ export class GeminiChat extends ChatCommand {
|
|||||||
|
|
||||||
console.log("editMessageText", text);
|
console.log("editMessageText", text);
|
||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
if (waitMessage) {
|
||||||
waitMessage.text = text;
|
waitMessage.reply_to_message = msg;
|
||||||
await MessageStore.put(waitMessage);
|
waitMessage.text = text;
|
||||||
|
await MessageStore.put(waitMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
@@ -175,17 +178,19 @@ export class GeminiChat extends ChatCommand {
|
|||||||
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e: any) {
|
||||||
logError(error);
|
logError(e);
|
||||||
|
|
||||||
if (error instanceof ApiError) {
|
if (waitMessage) {
|
||||||
if (error.status === 429) {
|
if (e instanceof ApiError) {
|
||||||
await oldReplyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
|
if (e.status === 429) {
|
||||||
return;
|
await oldReplyToMessage(waitMessage, "На сегодня всё, лимиты закончились.").catch(logError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,14 +18,14 @@ export class GeminiGenerateImage extends Command {
|
|||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
|
|
||||||
const prompt = match?.[3];
|
const prompt = match?.[3] || "";
|
||||||
return this.executeGenImage(msg, prompt);
|
return this.executeGenImage(msg, prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeGenImage(msg: Message, text: string): Promise<void> {
|
async executeGenImage(msg: Message, text: string): Promise<void> {
|
||||||
if (!text || text.trim().length === 0) return;
|
if (!text || !text.trim().length) return;
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
waitMessage = await replyToMessage({
|
waitMessage = await replyToMessage({
|
||||||
@@ -47,14 +47,16 @@ export class GeminiGenerateImage extends Command {
|
|||||||
console.log(`Output ${index + 1}: ${output}`);
|
console.log(`Output ${index + 1}: ${output}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
logError(e);
|
logError(e);
|
||||||
|
|
||||||
await replyToMessage({
|
if (waitMessage) {
|
||||||
message: waitMessage,
|
await replyToMessage({
|
||||||
text: `Произошла ошибка!\n${e.toString()}`,
|
message: waitMessage,
|
||||||
link_preview_options: {is_disabled: true}
|
text: `Произошла ошибка!\n${e.toString()}`,
|
||||||
}).catch(logError);
|
link_preview_options: {is_disabled: true}
|
||||||
|
}).catch(logError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,9 @@ export class GeminiGetModel extends Command {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
vision: {supported: true},
|
vision: {supported: true},
|
||||||
ocr: null,
|
ocr: undefined,
|
||||||
thinking: {supported: info.thinking},
|
thinking: {supported: info.thinking},
|
||||||
tools: null
|
tools: undefined
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export class GeminiListModels extends Command {
|
|||||||
console.log(listResponse);
|
console.log(listResponse);
|
||||||
|
|
||||||
const modelsString = listResponse.page
|
const modelsString = listResponse.page
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => (a.name || "").localeCompare((b.name || "")))
|
||||||
.map(e => `${e.name}`)
|
.map(e => `${e.name}`)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class Help extends Command {
|
|||||||
description = "Show list of commands";
|
description = "Show list of commands";
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
|
if (!msg.from) return;
|
||||||
let text = "Commands:\n\n";
|
let text = "Commands:\n\n";
|
||||||
|
|
||||||
commands.forEach(c => {
|
commands.forEach(c => {
|
||||||
|
|||||||
+2
-2
@@ -7,9 +7,9 @@ export class Id extends Command {
|
|||||||
description = "ID of chat, user and reply (if replied to any message)";
|
description = "ID of chat, user and reply (if replied to any message)";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
let text = `chat id: \n\`\`\`${msg.chat.id}\`\`\` \nfrom id: \n\`\`\`${msg.from.id}\`\`\``;
|
let text = `chat id: \n\`\`\`${msg.chat.id}\`\`\` \nfrom id: \n\`\`\`${msg.from?.id}\`\`\``;
|
||||||
if (msg.reply_to_message) {
|
if (msg.reply_to_message) {
|
||||||
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from.id}\`\`\``;
|
text += ` \nreply id: \n\`\`\`${msg.reply_to_message.from?.id}\`\`\``;
|
||||||
}
|
}
|
||||||
|
|
||||||
await oldReplyToMessage(msg, text, "MarkdownV2").catch(logError);
|
await oldReplyToMessage(msg, text, "MarkdownV2").catch(logError);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class Ignore extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const id = msg.reply_to_message.from.id;
|
const id = msg.reply_to_message.from.id;
|
||||||
const text = fullName(msg.reply_to_message.from);
|
const text = fullName(msg.reply_to_message.from);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export class Info extends Command {
|
|||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
const aiProvider = Environment.DEFAULT_AI_PROVIDER;
|
const aiProvider = Environment.DEFAULT_AI_PROVIDER;
|
||||||
const aiModel = getCurrentModel();
|
const aiModel = getCurrentModel();
|
||||||
let aiModelCapabilities: AiModelCapabilities = {};
|
let aiModelCapabilities: AiModelCapabilities | null = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
aiModelCapabilities = await getCurrentModelCapabilities();
|
aiModelCapabilities = await getCurrentModelCapabilities();
|
||||||
@@ -33,11 +33,11 @@ export class Info extends Command {
|
|||||||
|
|
||||||
`provider: ${aiProvider.toLowerCase()}\n` +
|
`provider: ${aiProvider.toLowerCase()}\n` +
|
||||||
`model: ${aiModel}\n\n` +
|
`model: ${aiModel}\n\n` +
|
||||||
`vision${aiModelCapabilities.vision?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.vision?.supported)}\n` +
|
`vision${aiModelCapabilities?.vision?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.vision?.supported)}\n` +
|
||||||
`ocr${aiModelCapabilities.ocr?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.ocr?.supported)}\n` +
|
`ocr${aiModelCapabilities?.ocr?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.ocr?.supported)}\n` +
|
||||||
`thinking${aiModelCapabilities.thinking?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.thinking?.supported)}\n` +
|
`thinking${aiModelCapabilities?.thinking?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.thinking?.supported)}\n` +
|
||||||
`tools${aiModelCapabilities.tools?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities.tools?.supported)}\n` +
|
`tools${aiModelCapabilities?.tools?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.tools?.supported)}\n` +
|
||||||
`audio${aiModelCapabilities.audio?.external ? "(ext)": ""}: ${boolToEmoji(aiModelCapabilities.audio?.supported)}` +
|
`audio${aiModelCapabilities?.audio?.external ? "(ext)" : ""}: ${boolToEmoji(aiModelCapabilities?.audio?.supported)}` +
|
||||||
"```";
|
"```";
|
||||||
|
|
||||||
const cmds = commands.filter(c => !(c instanceof ChatCommand));
|
const cmds = commands.filter(c => !(c instanceof ChatCommand));
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ export class MistralChat extends ChatCommand {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeMistral(msg, match?.[3]);
|
return this.executeMistral(msg, match?.[3] || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeMistral(msg: Message, text: string): Promise<void> {
|
async executeMistral(msg: Message, text: string): Promise<void> {
|
||||||
if (!text || text.trim().length === 0) return;
|
if (!text || !text.trim().length) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export class MistralChat extends ChatCommand {
|
|||||||
chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
|
chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
|
||||||
}
|
}
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ export class MistralChat extends ChatCommand {
|
|||||||
|
|
||||||
if (imagesCount) {
|
if (imagesCount) {
|
||||||
try {
|
try {
|
||||||
const modelInfo = await commands.find(c => c instanceof MistralGetModel).getModelCapabilities();
|
const modelInfo = await commands.find(c => c instanceof MistralGetModel)?.getModelCapabilities();
|
||||||
if (modelInfo) {
|
if (modelInfo) {
|
||||||
if (!modelInfo.vision?.supported) {
|
if (!modelInfo.vision?.supported) {
|
||||||
await replyToMessage({
|
await replyToMessage({
|
||||||
@@ -117,7 +117,7 @@ export class MistralChat extends ChatCommand {
|
|||||||
await bot.editMessageText(
|
await bot.editMessageText(
|
||||||
{
|
{
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: waitMessage.message_id,
|
message_id: <number>waitMessage?.message_id,
|
||||||
text: escapeMarkdownV2Text(text),
|
text: escapeMarkdownV2Text(text),
|
||||||
parse_mode: "MarkdownV2"
|
parse_mode: "MarkdownV2"
|
||||||
}
|
}
|
||||||
@@ -125,9 +125,11 @@ export class MistralChat extends ChatCommand {
|
|||||||
|
|
||||||
console.log("editMessageText", text);
|
console.log("editMessageText", text);
|
||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
if (waitMessage) {
|
||||||
waitMessage.text = text;
|
waitMessage.reply_to_message = msg;
|
||||||
await MessageStore.put(waitMessage);
|
waitMessage.text = text;
|
||||||
|
await MessageStore.put(waitMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
@@ -172,9 +174,12 @@ export class MistralChat extends ChatCommand {
|
|||||||
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e: any) {
|
||||||
logError(error);
|
logError(e);
|
||||||
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
|
||||||
|
if (waitMessage) {
|
||||||
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,6 @@ import {Requirements} from "../base/requirements";
|
|||||||
import {Requirement} from "../base/requirement";
|
import {Requirement} from "../base/requirement";
|
||||||
import {mistralAi} from "../index";
|
import {mistralAi} from "../index";
|
||||||
import {AiModelCapabilities} from "../model/ai-model-capabilities";
|
import {AiModelCapabilities} from "../model/ai-model-capabilities";
|
||||||
import {BaseModelCard} from "@mistralai/mistralai/models/components/basemodelcard";
|
|
||||||
|
|
||||||
export class MistralGetModel extends Command {
|
export class MistralGetModel extends Command {
|
||||||
title = "/mistralGetModel";
|
title = "/mistralGetModel";
|
||||||
@@ -20,13 +19,13 @@ export class MistralGetModel extends Command {
|
|||||||
|
|
||||||
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
|
async getModelCapabilities(): Promise<AiModelCapabilities | null> {
|
||||||
try {
|
try {
|
||||||
const info: BaseModelCard = await mistralAi.models.retrieve({modelId: Environment.MISTRAL_MODEL}) as BaseModelCard;
|
const info = await mistralAi.models.retrieve({modelId: Environment.MISTRAL_MODEL}) as any;
|
||||||
console.log(info);
|
console.log(info);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vision: {supported: info.capabilities.vision},
|
vision: {supported: info.capabilities.vision},
|
||||||
ocr: {supported: info.capabilities.ocr},
|
ocr: {supported: info.capabilities.ocr},
|
||||||
thinking: null,
|
thinking: undefined,
|
||||||
tools: {supported: info.capabilities.functionCalling},
|
tools: {supported: info.capabilities.functionCalling},
|
||||||
audio: {supported: info.capabilities.audioTranscription}
|
audio: {supported: info.capabilities.audioTranscription}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {Requirement} from "../base/requirement";
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {mistralAi} from "../index";
|
import {mistralAi} from "../index";
|
||||||
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
|
import {logError, oldReplyToMessage, replyToMessage} from "../util/utils";
|
||||||
import {BaseModelCard} from "@mistralai/mistralai/models/components/basemodelcard";
|
|
||||||
|
|
||||||
export class MistralListModels extends Command {
|
export class MistralListModels extends Command {
|
||||||
title = "/mistralListModels";
|
title = "/mistralListModels";
|
||||||
@@ -21,7 +20,7 @@ export class MistralListModels extends Command {
|
|||||||
console.log(listResponse);
|
console.log(listResponse);
|
||||||
|
|
||||||
const modelsString = listResponse.data
|
const modelsString = listResponse.data
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => a?.name?.localeCompare(b.name || "") || -1)
|
||||||
.map(e => `${e.id}`)
|
.map(e => `${e.id}`)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
@@ -38,3 +37,41 @@ export class MistralListModels extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BaseModelCard = {
|
||||||
|
id: string;
|
||||||
|
object: string;
|
||||||
|
created?: number | undefined;
|
||||||
|
ownedBy: string;
|
||||||
|
/**
|
||||||
|
* This is populated by Harmattan, but some fields have a name
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* that we don't want to expose in the API.
|
||||||
|
*/
|
||||||
|
capabilities: ModelCapabilities;
|
||||||
|
name?: string | null | undefined;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
maxContextLength: number;
|
||||||
|
aliases?: Array<string> | undefined;
|
||||||
|
deprecation?: Date | null | undefined;
|
||||||
|
deprecationReplacementModel?: string | null | undefined;
|
||||||
|
defaultModelTemperature?: number | null | undefined;
|
||||||
|
type: "base";
|
||||||
|
};
|
||||||
|
|
||||||
|
type ModelCapabilities = {
|
||||||
|
completionChat: boolean;
|
||||||
|
functionCalling: boolean;
|
||||||
|
reasoning: boolean;
|
||||||
|
completionFim: boolean;
|
||||||
|
fineTuning: boolean;
|
||||||
|
vision: boolean;
|
||||||
|
ocr: boolean;
|
||||||
|
classification: boolean;
|
||||||
|
moderation: boolean;
|
||||||
|
audio: boolean;
|
||||||
|
audioTranscription: boolean;
|
||||||
|
audioTranscriptionRealtime: boolean;
|
||||||
|
audioSpeech: boolean;
|
||||||
|
};
|
||||||
+27
-22
@@ -28,11 +28,12 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeOllama(msg, match?.[3], match?.[1]?.toLowerCase()?.startsWith("ollamathink"));
|
return this.executeOllama(msg, match?.[3] || "", match?.[1]?.toLowerCase()?.startsWith("ollamathink"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeOllama(msg: Message, text: string, think: boolean = false, voiceB64?: string): Promise<void> {
|
async executeOllama(msg: Message, text: string, think: boolean = false, voiceB64?: string | null): Promise<void> {
|
||||||
if ((!text || text.trim().length === 0) && !voiceB64) return;
|
if (!msg.from) return;
|
||||||
|
if ((!text || !text.trim().length) && !voiceB64) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
|
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT, images: []});
|
||||||
}
|
}
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
if (!think && imagesCount) {
|
if (!think && imagesCount) {
|
||||||
try {
|
try {
|
||||||
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadImageModelInfo();
|
const modelInfo = await commands.find(c => c instanceof OllamaGetModel)?.loadImageModelInfo();
|
||||||
if (modelInfo) {
|
if (modelInfo) {
|
||||||
if (!modelInfo.vision?.supported) {
|
if (!modelInfo.vision?.supported) {
|
||||||
await replyToMessage({
|
await replyToMessage({
|
||||||
@@ -94,7 +95,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
if (think) {
|
if (think) {
|
||||||
try {
|
try {
|
||||||
const modelInfo = await commands.find(c => c instanceof OllamaGetModel).loadThinkModelInfo();
|
const modelInfo = await commands.find(c => c instanceof OllamaGetModel)?.loadThinkModelInfo();
|
||||||
if (modelInfo) {
|
if (modelInfo) {
|
||||||
if (!modelInfo.thinking?.supported) {
|
if (!modelInfo.thinking?.supported) {
|
||||||
await replyToMessage({
|
await replyToMessage({
|
||||||
@@ -131,11 +132,11 @@ export class OllamaChat extends ChatCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stream = await ollama.chat({
|
const stream = await ollama.chat({
|
||||||
model: think ? Environment.OLLAMA_THINK_MODEL : imagesCount ? Environment.OLLAMA_IMAGE_MODEL : Environment.OLLAMA_MODEL,
|
model: <string>(think ? Environment.OLLAMA_THINK_MODEL : imagesCount ? Environment.OLLAMA_IMAGE_MODEL : Environment.OLLAMA_MODEL),
|
||||||
stream: true,
|
stream: true,
|
||||||
think: think,
|
think: think,
|
||||||
messages: chatMessages,
|
messages: chatMessages,
|
||||||
options: options
|
options: <Partial<Options>>options
|
||||||
});
|
});
|
||||||
|
|
||||||
const newRequest = {
|
const newRequest = {
|
||||||
@@ -170,7 +171,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
try {
|
try {
|
||||||
await bot.editMessageText({
|
await bot.editMessageText({
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: waitMessage.message_id,
|
message_id: <number>waitMessage?.message_id,
|
||||||
text: escapeMarkdownV2Text(text),
|
text: escapeMarkdownV2Text(text),
|
||||||
parse_mode: "MarkdownV2",
|
parse_mode: "MarkdownV2",
|
||||||
reply_markup: cancelMarkup
|
reply_markup: cancelMarkup
|
||||||
@@ -178,9 +179,11 @@ export class OllamaChat extends ChatCommand {
|
|||||||
|
|
||||||
console.log("editMessageText", text);
|
console.log("editMessageText", text);
|
||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
if (waitMessage) {
|
||||||
waitMessage.text = text;
|
waitMessage.reply_to_message = msg;
|
||||||
await MessageStore.put(waitMessage);
|
waitMessage.text = text;
|
||||||
|
await MessageStore.put(waitMessage);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
}
|
}
|
||||||
@@ -225,7 +228,7 @@ export class OllamaChat extends ChatCommand {
|
|||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getOllamaRequest(uuid).done) {
|
if (getOllamaRequest(uuid)?.done) {
|
||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,17 +269,19 @@ export class OllamaChat extends ChatCommand {
|
|||||||
}).catch(logError);
|
}).catch(logError);
|
||||||
console.log(`aborted request ${uuid}:`, abortOllamaRequest(uuid));
|
console.log(`aborted request ${uuid}:`, abortOllamaRequest(uuid));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e: any) {
|
||||||
if (error.message.toLowerCase().includes("aborted")) return;
|
if (e.message.toLowerCase().includes("aborted")) return;
|
||||||
|
logError(e);
|
||||||
|
|
||||||
await bot.editMessageReplyMarkup({
|
if (waitMessage) {
|
||||||
chat_id: chatId,
|
await bot.editMessageReplyMarkup({
|
||||||
message_id: waitMessage.message_id,
|
chat_id: chatId,
|
||||||
reply_markup: {inline_keyboard: []}
|
message_id: waitMessage.message_id,
|
||||||
}).catch(logError);
|
reply_markup: {inline_keyboard: []}
|
||||||
|
}).catch(logError);
|
||||||
|
|
||||||
logError(error);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
|
||||||
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,22 +56,24 @@ export class OllamaGetModel extends Command {
|
|||||||
parse_mode: "Markdown"
|
parse_mode: "Markdown"
|
||||||
}).catch(logError);
|
}).catch(logError);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
logError(e);
|
logError(e);
|
||||||
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
|
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getModelText(model: string, info: AiModelCapabilities): string {
|
private getModelText(model: string | undefined, info: AiModelCapabilities | null): string {
|
||||||
return `model: ${model}\n\n` +
|
return `model: ${model}\n\n` +
|
||||||
`vision: ${boolToEmoji(info.vision?.supported)}\n` +
|
`vision: ${boolToEmoji(info?.vision?.supported)}\n` +
|
||||||
`ocr: ${boolToEmoji(info.ocr?.supported)}\n` +
|
`ocr: ${boolToEmoji(info?.ocr?.supported)}\n` +
|
||||||
`thinking: ${boolToEmoji(info.thinking?.supported)}\n` +
|
`thinking: ${boolToEmoji(info?.thinking?.supported)}\n` +
|
||||||
`tools: ${boolToEmoji(info.tools?.supported)}\n` +
|
`tools: ${boolToEmoji(info?.tools?.supported)}\n` +
|
||||||
`audio: ${boolToEmoji(info.audio?.supported)}`;
|
`audio: ${boolToEmoji(info?.audio?.supported)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getModelCapabilities(model: string = Environment.OLLAMA_MODEL): Promise<AiModelCapabilities | null> {
|
async getModelCapabilities(model: string | undefined = Environment.OLLAMA_MODEL): Promise<AiModelCapabilities | null> {
|
||||||
|
if (!model) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const info = await ollama.show({model: model});
|
const info = await ollama.show({model: model});
|
||||||
console.log(info);
|
console.log(info);
|
||||||
|
|||||||
@@ -20,14 +20,16 @@ export class OllamaPrompt extends Command {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
return this.executeOllama(msg, match?.[3]);
|
return this.executeOllama(msg, match?.[3] || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeOllama(msg: Message, text: string): Promise<void> {
|
async executeOllama(msg: Message, text: string): Promise<void> {
|
||||||
if (!text || text.trim().length === 0) return;
|
if (!text || !text.trim().length) return;
|
||||||
|
if (!msg.from) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ export class OllamaPrompt extends Command {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const stream = await ollama.generate({
|
const stream = await ollama.generate({
|
||||||
model: Environment.OLLAMA_MODEL,
|
model: <string>Environment.OLLAMA_MODEL,
|
||||||
stream: true,
|
stream: true,
|
||||||
think: false,
|
think: false,
|
||||||
prompt: text
|
prompt: text
|
||||||
@@ -83,7 +85,7 @@ export class OllamaPrompt extends Command {
|
|||||||
try {
|
try {
|
||||||
await bot.editMessageText({
|
await bot.editMessageText({
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: waitMessage.message_id,
|
message_id: <number>waitMessage?.message_id,
|
||||||
text: escapeMarkdownV2Text(text),
|
text: escapeMarkdownV2Text(text),
|
||||||
parse_mode: "Markdown",
|
parse_mode: "Markdown",
|
||||||
reply_markup: cancelMarkup
|
reply_markup: cancelMarkup
|
||||||
@@ -91,9 +93,11 @@ export class OllamaPrompt extends Command {
|
|||||||
|
|
||||||
console.log("editMessageText", text);
|
console.log("editMessageText", text);
|
||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
if (waitMessage) {
|
||||||
waitMessage.text = text;
|
waitMessage.reply_to_message = msg;
|
||||||
await MessageStore.put(waitMessage);
|
waitMessage.text = text;
|
||||||
|
await MessageStore.put(waitMessage);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
}
|
}
|
||||||
@@ -138,7 +142,7 @@ export class OllamaPrompt extends Command {
|
|||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getOllamaRequest(uuid).done) {
|
if (getOllamaRequest(uuid)?.done) {
|
||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,17 +177,19 @@ export class OllamaPrompt extends Command {
|
|||||||
reply_markup: {inline_keyboard: []}
|
reply_markup: {inline_keyboard: []}
|
||||||
}).catch(logError);
|
}).catch(logError);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e: any) {
|
||||||
if (error.message.toLowerCase().includes("aborted")) return;
|
if (e.message.toLowerCase().includes("aborted")) return;
|
||||||
|
logError(e);
|
||||||
|
|
||||||
await bot.editMessageReplyMarkup({
|
if (waitMessage) {
|
||||||
chat_id: chatId,
|
await bot.editMessageReplyMarkup({
|
||||||
message_id: waitMessage.message_id,
|
chat_id: chatId,
|
||||||
reply_markup: {inline_keyboard: []}
|
message_id: waitMessage.message_id,
|
||||||
}).catch(logError);
|
reply_markup: {inline_keyboard: []}
|
||||||
|
}).catch(logError);
|
||||||
|
|
||||||
logError(error);
|
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${e.toString()}`).catch(logError);
|
||||||
await oldReplyToMessage(waitMessage, `Произошла ошибка!\n${error.toString()}`).catch(logError);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import {Requirement} from "../base/requirement";
|
|||||||
import {Message} from "typescript-telegram-bot-api";
|
import {Message} from "typescript-telegram-bot-api";
|
||||||
import {bot, ollama} from "../index";
|
import {bot, ollama} from "../index";
|
||||||
import {WebSearchResponse} from "../model/web-search-response";
|
import {WebSearchResponse} from "../model/web-search-response";
|
||||||
import {oldEditMessageText, logError} from "../util/utils";
|
import {logError, oldEditMessageText} from "../util/utils";
|
||||||
import {Environment} from "../common/environment";
|
import {Environment} from "../common/environment";
|
||||||
|
|
||||||
export class OllamaSearch extends Command {
|
export class OllamaSearch extends Command {
|
||||||
@@ -18,6 +18,10 @@ export class OllamaSearch extends Command {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
console.log("match", match);
|
console.log("match", match);
|
||||||
|
|
||||||
|
const query = match?.[3] || "";
|
||||||
|
if (!query || !query.length) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -31,7 +35,7 @@ export class OllamaSearch extends Command {
|
|||||||
parse_mode: "Markdown"
|
parse_mode: "Markdown"
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = await ollama.webSearch({query: match?.[3]});
|
const results = await ollama.webSearch({query: query});
|
||||||
console.log("results", results);
|
console.log("results", results);
|
||||||
|
|
||||||
let message = "Результаты:\n\n";
|
let message = "Результаты:\n\n";
|
||||||
|
|||||||
@@ -15,18 +15,19 @@ export class OllamaSetModel extends Command {
|
|||||||
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
requirements = Requirements.Build(Requirement.BOT_CREATOR);
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray | null): Promise<void> {
|
||||||
const newModel = match?.[3];
|
const newModel = match?.[3] || "";
|
||||||
|
if (!newModel || !newModel.length) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ollama.show({model: newModel});
|
await ollama.show({model: newModel});
|
||||||
|
|
||||||
Environment.setOllamaModel(newModel || Environment.OLLAMA_MODEL);
|
Environment.setOllamaModel(newModel || <string>Environment.OLLAMA_MODEL);
|
||||||
|
|
||||||
const text = newModel ? `Выбрана модель "${newModel}"`
|
const text = newModel ? `Выбрана модель "${newModel}"`
|
||||||
: `Модель не задана. Будет использоваться стандартная модель "${Environment.OLLAMA_MODEL}".`;
|
: `Модель не задана. Будет использоваться стандартная модель "${Environment.OLLAMA_MODEL}".`;
|
||||||
|
|
||||||
await replyToMessage({message: msg, text: text}).catch(logError);
|
await replyToMessage({message: msg, text: text}).catch(logError);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
logError(e);
|
logError(e);
|
||||||
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
|
await replyToMessage({message: msg, text: e.toString()}).catch(logError);
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-13
@@ -24,11 +24,11 @@ export class OpenAIChat extends ChatCommand {
|
|||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
||||||
console.log("OpenAI Chat: ", match);
|
console.log("OpenAI Chat: ", match);
|
||||||
return this.executeOpenAI(msg, match?.[3]);
|
return this.executeOpenAI(msg, match?.[3] || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeOpenAI(msg: Message, text: string): Promise<void> {
|
async executeOpenAI(msg: Message, text: string): Promise<void> {
|
||||||
if (!text || text.trim().length === 0) return;
|
if (!text || !text.trim().length) return;
|
||||||
|
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ export class OpenAIChat extends ChatCommand {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let waitMessage: Message;
|
let waitMessage: Message | null = null;
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ export class OpenAIChat extends ChatCommand {
|
|||||||
await bot.editMessageText(
|
await bot.editMessageText(
|
||||||
{
|
{
|
||||||
chat_id: chatId,
|
chat_id: chatId,
|
||||||
message_id: waitMessage.message_id,
|
message_id: <number>waitMessage?.message_id,
|
||||||
text: escapeMarkdownV2Text(text),
|
text: escapeMarkdownV2Text(text),
|
||||||
parse_mode: "MarkdownV2"
|
parse_mode: "MarkdownV2"
|
||||||
}
|
}
|
||||||
@@ -106,9 +106,11 @@ export class OpenAIChat extends ChatCommand {
|
|||||||
|
|
||||||
console.log("editMessageText", text);
|
console.log("editMessageText", text);
|
||||||
|
|
||||||
waitMessage.reply_to_message = msg;
|
if (waitMessage) {
|
||||||
waitMessage.text = text;
|
waitMessage.reply_to_message = msg;
|
||||||
await MessageStore.put(waitMessage);
|
waitMessage.text = text;
|
||||||
|
await MessageStore.put(waitMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onStop: async () => {
|
onStop: async () => {
|
||||||
}
|
}
|
||||||
@@ -156,12 +158,15 @@ export class OpenAIChat extends ChatCommand {
|
|||||||
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
await replyToMessage({message: waitMessage, text: `⏱️ ${diff}s`});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e: any) {
|
||||||
logError(error);
|
logError(e);
|
||||||
await replyToMessage({
|
|
||||||
message: waitMessage,
|
if (waitMessage) {
|
||||||
text: `Произошла ошибка!\n${error.toString()}`
|
await replyToMessage({
|
||||||
}).catch(logError);
|
message: waitMessage,
|
||||||
|
text: `Произошла ошибка!\n${e.toString()}`
|
||||||
|
}).catch(logError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ export class OpenAIGetModel extends Command {
|
|||||||
try {
|
try {
|
||||||
return {
|
return {
|
||||||
vision: {supported: true},
|
vision: {supported: true},
|
||||||
ocr: null,
|
ocr: undefined,
|
||||||
thinking: {supported: true},
|
thinking: {supported: true},
|
||||||
tools: {supported: true},
|
tools: {supported: true},
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ export class Qr extends Command {
|
|||||||
},
|
},
|
||||||
parse_mode: "HTML"
|
parse_mode: "HTML"
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
await replyToMessage({
|
await replyToMessage({
|
||||||
message: msg,
|
message: msg,
|
||||||
text: `Не получилось сгенерировать QR: ${e?.message ?? String(e)}`
|
text: `Не получилось сгенерировать QR: ${e?.message ?? String(e)}`
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export class Quote extends Command {
|
|||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
const chatId = msg.chat.id;
|
const chatId = msg.chat.id;
|
||||||
const reply = msg.reply_to_message;
|
const reply = msg.reply_to_message;
|
||||||
|
if (!reply) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
|
const quoteRaw = (msg.quote?.text ?? reply.text ?? reply.caption ?? "").trim();
|
||||||
@@ -97,7 +98,9 @@ function twemojiUrl(emoji: string) {
|
|||||||
return `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/${code}.png`;
|
return `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/${code}.png`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadEmoji(emoji: string): Promise<CanvasImage> {
|
async function loadEmoji(emoji: string | undefined): Promise<CanvasImage | null> {
|
||||||
|
if (!emoji) return null;
|
||||||
|
|
||||||
const downloadAndCache = async (url: string): Promise<Image> => {
|
const downloadAndCache = async (url: string): Promise<Image> => {
|
||||||
const res = await axios.get<ArrayBuffer>(url, {responseType: "arraybuffer"});
|
const res = await axios.get<ArrayBuffer>(url, {responseType: "arraybuffer"});
|
||||||
const img = await loadImage(Buffer.from(res.data));
|
const img = await loadImage(Buffer.from(res.data));
|
||||||
@@ -491,7 +494,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
|
|||||||
try {
|
try {
|
||||||
const img = await loadEmoji(seg.v);
|
const img = await loadEmoji(seg.v);
|
||||||
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
||||||
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
|
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
ctx.fillText(seg.v, cx, baselineY);
|
ctx.fillText(seg.v, cx, baselineY);
|
||||||
@@ -506,7 +509,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
|
|||||||
} else {
|
} else {
|
||||||
const img = await loadEmoji("😥");
|
const img = await loadEmoji("😥");
|
||||||
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
||||||
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
|
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Failed to draw custom emoji:", e);
|
console.warn("Failed to draw custom emoji:", e);
|
||||||
@@ -514,7 +517,7 @@ async function drawLine(ctx: SKRSContext2D, line: Segment[], x: number, baseline
|
|||||||
try {
|
try {
|
||||||
const img = await loadEmoji("😥");
|
const img = await loadEmoji("😥");
|
||||||
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
const y = baselineY - emojiSize + Math.round(fontSize * 0.2);
|
||||||
ctx.drawImage(img, cx, y, emojiSize, emojiSize);
|
ctx.drawImage(<Image>img, cx, y, emojiSize, emojiSize);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export class RandomInt extends Command {
|
|||||||
description = "Ranged random integer from parameters";
|
description = "Ranged random integer from parameters";
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
|
// TODO: 01/05/2026, Danil Nikolaev: improve
|
||||||
|
if (!msg.text) return;
|
||||||
|
|
||||||
const split = msg.text.split(" ");
|
const split = msg.text.split(" ");
|
||||||
const min = parseInt(split[1]);
|
const min = parseInt(split[1]);
|
||||||
const max = parseInt(split[2]);
|
const max = parseInt(split[2]);
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export class RandomString extends Command {
|
|||||||
description = "literally random string (up to 4096 symbols)";
|
description = "literally random string (up to 4096 symbols)";
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
|
// TODO: 01/05/2026, Danil Nikolaev: improve
|
||||||
|
if (!msg.text) return;
|
||||||
|
|
||||||
const split = msg.text.split(" ");
|
const split = msg.text.split(" ");
|
||||||
const l = parseInt(split.length > 1 ? split[1] : "1");
|
const l = parseInt(split.length > 1 ? split[1] : "1");
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ export class Start extends Command {
|
|||||||
description = "Start the bot";
|
description = "Start the bot";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
await commands.find(e => e instanceof Help).execute(msg);
|
await commands.find(e => e instanceof Help)?.execute(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,12 +81,14 @@ export class Transliteration extends Command {
|
|||||||
description = "Transliteration EN <--> RU";
|
description = "Transliteration EN <--> RU";
|
||||||
|
|
||||||
async execute(msg: Message): Promise<void> {
|
async execute(msg: Message): Promise<void> {
|
||||||
|
if (!msg.text && !msg.caption) return;
|
||||||
|
|
||||||
let text: string = "";
|
let text: string = "";
|
||||||
|
|
||||||
if (msg.reply_to_message) {
|
if (msg.reply_to_message) {
|
||||||
text = (msg.reply_to_message.text || msg.reply_to_message.caption || "");
|
text = (msg.reply_to_message.text || msg.reply_to_message.caption || "");
|
||||||
} else {
|
} else {
|
||||||
const split = (msg.text || msg.caption).split("/tr ");
|
const split = (<string>(msg.text || msg.caption)).split("/tr ");
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
text = split[1].trim();
|
text = split[1].trim();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class Unban extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const user = msg.reply_to_message.from;
|
const user = msg.reply_to_message.from;
|
||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
@@ -34,7 +34,7 @@ export class Unban extends Command {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.from.id !== Environment.CREATOR_ID && Environment.ADMIN_IDS.has(userId)) {
|
if (msg.from?.id !== Environment.CREATOR_ID && Environment.ADMIN_IDS.has(userId)) {
|
||||||
await oldReplyToMessage(msg, "Админимтраторы бота и так не в бане.").catch(logError);
|
await oldReplyToMessage(msg, "Админимтраторы бота и так не в бане.").catch(logError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class Unignore extends Command {
|
|||||||
);
|
);
|
||||||
|
|
||||||
async execute(msg: Message) {
|
async execute(msg: Message) {
|
||||||
if (!msg.reply_to_message) return;
|
if (!msg.reply_to_message || !msg.reply_to_message.from) return;
|
||||||
|
|
||||||
const id = msg.reply_to_message.from.id;
|
const id = msg.reply_to_message.from.id;
|
||||||
const text = fullName(msg.reply_to_message.from);
|
const text = fullName(msg.reply_to_message.from);
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import {Command} from "../base/command";
|
|
||||||
import {Message} from "typescript-telegram-bot-api";
|
|
||||||
import {editMessageText, logError, replyToMessage} from "../util/utils";
|
|
||||||
import {bot, botUser} from "../index";
|
|
||||||
import {DownloadOptions, downloadVideoFromYouTube, getYouTubeVideoId} from "../util/ytdl";
|
|
||||||
import {Environment} from "../common/environment";
|
|
||||||
import {TryAgain} from "../callback_commands/try-again";
|
|
||||||
|
|
||||||
export class YouTubeDownload extends Command {
|
|
||||||
command = ["ytdl", "youtube"];
|
|
||||||
argsMode = "required" as const;
|
|
||||||
|
|
||||||
async execute(msg: Message, match?: RegExpExecArray): Promise<void> {
|
|
||||||
const url = match?.[3];
|
|
||||||
return this.downloadYouTubeVideo(msg, {url: url});
|
|
||||||
}
|
|
||||||
|
|
||||||
async downloadYouTubeVideo(msg: Message, options: DownloadOptions): Promise<void> {
|
|
||||||
// TODO: 02.03.2026, Danil Nikolaev: add check for date
|
|
||||||
let waitMessage: Message | null = (msg.from.id === botUser.id) ? msg : null;
|
|
||||||
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!waitMessage) {
|
|
||||||
waitMessage = await replyToMessage({message: msg, text: "⏳ Скачиваю видео..."});
|
|
||||||
} else {
|
|
||||||
await editMessageText({message: msg, text: "⏳ Скачиваю видео..."});
|
|
||||||
}
|
|
||||||
|
|
||||||
const {time, exists, buffer} = await downloadVideoFromYouTube({videoId: videoId});
|
|
||||||
if (buffer) {
|
|
||||||
const start = Date.now();
|
|
||||||
waitMessage = await bot.editMessageMedia({
|
|
||||||
chat_id: msg.chat.id,
|
|
||||||
message_id: waitMessage.message_id,
|
|
||||||
media: {
|
|
||||||
type: "video",
|
|
||||||
media: buffer
|
|
||||||
}
|
|
||||||
}) as Message;
|
|
||||||
|
|
||||||
const diff = Date.now() - start;
|
|
||||||
waitMessage = await bot.editMessageCaption({
|
|
||||||
chat_id: msg.chat.id,
|
|
||||||
message_id: waitMessage.message_id,
|
|
||||||
caption: "✅ Видео" + (exists ? " загружено из кэша" : " успешно скачано") + " за " + (time + diff) + "мс",
|
|
||||||
}) as Message;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
|
|
||||||
if (waitMessage && "text" in waitMessage) {
|
|
||||||
await bot.editMessageText({
|
|
||||||
chat_id: msg.chat.id,
|
|
||||||
message_id: waitMessage.message_id,
|
|
||||||
text: Environment.errorText,
|
|
||||||
reply_markup: {
|
|
||||||
inline_keyboard: [[
|
|
||||||
TryAgain.withData("/ytdl " + videoId).asButton()
|
|
||||||
]]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -67,7 +67,7 @@ export class Environment {
|
|||||||
static ollamaCancelledText = "```Ollama\n❌ Отменено```";
|
static ollamaCancelledText = "```Ollama\n❌ Отменено```";
|
||||||
|
|
||||||
static load() {
|
static load() {
|
||||||
Environment.BOT_TOKEN = process.env.BOT_TOKEN;
|
Environment.BOT_TOKEN = <string>process.env.BOT_TOKEN;
|
||||||
Environment.TEST_ENVIRONMENT = ifTrue(process.env.TEST_ENVIRONMENT);
|
Environment.TEST_ENVIRONMENT = ifTrue(process.env.TEST_ENVIRONMENT);
|
||||||
Environment.CHAT_IDS_WHITELIST = new Set(process.env.CHAT_IDS_WHITELIST?.split(",")?.map(e => parseInt(e.trim(), 10)) || []);
|
Environment.CHAT_IDS_WHITELIST = new Set(process.env.CHAT_IDS_WHITELIST?.split(",")?.map(e => parseInt(e.trim(), 10)) || []);
|
||||||
Environment.BOT_PREFIX = process.env.BOT_PREFIX || "";
|
Environment.BOT_PREFIX = process.env.BOT_PREFIX || "";
|
||||||
|
|||||||
@@ -15,14 +15,16 @@ export class MessageStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async put(m: Message | StoredMessage): Promise<StoredMessage> {
|
static async put(m: Message | StoredMessage): Promise<StoredMessage> {
|
||||||
|
const maxSizePath = isStoredMessage(m) ? null : getPhotoMaxSize(m.photo)?.file_unique_id;
|
||||||
|
|
||||||
const msg: StoredMessage = isStoredMessage(m) ? m : {
|
const msg: StoredMessage = isStoredMessage(m) ? m : {
|
||||||
chatId: m.chat.id,
|
chatId: m.chat.id,
|
||||||
id: m.message_id,
|
id: m.message_id,
|
||||||
replyToMessageId: m.reply_to_message?.message_id ?? null,
|
replyToMessageId: m.reply_to_message?.message_id,
|
||||||
fromId: m.from.id,
|
fromId: <number>m.from?.id,
|
||||||
text: extractTextMessage(m),
|
text: extractTextMessage(m),
|
||||||
date: m.date ?? 0,
|
date: m.date ?? 0,
|
||||||
photoMaxSizeFilePath: m.photo ? [getPhotoMaxSize(m.photo).file_unique_id] : null
|
photoMaxSizeFilePath: maxSizePath ? [maxSizePath] : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.map.set(this.key(msg.chatId, msg.id), msg);
|
this.map.set(this.key(msg.chatId, msg.id), msg);
|
||||||
@@ -30,7 +32,9 @@ export class MessageStore {
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async get(chatId: number, messageId: number): Promise<StoredMessage | null> {
|
static async get(chatId: number, messageId: number | undefined): Promise<StoredMessage | null> {
|
||||||
|
if (!messageId) return null;
|
||||||
|
|
||||||
const message = await messageDao.getById({chatId: chatId, id: messageId});
|
const message = await messageDao.getById({chatId: chatId, id: messageId});
|
||||||
if (!message) return null;
|
if (!message) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ export class MessageDao extends Dao<StoredMessage> {
|
|||||||
return messages.map(m => {
|
return messages.map(m => {
|
||||||
return {
|
return {
|
||||||
chatId: m.chatId,
|
chatId: m.chatId,
|
||||||
id: m.id,
|
id: <number>m.id,
|
||||||
replyToMessageId: m.replyToMessageId,
|
replyToMessageId: m.replyToMessageId || undefined,
|
||||||
fromId: m.fromId,
|
fromId: m.fromId,
|
||||||
text: m.text,
|
text: m.text,
|
||||||
date: m.date,
|
date: m.date,
|
||||||
|
|||||||
+1
-1
@@ -93,7 +93,7 @@ export class UserDao extends Dao<StoredUser> {
|
|||||||
mapFrom(users: UserInsert[]): StoredUser[] {
|
mapFrom(users: UserInsert[]): StoredUser[] {
|
||||||
return users.map(u => {
|
return users.map(u => {
|
||||||
return {
|
return {
|
||||||
id: u.id,
|
id: <number>u.id,
|
||||||
isBot: u.isBot === 1,
|
isBot: u.isBot === 1,
|
||||||
firstName: u.firstName,
|
firstName: u.firstName,
|
||||||
lastName: u.lastName,
|
lastName: u.lastName,
|
||||||
|
|||||||
+4
-11
@@ -1,6 +1,6 @@
|
|||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import {Environment} from "./common/environment";
|
import {Environment} from "./common/environment";
|
||||||
import {TelegramBot, User} from "typescript-telegram-bot-api";
|
import {BotCommand, TelegramBot, User} from "typescript-telegram-bot-api";
|
||||||
import {Command} from "./base/command";
|
import {Command} from "./base/command";
|
||||||
import {
|
import {
|
||||||
delay,
|
delay,
|
||||||
@@ -67,7 +67,6 @@ import {GeminiGetModel} from "./commands/gemini-get-model";
|
|||||||
import {GeminiSetModel} from "./commands/gemini-set-model";
|
import {GeminiSetModel} from "./commands/gemini-set-model";
|
||||||
import {Debug} from "./commands/debug";
|
import {Debug} from "./commands/debug";
|
||||||
import {GeminiGenerateImage} from "./commands/gemini-generate-image";
|
import {GeminiGenerateImage} from "./commands/gemini-generate-image";
|
||||||
import {YouTubeDownload} from "./commands/youtube-download";
|
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {setInterval} from "node:timers";
|
import {setInterval} from "node:timers";
|
||||||
@@ -79,8 +78,6 @@ import {OpenAISetModel} from "./commands/openai-set-model";
|
|||||||
import {Info} from "./commands/info";
|
import {Info} from "./commands/info";
|
||||||
import {OpenAIGenImage} from "./commands/openai-gen-image";
|
import {OpenAIGenImage} from "./commands/openai-gen-image";
|
||||||
import {clearUpFolderFromOldFiles} from "./util/files";
|
import {clearUpFolderFromOldFiles} from "./util/files";
|
||||||
import {DownloadYtVideo} from "./callback_commands/download-yt-video";
|
|
||||||
import {YtInfo} from "./callback_commands/yt-info";
|
|
||||||
import {AdminsList} from "./commands/admins-list";
|
import {AdminsList} from "./commands/admins-list";
|
||||||
import {ExportDb} from "./commands/export-db";
|
import {ExportDb} from "./commands/export-db";
|
||||||
|
|
||||||
@@ -106,7 +103,7 @@ export const ollama = new Ollama({
|
|||||||
|
|
||||||
export const ollamaRequests: OllamaRequest[] = [];
|
export const ollamaRequests: OllamaRequest[] = [];
|
||||||
|
|
||||||
export function getOllamaRequest(uuid: string): OllamaRequest | null {
|
export function getOllamaRequest(uuid: string): OllamaRequest | undefined {
|
||||||
return ollamaRequests.find(r => r.uuid === uuid);
|
return ollamaRequests.find(r => r.uuid === uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,8 +166,6 @@ export const commands: Command[] = [
|
|||||||
|
|
||||||
new Shutdown(),
|
new Shutdown(),
|
||||||
new Leave(),
|
new Leave(),
|
||||||
|
|
||||||
new YouTubeDownload()
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Environment.ENABLE_UNSAFE_EVAL) {
|
if (Environment.ENABLE_UNSAFE_EVAL) {
|
||||||
@@ -179,8 +174,6 @@ if (Environment.ENABLE_UNSAFE_EVAL) {
|
|||||||
|
|
||||||
export const callbackCommands: CallbackCommand[] = [
|
export const callbackCommands: CallbackCommand[] = [
|
||||||
new OllamaCancel(),
|
new OllamaCancel(),
|
||||||
new DownloadYtVideo(),
|
|
||||||
new YtInfo()
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL) {
|
if (Environment.OLLAMA_ADDRESS && Environment.OLLAMA_MODEL) {
|
||||||
@@ -288,10 +281,10 @@ async function main() {
|
|||||||
return cmd.title && cmd.title.startsWith("/") && cmd.title.split(" ").length === 1 && cmd.description;
|
return cmd.title && cmd.title.startsWith("/") && cmd.title.split(" ").length === 1 && cmd.description;
|
||||||
}).map(cmd => {
|
}).map(cmd => {
|
||||||
return {
|
return {
|
||||||
command: cmd.title.toLowerCase(),
|
command: cmd.title?.toLowerCase() || "",
|
||||||
description: cmd.description,
|
description: cmd.description,
|
||||||
};
|
};
|
||||||
});
|
}) as BotCommand[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export type StoredMessage = {
|
|||||||
id: number;
|
id: number;
|
||||||
replyToMessageId?: number;
|
replyToMessageId?: number;
|
||||||
fromId: number;
|
fromId: number;
|
||||||
text?: string;
|
text?: string | null;
|
||||||
date: number;
|
date: number;
|
||||||
photoMaxSizeFilePath?: string[];
|
photoMaxSizeFilePath?: string[] | null;
|
||||||
};
|
};
|
||||||
@@ -2,7 +2,7 @@ export type StoredUser = {
|
|||||||
id: number;
|
id: number;
|
||||||
isBot: boolean;
|
isBot: boolean;
|
||||||
firstName: string;
|
firstName: string;
|
||||||
lastName?: string;
|
lastName?: string | null;
|
||||||
userName?: string;
|
userName?: string | null;
|
||||||
isPremium?: boolean;
|
isPremium?: boolean;
|
||||||
}
|
}
|
||||||
+103
-213
@@ -32,8 +32,6 @@ import {MessageStore} from "../common/message-store";
|
|||||||
import {SystemInfo} from "../commands/system-info";
|
import {SystemInfo} from "../commands/system-info";
|
||||||
import {PrefixResponse} from "../commands/prefix-response";
|
import {PrefixResponse} from "../commands/prefix-response";
|
||||||
import {OllamaChat} from "../commands/ollama-chat";
|
import {OllamaChat} from "../commands/ollama-chat";
|
||||||
import {getYouTubeVideoId, getYouTubeVideoInfo, isVideoExists} from "./ytdl";
|
|
||||||
import {YouTubeDownload} from "../commands/youtube-download";
|
|
||||||
import {ChatCommand} from "../base/chat-command";
|
import {ChatCommand} from "../base/chat-command";
|
||||||
import {WebSearchResponse} from "../model/web-search-response";
|
import {WebSearchResponse} from "../model/web-search-response";
|
||||||
import {GeminiChat} from "../commands/gemini-chat";
|
import {GeminiChat} from "../commands/gemini-chat";
|
||||||
@@ -47,9 +45,6 @@ import {MistralGetModel} from "../commands/mistral-get-model";
|
|||||||
import {OpenAIGetModel} from "../commands/openai-get-model";
|
import {OpenAIGetModel} from "../commands/openai-get-model";
|
||||||
import {SendOptions} from "../model/send-options";
|
import {SendOptions} from "../model/send-options";
|
||||||
import {EditOptions} from "../model/edit-options";
|
import {EditOptions} from "../model/edit-options";
|
||||||
import VideoInfo from "youtubei.js/dist/src/parser/youtube/VideoInfo";
|
|
||||||
import {DownloadYtVideo} from "../callback_commands/download-yt-video";
|
|
||||||
import {TryAgain} from "../callback_commands/try-again";
|
|
||||||
import {StoredUser} from "../model/stored-user";
|
import {StoredUser} from "../model/stored-user";
|
||||||
import {performFFmpeg} from "./ffmpeg";
|
import {performFFmpeg} from "./ffmpeg";
|
||||||
|
|
||||||
@@ -68,7 +63,7 @@ export const ignoreIfMarkupFailed = (e: Error | TelegramError) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logError = (e: Error | TelegramError | string) => {
|
export const logError = (e: Error | TelegramError | string | unknown) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,7 +86,7 @@ export const isMessageTooLong = (e: Error | TelegramError) => {
|
|||||||
export function searchChatCommand(
|
export function searchChatCommand(
|
||||||
commands: Command[],
|
commands: Command[],
|
||||||
text: string,
|
text: string,
|
||||||
botUsername: string = botUser.username
|
botUsername: string | undefined = botUser.username
|
||||||
): Command | null {
|
): Command | null {
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
const match = command.finalRegexp.exec(text);
|
const match = command.finalRegexp.exec(text);
|
||||||
@@ -129,7 +124,7 @@ export async function checkRequirements(cmd: Command | CallbackCommand | null, m
|
|||||||
let title: string;
|
let title: string;
|
||||||
|
|
||||||
if (isChatCommand) {
|
if (isChatCommand) {
|
||||||
title = cmd.title;
|
title = cmd.title || "";
|
||||||
} else if (isCallbackCommand) {
|
} else if (isCallbackCommand) {
|
||||||
title = cmd.data;
|
title = cmd.data;
|
||||||
} else {
|
} else {
|
||||||
@@ -138,7 +133,7 @@ export async function checkRequirements(cmd: Command | CallbackCommand | null, m
|
|||||||
|
|
||||||
const cbId = cb?.id;
|
const cbId = cb?.id;
|
||||||
const chatId = msg?.chat?.id || cb?.message?.chat?.id || -1;
|
const chatId = msg?.chat?.id || cb?.message?.chat?.id || -1;
|
||||||
const messageId = msg?.message_id || (cb && cb.message && "reply_to_message" in cb.message ? cb.message.reply_to_message.message_id : null) || -1;
|
const messageId = msg?.message_id || (cb && cb.message && "reply_to_message" in cb.message ? cb.message.reply_to_message?.message_id : null) || -1;
|
||||||
const fromId = msg?.from?.id || cb?.from?.id || -1;
|
const fromId = msg?.from?.id || cb?.from?.id || -1;
|
||||||
const chatType = msg?.chat?.type || cb?.message?.chat?.type || null;
|
const chatType = msg?.chat?.type || cb?.message?.chat?.type || null;
|
||||||
|
|
||||||
@@ -162,7 +157,7 @@ export async function checkRequirements(cmd: Command | CallbackCommand | null, m
|
|||||||
await replyToMessage({chat_id: chatId, message_id: messageId, text: text});
|
await replyToMessage({chat_id: chatId, message_id: messageId, text: text});
|
||||||
} else if (cb) {
|
} else if (cb) {
|
||||||
await bot.answerCallbackQuery({
|
await bot.answerCallbackQuery({
|
||||||
callback_query_id: cbId,
|
callback_query_id: cbId || "",
|
||||||
text: text,
|
text: text,
|
||||||
cache_time: 0,
|
cache_time: 0,
|
||||||
show_alert: true
|
show_alert: true
|
||||||
@@ -182,7 +177,7 @@ export async function checkRequirements(cmd: Command | CallbackCommand | null, m
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reqs.isRequiresChat() && msg.chat.type === "private") {
|
if (reqs.isRequiresChat() && msg?.chat?.type === "private") {
|
||||||
console.log(`${title}: chatId is bad`);
|
console.log(`${title}: chatId is bad`);
|
||||||
await notifyUser("Тут Вам не чат.");
|
await notifyUser("Тут Вам не чат.");
|
||||||
return false;
|
return false;
|
||||||
@@ -215,13 +210,13 @@ export async function checkRequirements(cmd: Command | CallbackCommand | null, m
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reqs.isRequiresSameUser()) {
|
if (reqs.isRequiresSameUser()) {
|
||||||
let originalFromId: number | null;
|
let originalFromId: number | undefined;
|
||||||
try {
|
try {
|
||||||
const originalMessage = await MessageStore.get(chatId, messageId);
|
const originalMessage = await MessageStore.get(chatId, messageId);
|
||||||
originalFromId = originalMessage?.fromId;
|
originalFromId = originalMessage?.fromId;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e);
|
logError(e);
|
||||||
originalFromId = null;
|
originalFromId = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originalFromId && fromId !== originalFromId && fromId !== Environment.CREATOR_ID) {
|
if (originalFromId && fromId !== originalFromId && fromId !== Environment.CREATOR_ID) {
|
||||||
@@ -239,7 +234,7 @@ export async function executeChatCommand(cmd: Command | null, msg: Message, text
|
|||||||
|
|
||||||
if (!await checkRequirements(cmd, msg)) return false;
|
if (!await checkRequirements(cmd, msg)) return false;
|
||||||
|
|
||||||
await cmd.execute(msg, cmd.regexp.exec(text));
|
await cmd.execute(msg, cmd.regexp?.exec(text));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +244,7 @@ export async function findAndExecuteCallbackCommand(commands: CallbackCommand[],
|
|||||||
const cmd = searchCallbackCommand(commands, data);
|
const cmd = searchCallbackCommand(commands, data);
|
||||||
if (!cmd) return false;
|
if (!cmd) return false;
|
||||||
|
|
||||||
if (!await checkRequirements(cmd, null, query)) return false;
|
if (!await checkRequirements(cmd, undefined, query)) return false;
|
||||||
|
|
||||||
await cmd.execute(query);
|
await cmd.execute(query);
|
||||||
await cmd.answerCallbackQuery(query);
|
await cmd.answerCallbackQuery(query);
|
||||||
@@ -281,7 +276,7 @@ export async function editMessageText(options: EditOptions) {
|
|||||||
link_preview_options: options.link_preview_options,
|
link_preview_options: options.link_preview_options,
|
||||||
});
|
});
|
||||||
return Promise.resolve(message);
|
return Promise.resolve(message);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
logError(e);
|
logError(e);
|
||||||
|
|
||||||
if (isMarkupFailed(e)) {
|
if (isMarkupFailed(e)) {
|
||||||
@@ -295,6 +290,8 @@ export async function editMessageText(options: EditOptions) {
|
|||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function oldSendMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
export async function oldSendMessage(message: Message, text: string, parseMode?: ParseMode): Promise<Message> {
|
||||||
@@ -337,7 +334,7 @@ export async function replyToMessage(options: SendOptions): Promise<Message> {
|
|||||||
text: options.text,
|
text: options.text,
|
||||||
parse_mode: options.parse_mode,
|
parse_mode: options.parse_mode,
|
||||||
reply_parameters: {
|
reply_parameters: {
|
||||||
message_id: "message" in options ? options.message.message_id : options.message_id
|
message_id: <number>("message" in options ? options.message.message_id : options.message_id)
|
||||||
},
|
},
|
||||||
link_preview_options: options.link_preview_options
|
link_preview_options: options.link_preview_options
|
||||||
});
|
});
|
||||||
@@ -1177,12 +1174,13 @@ export function extractTextMessage(msg: Message | StoredMessage | string): strin
|
|||||||
if (!msg) return null;
|
if (!msg) return null;
|
||||||
if (typeof msg === "string") return msg;
|
if (typeof msg === "string") return msg;
|
||||||
|
|
||||||
const text = (isStoredMessage(msg) ? msg.text : msg.text || msg.caption || "").trim();
|
const text = (isStoredMessage(msg) ? msg.text : msg.text || msg.caption || "")?.trim();
|
||||||
if (text.length === 0) return null;
|
if (!text || !text?.length) return null;
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cutPrefixes(msg: Message | StoredMessage | string): string {
|
export function cutPrefixes(msg: Message | StoredMessage | string | null): string | null {
|
||||||
|
if (!msg) return null;
|
||||||
const chatCommands = commands.filter(c => c instanceof ChatCommand);
|
const chatCommands = commands.filter(c => c instanceof ChatCommand);
|
||||||
|
|
||||||
const prefixes = [Environment.BOT_PREFIX];
|
const prefixes = [Environment.BOT_PREFIX];
|
||||||
@@ -1193,10 +1191,12 @@ export function cutPrefixes(msg: Message | StoredMessage | string): string {
|
|||||||
|
|
||||||
chatCommands.forEach((cmd) => {
|
chatCommands.forEach((cmd) => {
|
||||||
const command = cmd.command;
|
const command = cmd.command;
|
||||||
if (Array.isArray(command)) {
|
if (command) {
|
||||||
command.forEach(pushPrefix);
|
if (Array.isArray(command)) {
|
||||||
} else {
|
command.forEach(pushPrefix);
|
||||||
pushPrefix(command);
|
} else {
|
||||||
|
pushPrefix(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1216,10 +1216,10 @@ export function cutPrefixes(msg: Message | StoredMessage | string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isStoredMessage(msg: Message | StoredMessage | null): msg is StoredMessage {
|
export function isStoredMessage(msg: Message | StoredMessage | null): msg is StoredMessage {
|
||||||
return msg && "id" in msg;
|
return !!msg && "id" in msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<string[] | null> {
|
export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<string[] | null | undefined> {
|
||||||
if (isStoredMessage(msg)) {
|
if (isStoredMessage(msg)) {
|
||||||
return msg.photoMaxSizeFilePath;
|
return msg.photoMaxSizeFilePath;
|
||||||
}
|
}
|
||||||
@@ -1237,7 +1237,7 @@ export async function loadImagesIfExists(msg: Message | StoredMessage): Promise<
|
|||||||
|
|
||||||
const maxSize = await mapPhotoSizeToMax(getPhotoMaxSize(msg.photo));
|
const maxSize = await mapPhotoSizeToMax(getPhotoMaxSize(msg.photo));
|
||||||
if (maxSize) {
|
if (maxSize) {
|
||||||
let imageFilePath = path.join(photoDir, maxSize.unique_file_id + ".jpg");
|
let imageFilePath: string | null = path.join(photoDir, maxSize.unique_file_id + ".jpg");
|
||||||
if (!fs.existsSync(imageFilePath)) {
|
if (!fs.existsSync(imageFilePath)) {
|
||||||
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
|
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
|
||||||
const src = Buffer.from(res.data);
|
const src = Buffer.from(res.data);
|
||||||
@@ -1268,7 +1268,7 @@ export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[
|
|||||||
const promises = sizes.filter(s => !fs.existsSync(photoPathByUniqueId(s.file_unique_id)))
|
const promises = sizes.filter(s => !fs.existsSync(photoPathByUniqueId(s.file_unique_id)))
|
||||||
.map(s => mapPhotoSizeToMax(s));
|
.map(s => mapPhotoSizeToMax(s));
|
||||||
|
|
||||||
const maxSizes = await Promise.all(promises);
|
const maxSizes = (await Promise.all(promises)).filter(e => !!e);
|
||||||
|
|
||||||
const imagePromises = maxSizes.map((size) => {
|
const imagePromises = maxSizes.map((size) => {
|
||||||
return axios.get<ArrayBuffer>(size.url, {responseType: "arraybuffer"});
|
return axios.get<ArrayBuffer>(size.url, {responseType: "arraybuffer"});
|
||||||
@@ -1287,37 +1287,40 @@ export async function loadImagesFromFileIds(sizes: PhotoSize[]): Promise<string[
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const finalPaths = paths.filter(p => p);
|
const finalPaths = existing.concat(...paths.filter(p => !!p).map(p => <string>p));
|
||||||
finalPaths.unshift(...existing);
|
|
||||||
return finalPaths;
|
return finalPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function collectReplyChainText(triggerMsg: Message | StoredMessage, limit: number = 40, includeTrigger = true, cutPrefix: boolean = true): Promise<MessagePart[]> {
|
export async function collectReplyChainText(triggerMsg: Message | StoredMessage | null, limit: number = 40, includeTrigger = true, cutPrefix: boolean = true): Promise<MessagePart[]> {
|
||||||
|
if (!triggerMsg) return [];
|
||||||
|
|
||||||
const parts: MessagePart[] = [];
|
const parts: MessagePart[] = [];
|
||||||
|
|
||||||
const pushPart = async (msg: Message | StoredMessage, textRequired: boolean = false) => {
|
const pushPart = async (msg: Message | StoredMessage | undefined | null, textRequired: boolean = false) => {
|
||||||
const rawText = extractTextMessage(msg);
|
if (msg) {
|
||||||
const cleanText = cutPrefix ? cutPrefixes(rawText) : rawText;
|
const rawText = extractTextMessage(msg);
|
||||||
const imageNames = await loadImagesIfExists(msg);
|
const cleanText = cutPrefix ? cutPrefixes(rawText) : rawText;
|
||||||
|
const imageNames = await loadImagesIfExists(msg);
|
||||||
|
|
||||||
if (!cleanText && textRequired) return;
|
if (!cleanText && textRequired) return;
|
||||||
if (!cleanText && !imageNames?.length) return;
|
if (!cleanText && !imageNames?.length) return;
|
||||||
|
|
||||||
const fromId = isStoredMessage(msg) ? msg.fromId : msg.from.id;
|
const fromId = isStoredMessage(msg) ? msg.fromId : msg.from?.id;
|
||||||
const firstName = isStoredMessage(msg) ?
|
const firstName = isStoredMessage(msg) ?
|
||||||
(await UserStore.get(msg.fromId))?.firstName : msg.from.first_name;
|
(await UserStore.get(msg.fromId))?.firstName : msg.from?.first_name;
|
||||||
|
|
||||||
const images = imageNames ? imageNames.map(n => {
|
const images = imageNames ? imageNames.map(n => {
|
||||||
const filePath = photoPathByUniqueId(n);
|
const filePath = photoPathByUniqueId(n);
|
||||||
return Buffer.from(fs.readFileSync(filePath)).toString("base64");
|
return Buffer.from(fs.readFileSync(filePath)).toString("base64");
|
||||||
}) : null;
|
}) : null;
|
||||||
|
|
||||||
parts.push({
|
parts.push({
|
||||||
bot: fromId === botUser.id,
|
bot: fromId === botUser.id,
|
||||||
content: cleanText ? cleanText : "",
|
content: cleanText ? cleanText : "",
|
||||||
name: firstName,
|
name: firstName,
|
||||||
images: images ? images : []
|
images: images ? images : []
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatId = isStoredMessage(triggerMsg) ? triggerMsg.chatId as number : triggerMsg.chat.id;
|
const chatId = isStoredMessage(triggerMsg) ? triggerMsg.chatId as number : triggerMsg.chat.id;
|
||||||
@@ -1428,7 +1431,8 @@ export async function waveDistortSharp(
|
|||||||
.toBuffer();
|
.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadTelegramFile(filePath: string): Promise<Buffer> {
|
export async function downloadTelegramFile(filePath?: string | null): Promise<Buffer | null> {
|
||||||
|
if (!filePath) return null;
|
||||||
const url = `https://api.telegram.org/file/bot${Environment.BOT_TOKEN}/${filePath}`;
|
const url = `https://api.telegram.org/file/bot${Environment.BOT_TOKEN}/${filePath}`;
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (!res.ok) throw new Error(`Failed to download file: ${res.status} ${res.statusText}`);
|
if (!res.ok) throw new Error(`Failed to download file: ${res.status} ${res.statusText}`);
|
||||||
@@ -1606,7 +1610,7 @@ export function startIntervalEditor(params: {
|
|||||||
try {
|
try {
|
||||||
await params.editFn(next);
|
await params.editFn(next);
|
||||||
lastSent = next;
|
lastSent = next;
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if ((e?.description ?? e?.message ?? "").includes("message is not modified")) return;
|
if ((e?.description ?? e?.message ?? "").includes("message is not modified")) return;
|
||||||
logError("edit failed: " + e);
|
logError("edit failed: " + e);
|
||||||
}
|
}
|
||||||
@@ -1624,7 +1628,7 @@ export function startIntervalEditor(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function boolToInt(bool: boolean): number {
|
export function boolToInt(bool: boolean | undefined): number {
|
||||||
return bool ? 1 : 0;
|
return bool ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1645,7 +1649,7 @@ export function buildExcludedSet<
|
|||||||
const entries = Object.keys(cols)
|
const entries = Object.keys(cols)
|
||||||
.filter((key) => !excludeSet.has(key))
|
.filter((key) => !excludeSet.has(key))
|
||||||
.map((key) => {
|
.map((key) => {
|
||||||
const realName = (cols as unknown)[key].name; // actual DB column name
|
const realName = (cols as any)[key].name; // actual DB column name
|
||||||
return [key, sql.raw(`excluded.${realName}`)] as const;
|
return [key, sql.raw(`excluded.${realName}`)] as const;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1674,7 +1678,7 @@ export function getRuntimeInfo(): RuntimeInfo {
|
|||||||
|
|
||||||
export type PhotoMaxSize = { width: number, height: number, url: string; file_id: string; unique_file_id: string; };
|
export type PhotoMaxSize = { width: number, height: number, url: string; file_id: string; unique_file_id: string; };
|
||||||
|
|
||||||
export function getPhotoMaxSize(photos: PhotoSize[], target: number = Environment.MAX_PHOTO_SIZE): PhotoSize | null {
|
export function getPhotoMaxSize(photos: PhotoSize[] | undefined, target: number = Environment.MAX_PHOTO_SIZE): PhotoSize | null {
|
||||||
if (!photos) return null;
|
if (!photos) return null;
|
||||||
|
|
||||||
photos = photos.filter(p => Math.max(p.width, p.height) <= target);
|
photos = photos.filter(p => Math.max(p.width, p.height) <= target);
|
||||||
@@ -1687,12 +1691,11 @@ export function getPhotoMaxSize(photos: PhotoSize[], target: number = Environmen
|
|||||||
|
|
||||||
return photos.reduce((prev, cur) => {
|
return photos.reduce((prev, cur) => {
|
||||||
if (!prev) return cur;
|
if (!prev) return cur;
|
||||||
|
|
||||||
return cur.width * cur.height > prev.width * prev.height ? cur : prev;
|
return cur.width * cur.height > prev.width * prev.height ? cur : prev;
|
||||||
}, null);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mapPhotoSizeToMax(size: PhotoSize): Promise<PhotoMaxSize | null> {
|
export async function mapPhotoSizeToMax(size: PhotoSize | null): Promise<PhotoMaxSize | null> {
|
||||||
if (!size) return null;
|
if (!size) return null;
|
||||||
return {
|
return {
|
||||||
width: size.width,
|
width: size.width,
|
||||||
@@ -1733,7 +1736,7 @@ export function boolToEmoji(bool: boolean | undefined): string {
|
|||||||
|
|
||||||
export const albumCache = new Map<string, { messages: Message[], timer: NodeJS.Timeout }>();
|
export const albumCache = new Map<string, { messages: Message[], timer: NodeJS.Timeout }>();
|
||||||
|
|
||||||
async function processAlbum(groupId: string): Promise<string[]> {
|
async function processAlbum(groupId: string): Promise<string[] | undefined | null> {
|
||||||
const entry = albumCache.get(groupId);
|
const entry = albumCache.get(groupId);
|
||||||
if (!entry) return;
|
if (!entry) return;
|
||||||
|
|
||||||
@@ -1741,10 +1744,10 @@ async function processAlbum(groupId: string): Promise<string[]> {
|
|||||||
.filter(m => m.photo)
|
.filter(m => m.photo)
|
||||||
.map(m => m.photo);
|
.map(m => m.photo);
|
||||||
|
|
||||||
const allPhotoMaxSizes = await Promise.all(allPhotos.map(photo => getPhotoMaxSize(photo)));
|
const allPhotoMaxSizes = await Promise.all(allPhotos.map(photo => getPhotoMaxSize(photo)).filter(s => !!s));
|
||||||
const ids = await loadImagesFromFileIds(allPhotoMaxSizes);
|
const ids = await loadImagesFromFileIds(allPhotoMaxSizes);
|
||||||
|
|
||||||
console.log(`Received album ${groupId} with ${ids.length} photos.`);
|
console.log(`Received album ${groupId} with ${ids?.length} photos.`);
|
||||||
console.log("File IDs:", ids);
|
console.log("File IDs:", ids);
|
||||||
|
|
||||||
albumCache.delete(groupId);
|
albumCache.delete(groupId);
|
||||||
@@ -1755,7 +1758,7 @@ export function photoPathByUniqueId(uniqueId: string): string {
|
|||||||
return path.join(photoDir, uniqueId + ".jpg");
|
return path.join(photoDir, uniqueId + ".jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentModel(): string {
|
export function getCurrentModel(): string | undefined {
|
||||||
switch (Environment.DEFAULT_AI_PROVIDER) {
|
switch (Environment.DEFAULT_AI_PROVIDER) {
|
||||||
case AiProvider.OLLAMA:
|
case AiProvider.OLLAMA:
|
||||||
return Environment.OLLAMA_MODEL;
|
return Environment.OLLAMA_MODEL;
|
||||||
@@ -1769,7 +1772,7 @@ export function getCurrentModel(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getCurrentModelCapabilities(): Promise<AiModelCapabilities | null> {
|
export async function getCurrentModelCapabilities(): Promise<AiModelCapabilities | null> {
|
||||||
let promise: Promise<AiModelCapabilities | null> = null;
|
let promise: Promise<AiModelCapabilities | null> | null | undefined = null;
|
||||||
switch (Environment.DEFAULT_AI_PROVIDER) {
|
switch (Environment.DEFAULT_AI_PROVIDER) {
|
||||||
case AiProvider.OLLAMA: {
|
case AiProvider.OLLAMA: {
|
||||||
const ollamaGetModel = commands.find(c => c instanceof OllamaGetModel);
|
const ollamaGetModel = commands.find(c => c instanceof OllamaGetModel);
|
||||||
@@ -1779,13 +1782,14 @@ export async function getCurrentModelCapabilities(): Promise<AiModelCapabilities
|
|||||||
promise = new Promise(async (resolve, reject) => {
|
promise = new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const defaultModelCapabilities = await ollamaGetModel.getModelCapabilities();
|
const defaultModelCapabilities = await ollamaGetModel.getModelCapabilities();
|
||||||
|
const imageModelCapabilities = await ollamaGetModel.loadImageModelInfo();
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
vision: (await ollamaGetModel.loadImageModelInfo()).vision,
|
vision: imageModelCapabilities?.vision,
|
||||||
ocr: null,
|
ocr: imageModelCapabilities?.ocr,
|
||||||
thinking: (await ollamaGetModel.loadThinkModelInfo()).thinking,
|
thinking: (await ollamaGetModel.loadThinkModelInfo())?.thinking,
|
||||||
tools: defaultModelCapabilities.tools,
|
tools: defaultModelCapabilities?.tools,
|
||||||
audio: defaultModelCapabilities.audio
|
audio: defaultModelCapabilities?.audio
|
||||||
};
|
};
|
||||||
resolve(result);
|
resolve(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1824,6 +1828,7 @@ export async function processMyChatMember(u: ChatMemberUpdated): Promise<void> {
|
|||||||
|
|
||||||
export async function processNewMessage(msg: Message): Promise<void> {
|
export async function processNewMessage(msg: Message): Promise<void> {
|
||||||
console.log("New Message", msg);
|
console.log("New Message", msg);
|
||||||
|
if (!msg.from) return;
|
||||||
|
|
||||||
const envFile: string = fs.readFileSync(".env").toString();
|
const envFile: string = fs.readFileSync(".env").toString();
|
||||||
const env = new Map(
|
const env = new Map(
|
||||||
@@ -2002,14 +2007,16 @@ export async function processNewMessage(msg: Message): Promise<void> {
|
|||||||
const photos = await processAlbum(groupId);
|
const photos = await processAlbum(groupId);
|
||||||
console.log("processedAlbum", photos);
|
console.log("processedAlbum", photos);
|
||||||
|
|
||||||
storedMsg.photoMaxSizeFilePath = photos;
|
if (storedMsg) {
|
||||||
await MessageStore.put(storedMsg).catch(logError);
|
storedMsg.photoMaxSizeFilePath = photos;
|
||||||
|
await MessageStore.put(storedMsg).catch(logError);
|
||||||
|
}
|
||||||
resolve(true);
|
resolve(true);
|
||||||
}, 1000)
|
}, 1000)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const entry = albumCache.get(groupId);
|
const entry = albumCache.get(groupId);
|
||||||
entry.messages.push(msg);
|
entry?.messages?.push(msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2044,9 +2051,7 @@ export async function processNewMessage(msg: Message): Promise<void> {
|
|||||||
|
|
||||||
const textToCheck = startsWithPrefix ? messageWithoutPrefix : cmdText;
|
const textToCheck = startsWithPrefix ? messageWithoutPrefix : cmdText;
|
||||||
|
|
||||||
if (Environment.PROCESS_LINKS && await processYouTubeLink(msg, getFirstLink(msg))) return;
|
if (msg.chat.type !== "private" && (!msg.reply_to_message || msg.reply_to_message.from?.id !== botUser.id) && !startsWithPrefix && !msg.voice) return;
|
||||||
|
|
||||||
if (msg.chat.type !== "private" && (!msg.reply_to_message || msg.reply_to_message.from.id !== botUser.id) && !startsWithPrefix && !msg.voice) return;
|
|
||||||
|
|
||||||
if (msg.chat.type === "private" && !Environment.ADMIN_IDS.has(msg.chat.id)) return;
|
if (msg.chat.type === "private" && !Environment.ADMIN_IDS.has(msg.chat.id)) return;
|
||||||
|
|
||||||
@@ -2060,167 +2065,52 @@ export async function processNewMessage(msg: Message): Promise<void> {
|
|||||||
const input = path.join(Environment.DATA_PATH, "input.ogg");
|
const input = path.join(Environment.DATA_PATH, "input.ogg");
|
||||||
const output = path.join(Environment.DATA_PATH, "output.wav")
|
const output = path.join(Environment.DATA_PATH, "output.wav")
|
||||||
|
|
||||||
try {
|
if (fileBuffer) {
|
||||||
fs.writeFileSync(input, fileBuffer);
|
try {
|
||||||
await performFFmpeg(() =>
|
fs.writeFileSync(input, fileBuffer);
|
||||||
ffmpeg(input)
|
await performFFmpeg(() =>
|
||||||
.toFormat("wav")
|
ffmpeg(input)
|
||||||
.save(output)
|
.toFormat("wav")
|
||||||
.on("progress", (progress) => {
|
.save(output)
|
||||||
console.log("progress", progress);
|
.on("progress", (progress) => {
|
||||||
})
|
console.log("progress", progress);
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
|
||||||
fileBuffer = fs.readFileSync(output);
|
fileBuffer = fs.readFileSync(output);
|
||||||
voiceB64 = fileBuffer.toString("base64");
|
voiceB64 = fileBuffer.toString("base64");
|
||||||
fs.rmSync(input);
|
fs.rmSync(input);
|
||||||
fs.rmSync(output);
|
fs.rmSync(output);
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
} catch (e) {
|
||||||
|
logError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Environment.DEFAULT_AI_PROVIDER) {
|
switch (Environment.DEFAULT_AI_PROVIDER) {
|
||||||
case AiProvider.OLLAMA: {
|
case AiProvider.OLLAMA: {
|
||||||
await commands.find(e => e instanceof OllamaChat).executeOllama(msg, textToCheck, false, voiceB64);
|
await commands.find(e => e instanceof OllamaChat)?.executeOllama(msg, textToCheck, false, voiceB64);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AiProvider.GEMINI: {
|
case AiProvider.GEMINI: {
|
||||||
await commands.find(e => e instanceof GeminiChat).executeGemini(msg, textToCheck);
|
await commands.find(e => e instanceof GeminiChat)?.executeGemini(msg, textToCheck);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AiProvider.MISTRAL: {
|
case AiProvider.MISTRAL: {
|
||||||
await commands.find(e => e instanceof MistralChat).executeMistral(msg, textToCheck);
|
await commands.find(e => e instanceof MistralChat)?.executeMistral(msg, textToCheck);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AiProvider.OPENAI: {
|
case AiProvider.OPENAI: {
|
||||||
await commands.find(e => e instanceof OpenAIChat).executeOpenAI(msg, textToCheck);
|
await commands.find(e => e instanceof OpenAIChat)?.executeOpenAI(msg, textToCheck);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFirstLink(msg: Message): string | null {
|
|
||||||
if (msg.entities) {
|
|
||||||
const urlEntities = msg.entities.filter(e => e.type === "url");
|
|
||||||
if (urlEntities.length) {
|
|
||||||
const e = urlEntities[0];
|
|
||||||
return msg.text.substring(e.offset, e.offset + e.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processYouTubeLink(msg: Message, url?: string, id?: string): Promise<boolean> {
|
|
||||||
if (!url && !id) return false;
|
|
||||||
|
|
||||||
let waitMessage: Message | null = msg.from.id === botUser.id ? msg : null;
|
|
||||||
let videoId: string | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
videoId = id || getYouTubeVideoId(url);
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const yt = commands.find(e => e instanceof YouTubeDownload);
|
|
||||||
|
|
||||||
if (await checkRequirements(yt, msg)) {
|
|
||||||
if (!waitMessage) {
|
|
||||||
waitMessage = await replyToMessage({
|
|
||||||
message: msg,
|
|
||||||
text: "⏳ Ищу информацию о видео..."
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await editMessageText({message: msg, text: "⏳ Ищу информацию о видео..."});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let videoInfo: VideoInfo | null = null;
|
|
||||||
let ytError: string = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
videoInfo = await getYouTubeVideoInfo(videoId);
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
|
|
||||||
if ("version" in e) {
|
|
||||||
ytError = e.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("VIDEO_INFO", videoInfo);
|
|
||||||
|
|
||||||
let text: string = null;
|
|
||||||
|
|
||||||
const inCache = isVideoExists({videoId: videoId});
|
|
||||||
|
|
||||||
const duration = videoInfo?.basic_info?.duration || null;
|
|
||||||
const canDownload = inCache || duration && duration <= 300;
|
|
||||||
|
|
||||||
if (videoInfo) {
|
|
||||||
text = "Видео с YouTube\n\n" +
|
|
||||||
`Название: ${videoInfo.basic_info?.title}\n` +
|
|
||||||
`Автор: ${videoInfo.secondary_info?.owner?.author?.name}\n` +
|
|
||||||
`Длительность: ${duration} сек.`;
|
|
||||||
|
|
||||||
if (!canDownload) {
|
|
||||||
text += `\n\nВидео слишком длинное (${duration} сек. > 300 сек.)`;
|
|
||||||
}
|
|
||||||
} else if (!ytError) {
|
|
||||||
text = "Информация о видео не найдена";
|
|
||||||
}
|
|
||||||
|
|
||||||
const errorButInCache = !videoInfo && ytError && inCache;
|
|
||||||
if (errorButInCache) {
|
|
||||||
text = "Я не смог получить информацию о видео, но нашёл его в кэше.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!text && ytError) {
|
|
||||||
await editMessageText({
|
|
||||||
message: waitMessage,
|
|
||||||
text: Environment.errorText,
|
|
||||||
reply_markup: {
|
|
||||||
inline_keyboard: [[
|
|
||||||
TryAgain.withData("/ytinfo " + videoId).asButton()
|
|
||||||
]]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await editMessageText({
|
|
||||||
message: waitMessage,
|
|
||||||
text: text,
|
|
||||||
reply_markup: canDownload ? {
|
|
||||||
inline_keyboard: [[
|
|
||||||
DownloadYtVideo.withData(inCache, "/ytdl " + videoId).asButton()
|
|
||||||
]]
|
|
||||||
} : {inline_keyboard: []}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
|
|
||||||
await editMessageText({
|
|
||||||
message: waitMessage,
|
|
||||||
text: Environment.errorText,
|
|
||||||
reply_markup: {
|
|
||||||
inline_keyboard: [[
|
|
||||||
TryAgain.withData("/ytinfo " + videoId).asButton()
|
|
||||||
]]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function processEditedMessage(msg: Message): Promise<void> {
|
export async function processEditedMessage(msg: Message): Promise<void> {
|
||||||
console.log("Edited Message", msg);
|
console.log("Edited Message", msg);
|
||||||
|
if (!msg.from) return;
|
||||||
|
|
||||||
await UserStore.put(msg.from);
|
await UserStore.put(msg.from);
|
||||||
|
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
import fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
import {videoDir, videoTempDir} from "../index";
|
|
||||||
import ffmpeg from "fluent-ffmpeg";
|
|
||||||
import Innertube, {Platform, Types} from "youtubei.js";
|
|
||||||
import {Readable} from "node:stream";
|
|
||||||
import {logError} from "./utils";
|
|
||||||
import {performFFmpeg} from "./ffmpeg";
|
|
||||||
import VideoInfo from "youtubei.js/dist/src/parser/youtube/VideoInfo";
|
|
||||||
|
|
||||||
let innertube: Innertube | null = null;
|
|
||||||
|
|
||||||
export async function getYT(): Promise<Innertube> {
|
|
||||||
if (innertube) {
|
|
||||||
return innertube;
|
|
||||||
} else {
|
|
||||||
innertube = await Innertube.create({
|
|
||||||
generate_session_locally: true,
|
|
||||||
retrieve_player: true
|
|
||||||
});
|
|
||||||
return innertube;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getYouTubeVideoId(url: string): string {
|
|
||||||
const regex = /(?:(?:youtube\.com|music\.youtube\.com)\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?|shorts|clip)\/|.*[?&]v=)|youtu\.be\/)([^"&?/\s]{11})/i;
|
|
||||||
const match = url.match(regex);
|
|
||||||
if (!match || !match[1]) throw new Error("Invalid YouTube or Shorts URL");
|
|
||||||
return match[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getYouTubeVideoInfo(videoId: string): Promise<VideoInfo> {
|
|
||||||
try {
|
|
||||||
return (await getYT()).getInfo(videoId, {client: "ANDROID"});
|
|
||||||
} catch (e) {
|
|
||||||
logError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isVideoExists(options: DownloadOptions): boolean {
|
|
||||||
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
|
|
||||||
const filePath = path.join(videoDir, `${videoId}.mp4`);
|
|
||||||
return fs.existsSync(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getVideoFromCache(videoId: string): Buffer | null {
|
|
||||||
if (!isVideoExists({videoId: videoId})) return null;
|
|
||||||
|
|
||||||
const filePath = path.join(videoDir, `${videoId}.mp4`);
|
|
||||||
return Buffer.from(fs.readFileSync(filePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DownloadOptions = {
|
|
||||||
url: string
|
|
||||||
} | {
|
|
||||||
videoId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function downloadVideoFromYouTube(options: DownloadOptions): Promise<{
|
|
||||||
time: number,
|
|
||||||
exists?: boolean,
|
|
||||||
buffer: Buffer | null
|
|
||||||
}> {
|
|
||||||
const start = Date.now();
|
|
||||||
let buffer: Buffer | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const videoId = "videoId" in options ? options.videoId : getYouTubeVideoId(options.url);
|
|
||||||
const filePath = path.join(videoDir, `${videoId}.mp4`);
|
|
||||||
if (fs.existsSync(filePath)) {
|
|
||||||
const buffer = Buffer.from(fs.readFileSync(filePath));
|
|
||||||
return {
|
|
||||||
time: Date.now() - start,
|
|
||||||
exists: true,
|
|
||||||
buffer: buffer
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.shim.eval = async (data: Types.BuildScriptResult, env: Record<string, Types.VMPrimative>) => {
|
|
||||||
const properties = [];
|
|
||||||
if (env.n) properties.push(`n: exportedVars.nFunction("${env.n}")`);
|
|
||||||
if (env.sig) properties.push(`sig: exportedVars.sigFunction("${env.sig}")`);
|
|
||||||
|
|
||||||
const code = `${data.output}\nreturn { ${properties.join(", ")} }`;
|
|
||||||
return new Function(code)();
|
|
||||||
};
|
|
||||||
|
|
||||||
const yt = await getYT();
|
|
||||||
|
|
||||||
const videoInfo = await yt.getInfo(videoId, {client: "ANDROID"});
|
|
||||||
console.log("Video info", videoInfo);
|
|
||||||
|
|
||||||
console.log(`Fetching metadata for: ${videoId}...`);
|
|
||||||
|
|
||||||
const targetQuality = "360p";
|
|
||||||
|
|
||||||
const videoFormat = videoInfo.streaming_data?.formats.find(f => f.quality_label.startsWith(targetQuality))
|
|
||||||
|| videoInfo.streaming_data?.adaptive_formats.find(f => f.quality_label.startsWith(targetQuality));
|
|
||||||
|
|
||||||
const audioFormat = videoInfo.chooseFormat({type: "audio", quality: "best", language: "original"});
|
|
||||||
|
|
||||||
console.log("Video format: ", videoFormat);
|
|
||||||
console.log("Audio Format: ", audioFormat);
|
|
||||||
|
|
||||||
if (!videoFormat) {
|
|
||||||
console.log(`Quality ${targetQuality} not found. Falling back to best available.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const videoWebStream = await videoInfo.download({
|
|
||||||
itag: videoFormat.itag,
|
|
||||||
client: "ANDROID"
|
|
||||||
});
|
|
||||||
|
|
||||||
const audioWebStream = await videoInfo.download({
|
|
||||||
itag: audioFormat.itag,
|
|
||||||
client: "ANDROID"
|
|
||||||
});
|
|
||||||
|
|
||||||
const videoStream = Readable.fromWeb(videoWebStream as any);
|
|
||||||
const audioStream = Readable.fromWeb(audioWebStream as any);
|
|
||||||
|
|
||||||
const videoPath = path.join(videoTempDir, `temp_video_${videoId}.mp4`);
|
|
||||||
const audioPath = path.join(videoTempDir, `temp_audio_${videoId}.mp4`);
|
|
||||||
|
|
||||||
const writeStream = (stream: any, path: string) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
const file = fs.createWriteStream(path);
|
|
||||||
stream.pipe(file);
|
|
||||||
file.on("finish", resolve);
|
|
||||||
file.on("error", reject);
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
writeStream(videoStream, videoPath),
|
|
||||||
writeStream(audioStream, audioPath)
|
|
||||||
]);
|
|
||||||
|
|
||||||
await performFFmpeg(() =>
|
|
||||||
ffmpeg()
|
|
||||||
.input(videoPath)
|
|
||||||
.input(audioPath)
|
|
||||||
.videoCodec("copy")
|
|
||||||
.audioCodec("copy")
|
|
||||||
.save(filePath)
|
|
||||||
.on("progress", (progress) => {
|
|
||||||
console.log("progress", progress);
|
|
||||||
})
|
|
||||||
).catch(logError);
|
|
||||||
|
|
||||||
fs.unlinkSync(videoPath);
|
|
||||||
fs.unlinkSync(audioPath);
|
|
||||||
|
|
||||||
buffer = fs.readFileSync(filePath);
|
|
||||||
|
|
||||||
console.log(`✅ Saved to ${videoId}.mp4`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("❌ Download failed:", error instanceof Error ? error.message : error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const end = Date.now();
|
|
||||||
const diff = end - start;
|
|
||||||
console.log(`Video downloaded.\ntook ${diff}ms`);
|
|
||||||
|
|
||||||
return {
|
|
||||||
time: diff,
|
|
||||||
buffer: buffer,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+14
-1
@@ -4,7 +4,20 @@
|
|||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es2024",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": ["dom", "dom.iterable", "ESNext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts"],
|
"include": ["src/**/*.ts"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
|
|||||||
Reference in New Issue
Block a user