diff --git a/README.md b/README.md index edb21ac..f785cf2 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,10 @@ - [x] Deploy using [docker compose](#use-with-docker-compose---recommended-) - [x] Add Railway deploy - [x] Add Fly.io deploy -- [x] Supports custom ChatGPT API +- [x] ~~Supports custom ChatGPT API~~ +- [x] Set prompt +- [x] Continuous conversation +- [x] Support command setting - [ ] Support proxy ## 🚀 Usage @@ -81,7 +84,6 @@ flyctl deploy ``` - ## Use with docker ```sh @@ -135,7 +137,7 @@ npm npm dev | name | default | example | description | |------------------------------|------------------------|------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| API | https://api.openai.com | | API endpoint of ChatGPT | +| ~~API~~ | https://api.openai.com | | ~~API endpoint of ChatGPT~~ | | OPENAI_API_KEY | 123456789 | sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | [create new secret key](https://platform.openai.com/account/api-keys) | | MODEL | gpt-3.5-turbo | | ID of the model to use. Currently, only gpt-3.5-turbo and gpt-3.5-turbo-0301 are supported. | | TEMPERATURE | 0.6 | | What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. | @@ -163,6 +165,14 @@ routes = [ ] ``` +## ⌨️ Commands +> Enter in the WeChat chat box +```shell +/cmd help # Show help +/cmd prompt # Set prompt +/cmd clear # Clear all sessions since last boot +``` + ## ✨ Contributor diff --git a/README_ZH.md b/README_ZH.md index 335d4e0..c6157e3 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -27,7 +27,10 @@ - [x] 使用[docker compose](#通过docker-compose使用-推荐)进行部署 - [x] 通过 Railway 进行部署 - [x] 通过 Fly.io 进行部署 -- [x] 支持自定义ChatGPT API +- [x] ~~支持自定义ChatGPT API~~ +- [x] 支持设置prompt +- [x] 支持连续对话 +- [x] 支持命令设置 - [ ] 支持代理 ## 🚀 使用 @@ -139,7 +142,7 @@ npm run dev | name | default | example | description | |------------------------------|------------------------|------------------------------------------------|-------------------------------------------------------------| -| API | https://api.openai.com | ChatGPT API 地址 | +| ~~API~~ | https://api.openai.com | | ~~ChatGPT API 地址~~ | | OPENAI_API_KEY | 123456789 | sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX | [创建你的 API 密钥](https://platform.openai.com/account/api-keys) | | MODEL | gpt-3.5-turbo | | 要使用的模型ID, 目前仅支持`gpt-3.5-turbo` 和 `gpt-3.5-turbo-0301` | | TEMPERATURE | 0.6 | | 在0和2之间。较高的数值如0.8会使 ChatGPT 输出更加随机,而较低的数值如0.2会使其更加稳定。 | @@ -149,7 +152,6 @@ npm run dev | BLOCK_WORDS | | "WORD1,WORD2,WORD3" | 聊天屏蔽关键词(同时在群组和私聊中生效, 避免 bot 用户恶意提问导致封号 | | CHATGPT_BLOCK_WORDS | | "WORD1,WORD2,WORD3" | ChatGPT回复屏蔽词, 如果ChatGPT的回复中包含了屏蔽词, 则不回复 | - ## 📝 使用自定义ChatGPT API > https://github.com/fuergaosi233/openai-proxy ```shell @@ -166,6 +168,14 @@ routes = [ ] ``` +## ⌨️ 命令 +> 在微信聊天框中输入 +```shell +/cmd help # 显示帮助信息 +/cmd prompt # 设置ChatGPT Prompt +/cmd clear # 清除WeChat-ChatGPT保存的会话记录 +``` + ## ✨ Contributor diff --git a/package-lock.json b/package-lock.json index 111368e..df01a76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "async-retry": "^1.3.3", "dotenv": "^16.0.3", "execa": "^6.1.0", + "openai": "^3.2.1", "qrcode": "^1.5.1", "uuid": "^9.0.0", "wechaty": "^1.20.2", @@ -948,9 +949,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "node_modules/axios": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.0.tgz", - "integrity": "sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -1021,9 +1022,9 @@ } }, "node_modules/bl/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1034,7 +1035,7 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/bl/node_modules/safe-buffer": { + "node_modules/bl/node_modules/readable-stream/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" @@ -1047,6 +1048,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/bl/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/bmp-js": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", @@ -1378,7 +1384,8 @@ "node_modules/cuid": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/cuid/-/cuid-2.1.8.tgz", - "integrity": "sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg==" + "integrity": "sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg==", + "deprecated": "Cuid and other k-sortable and non-cryptographic ids (Ulid, ObjectId, KSUID, all UUIDs) are all insecure. Use @paralleldrive/cuid2 instead." }, "node_modules/dashdash": { "version": "1.14.1", @@ -1416,9 +1423,9 @@ } }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "engines": { "node": ">=0.10.0" } @@ -1543,16 +1550,6 @@ "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "peer": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, "node_modules/encoding-down": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", @@ -1567,19 +1564,6 @@ "node": ">=10" } }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -2005,9 +1989,9 @@ "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/har-schema": { "version": "2.0.0", @@ -3046,6 +3030,36 @@ "request": "^2.73.0" } }, + "node_modules/openai": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", + "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, + "node_modules/openai/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/openai/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -3287,6 +3301,7 @@ "version": "13.7.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.7.0.tgz", "integrity": "sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==", + "deprecated": "< 19.2.0 is no longer supported", "hasInstallScript": true, "dependencies": { "cross-fetch": "3.1.5", @@ -3307,9 +3322,9 @@ } }, "node_modules/puppeteer-extra": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.4.tgz", - "integrity": "sha512-fN5pHvSMJ8d1o7Z8wLLTQOUBpORD2BcFn+KDs7QnkGZs9SV69hcUcce67vX4L4bNSEG3A0P6Osrv+vWNhhdm8w==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz", + "integrity": "sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==", "dependencies": { "@types/debug": "^4.1.0", "debug": "^4.1.1", @@ -3336,9 +3351,9 @@ } }, "node_modules/puppeteer-extra-plugin": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.2.tgz", - "integrity": "sha512-0uatQxzuVn8yegbrEwSk03wvwpMB5jNs7uTTnermylLZzoT+1rmAQaJXwlS3+vADUbw6ELNgNEHC7Skm0RqHbQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.3.tgz", + "integrity": "sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q==", "dependencies": { "@types/debug": "^4.1.0", "debug": "^4.1.1", @@ -3361,13 +3376,13 @@ } }, "node_modules/puppeteer-extra-plugin-stealth": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.1.tgz", - "integrity": "sha512-n0wdC0Ilc9tk5L6FWLyd0P2gT8b2fp+2NuB+KB0oTSw3wXaZ0D6WNakjJsayJ4waGzIJFCUHkmK9zgx5NKMoFw==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.2.tgz", + "integrity": "sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ==", "dependencies": { "debug": "^4.1.1", - "puppeteer-extra-plugin": "^3.2.2", - "puppeteer-extra-plugin-user-preferences": "^2.4.0" + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-preferences": "^2.4.1" }, "engines": { "node": ">=8" @@ -3386,13 +3401,13 @@ } }, "node_modules/puppeteer-extra-plugin-user-data-dir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.0.tgz", - "integrity": "sha512-qrhYPTGIqzL2hpeJ5DXjf8xMy5rt1UvcqSgpGTTOUOjIMz1ROWnKHjBoE9fNBJ4+ToRZbP8MzIDXWlEk/e1zJA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.1.tgz", + "integrity": "sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g==", "dependencies": { "debug": "^4.1.1", "fs-extra": "^10.0.0", - "puppeteer-extra-plugin": "^3.2.2", + "puppeteer-extra-plugin": "^3.2.3", "rimraf": "^3.0.2" }, "engines": { @@ -3412,14 +3427,14 @@ } }, "node_modules/puppeteer-extra-plugin-user-preferences": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.0.tgz", - "integrity": "sha512-4XxMhMkJ+qqLsPY9ULF90qS9Bj1Qrwwgp1TY9zTdp1dJuy7QSgYE7xlyamq3cKrRuzg3QUOqygJo52sVeXSg5A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.1.tgz", + "integrity": "sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A==", "dependencies": { "debug": "^4.1.1", "deepmerge": "^4.2.2", - "puppeteer-extra-plugin": "^3.2.2", - "puppeteer-extra-plugin-user-data-dir": "^2.4.0" + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-data-dir": "^2.4.1" }, "engines": { "node": ">=8" @@ -4103,9 +4118,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "peer": true, "bin": { @@ -4113,7 +4128,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/unbzip2-stream": { @@ -4213,9 +4228,9 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/wechat4u": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/wechat4u/-/wechat4u-0.7.8.tgz", - "integrity": "sha512-2k9FRiYV8G4KM9aHJXIpgqiMAcln5vieXWbBAxlUQY/B9buxgEkRHYH4mZSY3AiIS1X+mFQkzCmG5/GgPLLwkw==", + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/wechat4u/-/wechat4u-0.7.10.tgz", + "integrity": "sha512-nUWN2ypjeuMXOAlU+NlwYdJhyonzCBprC5O9Wms1YwgG/TPhvtmKKkpuaD2JJ5/h2wrqXfs+r/dsemAPuySFAA==", "dependencies": { "axios": "^1.1.3", "bl": "^1.1.2", @@ -4412,25 +4427,6 @@ "brolog": "^1.3.3" } }, - "node_modules/wechaty-puppet-wechat4u": { - "version": "1.13.11", - "resolved": "https://registry.npmjs.org/wechaty-puppet-wechat4u/-/wechaty-puppet-wechat4u-1.13.11.tgz", - "integrity": "sha512-OM+pXAcEYWcMmoscJLPazn5Ji+8ZFNetyromyzq05crDAM4ra7CQmUkJaQNZHxZZdoioTiBsTCAhDsIpHeOdDA==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "fast-xml-parser": "^3.21.1", - "promise-retry": "^2.0.1", - "wechat4u": "^0.7.8", - "xml2js": "^0.4.23" - }, - "engines": { - "node": ">=16", - "npm": ">=7" - }, - "peerDependencies": { - "wechaty-puppet": "^1.18.3" - } - }, "node_modules/wechaty-puppet/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -4517,6 +4513,25 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/wechaty/node_modules/wechaty-puppet-wechat4u": { + "version": "1.13.14", + "resolved": "https://registry.npmjs.org/wechaty-puppet-wechat4u/-/wechaty-puppet-wechat4u-1.13.14.tgz", + "integrity": "sha512-k32aQJHjQdE/Hsj1OE44lle6zSMaSusHAlS+LOmxW5AcTQni4kEGA1UteN3MvlRc6K8INxc2Ol85HwacVob3bA==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "fast-xml-parser": "^3.21.1", + "promise-retry": "^2.0.1", + "wechat4u": "^0.7.10", + "xml2js": "^0.4.23" + }, + "engines": { + "node": ">=16", + "npm": ">=7" + }, + "peerDependencies": { + "wechaty-puppet": "^1.18.3" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -5425,9 +5440,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axios": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.0.tgz", - "integrity": "sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -5480,9 +5495,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5491,19 +5506,28 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } } } } @@ -5782,9 +5806,9 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" }, "deferred-leveldown": { "version": "7.0.0", @@ -5887,28 +5911,6 @@ "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "peer": true, - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "peer": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, "encoding-down": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz", @@ -6232,9 +6234,9 @@ "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "har-schema": { "version": "2.0.0", @@ -7024,6 +7026,35 @@ "request": "^2.73.0" } }, + "openai": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", + "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", + "requires": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + }, + "dependencies": { + "axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "requires": { + "follow-redirects": "^1.14.8" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -7239,9 +7270,9 @@ } }, "puppeteer-extra": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.4.tgz", - "integrity": "sha512-fN5pHvSMJ8d1o7Z8wLLTQOUBpORD2BcFn+KDs7QnkGZs9SV69hcUcce67vX4L4bNSEG3A0P6Osrv+vWNhhdm8w==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz", + "integrity": "sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==", "requires": { "@types/debug": "^4.1.0", "debug": "^4.1.1", @@ -7249,9 +7280,9 @@ } }, "puppeteer-extra-plugin": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.2.tgz", - "integrity": "sha512-0uatQxzuVn8yegbrEwSk03wvwpMB5jNs7uTTnermylLZzoT+1rmAQaJXwlS3+vADUbw6ELNgNEHC7Skm0RqHbQ==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.3.tgz", + "integrity": "sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q==", "requires": { "@types/debug": "^4.1.0", "debug": "^4.1.1", @@ -7259,35 +7290,35 @@ } }, "puppeteer-extra-plugin-stealth": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.1.tgz", - "integrity": "sha512-n0wdC0Ilc9tk5L6FWLyd0P2gT8b2fp+2NuB+KB0oTSw3wXaZ0D6WNakjJsayJ4waGzIJFCUHkmK9zgx5NKMoFw==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.2.tgz", + "integrity": "sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ==", "requires": { "debug": "^4.1.1", - "puppeteer-extra-plugin": "^3.2.2", - "puppeteer-extra-plugin-user-preferences": "^2.4.0" + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-preferences": "^2.4.1" } }, "puppeteer-extra-plugin-user-data-dir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.0.tgz", - "integrity": "sha512-qrhYPTGIqzL2hpeJ5DXjf8xMy5rt1UvcqSgpGTTOUOjIMz1ROWnKHjBoE9fNBJ4+ToRZbP8MzIDXWlEk/e1zJA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.1.tgz", + "integrity": "sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g==", "requires": { "debug": "^4.1.1", "fs-extra": "^10.0.0", - "puppeteer-extra-plugin": "^3.2.2", + "puppeteer-extra-plugin": "^3.2.3", "rimraf": "^3.0.2" } }, "puppeteer-extra-plugin-user-preferences": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.0.tgz", - "integrity": "sha512-4XxMhMkJ+qqLsPY9ULF90qS9Bj1Qrwwgp1TY9zTdp1dJuy7QSgYE7xlyamq3cKrRuzg3QUOqygJo52sVeXSg5A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.1.tgz", + "integrity": "sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A==", "requires": { "debug": "^4.1.1", "deepmerge": "^4.2.2", - "puppeteer-extra-plugin": "^3.2.2", - "puppeteer-extra-plugin-user-data-dir": "^2.4.0" + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-data-dir": "^2.4.1" } }, "qr-image": { @@ -7761,9 +7792,9 @@ "integrity": "sha512-bna6Yi1pRznoo6Bz1cE6btB/Yy8Xywytyfrzu/wc+NFW3ZF0I+2iCGImhBsoYYCOWuICtRO4yHcnDlzgo1AdNg==" }, "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "peer": true }, @@ -7848,9 +7879,9 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "wechat4u": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/wechat4u/-/wechat4u-0.7.8.tgz", - "integrity": "sha512-2k9FRiYV8G4KM9aHJXIpgqiMAcln5vieXWbBAxlUQY/B9buxgEkRHYH4mZSY3AiIS1X+mFQkzCmG5/GgPLLwkw==", + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/wechat4u/-/wechat4u-0.7.10.tgz", + "integrity": "sha512-nUWN2ypjeuMXOAlU+NlwYdJhyonzCBprC5O9Wms1YwgG/TPhvtmKKkpuaD2JJ5/h2wrqXfs+r/dsemAPuySFAA==", "requires": { "axios": "^1.1.3", "bl": "^1.1.2", @@ -7911,6 +7942,18 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "wechaty-puppet-wechat4u": { + "version": "1.13.14", + "resolved": "https://registry.npmjs.org/wechaty-puppet-wechat4u/-/wechaty-puppet-wechat4u-1.13.14.tgz", + "integrity": "sha512-k32aQJHjQdE/Hsj1OE44lle6zSMaSusHAlS+LOmxW5AcTQni4kEGA1UteN3MvlRc6K8INxc2Ol85HwacVob3bA==", + "requires": { + "@alloc/quick-lru": "^5.2.0", + "fast-xml-parser": "^3.21.1", + "promise-retry": "^2.0.1", + "wechat4u": "^0.7.10", + "xml2js": "^0.4.23" + } } } }, @@ -8015,18 +8058,6 @@ } } }, - "wechaty-puppet-wechat4u": { - "version": "1.13.11", - "resolved": "https://registry.npmjs.org/wechaty-puppet-wechat4u/-/wechaty-puppet-wechat4u-1.13.11.tgz", - "integrity": "sha512-OM+pXAcEYWcMmoscJLPazn5Ji+8ZFNetyromyzq05crDAM4ra7CQmUkJaQNZHxZZdoioTiBsTCAhDsIpHeOdDA==", - "requires": { - "@alloc/quick-lru": "^5.2.0", - "fast-xml-parser": "^3.21.1", - "promise-retry": "^2.0.1", - "wechat4u": "^0.7.8", - "xml2js": "^0.4.23" - } - }, "wechaty-redux": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/wechaty-redux/-/wechaty-redux-1.20.2.tgz", diff --git a/package.json b/package.json index 1b6ee6f..568aaf6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "async-retry": "^1.3.3", "dotenv": "^16.0.3", "execa": "^6.1.0", + "openai": "^3.2.1", "qrcode": "^1.5.1", "uuid": "^9.0.0", "wechaty": "^1.20.2", diff --git a/src/bot.ts b/src/bot.ts index 8c8b509..01b21a4 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,7 +1,8 @@ import { config } from "./config.js"; -import { ContactInterface, RoomInterface } from "wechaty/impls"; +import {ContactImpl, ContactInterface, RoomImpl, RoomInterface} from "wechaty/impls"; import { Message } from "wechaty"; -import {sendMessage} from "./chatgpt.js"; +import {getCompletion} from "./openai.js"; +import {addSessionByUsername, clearUserData, setPromptByUsername} from "./data.js"; enum MessageType { Unknown = 0, @@ -44,7 +45,43 @@ export class ChatGPTBot { } return regEx } - async command(): Promise {} + async command(talker:RoomInterface|ContactInterface, text:string): Promise { + // 找到第一个空格之前的字符串 + const command = text.split(" ")[0]; + console.log(`command: ${command}`); + switch (command) { + case "help": + await this.trySay(talker,"========\n" + + "/cmd help\n" + + "# 显示帮助信息\n" + + "/cmd prompt \n" + + "# 设置当前会话的prompt\n" + + "/cmd clear\n" + + "# 清除自上次启动以来的所有会话\n" + + "========"); + break; + case "prompt": + let prompt = text.slice(command.length+1); + if (talker instanceof RoomImpl) { + setPromptByUsername(talker.id, prompt); + await this.trySay(talker,"设置成功!"); + }else if (talker instanceof ContactImpl) { + setPromptByUsername(talker.name(), prompt); + await this.trySay(talker,"设置成功"); + } + break; + case "clear": + console.log("清除会话"); + if (talker instanceof RoomImpl) { + clearUserData(talker.id); + await this.trySay(talker,"清除成功!"); + }else if (talker instanceof ContactImpl) { + clearUserData(talker.name()); + await this.trySay(talker,"清除成功"); + } + break; + } + } // remove more times conversation and mention cleanMessage(rawText: string, privateChat: boolean = false): string { let text = rawText; @@ -64,8 +101,10 @@ export class ChatGPTBot { // remove more text via - - - - - - - - - - - - - - - return text } - async getGPTMessage(text: string): Promise { - return await sendMessage(text); + async getGPTMessage(talkerName: string,text: string): Promise { + let gptMessage = await getCompletion(talkerName,text); + addSessionByUsername(talkerName, {assistantMsg:gptMessage}); + return gptMessage; } // Check if the message returned by chatgpt contains masked words] checkChatGPTBlockWords(message: string): boolean { @@ -145,7 +184,7 @@ export class ChatGPTBot { } async onPrivateMessage(talker: ContactInterface, text: string) { - const gptMessage = await this.getGPTMessage(text); + const gptMessage = await this.getGPTMessage(talker.name(),text); await this.trySay(talker, gptMessage); } @@ -154,20 +193,30 @@ export class ChatGPTBot { text: string, room: RoomInterface ) { - const gptMessage = await this.getGPTMessage(text); - const result = `@${talker.name()} ${text}\n\n------ ${gptMessage}`; + const gptMessage = await this.getGPTMessage(room.id,text); + const result = `@${talker.name()} ${text}\n\n------\n ${gptMessage}`; await this.trySay(room, result); } async onMessage(message: Message) { - console.log(`🎯 ${message.date()} Message: ${message}`); const talker = message.talker(); const rawText = message.text(); const room = message.room(); const messageType = message.type(); const privateChat = !room; + if (privateChat) { + console.log(`🤵 Contact: ${talker.name()} 💬 Text: ${rawText}`) + } else { + const topic = await room.topic() + console.log(`🚪 Room: ${topic} 🤵 Contact: ${talker.name()} 💬 Text: ${rawText}`) + } if (this.isNonsense(talker, messageType, rawText)) { return; } + if (rawText.startsWith("/cmd ")){ + console.log(`🤖 Command: ${rawText}`) + const text = rawText.slice(5) // 「/cmd 」一共5个字符(注意空格) + return await this.command(privateChat?talker:room, text); + } if (this.triggerGPTMessage(rawText, privateChat)) { const text = this.cleanMessage(rawText, privateChat); if (privateChat) { diff --git a/src/chatgpt.ts b/src/chatgpt.ts deleted file mode 100644 index c906ecf..0000000 --- a/src/chatgpt.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {config} from "./config.js"; - -let api = config.api; -let apiKey = config.openai_api_key; -let model = config.model; -let temperature = config.temperature; -const sendMessage = async (message: string) => { - try { - const response = await fetch(`${api}/v1/chat/completions`, { - method: "POST", - headers: { - Authorization: `Bearer ${apiKey}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - model: model, - messages: [ - { - "role": "user", - "content": message - } - ], - temperature: temperature - }), - }).then((res) => res.json()); - if (response.error?.message) { - console.log("OpenAI API ERROR: ",response.error.message) - // throw new Error(`OpenAI API ${response.error.message}`); - } - return response.choices[0].message.content; - } catch (e) { - console.error(e) - return "Something went wrong" - } -} - -export {sendMessage}; \ No newline at end of file diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..4ed0c27 --- /dev/null +++ b/src/data.ts @@ -0,0 +1,83 @@ +/** + * 使用内存作为数据库 + */ +type session = { + userMsg?: string, + assistantMsg?: string +} +type user = { + username: string, + prompt: string, + session: session[] +} +type data = user[] +// Initialize data +const data: data = [] + +/** + * Add user + * @param username + * @param prompt default: "" + */ +function addUser(username: string, prompt: string = ""): user { + const user = { + username: username, + prompt: prompt, + session: [{ + userMsg: "", + assistantMsg: "" + }] + } + data.push(user) + return data.find(user => user.username === username) as user; +} + +function addSessionByUsername( + username: string, + {userMsg = "", assistantMsg = ""}: session +): void { + const user = getUserByUsername(username) + if (user) { + user.session.push({ + userMsg: userMsg, + assistantMsg: assistantMsg + }) + } +} + +/** + * Get user by username + * @param username + */ +function getUserByUsername(username: string): user | undefined { + let user = data.find(user => user.username === username); + return user +} +function getSessionByUsername(username: string): session[] | undefined { + const user = getUserByUsername(username) + if (user) { + return user.session + } +} +function getAllData(): data { + return data +} +function setPromptByUsername(username: string, prompt: string): void { + const user = getUserByUsername(username) + if (user) { + user.prompt = prompt + }else{ + addUser(username,prompt).prompt= prompt + } +} +function clearUserData(username: string): void { + const user = getUserByUsername(username) + if (user) { + user.prompt = "" + user.session = [{ + userMsg: "", + assistantMsg: "" + }] + } +} +export {addUser, addSessionByUsername,getUserByUsername, getSessionByUsername,getAllData,setPromptByUsername,clearUserData} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 2e77740..3d1eadf 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,10 +2,15 @@ import { WechatyBuilder } from "wechaty"; import QRCode from "qrcode"; import { ChatGPTBot } from "./bot.js"; import {config} from "./config.js"; + const chatGPTBot = new ChatGPTBot(); const bot = WechatyBuilder.build({ name: "wechat-assistant", // generate xxxx.memory-card.json and save login data for the next login + puppet: "wechaty-puppet-wechat", + puppetOptions: { + uos:true + } }); async function main() { const initializedAt = Date.now() @@ -37,6 +42,9 @@ async function main() { } catch (e) { console.error(e); } + }) + .on("error",()=>{ + console.log("ERROR !!!"); }); try { await bot.start(); diff --git a/src/openai.ts b/src/openai.ts new file mode 100644 index 0000000..4352b22 --- /dev/null +++ b/src/openai.ts @@ -0,0 +1,61 @@ +import {Configuration, OpenAIApi, ChatCompletionRequestMessageRoleEnum} from "openai"; +import {addSessionByUsername, getUserByUsername} from "./data.js"; +import {ChatCompletionRequestMessage} from "openai/api"; + + +const configuration = new Configuration({ + apiKey: process.env.OPENAI_API_KEY, +}); +const openai = new OpenAIApi(configuration); + +/** + * Get completion from OpenAI + * @param username + * @param message + */ +async function getCompletion(username:string,message: string): Promise { + // 先将用户输入的消息添加到数据库中 + let userData = getUserByUsername(username) + const messages:ChatCompletionRequestMessage[] = []; + if (userData) { + // 添加用户输入的消息 + addSessionByUsername(username, {userMsg: message}) + // fill prompt + if(userData.prompt!==""){ + messages.push({ + role: ChatCompletionRequestMessageRoleEnum.System, + content: userData.prompt + }) + } + // fill messages + userData.session.map((item) => { + if (item.userMsg!=="") { + messages.push({ + role: ChatCompletionRequestMessageRoleEnum.User, + content: item.userMsg as string + }) + } + if (item.assistantMsg!=="") { + messages.push({ + role: ChatCompletionRequestMessageRoleEnum.Assistant, + content: item.assistantMsg as string + }) + } + }) + }else{ + return "请先执行/cmd prompt命令. \n EXAMPLE: /cmd prompt 你的prompt" + } + console.log("ChatGPT MESSages: ", messages) + const response = await openai.createChatCompletion({ + model: "gpt-3.5-turbo", + messages: messages, + temperature: 0.6 + }).then((res) => res.data); + if (response.choices[0].message) { + return response.choices[0].message.content.replace(/^\n+|\n+$/g, ""); + } else { + return "Something went wrong" + } +} + +export {getCompletion}; \ No newline at end of file