From 128968909d6e2635b6384b0af0e99657dd8eef2b Mon Sep 17 00:00:00 2001 From: lengsukq Date: Sun, 23 Jun 2024 17:04:55 +0800 Subject: [PATCH 01/14] =?UTF-8?q?README.md=E6=96=87=E4=BB=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9dbb4fc0..2e8d7123 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 使用前需要配置的 AI 服务(目前支持 4 种,可任选其一) - deepseek获取自己的 `api key`,地址戳这里 👉🏻 :[deepseek开放平台](https://platform.deepseek.com/usage) - 将获取到的`api key`填入 `.evn` 文件中,`` + 将获取到的`api key`填入 `.evn` 文件中的 `DEEPSEEK_FREE_TOKEN` 中。 - 科大讯飞 新增科大讯飞,去这里申请一个 key:[科大讯飞](https://console.xfyun.cn/services/bm35),每个模型都有 200 万的免费 token ,感觉很难用完。 From 53a99ed0c9978dc39491a2050ce902b78bb8427b Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 08:45:56 +0800 Subject: [PATCH 02/14] =?UTF-8?q?openai=E4=BD=BF=E7=94=A8=E8=80=81?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/openai/__test__.js | 4 ++-- src/openai/index.js | 22 +++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 9c339281..19808654 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "inquirer": "^9.2.16", - "openai": "^4.52.0", + "openai": "^3.1.0", "p-timeout": "^6.0.0", "qrcode-terminal": "^0.12.0", "remark": "^14.0.2", diff --git a/src/openai/__test__.js b/src/openai/__test__.js index becb4bc3..bfeb81fc 100644 --- a/src/openai/__test__.js +++ b/src/openai/__test__.js @@ -2,8 +2,8 @@ import { getGptReply } from './index.js' // 测试 open ai api async function testMessage() { - const message = await getGptReply('hello') + const message = await getGptReply("hello") console.log('🌸🌸🌸 / message: ', message) } -testMessage() +testMessage() \ No newline at end of file diff --git a/src/openai/index.js b/src/openai/index.js index 3328521b..ea3d5d71 100644 --- a/src/openai/index.js +++ b/src/openai/index.js @@ -1,15 +1,13 @@ import { remark } from 'remark' import stripMarkdown from 'strip-markdown' -import OpenAIApi from 'openai' +import { Configuration, OpenAIApi } from 'openai' import dotenv from 'dotenv' const env = dotenv.config().parsed // 环境参数 -let config = { + +const configuration = new Configuration({ apiKey: env.OPENAI_API_KEY, -} -if (process.env.OPENAI_PROXY_URL) { - config.baseURL = process.env.OPENAI_PROXY_URL -} -const openai = new OpenAIApi(config) +}) +const openai = new OpenAIApi(configuration) export async function getGptReply(prompt) { console.log('🚀🚀🚀 / prompt', prompt) @@ -33,12 +31,12 @@ export async function getGptReply(prompt) { reply = markdownToText(response.data.choices[0].text) } else if (chosen_model == 'gpt-3.5-turbo') { console.log('🚀🚀🚀 / Using model', chosen_model) - const response = await openai.chat.completions.create({ + const response = await openai.createChatCompletion({ model: chosen_model, messages: [ - { role: 'system', content: 'You are a personal assistant.' }, - { role: 'user', content: prompt }, - ], + { "role": "system", content: "You are a personal assistant." }, + { "role": "user", content: prompt } + ] }) reply = markdownToText(response.data.choices[0].message.content) @@ -53,3 +51,5 @@ function markdownToText(markdown) { .processSync(markdown ?? '') .toString() } + + From d7c63efd9d2d834e1fc0906adf8a0dcc44f4aa65 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 10:12:42 +0800 Subject: [PATCH 03/14] =?UTF-8?q?openai=EF=BC=9A=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=AE=98=E6=96=B9=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 3 ++- package.json | 2 +- src/index.js | 2 +- src/openai/__test__.js | 4 +-- src/openai/index.js | 55 ++++++++++++------------------------------ 5 files changed, 21 insertions(+), 45 deletions(-) diff --git a/.env.example b/.env.example index 53084a6c..df2e34bf 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,9 @@ # .env -# OpenAi 的api key, 去 https://beta.openai.com/account/api-keys 中生成一个即可 +# OpenAi 的api key, 去 https://beta.openai.com/account/api-keys 中生成一个即可,OPENAI_MODEL不填则默认gpt-4o OPENAI_API_KEY='' OPENAI_PROXY_URL='https://openai.xxxx.com/v1/' +OPENAI_MODEL='' # Kimi 的api key, 去 https://platform.moonshot.cn/console/api-keys KIMI_API_KEY='' diff --git a/package.json b/package.json index 19808654..9c339281 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "inquirer": "^9.2.16", - "openai": "^3.1.0", + "openai": "^4.52.0", "p-timeout": "^6.0.0", "qrcode-terminal": "^0.12.0", "remark": "^14.0.2", diff --git a/src/index.js b/src/index.js index 3748eb1d..2361bffc 100644 --- a/src/index.js +++ b/src/index.js @@ -178,7 +178,7 @@ function init() { handleStart(res.serviceType) }) .catch((error) => { - console.log('❌ inquirer error:', error) + console.log('❌ inquirer error:', error) }) } } diff --git a/src/openai/__test__.js b/src/openai/__test__.js index bfeb81fc..becb4bc3 100644 --- a/src/openai/__test__.js +++ b/src/openai/__test__.js @@ -2,8 +2,8 @@ import { getGptReply } from './index.js' // 测试 open ai api async function testMessage() { - const message = await getGptReply("hello") + const message = await getGptReply('hello') console.log('🌸🌸🌸 / message: ', message) } -testMessage() \ No newline at end of file +testMessage() diff --git a/src/openai/index.js b/src/openai/index.js index ea3d5d71..1cc3c7c1 100644 --- a/src/openai/index.js +++ b/src/openai/index.js @@ -1,48 +1,25 @@ import { remark } from 'remark' import stripMarkdown from 'strip-markdown' -import { Configuration, OpenAIApi } from 'openai' +import OpenAIApi from 'openai' import dotenv from 'dotenv' const env = dotenv.config().parsed // 环境参数 - -const configuration = new Configuration({ +let config = { apiKey: env.OPENAI_API_KEY, -}) -const openai = new OpenAIApi(configuration) - + organization: '', +} +if (process.env.OPENAI_PROXY_URL) { + config.baseURL = process.env.OPENAI_PROXY_URL +} +const openai = new OpenAIApi(config) +const chosen_model = process.env.OPENAI_MODEL || 'gpt-4o' export async function getGptReply(prompt) { console.log('🚀🚀🚀 / prompt', prompt) - //let chosen_model = 'text-davinci-003' - let chosen_model = 'gpt-3.5-turbo' - let reply = '' - //'gpt-3.5-turbo', - if (chosen_model == 'text-davinci-003') { - console.log('🚀🚀🚀 / Using model', chosen_model) - const response = await openai.createCompletion({ - model: chosen_model, - prompt: prompt, - temperature: 0.8, // 每次返回的答案的相似度0-1(0:每次都一样,1:每次都不一样) - max_tokens: 4_000, - top_p: 1, - frequency_penalty: 0.0, - presence_penalty: 0.6, - stop: [' Human:', ' AI:'], - }) - - reply = markdownToText(response.data.choices[0].text) - } else if (chosen_model == 'gpt-3.5-turbo') { - console.log('🚀🚀🚀 / Using model', chosen_model) - const response = await openai.createChatCompletion({ - model: chosen_model, - messages: [ - { "role": "system", content: "You are a personal assistant." }, - { "role": "user", content: prompt } - ] - }) - - reply = markdownToText(response.data.choices[0].message.content) - } - console.log('🚀🚀🚀 / reply', reply) - return `${reply}\nVia ${chosen_model}` + const response = await openai.chat.completions.create({ + messages: [{ role: 'user', content: prompt }], + model: chosen_model, + }) + console.log('🚀🚀🚀 / reply', response.choices[0].message.content) + return `${response.choices[0].message.content}\nVia ${chosen_model}` } function markdownToText(markdown) { @@ -51,5 +28,3 @@ function markdownToText(markdown) { .processSync(markdown ?? '') .toString() } - - From 60199e2c3ff8e5ca3a10b49f940d26786526aeb4 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 10:28:46 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9C=BA=E5=99=A8?= =?UTF-8?q?=E4=BA=BA=E9=85=8D=E7=BD=AE=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 2 ++ src/wechaty/testMessage.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/index.js b/src/index.js index 2361bffc..7f1a1ce5 100644 --- a/src/index.js +++ b/src/index.js @@ -116,9 +116,11 @@ process.on('uncaughtException', (err) => { // fs.unlinkSync('WechatEveryDay.memory-card.json') // } }) +import { botName, roomWhiteList, aliasWhiteList } from '../config.js' // 控制启动 function handleStart(type) { + console.log(`botName:${botName}, roomWhiteList${roomWhiteList}, aliasWhiteList$${aliasWhiteList}`) serviceType = type console.log('🌸🌸🌸 / type: ', type) switch (type) { diff --git a/src/wechaty/testMessage.js b/src/wechaty/testMessage.js index 77bc8e90..40874c06 100644 --- a/src/wechaty/testMessage.js +++ b/src/wechaty/testMessage.js @@ -5,9 +5,12 @@ import dotenv from 'dotenv' import inquirer from 'inquirer' import { getDeepSeekFreeReply } from '../deepseek-free/index.js' const env = dotenv.config().parsed // 环境参数 +import { botName, roomWhiteList, aliasWhiteList } from '../../config.js' // 控制启动 async function handleRequest(type) { + console.log(`botName:${botName}, roomWhiteList${roomWhiteList}, aliasWhiteList${aliasWhiteList}`) + console.log('type: ', type) switch (type) { case 'ChatGPT': From a873b0faece6de2bd3d763dbe9c44d7b35cbc5bf Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 10:34:08 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E4=BB=8Edotenv=E5=BC=95=E5=85=A5?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.js | 11 ++++++++--- src/openai/index.js | 14 ++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/config.js b/config.js index 7e723bb9..6e6fb06f 100644 --- a/config.js +++ b/config.js @@ -1,13 +1,18 @@ +import dotenv from 'dotenv' +// 加载环境变量 +dotenv.config() +const env = dotenv.config().parsed // 环境参数 + // 定义机器人的名称,这里是为了防止群聊消息太多,所以只有艾特机器人才会回复, // 这里不要把@去掉,在@后面加上你启动机器人账号的微信名称 // 从环境变量中导入机器人的名称 -const botName = process.env.BOT_NAME; +const botName = env.BOT_NAME; // 从环境变量中导入联系人白名单 -const aliasWhiteList = process.env.ALIAS_WHITELIST ? process.env.ALIAS_WHITELIST.split(',') : []; +const aliasWhiteList = env.ALIAS_WHITELIST ? env.ALIAS_WHITELIST.split(',') : []; // 从环境变量中导入群聊白名单 -const roomWhiteList = process.env.ROOM_WHITELIST ? process.env.ROOM_WHITELIST.split(',') : []; +const roomWhiteList = env.ROOM_WHITELIST ? env.ROOM_WHITELIST.split(',') : []; // 导出机器人的名称、群聊白名单和联系人白名单 export { botName, roomWhiteList, aliasWhiteList }; \ No newline at end of file diff --git a/src/openai/index.js b/src/openai/index.js index 1cc3c7c1..dbb97ce3 100644 --- a/src/openai/index.js +++ b/src/openai/index.js @@ -3,15 +3,16 @@ import stripMarkdown from 'strip-markdown' import OpenAIApi from 'openai' import dotenv from 'dotenv' const env = dotenv.config().parsed // 环境参数 + let config = { apiKey: env.OPENAI_API_KEY, organization: '', } -if (process.env.OPENAI_PROXY_URL) { - config.baseURL = process.env.OPENAI_PROXY_URL +if (env.OPENAI_PROXY_URL) { + config.baseURL = env.OPENAI_PROXY_URL } const openai = new OpenAIApi(config) -const chosen_model = process.env.OPENAI_MODEL || 'gpt-4o' +const chosen_model = env.OPENAI_MODEL || 'gpt-4o' export async function getGptReply(prompt) { console.log('🚀🚀🚀 / prompt', prompt) const response = await openai.chat.completions.create({ @@ -21,10 +22,3 @@ export async function getGptReply(prompt) { console.log('🚀🚀🚀 / reply', response.choices[0].message.content) return `${response.choices[0].message.content}\nVia ${chosen_model}` } - -function markdownToText(markdown) { - return remark() - .use(stripMarkdown) - .processSync(markdown ?? '') - .toString() -} From 4836d30c9308d64cee92320c6f1d0a5688371bad Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 10:53:59 +0800 Subject: [PATCH 06/14] =?UTF-8?q?README.md=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 537b3e2a..6fdfa890 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ - deepseek获取自己的 `api key`,地址戳这里 👉🏻 :[deepseek开放平台](https://platform.deepseek.com/usage) 将获取到的`api key`填入 `.evn` 文件中的 `DEEPSEEK_FREE_TOKEN` 中。 + - 科大讯飞 新增科大讯飞,去这里申请一个 key:[科大讯飞](https://console.xfyun.cn/services/bm35),每个模型都有 200 万的免费 token ,感觉很难用完。 @@ -35,6 +36,9 @@ OPENAI_API_KEY='你的key' ``` +- 其他 + (待实践)理论上使用openAI格式的api,都可以使用,在env文件中修改对应的key、moudel、url即可。 + ## 赞助商

From 92602025e317d583a1b971cefcd8749a5af3dac3 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 10:59:36 +0800 Subject: [PATCH 07/14] =?UTF-8?q?README.md=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fdfa890..dbb0bd94 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ ``` - 其他 - (待实践)理论上使用openAI格式的api,都可以使用,在env文件中修改对应的key、moudel、url即可。 + (待实践)理论上使用openAI格式的api,都可以使用,在env文件中修改对应的api_key、model、proxy_url即可。 ## 赞助商 From f88e45e779bd090d2a2714a1376734bb036299cb Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 11:38:32 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E6=96=B0=E5=A2=9Esystem=E6=B6=88?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8FOPENAI=5F?= =?UTF-8?q?SYSTEM=5FMESSAGE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/openai/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openai/index.js b/src/openai/index.js index dbb97ce3..ad616e4c 100644 --- a/src/openai/index.js +++ b/src/openai/index.js @@ -16,7 +16,10 @@ const chosen_model = env.OPENAI_MODEL || 'gpt-4o' export async function getGptReply(prompt) { console.log('🚀🚀🚀 / prompt', prompt) const response = await openai.chat.completions.create({ - messages: [{ role: 'user', content: prompt }], + messages: [ + { role: 'system', content: env.OPENAI_SYSTEM_MESSAGE }, + { role: 'user', content: prompt }, + ], model: chosen_model, }) console.log('🚀🚀🚀 / reply', response.choices[0].message.content) From 04547a523bc89a11b1ba94dfaf2c1e2a75e68455 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 11:41:16 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E6=9B=B4=E6=96=B0env.example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index df2e34bf..4e5e51c2 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,10 @@ # .env -# OpenAi 的api key, 去 https://beta.openai.com/account/api-keys 中生成一个即可,OPENAI_MODEL不填则默认gpt-4o +# OpenAi 的api key, 去 https://beta.openai.com/account/api-keys 中生成一个即可,OPENAI_MODEL不填则默认gpt-4o,OPENAI_SYSTEM_MESSAGE为默认角色设定 OPENAI_API_KEY='' OPENAI_PROXY_URL='https://openai.xxxx.com/v1/' OPENAI_MODEL='' +OPENAI_SYSTEM_MESSAGE=You are a personal assistant. # Kimi 的api key, 去 https://platform.moonshot.cn/console/api-keys KIMI_API_KEY='' From 2ee6f9793d51fe3020275a61edd38a3790f6ba1a Mon Sep 17 00:00:00 2001 From: lengsukq Date: Tue, 25 Jun 2024 14:20:55 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E5=88=A0=E9=99=A4config.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - README.md | 4 ++-- config.js | 18 ------------------ config.js.example | 11 ----------- src/index.js | 4 +--- src/wechaty/sendMessage.js | 15 ++++++++++++++- src/wechaty/testMessage.js | 3 --- 7 files changed, 17 insertions(+), 39 deletions(-) delete mode 100644 config.js delete mode 100644 config.js.example diff --git a/.gitignore b/.gitignore index e1039fe1..b31eccd0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,5 @@ test.js package-lock.json yarn.lock Chromium.app -config.js .DS_Store diff --git a/README.md b/README.md index dbb0bd94..375ba07d 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ ROOM_WHITELIST=XX群1,群2 ![](https://raw.githubusercontent.com/wangrongding/image-house/master/202403231002859.png) - 确保你的 openai key 有余额 -- 配置好 config.js 和 .env 文件 +- 配置好 .env 文件 - 执行 npm run test 能成功拿到 openai 的回复 - 执行 npm run dev 愉快的玩耍吧~ 🎉 @@ -172,7 +172,7 @@ ROOM_WHITELIST=XX群1,群2 ```sh $ docker build . -t wechat-bot -$ docker run -d --rm --name wechat-bot -v $(pwd)/config.js:/app/config.js -v $(pwd)/.env:/app/.env wechat-bot +$ docker run -d --rm --name wechat-bot -v $(pwd)/.env:/app/.env wechat-bot ``` ## Star History Chart diff --git a/config.js b/config.js deleted file mode 100644 index 6e6fb06f..00000000 --- a/config.js +++ /dev/null @@ -1,18 +0,0 @@ -import dotenv from 'dotenv' -// 加载环境变量 -dotenv.config() -const env = dotenv.config().parsed // 环境参数 - -// 定义机器人的名称,这里是为了防止群聊消息太多,所以只有艾特机器人才会回复, -// 这里不要把@去掉,在@后面加上你启动机器人账号的微信名称 -// 从环境变量中导入机器人的名称 -const botName = env.BOT_NAME; - -// 从环境变量中导入联系人白名单 -const aliasWhiteList = env.ALIAS_WHITELIST ? env.ALIAS_WHITELIST.split(',') : []; - -// 从环境变量中导入群聊白名单 -const roomWhiteList = env.ROOM_WHITELIST ? env.ROOM_WHITELIST.split(',') : []; - -// 导出机器人的名称、群聊白名单和联系人白名单 -export { botName, roomWhiteList, aliasWhiteList }; \ No newline at end of file diff --git a/config.js.example b/config.js.example deleted file mode 100644 index 9fc9df15..00000000 --- a/config.js.example +++ /dev/null @@ -1,11 +0,0 @@ -// 真实微信名 -export const botWechatName = 'arXiv' - -// 定义机器人的名称,这里是为了防止群聊消息太多,所以只有艾特机器人才会回复, -export const botName = '小G' - -// 群聊白名单,白名单内的群聊才会自动回复 -export const roomWhiteList = ['群名称'] - -// 联系人白名单,白名单内的联系人才会自动回复 -export const aliasWhiteList = ['备注名', '李四'] diff --git a/src/index.js b/src/index.js index 7f1a1ce5..63f3f81a 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,7 @@ import dotenv from 'dotenv' import fs from 'fs' import path, { dirname } from 'path' import { fileURLToPath } from 'url' -import { defaultMessage, shardingMessage } from './wechaty/sendMessage.js' +import { defaultMessage } from './wechaty/sendMessage.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -116,11 +116,9 @@ process.on('uncaughtException', (err) => { // fs.unlinkSync('WechatEveryDay.memory-card.json') // } }) -import { botName, roomWhiteList, aliasWhiteList } from '../config.js' // 控制启动 function handleStart(type) { - console.log(`botName:${botName}, roomWhiteList${roomWhiteList}, aliasWhiteList$${aliasWhiteList}`) serviceType = type console.log('🌸🌸🌸 / type: ', type) switch (type) { diff --git a/src/wechaty/sendMessage.js b/src/wechaty/sendMessage.js index 81f1eaef..6d48d61e 100644 --- a/src/wechaty/sendMessage.js +++ b/src/wechaty/sendMessage.js @@ -1,4 +1,17 @@ -import { botName, roomWhiteList, aliasWhiteList } from '../../config.js' +import dotenv from 'dotenv' +// 加载环境变量 +dotenv.config() +const env = dotenv.config().parsed // 环境参数 + +// 从环境变量中导入机器人的名称 +const botName = env.BOT_NAME + +// 从环境变量中导入联系人白名单 +const aliasWhiteList = env.ALIAS_WHITELIST ? env.ALIAS_WHITELIST.split(',') : [] + +// 从环境变量中导入群聊白名单 +const roomWhiteList = env.ROOM_WHITELIST ? env.ROOM_WHITELIST.split(',') : [] + import { getServe } from './serve.js' /** diff --git a/src/wechaty/testMessage.js b/src/wechaty/testMessage.js index 40874c06..77bc8e90 100644 --- a/src/wechaty/testMessage.js +++ b/src/wechaty/testMessage.js @@ -5,12 +5,9 @@ import dotenv from 'dotenv' import inquirer from 'inquirer' import { getDeepSeekFreeReply } from '../deepseek-free/index.js' const env = dotenv.config().parsed // 环境参数 -import { botName, roomWhiteList, aliasWhiteList } from '../../config.js' // 控制启动 async function handleRequest(type) { - console.log(`botName:${botName}, roomWhiteList${roomWhiteList}, aliasWhiteList${aliasWhiteList}`) - console.log('type: ', type) switch (type) { case 'ChatGPT': From b071e4f4a910dbb0ff27864779d9172774d81b39 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Fri, 28 Jun 2024 11:15:19 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E3=80=81=E9=92=89=E9=92=89=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 14 +++++- package.json | 1 + src/index.js | 4 ++ src/utils/sendMessage.js | 106 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/utils/sendMessage.js diff --git a/.env.example b/.env.example index 4e5e51c2..9179fe12 100644 --- a/.env.example +++ b/.env.example @@ -29,4 +29,16 @@ ALIAS_WHITELIST=微信名1,备注名2 ROOM_WHITELIST=XX群1,群2 # 默认服务 ChatGPT、Kimi、Xunfei、deepseek-free 四选一,不填则键盘交互 -SERVICE_TYPE='' \ No newline at end of file +SERVICE_TYPE='' + +# 邮件通知 +MAIL_HOST=smtp.qq.com +MAIL_PORT=465 +MAIL_USERNAME=xxx@qq.com +#你的邮箱密码或授权码 +MAIL_PASSWORD=****** +MAIL_TO=*****@qq.com + +# 钉钉机器人 仅测试加签机器人 +DING_TOKEN=***** +DING_SIGN=****** \ No newline at end of file diff --git a/package.json b/package.json index 9c339281..ff3f7cb8 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "crypto-js": "^4.2.0", "dotenv": "^16.4.5", "inquirer": "^9.2.16", + "nodemailer": "^6.9.14", "openai": "^4.52.0", "p-timeout": "^6.0.0", "qrcode-terminal": "^0.12.0", diff --git a/src/index.js b/src/index.js index 63f3f81a..a4fd49e0 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,7 @@ import fs from 'fs' import path, { dirname } from 'path' import { fileURLToPath } from 'url' import { defaultMessage } from './wechaty/sendMessage.js' +import { sendMessage } from './utils/sendMessage.js' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -20,6 +21,8 @@ function onScan(qrcode, status) { // 在控制台显示二维码 qrTerminal.generate(qrcode, { small: true }) const qrcodeImageUrl = ['https://api.qrserver.com/v1/create-qr-code/?data=', encodeURIComponent(qrcode)].join('') + sendMessage(qrcodeImageUrl, 'qr') + console.log('onScan:', qrcodeImageUrl, ScanStatus[status], status) } else { log.info('onScan: %s(%s)', ScanStatus[status], status) @@ -88,6 +91,7 @@ bot.on('friendship', onFriendShip) // 错误 bot.on('error', (e) => { console.error('❌ bot error handle: ', e) + sendMessage(e, 'error') // console.log('❌ 程序退出,请重新运行程序') // bot.stop() diff --git a/src/utils/sendMessage.js b/src/utils/sendMessage.js new file mode 100644 index 00000000..fd5c9116 --- /dev/null +++ b/src/utils/sendMessage.js @@ -0,0 +1,106 @@ +import dotenv from 'dotenv' +import CryptoJS from 'crypto-js' +import nodemailer from 'nodemailer' + +const env = dotenv.config().parsed // 环境参数 + +export function sendMessage(resultText, messageType = 'qr') { + try { + switch (messageType) { + case 'qr': + sendMail(resultText, messageType) + dingSend(resultText, 'markdown') + break + case 'error': + sendMail(resultText, messageType) + dingSend(resultText, 'text') + break + default: + sendMail(resultText) + dingSend(resultText) + } + } catch (e) { + console.log(e) + } +} + +export function sendMail(resultText, messageType = 'text') { + // 创建一个SMTP传输器 + const transporter = nodemailer.createTransport({ + host: env.MAIL_HOST, // QQ邮箱的SMTP服务器地址 + port: env.MAIL_HOST || 465, // 通常SMTP服务器使用的端口是465(SSL)或587(TLS) + secure: env.MAIL_HOST.toString() === '465', // 如果端口是465,则设置为true + auth: { + user: env.MAIL_USERNAME, // 你的邮箱地址 + pass: env.MAIL_PASSWORD, // 你的邮箱密码或授权码 + }, + }) + // 假设你有一个包含多个邮箱地址的字符串,用分号分隔 + const emailString = env.MAIL_TO + // 使用分号将字符串分割成数组 + const emailAddresses = emailString.split(';') + + // 设置邮件选项 + let mailOptions = { + from: env.MAIL_USERNAME, // 发件人邮箱地址 + to: emailAddresses, // 收件人邮箱地址 + subject: 'wechat-bot通知', // 邮件主题 + } + if (messageType === 'text') { + mailOptions.text = `【wechat-bot】:${resultText}` + } else if (messageType === 'error') { + mailOptions.html = `【wechat-bot报错】:${resultText}` + } else if (messageType === 'qr') { + mailOptions.html = `

【wechat-bot】微信扫码登录

Network Image` + } + + // 发送邮件 + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + console.log(error) + } else { + console.log('Email sent: ' + info.response) + } + }) +} + +// 钉钉机器人 +export async function dingSend(resultText, msgtype = 'text') { + // 发送钉钉消息 + try { + const timestamp = new Date().getTime() // 时间戳 + const secret = env.DING_SIGN // 钉钉机器人密钥 + let stringToSign = `${timestamp}\n${secret}` + let signature = CryptoJS.HmacSHA256(stringToSign, secret) + const hashInBase64 = CryptoJS.enc.Base64.stringify(signature) //base64加密 + const encodesign = encodeURI(hashInBase64) //解密 + // 钉钉机器人地址 + let url = `https://oapi.dingtalk.com/robot/send?access_token=${env.DING_TOKEN}×tamp=${timestamp}&sign=${encodesign}` + // 钉钉消息内容 + let text = { + msgtype: msgtype, + text: { + content: resultText, + }, + markdown: { + title: 'QR Code for your URL', + text: `### 【wechat-bot】微信扫码登录\n\n![Base64 Image](${resultText})`, + }, + } + let response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(text), + }) + let responseData = await response.json() + if (response.ok) { + console.log('钉钉消息发送成功,返回信息:', responseData) + } else { + console.log('钉钉消息发送失败', responseData) + } + } catch (error) { + console.log('钉钉消息发送失败', error) + } +} From 493d066cdfd29c6f753c17d97f6faeaa2ae6830b Mon Sep 17 00:00:00 2001 From: lengsukq Date: Fri, 28 Jun 2024 11:25:31 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=E5=88=A4=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/sendMessage.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/sendMessage.js b/src/utils/sendMessage.js index fd5c9116..76f98d35 100644 --- a/src/utils/sendMessage.js +++ b/src/utils/sendMessage.js @@ -25,6 +25,10 @@ export function sendMessage(resultText, messageType = 'qr') { } export function sendMail(resultText, messageType = 'text') { + // 环境变量判空 + if (!env.MAIL_HOST || !env.MAIL_USERNAME || !env.MAIL_PASSWORD || !env.MAIL_TO) { + return false + } // 创建一个SMTP传输器 const transporter = nodemailer.createTransport({ host: env.MAIL_HOST, // QQ邮箱的SMTP服务器地址 @@ -66,6 +70,10 @@ export function sendMail(resultText, messageType = 'text') { // 钉钉机器人 export async function dingSend(resultText, msgtype = 'text') { + // 环境变量判空 + if (!env.DING_TOKEN) { + return false + } // 发送钉钉消息 try { const timestamp = new Date().getTime() // 时间戳 From 64b807943541ff38499fcf5f618fa3d06d472a7e Mon Sep 17 00:00:00 2001 From: lengsukq Date: Fri, 28 Jun 2024 11:35:31 +0800 Subject: [PATCH 13/14] =?UTF-8?q?readme=E6=96=87=E4=BB=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 1 + README.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.env.example b/.env.example index 9179fe12..fb89e0c4 100644 --- a/.env.example +++ b/.env.example @@ -37,6 +37,7 @@ MAIL_PORT=465 MAIL_USERNAME=xxx@qq.com #你的邮箱密码或授权码 MAIL_PASSWORD=****** +#收件人邮箱 MAIL_TO=*****@qq.com # 钉钉机器人 仅测试加签机器人 diff --git a/README.md b/README.md index 375ba07d..b0396116 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,29 @@ ROOM_WHITELIST=XX群1,群2 ![](https://assets.fedtop.com/picbed/202212131123257.png) +4. 消息通知 + +- 运行报错通知 +- 登录扫码通知 + +目前仅支持邮件通知,钉钉机器人通知,后续会继续增加。 +.env文件填写对应的配置,不填则不会通知 + +```sh +# 邮件通知 +MAIL_HOST=smtp.qq.com +MAIL_PORT=465 +MAIL_USERNAME=xxx@qq.com +#你的邮箱密码或授权码 +MAIL_PASSWORD=****** +#收件人邮箱 +MAIL_TO=*****@qq.com + +# 钉钉机器人 仅测试加签机器人 +DING_TOKEN=***** +DING_SIGN=****** +``` + ## 常见问题 可以进交流群,一起交流探讨相关问题和解决方案,添加的时候记得备注来意。(如果项目对你有所帮助,也可以请我喝杯咖啡 ☕️ ~) From aab0ff16edd4db6bfd830bcff2a4d0455cf9a701 Mon Sep 17 00:00:00 2001 From: lengsukq Date: Thu, 11 Jul 2024 09:43:53 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=97=B4=E9=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 3 +++ src/utils/sendMessage.js | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/.env.example b/.env.example index fb89e0c4..2b2c3913 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,9 @@ ROOM_WHITELIST=XX群1,群2 # 默认服务 ChatGPT、Kimi、Xunfei、deepseek-free 四选一,不填则键盘交互 SERVICE_TYPE='' +# 通知间隔,单位为分钟,不填默认为30 +MASSAGE_INTERVAL=60 + # 邮件通知 MAIL_HOST=smtp.qq.com MAIL_PORT=465 diff --git a/src/utils/sendMessage.js b/src/utils/sendMessage.js index 76f98d35..d9bcc980 100644 --- a/src/utils/sendMessage.js +++ b/src/utils/sendMessage.js @@ -5,6 +5,9 @@ import nodemailer from 'nodemailer' const env = dotenv.config().parsed // 环境参数 export function sendMessage(resultText, messageType = 'qr') { + if (checkDate()) { + return false + } try { switch (messageType) { case 'qr': @@ -112,3 +115,43 @@ export async function dingSend(resultText, msgtype = 'text') { console.log('钉钉消息发送失败', error) } } + +// 检测目录下是否有date.json文件,没有则创建,读取其中的date时间,超过30分钟则返回true +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +function checkDate() { + let massageInterval + try { + massageInterval = Number(env.MASSAGE_INTERVAL) || 30 // 默认30分钟 + } catch (e) { + massageInterval = 30 // 默认30分钟 + } + let date = new Date().getTime() // 当前时间 + const fileDir = path.resolve(__dirname, 'date.json') // 文件路径 + const dirPath = path.dirname(fileDir) // 获取目录路径 + + // 确保目录存在 + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }) + } + + if (fs.existsSync(fileDir)) { + // 读取文件内容 + const data = fs.readFileSync(fileDir, 'utf-8') + const jsonData = JSON.parse(data) + console.log('读取到date.json文件,内容为:', jsonData) + return (date - jsonData.time) / 60000 > massageInterval + } else { + // 创建date.json文件 + const obj = { time: date } + fs.writeFileSync(fileDir, JSON.stringify(obj), 'utf-8') + return true + } +} + +// 示例调用 +console.log(checkDate())