From 57f996797597cbd6a830098b0143d30573e3a8dc Mon Sep 17 00:00:00 2001 From: Cheivin Date: Thu, 9 Mar 2023 09:31:06 -0500 Subject: [PATCH 01/32] =?UTF-8?q?pref:=20=E5=AF=B9openai=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=8C=85=E8=A3=85=EF=BC=8C=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E7=9A=84=E4=B8=8D=E5=AD=98=E5=85=A5history?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/message.js | 16 ++++++++++------ src/openai.js | 19 +++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/message.js b/src/message.js index 631e45cc..912a9d4c 100644 --- a/src/message.js +++ b/src/message.js @@ -223,14 +223,18 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { - sendChatActionToTelegram('typing').then(console.log).catch(console.error); + sendChatActionToTelegram('typing').catch(console.error); const historyKey = SHARE_CONTEXT.chatHistoryKey; - const {real: history, fake: fakeHistory} = await loadHistory(historyKey); + const { real: history, fake: fakeHistory } = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - history.push({role: 'user', content: message.text || ''}); - history.push({role: 'assistant', content: answer}); - await DATABASE.put(historyKey, JSON.stringify(history)); - return sendMessageToTelegram(answer); + if (answer.ok) { + history.push({ role: 'user', content: message.text || '' }); + history.push({ role: 'assistant', content: answer.message }); + await DATABASE.put(historyKey, JSON.stringify(history)); + return sendMessageToTelegram(answer.message); + } else { + return sendMessageToTelegram(answer.error||'未知错误'); + } } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); } diff --git a/src/openai.js b/src/openai.js index eae4a0b8..2e5ae13a 100644 --- a/src/openai.js +++ b/src/openai.js @@ -7,7 +7,7 @@ export async function sendMessageToChatGPT(message, history) { const body = { model: ENV.CHAT_MODEL, ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: [...(history || []), {role: 'user', content: message}], + messages: [...(history || []), { role: 'user', content: message }], }; const resp = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', @@ -17,15 +17,22 @@ export async function sendMessageToChatGPT(message, history) { }, body: JSON.stringify(body), }).then((res) => res.json()); - if (resp.error?.message) { - return `OpenAI API 错误\n> ${resp.error.message}}`; + return { + ok: false, + error: `OpenAI API 错误\n> ${resp.error.message}` + } } setTimeout(() => updateBotUsage(resp.usage), 0); - return resp.choices[0].message.content; + return { + ok: true, + message: resp.choices[0].message.content + } } catch (e) { - console.error(e); - return `我不知道该怎么回答\n> ${e.message}}`; + return { + ok: false, + error: "接口发生错误:"+e.message + } } } From 352bf34dcda2fdbf27343621adb2a66bd7dfa0e8 Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:26:09 +0800 Subject: [PATCH 02/32] =?UTF-8?q?-=20=E5=AE=8C=E5=96=84/system=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E4=BF=A1=E6=81=AF=20-=20=E8=B0=83=E6=95=B4=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E5=88=9D=E5=A7=8B=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 144 ++++++++++++++++++++++++-------------------- dist/timestamp | 2 +- src/command.js | 16 ++--- src/context.js | 87 +++++++++++++++++++++++++- src/message.js | 94 ++++------------------------- src/openai.js | 9 +-- src/telegram.js | 4 +- 8 files changed, 192 insertions(+), 166 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 5cad02d6..06b7d576 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "7b9b91f", "timestamp": 1678363377} +{"sha": "4c1096c", "timestamp": 1678371905} diff --git a/dist/index.js b/dist/index.js index fa13b791..ff65d28a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678363377, + BUILD_TIMESTAMP: 1678371905, // 当前版本 commit id - BUILD_VERSION: "7b9b91f", + BUILD_VERSION: "4c1096c", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B" }; @@ -117,6 +117,10 @@ var SHARE_CONTEXT = { speekerId: null // 发言人 id }; +async function initChatContext(chatId, replyToMessageId) { + CURRENT_CHAT_CONTEXT.chat_id = chatId; + CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; +} async function initUserConfig(storeKey) { try { const userConfig = JSON.parse(await DATABASE.get(storeKey)); @@ -129,6 +133,58 @@ async function initUserConfig(storeKey) { console.error(e); } } +async function initShareContext(message, request) { + const { pathname } = new URL(request.url); + const token = pathname.match( + /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/ + )[1]; + const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); + if (telegramIndex === -1) { + throw new Error("Token not found"); + } + SHARE_CONTEXT.currentBotToken = token; + SHARE_CONTEXT.currentBotId = token.split(":")[0]; + SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; + if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { + SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; + } + const id = message?.chat?.id; + if (id === void 0 || id === null) { + throw new Error("Chat id not found"); + } + const botId = SHARE_CONTEXT.currentBotId; + let historyKey = `history:${id}`; + let configStoreKey = `user_config:${id}`; + let groupAdminKey = null; + if (botId) { + historyKey += `:${botId}`; + configStoreKey += `:${botId}`; + } + if (CONST.GROUP_TYPES.includes(message.chat?.type)) { + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { + historyKey += `:${message.from.id}`; + configStoreKey += `:${message.from.id}`; + } + groupAdminKey = `group_admin:${id}`; + } + SHARE_CONTEXT.chatHistoryKey = historyKey; + SHARE_CONTEXT.configStoreKey = configStoreKey; + SHARE_CONTEXT.groupAdminKey = groupAdminKey; + SHARE_CONTEXT.chatType = message.chat?.type; + SHARE_CONTEXT.chatId = message.chat.id; + SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; +} +async function initContext(message, request) { + console.log(ENV); + const chatId = message?.chat?.id; + const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; + initChatContext(chatId, replyId); + console.log(CURRENT_CHAT_CONTEXT); + await initShareContext(message, request); + console.log(SHARE_CONTEXT); + await initUserConfig(SHARE_CONTEXT.configStoreKey); + console.log(USER_CONFIG); +} // src/telegram.js async function sendMessageToTelegram(message, token, context) { @@ -194,9 +250,7 @@ async function bindTelegramWebHook(token, url) { async function getChatRole(id) { let groupAdmin; try { - groupAdmin = await DATABASE.get(SHARE_CONTEXT.groupAdminKey).then( - (res) => JSON.parse(res) - ); + groupAdmin = JSON.parse(await DATABASE.get(SHARE_CONTEXT.groupAdminKey)); } catch (e) { console.error(e); return e.message; @@ -286,7 +340,7 @@ async function sendMessageToChatGPT(message, history) { return `OpenAI API \u9519\u8BEF > ${resp.error.message}}`; } - setTimeout(() => updateBotUsage(resp.usage), 0); + setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); return resp.choices[0].message.content; } catch (e) { console.error(e); @@ -295,7 +349,7 @@ async function sendMessageToChatGPT(message, history) { } } async function updateBotUsage(usage) { - let dbValue = await DATABASE.get(SHARE_CONTEXT.usageKey).then((res) => JSON.parse(res)); + let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); if (!dbValue) { dbValue = { tokens: { @@ -482,14 +536,22 @@ async function commandUsage() { return sendMessageToTelegram(text); } async function commandSystem(message) { - let msg = `\u5F53\u524D\u7CFB\u7EDF\u4FE1\u606F\u5982\u4E0B: -`; + let msg = "\u5F53\u524D\u7CFB\u7EDF\u4FE1\u606F\u5982\u4E0B:\n"; msg += "OpenAI\u6A21\u578B:" + ENV.CHAT_MODEL + "\n"; if (ENV.DEBUG_MODE) { - msg += `OpenAI\u53C2\u6570: ${JSON.stringify(USER_CONFIG.OPENAI_API_EXTRA_PARAMS)} + msg += `USER_CONFIG: +\`${JSON.stringify(USER_CONFIG, null, 2)}\` `; - msg += `\u521D\u59CB\u5316\u6587\u672C: ${USER_CONFIG.SYSTEM_INIT_MESSAGE} + if (ENV.DEV_MODE) { + const shareCtx = { ...SHARE_CONTEXT }; + shareCtx.currentBotToken = "ENPYPTED"; + msg += `CHAT_CONTEXT: +\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\` `; + msg += `SHARE_CONTEXT: +\`${JSON.stringify(shareCtx, null, 2)}\` +`; + } } return sendMessageToTelegram(msg); } @@ -640,57 +702,12 @@ function errorToString(e) { // src/message.js var MAX_TOKEN_LENGTH = 2048; -async function msgInitTelegramToken(message, request) { +async function msgInitChatContext(message, request) { try { - const { pathname } = new URL(request.url); - const token = pathname.match( - /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/ - )[1]; - const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); - if (telegramIndex === -1) { - throw new Error("Token not found"); - } - SHARE_CONTEXT.currentBotToken = token; - SHARE_CONTEXT.currentBotId = token.split(":")[0]; - SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; - if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { - SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; - } + await initContext(message, request); } catch (e) { - return new Response( - e.message, - { status: 200 } - ); - } -} -async function msgInitChatContext(message) { - const id = message?.chat?.id; - if (id === void 0 || id === null) { - return new Response("ID NOT FOUND", { status: 200 }); - } - let historyKey = `history:${id}`; - let configStoreKey = `user_config:${id}`; - let groupAdminKey = null; - CURRENT_CHAT_CONTEXT.chat_id = id; - if (SHARE_CONTEXT.currentBotId) { - historyKey += `:${SHARE_CONTEXT.currentBotId}`; - configStoreKey += `:${SHARE_CONTEXT.currentBotId}`; - } - if (CONST.GROUP_TYPES.includes(message.chat?.type)) { - CURRENT_CHAT_CONTEXT.reply_to_message_id = message.message_id; - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { - historyKey += `:${message.from.id}`; - configStoreKey += `:${message.from.id}`; - } - groupAdminKey = `group_admin:${id}`; + return new Response(errorToString(e), { status: 200 }); } - SHARE_CONTEXT.chatHistoryKey = historyKey; - SHARE_CONTEXT.configStoreKey = configStoreKey; - SHARE_CONTEXT.groupAdminKey = groupAdminKey; - SHARE_CONTEXT.chatType = message.chat?.type; - SHARE_CONTEXT.chatId = message.chat.id; - SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; - await initUserConfig(configStoreKey); return null; } async function msgSaveLastMessage(message) { @@ -720,7 +737,8 @@ async function msgFilterWhiteList(message) { ); } return null; - } else if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + } + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { if (!ENV.GROUP_CHAT_BOT_ENABLE) { return new Response("ID SUPPORT", { status: 200 }); } @@ -805,7 +823,7 @@ async function msgHandleCommand(message) { } async function msgChatWithOpenAI(message) { try { - sendChatActionToTelegram("typing").then(console.log).catch(console.error); + setTimeout(() => sendChatActionToTelegram("typing").catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const { real: history, fake: fakeHistory } = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); @@ -860,7 +878,7 @@ async function loadHistory(key) { const initMessage = { role: "system", content: USER_CONFIG.SYSTEM_INIT_MESSAGE }; let history = []; try { - history = await DATABASE.get(key).then((res) => JSON.parse(res)); + history = JSON.parse(await DATABASE.get(key)); } catch (e) { console.error(e); } @@ -900,8 +918,6 @@ async function loadHistory(key) { async function handleMessage(request) { const { message } = await request.json(); const handlers = [ - msgInitTelegramToken, - // 初始化token msgInitChatContext, // 初始化聊天上下文: 生成chat_id, reply_to_message_id(群组消息), SHARE_CONTEXT msgSaveLastMessage, diff --git a/dist/timestamp b/dist/timestamp index 55ce87ee..d5c6935c 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678363377 +1678371905 diff --git a/src/command.js b/src/command.js index 764dc0de..60d75c7d 100644 --- a/src/command.js +++ b/src/command.js @@ -196,16 +196,16 @@ async function commandUsage() { } async function commandSystem(message) { - let msg = `当前系统信息如下:\n`; + let msg = '当前系统信息如下:\n'; msg+='OpenAI模型:'+ENV.CHAT_MODEL+'\n'; if (ENV.DEBUG_MODE) { - msg+=`OpenAI参数: ${JSON.stringify(USER_CONFIG.OPENAI_API_EXTRA_PARAMS)}\n`; - msg+=`初始化文本: ${USER_CONFIG.SYSTEM_INIT_MESSAGE}\n`; - // if (ENV.DEV_MODE) { - // const shareCtx = {...SHARE_CONTEXT}; - // shareCtx.currentBotToken = '***'; - // msg += `当前上下文: \n${JSON.stringify(shareCtx, null, 2)}\n`; - // } + msg+=`USER_CONFIG: \n\`${JSON.stringify(USER_CONFIG, null, 2)}\`\n`; + if (ENV.DEV_MODE) { + const shareCtx = {...SHARE_CONTEXT}; + shareCtx.currentBotToken = 'ENPYPTED'; + msg +=`CHAT_CONTEXT: \n\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\`\n`; + msg += `SHARE_CONTEXT: \n\`${JSON.stringify(shareCtx, null, 2)}\`\n`; + } } return sendMessageToTelegram(msg); } diff --git a/src/context.js b/src/context.js index d22e15c9..47f6afba 100644 --- a/src/context.js +++ b/src/context.js @@ -1,4 +1,4 @@ -import {DATABASE, ENV} from './env.js'; +import {DATABASE, ENV, CONST} from './env.js'; // 用户配置 export const USER_CONFIG = { @@ -29,8 +29,14 @@ export const SHARE_CONTEXT = { speekerId: null, // 发言人 id }; + +async function initChatContext(chatId, replyToMessageId) { + CURRENT_CHAT_CONTEXT.chat_id = chatId; + CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; +} + // 初始化用户配置 -export async function initUserConfig(storeKey) { +async function initUserConfig(storeKey) { try { const userConfig = JSON.parse(await DATABASE.get(storeKey)); for (const key in userConfig) { @@ -45,3 +51,80 @@ export async function initUserConfig(storeKey) { console.error(e); } } + +async function initShareContext(message, request) { + const {pathname} = new URL(request.url); + const token = pathname.match( + /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/, + )[1]; + const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); + if (telegramIndex === -1) { + throw new Error('Token not found'); + } + + SHARE_CONTEXT.currentBotToken = token; + SHARE_CONTEXT.currentBotId = token.split(':')[0]; + SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; + if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { + SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; + } + + const id = message?.chat?.id; + if (id === undefined || id === null) { + throw new Error('Chat id not found'); + } + + /* + message_id每次都在变的。 + 私聊消息中: + message.chat.id 是发言人id + 群组消息中: + message.chat.id 是群id + message.from.id 是发言人id + + 没有开启群组共享模式时,要加上发言人id + chatHistoryKey = history:chat_id:bot_id:(from_id) + configStoreKey = user_config:chat_id:bot_id:(from_id) + * */ + + const botId = SHARE_CONTEXT.currentBotId; + let historyKey = `history:${id}`; + let configStoreKey = `user_config:${id}`; + let groupAdminKey = null; + + + if (botId) { + historyKey += `:${botId}`; + configStoreKey += `:${botId}`; + } + // 标记群组消息 + if (CONST.GROUP_TYPES.includes(message.chat?.type)) { + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { + historyKey += `:${message.from.id}`; + configStoreKey += `:${message.from.id}`; + } + groupAdminKey = `group_admin:${id}`; + } + + SHARE_CONTEXT.chatHistoryKey = historyKey; + SHARE_CONTEXT.configStoreKey = configStoreKey; + SHARE_CONTEXT.groupAdminKey = groupAdminKey; + + SHARE_CONTEXT.chatType = message.chat?.type; + SHARE_CONTEXT.chatId = message.chat.id; + SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; +} + + +export async function initContext(message, request) { + // 按顺序初始化上下文 + console.log(ENV) + const chatId = message?.chat?.id + const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null + initChatContext(chatId, replyId); + console.log(CURRENT_CHAT_CONTEXT) + await initShareContext(message, request); + console.log(SHARE_CONTEXT) + await initUserConfig(SHARE_CONTEXT.configStoreKey); + console.log(USER_CONFIG) +} diff --git a/src/message.js b/src/message.js index 912a9d4c..1dad539a 100644 --- a/src/message.js +++ b/src/message.js @@ -1,5 +1,5 @@ import {ENV, DATABASE, CONST} from './env.js'; -import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initUserConfig} from './context.js'; +import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; import {sendMessageToTelegram, sendChatActionToTelegram} from './telegram.js'; import {sendMessageToChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; @@ -7,83 +7,13 @@ import {errorToString} from './utils.js'; const MAX_TOKEN_LENGTH = 2048; -// 初始化当前Telegram Token -async function msgInitTelegramToken(message, request) { +// 初始化聊天上下文 +async function msgInitChatContext(message, request) { try { - const {pathname} = new URL(request.url); - const token = pathname.match( - /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/, - )[1]; - const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); - if (telegramIndex === -1) { - throw new Error('Token not found'); - } - SHARE_CONTEXT.currentBotToken = token; - SHARE_CONTEXT.currentBotId = token.split(':')[0]; - SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; - if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { - SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; - } + await initContext(message, request); } catch (e) { - return new Response( - e.message, - {status: 200}, - ); - } -} - - -// 初始化聊天上下文 -async function msgInitChatContext(message) { - const id = message?.chat?.id; - if (id === undefined || id === null) { - return new Response('ID NOT FOUND', {status: 200}); - } - - /* - message_id每次都在变的。 - 私聊消息中: - message.chat.id 是发言人id - 群组消息中: - message.chat.id 是群id - message.from.id 是发言人id - - 没有开启群组共享模式时,要加上发言人id - chatHistoryKey = history:chat_id:bot_id:(from_id) - configStoreKey = user_config:chat_id:bot_id:(from_id) - * */ - - let historyKey = `history:${id}`; - let configStoreKey = `user_config:${id}`; - let groupAdminKey = null; - - CURRENT_CHAT_CONTEXT.chat_id = id; - - if (SHARE_CONTEXT.currentBotId) { - historyKey += `:${SHARE_CONTEXT.currentBotId}`; - configStoreKey += `:${SHARE_CONTEXT.currentBotId}`; - } - - // 标记群组消息 - if (CONST.GROUP_TYPES.includes(message.chat?.type)) { - CURRENT_CHAT_CONTEXT.reply_to_message_id = message.message_id; - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE && message.from.id) { - historyKey += `:${message.from.id}`; - configStoreKey += `:${message.from.id}`; - } - groupAdminKey = `group_admin:${id}`; + return new Response(errorToString(e), {status: 200}); } - - SHARE_CONTEXT.chatHistoryKey = historyKey; - SHARE_CONTEXT.configStoreKey = configStoreKey; - SHARE_CONTEXT.groupAdminKey = groupAdminKey; - - SHARE_CONTEXT.chatType = message.chat?.type; - SHARE_CONTEXT.chatId = message.chat.id; - SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; - - await initUserConfig(configStoreKey); - return null; } @@ -122,7 +52,10 @@ async function msgFilterWhiteList(message) { ); } return null; - } else if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + } + + // 判断群聊消息 + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { // 未打开群组机器人开关,直接忽略 if (!ENV.GROUP_CHAT_BOT_ENABLE) { return new Response('ID SUPPORT', {status: 200}); @@ -223,7 +156,7 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { - sendChatActionToTelegram('typing').catch(console.error); + setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const { real: history, fake: fakeHistory } = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); @@ -244,7 +177,7 @@ async function msgChatWithOpenAI(message) { export async function processMessageByChatType(message) { const handlerMap = { 'private': [ - msgFilterWhiteList, + msgFilterWhiteList, msgFilterNonTextMessage, msgHandleCommand, ], @@ -255,7 +188,7 @@ export async function processMessageByChatType(message) { ], 'supergroup': [ msgHandleGroupMessage, - msgFilterWhiteList, + msgFilterWhiteList, msgHandleCommand, ], }; @@ -286,7 +219,7 @@ async function loadHistory(key) { const initMessage = {role: 'system', content: USER_CONFIG.SYSTEM_INIT_MESSAGE}; let history = []; try { - history = await DATABASE.get(key).then((res) => JSON.parse(res)); + history = JSON.parse(await DATABASE.get(key)); } catch (e) { console.error(e); } @@ -332,7 +265,6 @@ export async function handleMessage(request) { // 消息处理中间件 const handlers = [ - msgInitTelegramToken, // 初始化token msgInitChatContext, // 初始化聊天上下文: 生成chat_id, reply_to_message_id(群组消息), SHARE_CONTEXT msgSaveLastMessage, // 保存最后一条消息 msgCheckEnvIsReady, // 检查环境是否准备好: API_KEY, DATABASE diff --git a/src/openai.js b/src/openai.js index 2e5ae13a..51de7403 100644 --- a/src/openai.js +++ b/src/openai.js @@ -23,11 +23,8 @@ export async function sendMessageToChatGPT(message, history) { error: `OpenAI API 错误\n> ${resp.error.message}` } } - setTimeout(() => updateBotUsage(resp.usage), 0); - return { - ok: true, - message: resp.choices[0].message.content - } + setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); + return resp.choices[0].message.content; } catch (e) { return { ok: false, @@ -38,7 +35,7 @@ export async function sendMessageToChatGPT(message, history) { // 更新当前机器人的用量统计 async function updateBotUsage(usage) { - let dbValue = await DATABASE.get(SHARE_CONTEXT.usageKey).then((res) => JSON.parse(res)); + let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); if (!dbValue) { dbValue = { diff --git a/src/telegram.js b/src/telegram.js index 06565f27..61be2925 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -70,9 +70,7 @@ export async function bindTelegramWebHook(token, url) { export async function getChatRole(id) { let groupAdmin; try { - groupAdmin = await DATABASE.get(SHARE_CONTEXT.groupAdminKey).then((res) => - JSON.parse(res), - ); + groupAdmin = JSON.parse(await DATABASE.get(SHARE_CONTEXT.groupAdminKey)); } catch (e) { console.error(e); return e.message; From 3ba12290eb4684d7380ae37f1976dc6d1db52010 Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:31:51 +0800 Subject: [PATCH 03/32] =?UTF-8?q?-=20fix=20merge=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/openai.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openai.js b/src/openai.js index 51de7403..9453c071 100644 --- a/src/openai.js +++ b/src/openai.js @@ -24,7 +24,10 @@ export async function sendMessageToChatGPT(message, history) { } } setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); - return resp.choices[0].message.content; + return { + ok: true, + message: resp.choices[0].message.content + } } catch (e) { return { ok: false, From 6ecb0b99042fc6342eb327049726ed306f937c21 Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:37:54 +0800 Subject: [PATCH 04/32] =?UTF-8?q?-=20=E8=B0=83=E6=95=B4OpenAI=20API?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/message.js | 12 ++++-------- src/openai.js | 47 +++++++++++++++++------------------------------ 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/message.js b/src/message.js index 1dad539a..22333e82 100644 --- a/src/message.js +++ b/src/message.js @@ -160,14 +160,10 @@ async function msgChatWithOpenAI(message) { const historyKey = SHARE_CONTEXT.chatHistoryKey; const { real: history, fake: fakeHistory } = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - if (answer.ok) { - history.push({ role: 'user', content: message.text || '' }); - history.push({ role: 'assistant', content: answer.message }); - await DATABASE.put(historyKey, JSON.stringify(history)); - return sendMessageToTelegram(answer.message); - } else { - return sendMessageToTelegram(answer.error||'未知错误'); - } + history.push({ role: 'user', content: message.text || '' }); + history.push({ role: 'assistant', content: answer }); + await DATABASE.put(historyKey, JSON.stringify(history)); + return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); } diff --git a/src/openai.js b/src/openai.js index 9453c071..a595a853 100644 --- a/src/openai.js +++ b/src/openai.js @@ -3,37 +3,24 @@ import {ENV, DATABASE} from './env.js'; // 发送消息到ChatGPT export async function sendMessageToChatGPT(message, history) { - try { - const body = { - model: ENV.CHAT_MODEL, - ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: [...(history || []), { role: 'user', content: message }], - }; - const resp = await fetch('https://api.openai.com/v1/chat/completions', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${ENV.API_KEY}`, - }, - body: JSON.stringify(body), - }).then((res) => res.json()); - if (resp.error?.message) { - return { - ok: false, - error: `OpenAI API 错误\n> ${resp.error.message}` - } - } - setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); - return { - ok: true, - message: resp.choices[0].message.content - } - } catch (e) { - return { - ok: false, - error: "接口发生错误:"+e.message - } + const body = { + model: ENV.CHAT_MODEL, + ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, + messages: [...(history || []), { role: 'user', content: message }], + }; + const resp = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${ENV.API_KEY}`, + }, + body: JSON.stringify(body), + }).then((res) => res.json()); + if (resp.error?.message) { + throw new Error(`OpenAI API 错误\n> ${resp.error.message}`); } + setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); + return resp.choices[0].message.content } // 更新当前机器人的用量统计 From c5f50fa3ce66d8db6bfa005e93bd23a35021d96b Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:43:06 +0800 Subject: [PATCH 05/32] - build 1.3.0 (dev 6ecb0b9) --- dist/buildinfo.json | 2 +- dist/index.js | 46 ++++++++++++++++++++------------------------- dist/timestamp | 2 +- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 06b7d576..3c803338 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "4c1096c", "timestamp": 1678371905} +{"sha": "6ecb0b9", "timestamp": 1678372856} diff --git a/dist/index.js b/dist/index.js index ff65d28a..ab414a44 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678371905, + BUILD_TIMESTAMP: 1678372856, // 当前版本 commit id - BUILD_VERSION: "4c1096c", + BUILD_VERSION: "6ecb0b9", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B" }; @@ -322,31 +322,25 @@ async function getBot(token) { // src/openai.js async function sendMessageToChatGPT(message, history) { - try { - const body = { - model: ENV.CHAT_MODEL, - ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: [...history || [], { role: "user", content: message }] - }; - const resp = await fetch("https://api.openai.com/v1/chat/completions", { - method: "POST", - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${ENV.API_KEY}` - }, - body: JSON.stringify(body) - }).then((res) => res.json()); - if (resp.error?.message) { - return `OpenAI API \u9519\u8BEF -> ${resp.error.message}}`; - } - setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); - return resp.choices[0].message.content; - } catch (e) { - console.error(e); - return `\u6211\u4E0D\u77E5\u9053\u8BE5\u600E\u4E48\u56DE\u7B54 -> ${e.message}}`; + const body = { + model: ENV.CHAT_MODEL, + ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, + messages: [...history || [], { role: "user", content: message }] + }; + const resp = await fetch("https://api.openai.com/v1/chat/completions", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${ENV.API_KEY}` + }, + body: JSON.stringify(body) + }).then((res) => res.json()); + if (resp.error?.message) { + throw new Error(`OpenAI API \u9519\u8BEF +> ${resp.error.message}`); } + setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); + return resp.choices[0].message.content; } async function updateBotUsage(usage) { let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); diff --git a/dist/timestamp b/dist/timestamp index d5c6935c..452a69ca 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678371905 +1678372856 From cc3201ee99cc2f844f38a59e26f07185f9835300 Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:45:58 +0800 Subject: [PATCH 06/32] =?UTF-8?q?doc:=20changelog=E6=B7=BB=E5=8A=A0bug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ doc/CHANGELOG.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 21906c60..322b5000 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ - 添加`CHAT_MODEL`环境变量 - 添加`Github Action`自动更新部署脚本 - 优化`/init`页面 显示更多错误信息 + - 修复`USER_CONFIG`加载异常BUG + - 修复把错误信息存入历史记录BUG - 修复历史记录裁剪BUG 其他更新日志见[CHANGELOG.md](./doc/CHANGELOG.md) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index ff69eb55..f1f6762c 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -8,6 +8,8 @@ - 添加`Github Action`自动更新部署脚本 - 优化`/init`页面 显示更多错误信息 - 修复历史记录裁剪BUG + - 修复`USER_CONFIG`加载异常BUG + - 修复把错误信息存入历史记录BUG - v1.2.0 - 修复高危漏洞,必须更新 From f35f40f2cc2ae2af018cfef5273e643e41ccc411 Mon Sep 17 00:00:00 2001 From: TBXark Date: Thu, 9 Mar 2023 22:57:12 +0800 Subject: [PATCH 07/32] =?UTF-8?q?-=20=E7=BD=91=E9=A1=B5=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=83=A8=E5=88=86key=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 9 +++++++-- dist/timestamp | 2 +- src/context.js | 12 ++++++------ src/message.js | 16 ++++++++-------- src/openai.js | 4 ++-- src/router.js | 10 ++++++++++ 7 files changed, 35 insertions(+), 20 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 3c803338..77fe1321 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "6ecb0b9", "timestamp": 1678372856} +{"sha": "cc3201e", "timestamp": 1678373682} diff --git a/dist/index.js b/dist/index.js index ab414a44..1ecbbd27 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678372856, + BUILD_TIMESTAMP: 1678373682, // 当前版本 commit id - BUILD_VERSION: "6ecb0b9", + BUILD_VERSION: "cc3201e", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B" }; @@ -945,6 +945,9 @@ var footer = `

For more information, please visit ${helpLink}

If you have any questions, please visit ${issueLink}

`; +var keyNotfoundRender = (key) => { + return `

Please set the ${key} environment variable in Cloudflare Workers.

`; +}; async function bindWebHookAction(request) { const result = []; const domain = new URL(request.url).host; @@ -959,6 +962,7 @@ async function bindWebHookAction(request) { const HTML = renderHTML(`

ChatGPT-Telegram-Workers

${domain}

+ ${ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender("TELEGRAM_AVAILABLE_TOKENS") : ""} ${Object.keys(result).map((id) => `

Bot ID: ${id}

@@ -1004,6 +1008,7 @@ async function defaultIndexAction() {

You must >>>>> click here <<<<< to bind the webhook.


+ ${ENV.API_KEY ? "" : keyNotfoundRender("API_KEY")}

After binding the webhook, you can use the following commands to control the bot:

${commandsHelp().map((item) => `

${item.command} - ${item.description}

`).join("")}
diff --git a/dist/timestamp b/dist/timestamp index 452a69ca..d30e8b35 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678372856 +1678373682 diff --git a/src/context.js b/src/context.js index 47f6afba..dcbcd4ff 100644 --- a/src/context.js +++ b/src/context.js @@ -118,13 +118,13 @@ async function initShareContext(message, request) { export async function initContext(message, request) { // 按顺序初始化上下文 - console.log(ENV) - const chatId = message?.chat?.id - const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null + console.log(ENV); + const chatId = message?.chat?.id; + const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; initChatContext(chatId, replyId); - console.log(CURRENT_CHAT_CONTEXT) + console.log(CURRENT_CHAT_CONTEXT); await initShareContext(message, request); - console.log(SHARE_CONTEXT) + console.log(SHARE_CONTEXT); await initUserConfig(SHARE_CONTEXT.configStoreKey); - console.log(USER_CONFIG) + console.log(USER_CONFIG); } diff --git a/src/message.js b/src/message.js index 22333e82..88991876 100644 --- a/src/message.js +++ b/src/message.js @@ -52,8 +52,8 @@ async function msgFilterWhiteList(message) { ); } return null; - } - + } + // 判断群聊消息 if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { // 未打开群组机器人开关,直接忽略 @@ -156,12 +156,12 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { - setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); + setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; - const { real: history, fake: fakeHistory } = await loadHistory(historyKey); + const {real: history, fake: fakeHistory} = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - history.push({ role: 'user', content: message.text || '' }); - history.push({ role: 'assistant', content: answer }); + history.push({role: 'user', content: message.text || ''}); + history.push({role: 'assistant', content: answer}); await DATABASE.put(historyKey, JSON.stringify(history)); return sendMessageToTelegram(answer); } catch (e) { @@ -173,7 +173,7 @@ async function msgChatWithOpenAI(message) { export async function processMessageByChatType(message) { const handlerMap = { 'private': [ - msgFilterWhiteList, + msgFilterWhiteList, msgFilterNonTextMessage, msgHandleCommand, ], @@ -184,7 +184,7 @@ export async function processMessageByChatType(message) { ], 'supergroup': [ msgHandleGroupMessage, - msgFilterWhiteList, + msgFilterWhiteList, msgHandleCommand, ], }; diff --git a/src/openai.js b/src/openai.js index a595a853..9d428064 100644 --- a/src/openai.js +++ b/src/openai.js @@ -6,7 +6,7 @@ export async function sendMessageToChatGPT(message, history) { const body = { model: ENV.CHAT_MODEL, ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, - messages: [...(history || []), { role: 'user', content: message }], + messages: [...(history || []), {role: 'user', content: message}], }; const resp = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', @@ -20,7 +20,7 @@ export async function sendMessageToChatGPT(message, history) { throw new Error(`OpenAI API 错误\n> ${resp.error.message}`); } setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); - return resp.choices[0].message.content + return resp.choices[0].message.content; } // 更新当前机器人的用量统计 diff --git a/src/router.js b/src/router.js index 77a2b42c..6396d2b1 100644 --- a/src/router.js +++ b/src/router.js @@ -15,6 +15,10 @@ const footer = `

If you have any questions, please visit ${issueLink}

`; +const keyNotfoundRender = (key) => { + return `

Please set the ${key} environment variable in Cloudflare Workers.

`; +}; + async function bindWebHookAction(request) { const result = []; const domain = new URL(request.url).host; @@ -31,6 +35,9 @@ async function bindWebHookAction(request) {

ChatGPT-Telegram-Workers

${domain}

${ + ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender('TELEGRAM_AVAILABLE_TOKENS') : '' +} + ${ Object.keys(result).map((id) => `

Bot ID: ${id}

@@ -82,6 +89,9 @@ async function defaultIndexAction() {

You must >>>>> click here <<<<< to bind the webhook.


+ ${ + ENV.API_KEY ? '' : keyNotfoundRender('API_KEY') +}

After binding the webhook, you can use the following commands to control the bot:

${ commandsHelp().map((item) => `

${item.command} - ${item.description}

`).join('') From 4f85b6827b566c6dc97074556e0f0da6e4daa801 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 09:47:02 +0800 Subject: [PATCH 08/32] =?UTF-8?q?feat:=20=20=E6=B7=BB=E5=8A=A0=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E6=B6=88=E6=81=AF=E8=A7=92=E8=89=B2=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=20#92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 15 ++++++++++++--- dist/timestamp | 2 +- src/env.js | 2 ++ src/message.js | 7 +++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 77fe1321..c6413352 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "cc3201e", "timestamp": 1678373682} +{"sha": "f35f40f", "timestamp": 1678412753} diff --git a/dist/index.js b/dist/index.js index 1ecbbd27..3015330e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,11 +30,13 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678373682, + BUILD_TIMESTAMP: 1678412753, // 当前版本 commit id - BUILD_VERSION: "cc3201e", + BUILD_VERSION: "f35f40f", // 全局默认初始化消息 - SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B" + SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", + // 全局默认初始化消息角色 + SYSTEM_INIT_MESSAGE_ROLE: "system" }; var CONST = { PASSWORD_KEY: "chat_history_password", @@ -907,6 +909,13 @@ async function loadHistory(key) { default: history.unshift(initMessage); } + if (ENV.SYSTEM_INIT_MESSAGE_ROLE !== "system" && history.length > 0 && history[0].role === "system") { + const fake = { + ...history + }; + fake[0].role = ENV.SYSTEM_INIT_MESSAGE_ROLE; + return { real: history, fake }; + } return { real: history }; } async function handleMessage(request) { diff --git a/dist/timestamp b/dist/timestamp index d30e8b35..76ee91a9 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678373682 +1678412753 diff --git a/src/env.js b/src/env.js index 360a72c1..890fb5ce 100644 --- a/src/env.js +++ b/src/env.js @@ -35,6 +35,8 @@ export const ENV = { BUILD_VERSION: process.env.BUILD_VERSION || '', // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: '你是一个得力的助手', + // 全局默认初始化消息角色 + SYSTEM_INIT_MESSAGE_ROLE: 'system', }; export const CONST = { diff --git a/src/message.js b/src/message.js index 88991876..fe3a52ef 100644 --- a/src/message.js +++ b/src/message.js @@ -253,6 +253,13 @@ async function loadHistory(key) { default:// 默认给第一条插入init history.unshift(initMessage); } + if (ENV.SYSTEM_INIT_MESSAGE_ROLE !== 'system' && history.length > 0 && history[0].role === 'system') { + const fake = { + ...history + } + fake[0].role = ENV.SYSTEM_INIT_MESSAGE_ROLE; + return {real: history, fake}; + } return {real: history}; } From d3a330f778054601bff4ec3876db66026161b5ab Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 09:54:23 +0800 Subject: [PATCH 09/32] =?UTF-8?q?fix:=20=E6=B6=88=E6=81=AF=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=8E=86=E5=8F=B2=E5=A4=8D=E5=88=B6BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 9 ++++++--- dist/timestamp | 2 +- src/message.js | 5 ++++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index c6413352..0d1395c3 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "f35f40f", "timestamp": 1678412753} +{"sha": "4f85b68", "timestamp": 1678413230} diff --git a/dist/index.js b/dist/index.js index 3015330e..4790c105 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678412753, + BUILD_TIMESTAMP: 1678413230, // 当前版本 commit id - BUILD_VERSION: "f35f40f", + BUILD_VERSION: "4f85b68", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -913,7 +913,10 @@ async function loadHistory(key) { const fake = { ...history }; - fake[0].role = ENV.SYSTEM_INIT_MESSAGE_ROLE; + fake[0] = { + ...fake[0], + role: ENV.SYSTEM_INIT_MESSAGE_ROLE + }; return { real: history, fake }; } return { real: history }; diff --git a/dist/timestamp b/dist/timestamp index 76ee91a9..466cbc50 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678412753 +1678413230 diff --git a/src/message.js b/src/message.js index fe3a52ef..b6ffd902 100644 --- a/src/message.js +++ b/src/message.js @@ -257,7 +257,10 @@ async function loadHistory(key) { const fake = { ...history } - fake[0].role = ENV.SYSTEM_INIT_MESSAGE_ROLE; + fake[0] = { + ...fake[0], + role: ENV.SYSTEM_INIT_MESSAGE_ROLE + }; return {real: history, fake}; } return {real: history}; From 1ab05add9076cc7f777c2aafd10f0c32a618e61a Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 10:05:32 +0800 Subject: [PATCH 10/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=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 - `ENABLE_USAGE_STATISTICS` 可关闭统计 #91 - `HIDE_COMMAND_BUTTONS` 可隐藏部分按钮 #86 --- dist/buildinfo.json | 2 +- dist/index.js | 25 +++++++++++++++++++++---- dist/timestamp | 2 +- doc/CONFIG.md | 3 +++ src/command.js | 12 +++++++++++- src/env.js | 4 ++++ src/openai.js | 4 ++++ 7 files changed, 45 insertions(+), 7 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 0d1395c3..29b63b61 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "4f85b68", "timestamp": 1678413230} +{"sha": "d3a330f", "timestamp": 1678413830} diff --git a/dist/index.js b/dist/index.js index 4790c105..f50b7087 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,13 +30,17 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678413230, + BUILD_TIMESTAMP: 1678413830, // 当前版本 commit id - BUILD_VERSION: "4f85b68", + BUILD_VERSION: "d3a330f", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 - SYSTEM_INIT_MESSAGE_ROLE: "system" + SYSTEM_INIT_MESSAGE_ROLE: "system", + // 是否开启使用统计 + ENABLE_USAGE_STATISTICS: true, + // 隐藏部分命令按钮 + HIDE_COMMAND_BUTTONS: [] }; var CONST = { PASSWORD_KEY: "chat_history_password", @@ -345,6 +349,9 @@ async function sendMessageToChatGPT(message, history) { return resp.choices[0].message.content; } async function updateBotUsage(usage) { + if (!ENV.ENABLE_USAGE_STATISTICS) { + return; + } let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); if (!dbValue) { dbValue = { @@ -510,6 +517,9 @@ async function commandFetchUpdate(message, command, subcommand) { } } async function commandUsage() { + if (!ENV.ENABLE_USAGE_STATISTICS) { + return sendMessageToTelegram("\u5F53\u524D\u673A\u5668\u4EBA\u672A\u5F00\u542F\u7528\u91CF\u7EDF\u8BA1"); + } const usage = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); let text = "\u{1F4CA} \u5F53\u524D\u673A\u5668\u4EBA\u7528\u91CF\n\nTokens:\n"; if (usage?.tokens) { @@ -582,8 +592,15 @@ async function handleCommandMessage(message) { return null; } async function bindCommandForTelegram(token) { - const scopeCommandMap = {}; + const scopeCommandMap = { + all_private_chats: [], + all_group_chats: [], + all_chat_administrators: [] + }; for (const key in commandHandlers) { + if (ENV.HIDE_COMMAND_BUTTONS.includes(key)) { + continue; + } if (commandHandlers.hasOwnProperty(key) && commandHandlers[key].scopes) { for (const scope of commandHandlers[key].scopes) { if (!scopeCommandMap[scope]) { diff --git a/dist/timestamp b/dist/timestamp index 466cbc50..da4d92b0 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678413230 +1678413830 diff --git a/doc/CONFIG.md b/doc/CONFIG.md index 62f6fd02..dcece04d 100644 --- a/doc/CONFIG.md +++ b/doc/CONFIG.md @@ -20,6 +20,9 @@ |MAX_HISTORY_LENGTH|最大历史记录长度|`20`|`AUTO_TRIM_HISTORY开启后` 为了避免4096字符限制,将消息删减| |CHAT_MODEL|open ai 模型选择 |`gpt-3.5-turbo`|| |SYSTEM_INIT_MESSAGE|系统初始化信息|`你是一个得力的助手`|默认机器人设定| +|SYSTEM_INIT_MESSAGE_ROLE|系统初始化信息角色|`system`|默认机器人设定| +|ENABLE_USAGE_STATISTICS|开启使用统计|`true`|开启后,每次调用API都会记录到KV,可以通过`/usage`查看| +|HIDE_COMMAND_BUTTONS|隐藏指令按钮|`null`|把想要隐藏的按钮写入用逗号分开`/start,/system`, 记得带上斜杠| |DEBUG_MODE|调试模式|`false`|目前可以把最新一条消息保存到KV方便调试| ### 群组配置 diff --git a/src/command.js b/src/command.js index 60d75c7d..e28e5951 100644 --- a/src/command.js +++ b/src/command.js @@ -174,6 +174,9 @@ async function commandFetchUpdate(message, command, subcommand) { async function commandUsage() { + if (!ENV.ENABLE_USAGE_STATISTICS) { + return sendMessageToTelegram('当前机器人未开启用量统计'); + } const usage = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); let text = '📊 当前机器人用量\n\nTokens:\n'; if (usage?.tokens) { @@ -244,8 +247,15 @@ export async function handleCommandMessage(message) { } export async function bindCommandForTelegram(token) { - const scopeCommandMap = {}; + const scopeCommandMap = { + all_private_chats: [], + all_group_chats: [], + all_chat_administrators: [] + }; for (const key in commandHandlers) { + if (ENV.HIDE_COMMAND_BUTTONS.includes(key)) { + continue; + } if (commandHandlers.hasOwnProperty(key) && commandHandlers[key].scopes) { for (const scope of commandHandlers[key].scopes) { if (!scopeCommandMap[scope]) { diff --git a/src/env.js b/src/env.js index 890fb5ce..d9134c9c 100644 --- a/src/env.js +++ b/src/env.js @@ -37,6 +37,10 @@ export const ENV = { SYSTEM_INIT_MESSAGE: '你是一个得力的助手', // 全局默认初始化消息角色 SYSTEM_INIT_MESSAGE_ROLE: 'system', + // 是否开启使用统计 + ENABLE_USAGE_STATISTICS: true, + // 隐藏部分命令按钮 + HIDE_COMMAND_BUTTONS: [], }; export const CONST = { diff --git a/src/openai.js b/src/openai.js index 9d428064..2ecdf414 100644 --- a/src/openai.js +++ b/src/openai.js @@ -25,6 +25,10 @@ export async function sendMessageToChatGPT(message, history) { // 更新当前机器人的用量统计 async function updateBotUsage(usage) { + if (!ENV.ENABLE_USAGE_STATISTICS) { + return + } + let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); if (!dbValue) { From a8d931cecd8d5663141f9fb1c47907080e57e96a Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 12:13:05 +0800 Subject: [PATCH 11/32] =?UTF-8?q?fix:=20=E6=B6=88=E6=81=AF=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E8=AE=B0=E5=BD=95=E7=9B=B8=E5=85=B3BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复历史长度为0时返回历史长度错误BUG - 修复KV超过写入限制返回数据失败BUG --- src/message.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/message.js b/src/message.js index b6ffd902..347e2c2f 100644 --- a/src/message.js +++ b/src/message.js @@ -156,13 +156,16 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const {real: history, fake: fakeHistory} = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - history.push({role: 'user', content: message.text || ''}); - history.push({role: 'assistant', content: answer}); - await DATABASE.put(historyKey, JSON.stringify(history)); + if (!historyDisable) { + history.push({role: 'user', content: message.text || ''}); + history.push({role: 'assistant', content: answer}); + await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + } return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -213,6 +216,10 @@ export async function processMessageByChatType(message) { // { real: [], fake: [] } async function loadHistory(key) { const initMessage = {role: 'system', content: USER_CONFIG.SYSTEM_INIT_MESSAGE}; + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; + if (historyDisable) { + return {real: [initMessage]}; + } let history = []; try { history = JSON.parse(await DATABASE.get(key)); From add0242b1300e46ad6a055063a68d3534a6ebbf8 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 12:34:06 +0800 Subject: [PATCH 12/32] =?UTF-8?q?fix:=20=E9=98=B2=E6=AD=A2webhook=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E9=9D=9E200=E5=93=8D=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.js | 3 +-- src/router.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/main.js b/main.js index e6616649..eab963b5 100644 --- a/main.js +++ b/main.js @@ -10,9 +10,8 @@ export default { const resp = await handleRequest(request); return resp || new Response('NOTFOUND', {status: 404}); } catch (e) { - // 如果返回4xx,5xx,Telegram会重试这个消息,后续消息就不会到达,所有webhook的错误都返回200 console.error(e); - return new Response(errorToString(e), {status: 200}); + return new Response(errorToString(e), {status: 500}); } }, }; diff --git a/src/router.js b/src/router.js index 6396d2b1..c96d08dc 100644 --- a/src/router.js +++ b/src/router.js @@ -141,7 +141,16 @@ export async function handleRequest(request) { return loadChatHistory(request); } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/webhook`)) { - return telegramWebhookAction(request); + const resp = await telegramWebhookAction(request); + if (resp.status === 200) { + return resp; + } else { + // 如果返回4xx,5xx,Telegram会重试这个消息,后续消息就不会到达,所有webhook的错误都返回200 + return new Response(resp.body, {status: 200, headers: { + 'Original-Status': resp.status, + ...resp.headers + }}); + } } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/bot`)) { return loadBotInfo(request); From 8fbb55861d0e0811f0922d16a448cee7344b6aa1 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 12:35:35 +0800 Subject: [PATCH 13/32] =?UTF-8?q?fix:=20=E9=98=B2=E6=AD=A2telegramWebhookA?= =?UTF-8?q?ction=E6=8A=9B=E5=87=BA=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/router.js b/src/router.js index c96d08dc..fbd90858 100644 --- a/src/router.js +++ b/src/router.js @@ -141,15 +141,19 @@ export async function handleRequest(request) { return loadChatHistory(request); } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/webhook`)) { - const resp = await telegramWebhookAction(request); - if (resp.status === 200) { - return resp; - } else { - // 如果返回4xx,5xx,Telegram会重试这个消息,后续消息就不会到达,所有webhook的错误都返回200 - return new Response(resp.body, {status: 200, headers: { - 'Original-Status': resp.status, - ...resp.headers - }}); + try { + const resp = await telegramWebhookAction(request); + if (resp.status === 200) { + return resp; + } else { + // 如果返回4xx,5xx,Telegram会重试这个消息,后续消息就不会到达,所有webhook的错误都返回200 + return new Response(resp.body, {status: 200, headers: { + 'Original-Status': resp.status, + ...resp.headers + }}); + } + } catch(e) { + return new Response(errorToString(e), {status: 200}); } } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/bot`)) { From d91d7f3c4109dc665e7a54ab85fe7a35d6e285a9 Mon Sep 17 00:00:00 2001 From: Cheivin Date: Thu, 9 Mar 2023 23:40:05 -0500 Subject: [PATCH 14/32] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0/img=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E6=8F=90=E4=BE=9B=E7=94=9F=E6=88=90=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/command.js | 26 +++++++++++++++++++++++++- src/context.js | 3 +++ src/openai.js | 21 +++++++++++++++++++++ src/telegram.js | 32 +++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/command.js b/src/command.js index e28e5951..9476d94a 100644 --- a/src/command.js +++ b/src/command.js @@ -1,6 +1,7 @@ -import {sendMessageToTelegram, getChatRole} from './telegram.js'; +import {sendMessageToTelegram,sendPhotoToTelegram,sendChatActionToTelegram, getChatRole} from './telegram.js'; import {DATABASE, ENV, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT} from './context.js'; +import {requestImageFromChatGPT} from './openai.js'; // / -- Command function defaultGroupAuthCheck() { @@ -42,6 +43,12 @@ const commandHandlers = { fn: commandCreateNewChatContext, needAuth: defaultGroupAuthCheck, }, + '/img':{ + help: '生成一张图片', + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandGenerateImg, + needAuth: shareModeGroupAuthCheck, + }, '/version': { help: '获取当前版本号, 判断是否需要更新', scopes: ['all_private_chats', 'all_chat_administrators'], @@ -68,6 +75,23 @@ const commandHandlers = { }, }; +async function commandGenerateImg(message,command,subcommand){ + if(subcommand===''){ + return sendMessageToTelegram('请输入图片描述。命令完整格式为 \`/img 狸花猫\`') + } + try{ + setTimeout(() => sendChatActionToTelegram('upload_photo').catch(console.error), 0); + const imgUrl =await requestImageFromChatGPT(subcommand) + try{ + return sendPhotoToTelegram(imgUrl) + }catch(e){ + return sendMessageToTelegram(`图片:\n${imgUrl}`) + } + }catch(e){ + return sendMessageToTelegram(`ERROR:IMG: ${e.message}`); + } +} + // 命令帮助 async function commandGetHelp(message, command, subcommand) { const helpMsg = diff --git a/src/context.js b/src/context.js index dcbcd4ff..038bbca1 100644 --- a/src/context.js +++ b/src/context.js @@ -33,6 +33,9 @@ export const SHARE_CONTEXT = { async function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; + if (replyToMessageId) { + CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true + } } // 初始化用户配置 diff --git a/src/openai.js b/src/openai.js index 2ecdf414..2f0d0ca7 100644 --- a/src/openai.js +++ b/src/openai.js @@ -23,6 +23,27 @@ export async function sendMessageToChatGPT(message, history) { return resp.choices[0].message.content; } +// 请求ChatGPT生成图片 +export async function requestImageFromChatGPT(prompt) { + const body = { + prompt:prompt, + n:1, + size:'512x512' + }; + const resp = await fetch('https://api.openai.com/v1/images/generations', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${ENV.API_KEY}`, + }, + body: JSON.stringify(body), + }).then((res) => res.json()); + if (resp.error?.message) { + throw new Error(`OpenAI API 错误\n> ${resp.error.message}`); + } + return resp.data[0].url; +} + // 更新当前机器人的用量统计 async function updateBotUsage(usage) { if (!ENV.ENABLE_USAGE_STATISTICS) { diff --git a/src/telegram.js b/src/telegram.js index 61be2925..fb359c68 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -17,21 +17,35 @@ export async function sendMessageToTelegram(message, token, context) { }, ); const json = await resp.json(); - if (!resp.ok) { - return sendMessageToTelegramFallback(json, message, token, context); - } return new Response(JSON.stringify(json), { status: 200, statusText: resp.statusText, headers: resp.headers, }); } -async function sendMessageToTelegramFallback(json, message, token, context) { - if (json.description === 'Bad Request: replied message not found') { - delete context.reply_to_message_id; - return sendMessageToTelegram(message, token, context); - } - return new Response(JSON.stringify(json), {status: 200}); + +// 发送图片消息到Telegram +export async function sendPhotoToTelegram(url, token, context) { + let chat_context = Object.assign((context || CURRENT_CHAT_CONTEXT),{parse_mode:null}) + const resp = await fetch( + `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ...chat_context, + photo: url, + }), + }, + ); + const json = await resp.json(); + return new Response(JSON.stringify(json), { + status: 200, + statusText: resp.statusText, + headers: resp.headers, + }); } // 发送聊天动作到TG From e9236bbdeab4c1bd9d389f67dd1de43d0ded78a0 Mon Sep 17 00:00:00 2001 From: Cheivin Date: Thu, 9 Mar 2023 23:40:53 -0500 Subject: [PATCH 15/32] Merge branch 'dev' of github.com:TBXark/ChatGPT-Telegram-Workers into dev --- src/message.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/message.js b/src/message.js index b6ffd902..347e2c2f 100644 --- a/src/message.js +++ b/src/message.js @@ -156,13 +156,16 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const {real: history, fake: fakeHistory} = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - history.push({role: 'user', content: message.text || ''}); - history.push({role: 'assistant', content: answer}); - await DATABASE.put(historyKey, JSON.stringify(history)); + if (!historyDisable) { + history.push({role: 'user', content: message.text || ''}); + history.push({role: 'assistant', content: answer}); + await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + } return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -213,6 +216,10 @@ export async function processMessageByChatType(message) { // { real: [], fake: [] } async function loadHistory(key) { const initMessage = {role: 'system', content: USER_CONFIG.SYSTEM_INIT_MESSAGE}; + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; + if (historyDisable) { + return {real: [initMessage]}; + } let history = []; try { history = JSON.parse(await DATABASE.get(key)); From f060ec764b8702e9fb23dfe5c92ef3730ca203c0 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 13:33:22 +0800 Subject: [PATCH 16/32] =?UTF-8?q?fix:=20[BUG]ROLE=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BAuser=E8=BF=94=E5=9B=9EERROR=20#94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 113 +++++++++++++++++++++++++++++++++++++------- dist/timestamp | 2 +- src/message.js | 4 +- 4 files changed, 99 insertions(+), 22 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 29b63b61..c52134cc 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "d3a330f", "timestamp": 1678413830} +{"sha": "bfd8d17", "timestamp": 1678426382} diff --git a/dist/index.js b/dist/index.js index f50b7087..0e0a60cf 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678413830, + BUILD_TIMESTAMP: 1678426382, // 当前版本 commit id - BUILD_VERSION: "d3a330f", + BUILD_VERSION: "bfd8d17", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -126,6 +126,9 @@ var SHARE_CONTEXT = { async function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; + if (replyToMessageId) { + CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true; + } } async function initUserConfig(storeKey) { try { @@ -208,21 +211,33 @@ async function sendMessageToTelegram(message, token, context) { } ); const json = await resp.json(); - if (!resp.ok) { - return sendMessageToTelegramFallback(json, message, token, context); - } return new Response(JSON.stringify(json), { status: 200, statusText: resp.statusText, headers: resp.headers }); } -async function sendMessageToTelegramFallback(json, message, token, context) { - if (json.description === "Bad Request: replied message not found") { - delete context.reply_to_message_id; - return sendMessageToTelegram(message, token, context); - } - return new Response(JSON.stringify(json), { status: 200 }); +async function sendPhotoToTelegram(url, token, context) { + let chat_context = Object.assign(context || CURRENT_CHAT_CONTEXT, { parse_mode: null }); + const resp = await fetch( + `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, + { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + ...chat_context, + photo: url + }) + } + ); + const json = await resp.json(); + return new Response(JSON.stringify(json), { + status: 200, + statusText: resp.statusText, + headers: resp.headers + }); } async function sendChatActionToTelegram(action, token) { return await fetch( @@ -348,6 +363,26 @@ async function sendMessageToChatGPT(message, history) { setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); return resp.choices[0].message.content; } +async function requestImageFromChatGPT(prompt) { + const body = { + prompt, + n: 1, + size: "512x512" + }; + const resp = await fetch("https://api.openai.com/v1/images/generations", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${ENV.API_KEY}` + }, + body: JSON.stringify(body) + }).then((res) => res.json()); + if (resp.error?.message) { + throw new Error(`OpenAI API \u9519\u8BEF +> ${resp.error.message}`); + } + return resp.data[0].url; +} async function updateBotUsage(usage) { if (!ENV.ENABLE_USAGE_STATISTICS) { return; @@ -404,6 +439,12 @@ var commandHandlers = { fn: commandCreateNewChatContext, needAuth: defaultGroupAuthCheck }, + "/img": { + help: "\u751F\u6210\u4E00\u5F20\u56FE\u7247", + scopes: ["all_private_chats", "all_chat_administrators"], + fn: commandGenerateImg, + needAuth: shareModeGroupAuthCheck + }, "/version": { help: "\u83B7\u53D6\u5F53\u524D\u7248\u672C\u53F7, \u5224\u65AD\u662F\u5426\u9700\u8981\u66F4\u65B0", scopes: ["all_private_chats", "all_chat_administrators"], @@ -429,6 +470,23 @@ var commandHandlers = { needAuth: defaultGroupAuthCheck } }; +async function commandGenerateImg(message, command, subcommand) { + if (subcommand === "") { + return sendMessageToTelegram("\u8BF7\u8F93\u5165\u56FE\u7247\u63CF\u8FF0\u3002\u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A `/img \u72F8\u82B1\u732B`"); + } + try { + setTimeout(() => sendChatActionToTelegram("upload_photo").catch(console.error), 0); + const imgUrl = await requestImageFromChatGPT(subcommand); + try { + return sendPhotoToTelegram(imgUrl); + } catch (e) { + return sendMessageToTelegram(`\u56FE\u7247: +${imgUrl}`); + } + } catch (e) { + return sendMessageToTelegram(`ERROR:IMG: ${e.message}`); + } +} async function commandGetHelp(message, command, subcommand) { const helpMsg = "\u5F53\u524D\u652F\u6301\u4EE5\u4E0B\u547D\u4EE4:\n" + Object.keys(commandHandlers).map((key) => `${key}\uFF1A${commandHandlers[key].help}`).join("\n"); return sendMessageToTelegram(helpMsg); @@ -836,13 +894,16 @@ async function msgHandleCommand(message) { } async function msgChatWithOpenAI(message) { try { + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram("typing").catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const { real: history, fake: fakeHistory } = await loadHistory(historyKey); const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); - history.push({ role: "user", content: message.text || "" }); - history.push({ role: "assistant", content: answer }); - await DATABASE.put(historyKey, JSON.stringify(history)); + if (!historyDisable) { + history.push({ role: "user", content: message.text || "" }); + history.push({ role: "assistant", content: answer }); + await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + } return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -889,6 +950,10 @@ async function processMessageByChatType(message) { } async function loadHistory(key) { const initMessage = { role: "system", content: USER_CONFIG.SYSTEM_INIT_MESSAGE }; + const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; + if (historyDisable) { + return { real: [initMessage] }; + } let history = []; try { history = JSON.parse(await DATABASE.get(key)); @@ -927,9 +992,9 @@ async function loadHistory(key) { history.unshift(initMessage); } if (ENV.SYSTEM_INIT_MESSAGE_ROLE !== "system" && history.length > 0 && history[0].role === "system") { - const fake = { + const fake = [ ...history - }; + ]; fake[0] = { ...fake[0], role: ENV.SYSTEM_INIT_MESSAGE_ROLE @@ -1081,7 +1146,19 @@ async function handleRequest(request) { return loadChatHistory(request); } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/webhook`)) { - return telegramWebhookAction(request); + try { + const resp = await telegramWebhookAction(request); + if (resp.status === 200) { + return resp; + } else { + return new Response(resp.body, { status: 200, headers: { + "Original-Status": resp.status, + ...resp.headers + } }); + } + } catch (e) { + return new Response(errorToString(e), { status: 200 }); + } } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/bot`)) { return loadBotInfo(request); @@ -1098,7 +1175,7 @@ var main_default = { return resp || new Response("NOTFOUND", { status: 404 }); } catch (e) { console.error(e); - return new Response(errorToString(e), { status: 200 }); + return new Response(errorToString(e), { status: 500 }); } } }; diff --git a/dist/timestamp b/dist/timestamp index da4d92b0..0a86d754 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678413830 +1678426382 diff --git a/src/message.js b/src/message.js index 347e2c2f..3f77379a 100644 --- a/src/message.js +++ b/src/message.js @@ -261,9 +261,9 @@ async function loadHistory(key) { history.unshift(initMessage); } if (ENV.SYSTEM_INIT_MESSAGE_ROLE !== 'system' && history.length > 0 && history[0].role === 'system') { - const fake = { + const fake = [ ...history - } + ] fake[0] = { ...fake[0], role: ENV.SYSTEM_INIT_MESSAGE_ROLE From 7677fcf72bd3a35a13cf87eb2ce08c9c3ab2fe4d Mon Sep 17 00:00:00 2001 From: Cheivin Date: Fri, 10 Mar 2023 01:54:26 -0500 Subject: [PATCH 17/32] =?UTF-8?q?fix:=20/system=E5=91=BD=E4=BB=A4=E8=BD=AC?= =?UTF-8?q?=E7=A0=81=E5=AF=BC=E8=87=B4=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/command.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/command.js b/src/command.js index 9476d94a..dc9416b3 100644 --- a/src/command.js +++ b/src/command.js @@ -226,6 +226,7 @@ async function commandSystem(message) { let msg = '当前系统信息如下:\n'; msg+='OpenAI模型:'+ENV.CHAT_MODEL+'\n'; if (ENV.DEBUG_MODE) { + msg+='
'
     msg+=`USER_CONFIG: \n\`${JSON.stringify(USER_CONFIG, null, 2)}\`\n`;
     if (ENV.DEV_MODE) {
       const shareCtx = {...SHARE_CONTEXT};
@@ -233,7 +234,9 @@ async function commandSystem(message) {
       msg +=`CHAT_CONTEXT: \n\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\`\n`;
       msg += `SHARE_CONTEXT: \n\`${JSON.stringify(shareCtx, null, 2)}\`\n`;
     }
+    msg+='
' } + CURRENT_CHAT_CONTEXT.parse_mode = "HTML" return sendMessageToTelegram(msg); } From 00efc88abe88a117c806e63c9674e5b2f930412f Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 14:59:15 +0800 Subject: [PATCH 18/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0/echo=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 46 ++++++++++++++++++++++++------------------- dist/timestamp | 2 +- src/command.js | 48 ++++++++++++++++++++++++++++++--------------- src/context.js | 2 +- src/env.js | 2 +- src/message.js | 10 +++++----- src/openai.js | 10 +++++----- src/router.js | 4 ++-- src/telegram.js | 20 ++++--------------- 10 files changed, 78 insertions(+), 68 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index c52134cc..5a2c6c68 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "bfd8d17", "timestamp": 1678426382} +{"sha": "087bb74", "timestamp": 1678431512} diff --git a/dist/index.js b/dist/index.js index 0e0a60cf..e65d9dc6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678426382, + BUILD_TIMESTAMP: 1678431512, // 当前版本 commit id - BUILD_VERSION: "bfd8d17", + BUILD_VERSION: "087bb74", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -197,7 +197,7 @@ async function initContext(message, request) { // src/telegram.js async function sendMessageToTelegram(message, token, context) { - const resp = await fetch( + return await fetch( `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendMessage`, { method: "POST", @@ -210,16 +210,10 @@ async function sendMessageToTelegram(message, token, context) { }) } ); - const json = await resp.json(); - return new Response(JSON.stringify(json), { - status: 200, - statusText: resp.statusText, - headers: resp.headers - }); } async function sendPhotoToTelegram(url, token, context) { - let chat_context = Object.assign(context || CURRENT_CHAT_CONTEXT, { parse_mode: null }); - const resp = await fetch( + const chatContext = Object.assign(context || CURRENT_CHAT_CONTEXT, { parse_mode: null }); + return await fetch( `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, { method: "POST", @@ -227,17 +221,11 @@ async function sendPhotoToTelegram(url, token, context) { "Content-Type": "application/json" }, body: JSON.stringify({ - ...chat_context, + ...chatContext, photo: url }) } ); - const json = await resp.json(); - return new Response(JSON.stringify(json), { - status: 200, - statusText: resp.statusText, - headers: resp.headers - }); } async function sendChatActionToTelegram(action, token) { return await fetch( @@ -603,6 +591,7 @@ async function commandSystem(message) { let msg = "\u5F53\u524D\u7CFB\u7EDF\u4FE1\u606F\u5982\u4E0B:\n"; msg += "OpenAI\u6A21\u578B:" + ENV.CHAT_MODEL + "\n"; if (ENV.DEBUG_MODE) { + msg += "
";
     msg += `USER_CONFIG: 
 \`${JSON.stringify(USER_CONFIG, null, 2)}\`
 `;
@@ -616,10 +605,27 @@ async function commandSystem(message) {
 \`${JSON.stringify(shareCtx, null, 2)}\`
 `;
     }
+    msg += "
"; } + CURRENT_CHAT_CONTEXT.parse_mode = "HTML"; + return sendMessageToTelegram(msg); +} +async function commandEcho(message) { + let msg = "
";
+  msg += JSON.stringify({ message }, null, 2);
+  msg += "
"; + CURRENT_CHAT_CONTEXT.parse_mode = "HTML"; return sendMessageToTelegram(msg); } async function handleCommandMessage(message) { + if (ENV.DEV_MODE) { + commandHandlers["/echo"] = { + help: "[DEBUG ONLY]\u56DE\u663E\u6D88\u606F", + scopes: ["all_private_chats", "all_chat_administrators"], + fn: commandEcho, + needAuth: defaultGroupAuthCheck + }; + } for (const key in commandHandlers) { if (message.text === key || message.text.startsWith(key + " ")) { const command = commandHandlers[key]; @@ -811,7 +817,7 @@ async function msgFilterWhiteList(message) { } if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { if (!ENV.GROUP_CHAT_BOT_ENABLE) { - return new Response("ID SUPPORT", { status: 200 }); + return new Response("ID SUPPORT", { status: 401 }); } if (!ENV.CHAT_GROUP_WHITE_LIST.includes(`${CURRENT_CHAT_CONTEXT.chat_id}`)) { return sendMessageToTelegram( @@ -1024,7 +1030,7 @@ async function handleMessage(request) { return result; } } catch (e) { - return new Response(errorToString(e), { status: 200 }); + return new Response(errorToString(e), { status: 500 }); } } return null; diff --git a/dist/timestamp b/dist/timestamp index 0a86d754..1d13875c 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678426382 +1678431512 diff --git a/src/command.js b/src/command.js index dc9416b3..0aa27f10 100644 --- a/src/command.js +++ b/src/command.js @@ -1,4 +1,4 @@ -import {sendMessageToTelegram,sendPhotoToTelegram,sendChatActionToTelegram, getChatRole} from './telegram.js'; +import {sendMessageToTelegram, sendPhotoToTelegram, sendChatActionToTelegram, getChatRole} from './telegram.js'; import {DATABASE, ENV, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT} from './context.js'; import {requestImageFromChatGPT} from './openai.js'; @@ -43,7 +43,7 @@ const commandHandlers = { fn: commandCreateNewChatContext, needAuth: defaultGroupAuthCheck, }, - '/img':{ + '/img': { help: '生成一张图片', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandGenerateImg, @@ -75,19 +75,19 @@ const commandHandlers = { }, }; -async function commandGenerateImg(message,command,subcommand){ - if(subcommand===''){ - return sendMessageToTelegram('请输入图片描述。命令完整格式为 \`/img 狸花猫\`') +async function commandGenerateImg(message, command, subcommand) { + if (subcommand==='') { + return sendMessageToTelegram('请输入图片描述。命令完整格式为 \`/img 狸花猫\`'); } - try{ + try { setTimeout(() => sendChatActionToTelegram('upload_photo').catch(console.error), 0); - const imgUrl =await requestImageFromChatGPT(subcommand) - try{ - return sendPhotoToTelegram(imgUrl) - }catch(e){ - return sendMessageToTelegram(`图片:\n${imgUrl}`) + const imgUrl =await requestImageFromChatGPT(subcommand); + try { + return sendPhotoToTelegram(imgUrl); + } catch (e) { + return sendMessageToTelegram(`图片:\n${imgUrl}`); } - }catch(e){ + } catch (e) { return sendMessageToTelegram(`ERROR:IMG: ${e.message}`); } } @@ -226,7 +226,7 @@ async function commandSystem(message) { let msg = '当前系统信息如下:\n'; msg+='OpenAI模型:'+ENV.CHAT_MODEL+'\n'; if (ENV.DEBUG_MODE) { - msg+='
'
+    msg+='
';
     msg+=`USER_CONFIG: \n\`${JSON.stringify(USER_CONFIG, null, 2)}\`\n`;
     if (ENV.DEV_MODE) {
       const shareCtx = {...SHARE_CONTEXT};
@@ -234,13 +234,29 @@ async function commandSystem(message) {
       msg +=`CHAT_CONTEXT: \n\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\`\n`;
       msg += `SHARE_CONTEXT: \n\`${JSON.stringify(shareCtx, null, 2)}\`\n`;
     }
-    msg+='
' + msg+='
'; } - CURRENT_CHAT_CONTEXT.parse_mode = "HTML" + CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; + return sendMessageToTelegram(msg); +} + +async function commandEcho(message) { + let msg = '
';
+  msg += JSON.stringify({message}, null, 2);
+  msg += '
'; + CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; return sendMessageToTelegram(msg); } export async function handleCommandMessage(message) { + if (ENV.DEV_MODE) { + commandHandlers['/echo'] = { + help: '[DEBUG ONLY]回显消息', + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandEcho, + needAuth: defaultGroupAuthCheck, + }; + } for (const key in commandHandlers) { if (message.text === key || message.text.startsWith(key + ' ')) { const command = commandHandlers[key]; @@ -277,7 +293,7 @@ export async function bindCommandForTelegram(token) { const scopeCommandMap = { all_private_chats: [], all_group_chats: [], - all_chat_administrators: [] + all_chat_administrators: [], }; for (const key in commandHandlers) { if (ENV.HIDE_COMMAND_BUTTONS.includes(key)) { diff --git a/src/context.js b/src/context.js index 038bbca1..3f36629e 100644 --- a/src/context.js +++ b/src/context.js @@ -34,7 +34,7 @@ async function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; if (replyToMessageId) { - CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true + CURRENT_CHAT_CONTEXT.allow_sending_without_reply = true; } } diff --git a/src/env.js b/src/env.js index d9134c9c..3ca15d69 100644 --- a/src/env.js +++ b/src/env.js @@ -36,7 +36,7 @@ export const ENV = { // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: '你是一个得力的助手', // 全局默认初始化消息角色 - SYSTEM_INIT_MESSAGE_ROLE: 'system', + SYSTEM_INIT_MESSAGE_ROLE: 'system', // 是否开启使用统计 ENABLE_USAGE_STATISTICS: true, // 隐藏部分命令按钮 diff --git a/src/message.js b/src/message.js index 3f77379a..52fa9525 100644 --- a/src/message.js +++ b/src/message.js @@ -58,7 +58,7 @@ async function msgFilterWhiteList(message) { if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { // 未打开群组机器人开关,直接忽略 if (!ENV.GROUP_CHAT_BOT_ENABLE) { - return new Response('ID SUPPORT', {status: 200}); + return new Response('ID SUPPORT', {status: 401}); } // 白名单判断 if (!ENV.CHAT_GROUP_WHITE_LIST.includes(`${CURRENT_CHAT_CONTEXT.chat_id}`)) { @@ -262,11 +262,11 @@ async function loadHistory(key) { } if (ENV.SYSTEM_INIT_MESSAGE_ROLE !== 'system' && history.length > 0 && history[0].role === 'system') { const fake = [ - ...history - ] + ...history, + ]; fake[0] = { ...fake[0], - role: ENV.SYSTEM_INIT_MESSAGE_ROLE + role: ENV.SYSTEM_INIT_MESSAGE_ROLE, }; return {real: history, fake}; } @@ -292,7 +292,7 @@ export async function handleMessage(request) { return result; } } catch (e) { - return new Response(errorToString(e), {status: 200}); + return new Response(errorToString(e), {status: 500}); } } return null; diff --git a/src/openai.js b/src/openai.js index 2f0d0ca7..f092b3f0 100644 --- a/src/openai.js +++ b/src/openai.js @@ -26,9 +26,9 @@ export async function sendMessageToChatGPT(message, history) { // 请求ChatGPT生成图片 export async function requestImageFromChatGPT(prompt) { const body = { - prompt:prompt, - n:1, - size:'512x512' + prompt: prompt, + n: 1, + size: '512x512', }; const resp = await fetch('https://api.openai.com/v1/images/generations', { method: 'POST', @@ -47,9 +47,9 @@ export async function requestImageFromChatGPT(prompt) { // 更新当前机器人的用量统计 async function updateBotUsage(usage) { if (!ENV.ENABLE_USAGE_STATISTICS) { - return + return; } - + let dbValue = JSON.parse(await DATABASE.get(SHARE_CONTEXT.usageKey)); if (!dbValue) { diff --git a/src/router.js b/src/router.js index fbd90858..a94599f6 100644 --- a/src/router.js +++ b/src/router.js @@ -149,10 +149,10 @@ export async function handleRequest(request) { // 如果返回4xx,5xx,Telegram会重试这个消息,后续消息就不会到达,所有webhook的错误都返回200 return new Response(resp.body, {status: 200, headers: { 'Original-Status': resp.status, - ...resp.headers + ...resp.headers, }}); } - } catch(e) { + } catch (e) { return new Response(errorToString(e), {status: 200}); } } diff --git a/src/telegram.js b/src/telegram.js index fb359c68..bc25c5d8 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -3,7 +3,7 @@ import {CURRENT_CHAT_CONTEXT, SHARE_CONTEXT} from './context.js'; // 发送消息到Telegram export async function sendMessageToTelegram(message, token, context) { - const resp = await fetch( + return await fetch( `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendMessage`, { method: 'POST', @@ -16,18 +16,12 @@ export async function sendMessageToTelegram(message, token, context) { }), }, ); - const json = await resp.json(); - return new Response(JSON.stringify(json), { - status: 200, - statusText: resp.statusText, - headers: resp.headers, - }); } // 发送图片消息到Telegram export async function sendPhotoToTelegram(url, token, context) { - let chat_context = Object.assign((context || CURRENT_CHAT_CONTEXT),{parse_mode:null}) - const resp = await fetch( + const chatContext = Object.assign((context || CURRENT_CHAT_CONTEXT), {parse_mode: null}); + return await fetch( `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, { method: 'POST', @@ -35,17 +29,11 @@ export async function sendPhotoToTelegram(url, token, context) { 'Content-Type': 'application/json', }, body: JSON.stringify({ - ...chat_context, + ...chatContext, photo: url, }), }, ); - const json = await resp.json(); - return new Response(JSON.stringify(json), { - status: 200, - statusText: resp.statusText, - headers: resp.headers, - }); } // 发送聊天动作到TG From f7b44330fd58a5900ab56a82a26137ddc7d3ce20 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 16:54:23 +0800 Subject: [PATCH 19/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0inline=20keyboa?= =?UTF-8?q?rd=E9=80=89=E9=A1=B9=EF=BC=8C"=E7=BB=A7=E7=BB=AD"=EF=BC=8C"?= =?UTF-8?q?=E6=96=B0=E4=BC=9A=E8=AF=9D"=EF=BC=9F=20#29?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 21 +++++++---- dist/buildinfo.json | 2 +- dist/index.js | 86 ++++++++++++++++++++++++++++++++++++++------- dist/timestamp | 2 +- package.json | 2 +- src/command.js | 8 ++--- src/context.js | 8 ++--- src/env.js | 2 ++ src/message.js | 47 +++++++++++++++++++++++-- src/telegram.js | 19 ++++++++++ 10 files changed, 166 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index db71419b..b832b866 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,25 @@ TIMESTAMP_FILE := ./dist/timestamp # 兼容旧版更新逻辑 -BUILDINFO_JSON := ./dist/buildinfo.json +BUILD_INFO_JSON := ./dist/buildinfo.json OUTPUT_FILE := ./dist/index.js ENTRY_FILE := main.js -ifeq (,$(shell which esbuild)) - export PATH := $(CURDIR)/node_modules/.bin:$(PATH) + +ifeq (,$(wildcard ./node_modules/.bin)) + PATH := ./node_modules/.bin:$(PATH) endif .PHONY: build -build: +build: clean COMMIT_HASH=$$(git rev-parse --short HEAD) && \ TIMESTAMP=$$(date +%s) && \ echo "$$TIMESTAMP" > $(TIMESTAMP_FILE) && \ - echo "{\"sha\": \"$$COMMIT_HASH\", \"timestamp\": $$TIMESTAMP}" > $(BUILDINFO_JSON) && \ - esbuild $(ENTRY_FILE) --bundle --outfile=$(OUTPUT_FILE) --format=esm --define:process.env.BUILD_VERSION="'$$COMMIT_HASH'" --define:process.env.BUILD_TIMESTAMP="$$TIMESTAMP" \ No newline at end of file + echo "{\"sha\": \"$$COMMIT_HASH\", \"timestamp\": $$TIMESTAMP}" > $(BUILD_INFO_JSON) && \ + esbuild $(ENTRY_FILE) --bundle --outfile=$(OUTPUT_FILE) --format=esm --define:process.env.BUILD_VERSION="'$$COMMIT_HASH'" --define:process.env.BUILD_TIMESTAMP="$$TIMESTAMP" + +.PHONY: clean +clean: + rm -f $(TIMESTAMP_FILE) $(BUILD_INFO_JSON) $(OUTPUT_FILE) + +.PHONY: lint +lint: + eslint --fix --ext .js,.jsx,.mjs main.js src diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 5a2c6c68..4498221e 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "087bb74", "timestamp": 1678431512} +{"sha": "00efc88", "timestamp": 1678438364} diff --git a/dist/index.js b/dist/index.js index e65d9dc6..e3f3392b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678431512, + BUILD_TIMESTAMP: 1678438364, // 当前版本 commit id - BUILD_VERSION: "087bb74", + BUILD_VERSION: "00efc88", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -40,7 +40,9 @@ var ENV = { // 是否开启使用统计 ENABLE_USAGE_STATISTICS: true, // 隐藏部分命令按钮 - HIDE_COMMAND_BUTTONS: [] + HIDE_COMMAND_BUTTONS: [], + // Inline keyboard: 实验性功能请勿开启 + INLINE_KEYBOARD_ENABLE: false }; var CONST = { PASSWORD_KEY: "chat_history_password", @@ -120,10 +122,10 @@ var SHARE_CONTEXT = { // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id - speekerId: null + speakerId: null // 发言人 id }; -async function initChatContext(chatId, replyToMessageId) { +function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; if (replyToMessageId) { @@ -149,7 +151,7 @@ async function initShareContext(message, request) { )[1]; const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); if (telegramIndex === -1) { - throw new Error("Token not found"); + throw new Error("Token not allowed"); } SHARE_CONTEXT.currentBotToken = token; SHARE_CONTEXT.currentBotId = token.split(":")[0]; @@ -181,7 +183,7 @@ async function initShareContext(message, request) { SHARE_CONTEXT.groupAdminKey = groupAdminKey; SHARE_CONTEXT.chatType = message.chat?.type; SHARE_CONTEXT.chatId = message.chat.id; - SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; + SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; } async function initContext(message, request) { console.log(ENV); @@ -242,6 +244,24 @@ async function sendChatActionToTelegram(action, token) { } ).then((res) => res.json()); } +async function deleteMessageInlineKeyboard(chatId, messageId, token) { + return await fetch( + `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/editMessageReplyMarkup`, + { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + chat_id: chatId, + message_id: messageId, + reply_markup: { + inline_keyboard: [] + } + }) + } + ).then((res) => res.json()); +} async function bindTelegramWebHook(token, url) { return await fetch( `https://api.telegram.org/bot${token}/setWebhook`, @@ -593,16 +613,16 @@ async function commandSystem(message) { if (ENV.DEBUG_MODE) { msg += "
";
     msg += `USER_CONFIG: 
-\`${JSON.stringify(USER_CONFIG, null, 2)}\`
+${JSON.stringify(USER_CONFIG, null, 2)}
 `;
     if (ENV.DEV_MODE) {
       const shareCtx = { ...SHARE_CONTEXT };
       shareCtx.currentBotToken = "ENPYPTED";
       msg += `CHAT_CONTEXT: 
-\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\`
+${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}
 `;
       msg += `SHARE_CONTEXT: 
-\`${JSON.stringify(shareCtx, null, 2)}\`
+${JSON.stringify(shareCtx, null, 2)}
 `;
     }
     msg += "
"; @@ -633,7 +653,7 @@ async function handleCommandMessage(message) { if (command.needAuth) { const roleList = command.needAuth(); if (roleList) { - const chatRole = await getChatRole(SHARE_CONTEXT.speekerId); + const chatRole = await getChatRole(SHARE_CONTEXT.speakerId); if (chatRole === null) { return sendMessageToTelegram("\u8EAB\u4EFD\u6743\u9650\u9A8C\u8BC1\u5931\u8D25"); } @@ -910,6 +930,20 @@ async function msgChatWithOpenAI(message) { history.push({ role: "assistant", content: answer }); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } + const replyMarkup = {}; + if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === "private") { + replyMarkup.inline_keyboard = [[ + { + text: "\u7EE7\u7EED", + callback_data: `#continue#${message.message_id}` + }, + { + text: "\u7ED3\u675F", + callback_data: `#end#${message.message_id}` + } + ]]; + } + CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -954,6 +988,34 @@ async function processMessageByChatType(message) { } return null; } +async function loadMessage(request) { + const raw = await request.json(); + if (ENV.DEV_MODE) { + setTimeout(() => { + DATABASE.put(`log:${(/* @__PURE__ */ new Date()).toISOString()}`, JSON.stringify(raw), { expirationTtl: 600 }).catch(console.error); + }); + } + if (raw.message) { + return raw.message; + } else if (raw.callback_query && raw.callback_query.message) { + let messageId = null; + const chatId = raw.callback_query.message?.chat?.id; + const data = raw.callback_query.data; + if (data.startsWith("#continue#")) { + messageId = data.split("#")[2]; + raw.callback_query.message = "\u7EE7\u7EED"; + } else if (data.startsWith("#end#")) { + messageId = data.split("#")[2]; + raw.callback_query.message = "/new"; + } + if (messageId && chatId) { + setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); + } + return raw.callback_query.message; + } else { + throw new Error("Invalid message"); + } +} async function loadHistory(key) { const initMessage = { role: "system", content: USER_CONFIG.SYSTEM_INIT_MESSAGE }; const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; @@ -1010,7 +1072,7 @@ async function loadHistory(key) { return { real: history }; } async function handleMessage(request) { - const { message } = await request.json(); + const message = await loadMessage(request); const handlers = [ msgInitChatContext, // 初始化聊天上下文: 生成chat_id, reply_to_message_id(群组消息), SHARE_CONTEXT diff --git a/dist/timestamp b/dist/timestamp index 1d13875c..bd2d582d 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678431512 +1678438364 diff --git a/package.json b/package.json index 680ed1f1..1b34fc00 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "main.js", "type": "module", "scripts": { - "lint": "eslint --fix --ext .js,.jsx,.mjs main.js src", + "lint": "make lint", "build": "make build", "debug": "wrangler dev --local", "wrangler": "wrangler2", diff --git a/src/command.js b/src/command.js index 0aa27f10..3076a9bc 100644 --- a/src/command.js +++ b/src/command.js @@ -227,12 +227,12 @@ async function commandSystem(message) { msg+='OpenAI模型:'+ENV.CHAT_MODEL+'\n'; if (ENV.DEBUG_MODE) { msg+='
';
-    msg+=`USER_CONFIG: \n\`${JSON.stringify(USER_CONFIG, null, 2)}\`\n`;
+    msg+=`USER_CONFIG: \n${JSON.stringify(USER_CONFIG, null, 2)}\n`;
     if (ENV.DEV_MODE) {
       const shareCtx = {...SHARE_CONTEXT};
       shareCtx.currentBotToken = 'ENPYPTED';
-      msg +=`CHAT_CONTEXT: \n\`${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\`\n`;
-      msg += `SHARE_CONTEXT: \n\`${JSON.stringify(shareCtx, null, 2)}\`\n`;
+      msg +=`CHAT_CONTEXT: \n${JSON.stringify(CURRENT_CHAT_CONTEXT, null, 2)}\n`;
+      msg += `SHARE_CONTEXT: \n${JSON.stringify(shareCtx, null, 2)}\n`;
     }
     msg+='
'; } @@ -266,7 +266,7 @@ export async function handleCommandMessage(message) { const roleList = command.needAuth(); if (roleList) { // 获取身份并判断 - const chatRole = await getChatRole(SHARE_CONTEXT.speekerId); + const chatRole = await getChatRole(SHARE_CONTEXT.speakerId); if (chatRole === null) { return sendMessageToTelegram('身份权限验证失败'); } diff --git a/src/context.js b/src/context.js index 3f36629e..57b514d6 100644 --- a/src/context.js +++ b/src/context.js @@ -26,11 +26,11 @@ export const SHARE_CONTEXT = { usageKey: null, // usage:bot_id chatType: null, // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id - speekerId: null, // 发言人 id + speakerId: null, // 发言人 id }; -async function initChatContext(chatId, replyToMessageId) { +function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; CURRENT_CHAT_CONTEXT.reply_to_message_id = replyToMessageId; if (replyToMessageId) { @@ -62,7 +62,7 @@ async function initShareContext(message, request) { )[1]; const telegramIndex = ENV.TELEGRAM_AVAILABLE_TOKENS.indexOf(token); if (telegramIndex === -1) { - throw new Error('Token not found'); + throw new Error('Token not allowed'); } SHARE_CONTEXT.currentBotToken = token; @@ -115,7 +115,7 @@ async function initShareContext(message, request) { SHARE_CONTEXT.chatType = message.chat?.type; SHARE_CONTEXT.chatId = message.chat.id; - SHARE_CONTEXT.speekerId = message.from.id || message.chat.id; + SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; } diff --git a/src/env.js b/src/env.js index 3ca15d69..2a27aefc 100644 --- a/src/env.js +++ b/src/env.js @@ -41,6 +41,8 @@ export const ENV = { ENABLE_USAGE_STATISTICS: true, // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], + // Inline keyboard: 实验性功能请勿开启 + INLINE_KEYBOARD_ENABLE: false, }; export const CONST = { diff --git a/src/message.js b/src/message.js index 52fa9525..452621ef 100644 --- a/src/message.js +++ b/src/message.js @@ -1,6 +1,6 @@ import {ENV, DATABASE, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; -import {sendMessageToTelegram, sendChatActionToTelegram} from './telegram.js'; +import {sendMessageToTelegram, sendChatActionToTelegram, deleteMessageInlineKeyboard} from './telegram.js'; import {sendMessageToChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; import {errorToString} from './utils.js'; @@ -166,6 +166,20 @@ async function msgChatWithOpenAI(message) { history.push({role: 'assistant', content: answer}); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } + const replyMarkup = { }; + if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === 'private') { + replyMarkup.inline_keyboard = [[ + { + text: '继续', + callback_data: `#continue#${message.message_id}`, + }, + { + text: '结束', + callback_data: `#end#${message.message_id}`, + }, + ]]; + } + CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -213,6 +227,35 @@ export async function processMessageByChatType(message) { return null; } +async function loadMessage(request) { + const raw = await request.json(); + if (ENV.DEV_MODE) { + setTimeout(() => { + DATABASE.put(`log:${new Date().toISOString()}`, JSON.stringify(raw), {expirationTtl: 600}).catch(console.error); + }); + } + if (raw.message) { + return raw.message; + } else if (raw.callback_query && raw.callback_query.message) { + let messageId = null; + const chatId = raw.callback_query.message?.chat?.id; + const data = raw.callback_query.data; + if (data.startsWith('#continue#')) { + messageId = data.split('#')[2]; + raw.callback_query.message = '继续'; + } else if (data.startsWith('#end#')) { + messageId = data.split('#')[2]; + raw.callback_query.message = '/new'; + } + if (messageId && chatId) { + setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); + } + return raw.callback_query.message; + } else { + throw new Error('Invalid message'); + } +} + // { real: [], fake: [] } async function loadHistory(key) { const initMessage = {role: 'system', content: USER_CONFIG.SYSTEM_INIT_MESSAGE}; @@ -274,7 +317,7 @@ async function loadHistory(key) { } export async function handleMessage(request) { - const {message} = await request.json(); + const message = await loadMessage(request); // 消息处理中间件 const handlers = [ diff --git a/src/telegram.js b/src/telegram.js index bc25c5d8..e1c1b41c 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -53,6 +53,25 @@ export async function sendChatActionToTelegram(action, token) { ).then((res) => res.json()); } +export async function deleteMessageInlineKeyboard(chatId, messageId, token) { + return await fetch( + `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/editMessageReplyMarkup`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + chat_id: chatId, + message_id: messageId, + reply_markup: { + inline_keyboard: [], + }, + }), + }, + ).then((res) => res.json()); +} + export async function bindTelegramWebHook(token, url) { return await fetch( `https://api.telegram.org/bot${token}/setWebhook`, From c0e2015a5ec9ac5b041c18ee76c9e3c34caa678e Mon Sep 17 00:00:00 2001 From: Cheivin Date: Fri, 10 Mar 2023 03:55:08 -0500 Subject: [PATCH 20/32] =?UTF-8?q?pref:=20=E8=B6=85=E8=BF=874096=E7=9A=84?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=88=86=E6=AE=B5=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/message.js | 1 + src/telegram.js | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/message.js b/src/message.js index 52fa9525..5c71b207 100644 --- a/src/message.js +++ b/src/message.js @@ -156,6 +156,7 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { + console.log("提问消息:"+message.text||"") const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; diff --git a/src/telegram.js b/src/telegram.js index bc25c5d8..7c19fc81 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -2,22 +2,40 @@ import {DATABASE} from './env.js'; import {CURRENT_CHAT_CONTEXT, SHARE_CONTEXT} from './context.js'; // 发送消息到Telegram -export async function sendMessageToTelegram(message, token, context) { +async function sendMessage(message, token, context) { return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendMessage`, + `https://api.telegram.org/bot${token}/sendMessage`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ - ...(context || CURRENT_CHAT_CONTEXT), + ...context, text: message, }), }, ); } +// 发送消息到Telegram +export async function sendMessageToTelegram(message, token, context) { + console.log("发送消息:\n",message) + let botToken = token || SHARE_CONTEXT.currentBotToken; + let chatContext = context || CURRENT_CHAT_CONTEXT + if(message.length<=4096){ + return await sendMessage(message,botToken,chatContext) + } + console.log("消息将分段发送") + const limit = 4000 + chatContext.parse_mode = 'HTML'; + for (let i = 0; i < string.length; i += limit) { + let msg = message.slice(i, i + limit) + await sendMessage(`
\n${msg}\n
`, botToken, chatContext) + } + return new Response('MESSAGE BATCH SEND', {status: 200}); +} + // 发送图片消息到Telegram export async function sendPhotoToTelegram(url, token, context) { const chatContext = Object.assign((context || CURRENT_CHAT_CONTEXT), {parse_mode: null}); From 71245732a8272c8dd499d40b824453f23c206c17 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 17:27:34 +0800 Subject: [PATCH 21/32] build : 1.3.0 pre-release 2 --- dist/buildinfo.json | 2 +- dist/index.js | 101 ++++++++++++++++++++++++++------------------ dist/timestamp | 2 +- src/command.js | 58 ++++++++++++------------- src/message.js | 13 +++--- src/openai.js | 4 +- src/router.js | 16 +++---- src/telegram.js | 18 ++++---- src/utils.js | 33 --------------- 9 files changed, 118 insertions(+), 129 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 4498221e..84c28bc0 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "00efc88", "timestamp": 1678438364} +{"sha": "aa15edc", "timestamp": 1678440309} diff --git a/dist/index.js b/dist/index.js index e3f3392b..581d27f5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678438364, + BUILD_TIMESTAMP: 1678440309, // 当前版本 commit id - BUILD_VERSION: "00efc88", + BUILD_VERSION: "aa15edc", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -198,21 +198,39 @@ async function initContext(message, request) { } // src/telegram.js -async function sendMessageToTelegram(message, token, context) { +async function sendMessage(message, token, context) { return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendMessage`, + `https://api.telegram.org/bot${token}/sendMessage`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - ...context || CURRENT_CHAT_CONTEXT, + ...context, text: message }) } ); } +async function sendMessageToTelegram(message, token, context) { + console.log("\u53D1\u9001\u6D88\u606F:\n", message); + const botToken = token || SHARE_CONTEXT.currentBotToken; + const chatContext = context || CURRENT_CHAT_CONTEXT; + if (message.length <= 4096) { + return await sendMessage(message, botToken, chatContext); + } + console.log("\u6D88\u606F\u5C06\u5206\u6BB5\u53D1\u9001"); + const limit = 4e3; + chatContext.parse_mode = "HTML"; + for (let i = 0; i < string.length; i += limit) { + const msg = message.slice(i, i + limit); + await sendMessage(`
+${msg}
+
`, botToken, chatContext); + } + return new Response("MESSAGE BATCH SEND", { status: 200 }); +} async function sendPhotoToTelegram(url, token, context) { const chatContext = Object.assign(context || CURRENT_CHAT_CONTEXT, { parse_mode: null }); return await fetch( @@ -350,7 +368,7 @@ async function getBot(token) { } // src/openai.js -async function sendMessageToChatGPT(message, history) { +async function requestCompletionsFromChatGPT(message, history) { const body = { model: ENV.CHAT_MODEL, ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, @@ -371,7 +389,7 @@ async function sendMessageToChatGPT(message, history) { setTimeout(() => updateBotUsage(resp.usage).catch(console.error), 0); return resp.choices[0].message.content; } -async function requestImageFromChatGPT(prompt) { +async function requestImageFromOpenAI(prompt) { const body = { prompt, n: 1, @@ -414,21 +432,23 @@ async function updateBotUsage(usage) { } // src/command.js -function defaultGroupAuthCheck() { - if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { - return ["administrator", "creator"]; - } - return false; -} -function shareModeGroupAuthCheck() { - if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { - return false; +var commandAuthCheck = { + default: function() { + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + return ["administrator", "creator"]; } - return ["administrator", "creator"]; + return false; + }, + shareModeGroup: function() { + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { + return false; + } + return ["administrator", "creator"]; + } + return false; } - return false; -} +}; var commandHandlers = { "/help": { help: "\u83B7\u53D6\u547D\u4EE4\u5E2E\u52A9", @@ -439,43 +459,43 @@ var commandHandlers = { help: "\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", scopes: ["all_private_chats", "all_group_chats", "all_chat_administrators"], fn: commandCreateNewChatContext, - needAuth: shareModeGroupAuthCheck + needAuth: commandAuthCheck.shareModeGroup }, "/start": { help: "\u83B7\u53D6\u4F60\u7684ID\uFF0C\u5E76\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandCreateNewChatContext, - needAuth: defaultGroupAuthCheck + needAuth: commandAuthCheck.default }, "/img": { help: "\u751F\u6210\u4E00\u5F20\u56FE\u7247", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandGenerateImg, - needAuth: shareModeGroupAuthCheck + needAuth: commandAuthCheck.shareModeGroup }, "/version": { help: "\u83B7\u53D6\u5F53\u524D\u7248\u672C\u53F7, \u5224\u65AD\u662F\u5426\u9700\u8981\u66F4\u65B0", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandFetchUpdate, - needAuth: defaultGroupAuthCheck + needAuth: commandAuthCheck.default }, "/setenv": { help: "\u8BBE\u7F6E\u7528\u6237\u914D\u7F6E\uFF0C\u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A /setenv KEY=VALUE", scopes: [], fn: commandUpdateUserConfig, - needAuth: shareModeGroupAuthCheck + needAuth: commandAuthCheck.shareModeGroup }, "/usage": { help: "\u83B7\u53D6\u5F53\u524D\u673A\u5668\u4EBA\u7684\u7528\u91CF\u7EDF\u8BA1", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandUsage, - needAuth: defaultGroupAuthCheck + needAuth: commandAuthCheck.default }, "/system": { help: "\u67E5\u770B\u5F53\u524D\u4E00\u4E9B\u7CFB\u7EDF\u4FE1\u606F", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandSystem, - needAuth: defaultGroupAuthCheck + needAuth: commandAuthCheck.default } }; async function commandGenerateImg(message, command, subcommand) { @@ -484,7 +504,7 @@ async function commandGenerateImg(message, command, subcommand) { } try { setTimeout(() => sendChatActionToTelegram("upload_photo").catch(console.error), 0); - const imgUrl = await requestImageFromChatGPT(subcommand); + const imgUrl = await requestImageFromOpenAI(subcommand); try { return sendPhotoToTelegram(imgUrl); } catch (e) { @@ -643,7 +663,7 @@ async function handleCommandMessage(message) { help: "[DEBUG ONLY]\u56DE\u663E\u6D88\u606F", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandEcho, - needAuth: defaultGroupAuthCheck + needAuth: commandAuthCheck.default }; } for (const key in commandHandlers) { @@ -717,7 +737,7 @@ async function bindCommandForTelegram(token) { } return { ok: true, result }; } -function commandsHelp() { +function commandsDocument() { return Object.keys(commandHandlers).map((key) => { const command = commandHandlers[key]; return { @@ -920,11 +940,12 @@ async function msgHandleCommand(message) { } async function msgChatWithOpenAI(message) { try { + console.log("\u63D0\u95EE\u6D88\u606F:" + message.text || ""); const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram("typing").catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const { real: history, fake: fakeHistory } = await loadHistory(historyKey); - const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); + const answer = await requestCompletionsFromChatGPT(message.text, fakeHistory || history); if (!historyDisable) { history.push({ role: "user", content: message.text || "" }); history.push({ role: "assistant", content: answer }); @@ -949,7 +970,7 @@ async function msgChatWithOpenAI(message) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); } } -async function processMessageByChatType(message) { +async function msgProcessByChatType(message) { const handlerMap = { "private": [ msgFilterWhiteList, @@ -1080,7 +1101,7 @@ async function handleMessage(request) { // 保存最后一条消息 msgCheckEnvIsReady, // 检查环境是否准备好: API_KEY, DATABASE - processMessageByChatType, + msgProcessByChatType, // 根据类型对消息进一步处理 msgChatWithOpenAI // 与OpenAI聊天 @@ -1107,9 +1128,9 @@ var footer = `

For more information, please visit ${helpLink}

If you have any questions, please visit ${issueLink}

`; -var keyNotfoundRender = (key) => { +function buildKeyNotFoundHTML(key) { return `

Please set the ${key} environment variable in Cloudflare Workers.

`; -}; +} async function bindWebHookAction(request) { const result = []; const domain = new URL(request.url).host; @@ -1124,7 +1145,7 @@ async function bindWebHookAction(request) { const HTML = renderHTML(`

ChatGPT-Telegram-Workers

${domain}

- ${ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender("TELEGRAM_AVAILABLE_TOKENS") : ""} + ${ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? buildKeyNotFoundHTML("TELEGRAM_AVAILABLE_TOKENS") : ""} ${Object.keys(result).map((id) => `

Bot ID: ${id}

@@ -1157,7 +1178,7 @@ async function loadChatHistory(request) { `); return new Response(HTML, { status: 200, headers: { "Content-Type": "text/html" } }); } -async function telegramWebhookAction(request) { +async function telegramWebhook(request) { const resp = await handleMessage(request); return resp || new Response("NOT HANDLED", { status: 200 }); } @@ -1170,9 +1191,9 @@ async function defaultIndexAction() {

You must >>>>> click here <<<<< to bind the webhook.


- ${ENV.API_KEY ? "" : keyNotfoundRender("API_KEY")} + ${ENV.API_KEY ? "" : buildKeyNotFoundHTML("API_KEY")}

After binding the webhook, you can use the following commands to control the bot:

- ${commandsHelp().map((item) => `

${item.command} - ${item.description}

`).join("")} + ${commandsDocument().map((item) => `

${item.command} - ${item.description}

`).join("")}

You can get bot information by visiting the following URL:

/telegram/:token/bot - Get bot information

@@ -1215,7 +1236,7 @@ async function handleRequest(request) { } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/webhook`)) { try { - const resp = await telegramWebhookAction(request); + const resp = await telegramWebhook(request); if (resp.status === 200) { return resp; } else { diff --git a/dist/timestamp b/dist/timestamp index bd2d582d..dc157602 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678438364 +1678440309 diff --git a/src/command.js b/src/command.js index 3076a9bc..dbd1e526 100644 --- a/src/command.js +++ b/src/command.js @@ -1,28 +1,26 @@ import {sendMessageToTelegram, sendPhotoToTelegram, sendChatActionToTelegram, getChatRole} from './telegram.js'; import {DATABASE, ENV, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT} from './context.js'; -import {requestImageFromChatGPT} from './openai.js'; +import {requestImageFromOpenAI} from './openai.js'; -// / -- Command -function defaultGroupAuthCheck() { - if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { - return ['administrator', 'creator']; - } - return false; -} - -function shareModeGroupAuthCheck() { - if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { - // 每个人在群里有上下文的时候,不限制 - if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { - return false; +const commandAuthCheck = { + default: function() { + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + return ['administrator', 'creator']; } - return ['administrator', 'creator']; - } - return false; -} - -// BotCommandScope: default, all_private_chats, all_group_chats, all_chat_administrators + return false; + }, + shareModeGroup: function() { + if (CONST.GROUP_TYPES.includes(SHARE_CONTEXT.chatType)) { + // 每个人在群里有上下文的时候,不限制 + if (!ENV.GROUP_CHAT_BOT_SHARE_MODE) { + return false; + } + return ['administrator', 'creator']; + } + return false; + }, +}; // 命令绑定 const commandHandlers = { @@ -35,43 +33,43 @@ const commandHandlers = { help: '发起新的对话', scopes: ['all_private_chats', 'all_group_chats', 'all_chat_administrators'], fn: commandCreateNewChatContext, - needAuth: shareModeGroupAuthCheck, + needAuth: commandAuthCheck.shareModeGroup, }, '/start': { help: '获取你的ID,并发起新的对话', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandCreateNewChatContext, - needAuth: defaultGroupAuthCheck, + needAuth: commandAuthCheck.default, }, '/img': { help: '生成一张图片', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandGenerateImg, - needAuth: shareModeGroupAuthCheck, + needAuth: commandAuthCheck.shareModeGroup, }, '/version': { help: '获取当前版本号, 判断是否需要更新', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandFetchUpdate, - needAuth: defaultGroupAuthCheck, + needAuth: commandAuthCheck.default, }, '/setenv': { help: '设置用户配置,命令完整格式为 /setenv KEY=VALUE', scopes: [], fn: commandUpdateUserConfig, - needAuth: shareModeGroupAuthCheck, + needAuth: commandAuthCheck.shareModeGroup, }, '/usage': { help: '获取当前机器人的用量统计', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandUsage, - needAuth: defaultGroupAuthCheck, + needAuth: commandAuthCheck.default, }, '/system': { help: '查看当前一些系统信息', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandSystem, - needAuth: defaultGroupAuthCheck, + needAuth: commandAuthCheck.default, }, }; @@ -81,7 +79,7 @@ async function commandGenerateImg(message, command, subcommand) { } try { setTimeout(() => sendChatActionToTelegram('upload_photo').catch(console.error), 0); - const imgUrl =await requestImageFromChatGPT(subcommand); + const imgUrl =await requestImageFromOpenAI(subcommand); try { return sendPhotoToTelegram(imgUrl); } catch (e) { @@ -254,7 +252,7 @@ export async function handleCommandMessage(message) { help: '[DEBUG ONLY]回显消息', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandEcho, - needAuth: defaultGroupAuthCheck, + needAuth: commandAuthCheck.default, }; } for (const key in commandHandlers) { @@ -334,7 +332,7 @@ export async function bindCommandForTelegram(token) { } -export function commandsHelp() { +export function commandsDocument() { return Object.keys(commandHandlers).map((key) => { const command = commandHandlers[key]; return { diff --git a/src/message.js b/src/message.js index c135554e..1fd5e46f 100644 --- a/src/message.js +++ b/src/message.js @@ -1,12 +1,14 @@ import {ENV, DATABASE, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; import {sendMessageToTelegram, sendChatActionToTelegram, deleteMessageInlineKeyboard} from './telegram.js'; -import {sendMessageToChatGPT} from './openai.js'; +import {requestCompletionsFromChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; import {errorToString} from './utils.js'; const MAX_TOKEN_LENGTH = 2048; +// Middleware + // 初始化聊天上下文 async function msgInitChatContext(message, request) { try { @@ -156,12 +158,12 @@ async function msgHandleCommand(message) { // 聊天 async function msgChatWithOpenAI(message) { try { - console.log("提问消息:"+message.text||"") + console.log('提问消息:'+message.text||''); const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; const {real: history, fake: fakeHistory} = await loadHistory(historyKey); - const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); + const answer = await requestCompletionsFromChatGPT(message.text, fakeHistory || history); if (!historyDisable) { history.push({role: 'user', content: message.text || ''}); history.push({role: 'assistant', content: answer}); @@ -188,7 +190,7 @@ async function msgChatWithOpenAI(message) { } // 根据类型对消息进一步处理 -export async function processMessageByChatType(message) { +export async function msgProcessByChatType(message) { const handlerMap = { 'private': [ msgFilterWhiteList, @@ -228,6 +230,7 @@ export async function processMessageByChatType(message) { return null; } +// Loader async function loadMessage(request) { const raw = await request.json(); if (ENV.DEV_MODE) { @@ -325,7 +328,7 @@ export async function handleMessage(request) { msgInitChatContext, // 初始化聊天上下文: 生成chat_id, reply_to_message_id(群组消息), SHARE_CONTEXT msgSaveLastMessage, // 保存最后一条消息 msgCheckEnvIsReady, // 检查环境是否准备好: API_KEY, DATABASE - processMessageByChatType, // 根据类型对消息进一步处理 + msgProcessByChatType, // 根据类型对消息进一步处理 msgChatWithOpenAI, // 与OpenAI聊天 ]; diff --git a/src/openai.js b/src/openai.js index f092b3f0..19f91ffe 100644 --- a/src/openai.js +++ b/src/openai.js @@ -2,7 +2,7 @@ import {USER_CONFIG, SHARE_CONTEXT} from './context.js'; import {ENV, DATABASE} from './env.js'; // 发送消息到ChatGPT -export async function sendMessageToChatGPT(message, history) { +export async function requestCompletionsFromChatGPT(message, history) { const body = { model: ENV.CHAT_MODEL, ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, @@ -24,7 +24,7 @@ export async function sendMessageToChatGPT(message, history) { } // 请求ChatGPT生成图片 -export async function requestImageFromChatGPT(prompt) { +export async function requestImageFromOpenAI(prompt) { const body = { prompt: prompt, n: 1, diff --git a/src/router.js b/src/router.js index a94599f6..a7f3221b 100644 --- a/src/router.js +++ b/src/router.js @@ -1,6 +1,6 @@ import {handleMessage} from './message.js'; import {DATABASE, ENV} from './env.js'; -import {bindCommandForTelegram, commandsHelp} from './command.js'; +import {bindCommandForTelegram, commandsDocument} from './command.js'; import {bindTelegramWebHook, getBot} from './telegram.js'; import {errorToString, historyPassword, renderHTML} from './utils.js'; @@ -15,9 +15,9 @@ const footer = `

If you have any questions, please visit ${issueLink}

`; -const keyNotfoundRender = (key) => { +function buildKeyNotFoundHTML(key) { return `

Please set the ${key} environment variable in Cloudflare Workers.

`; -}; +} async function bindWebHookAction(request) { const result = []; @@ -35,7 +35,7 @@ async function bindWebHookAction(request) {

ChatGPT-Telegram-Workers

${domain}

${ - ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender('TELEGRAM_AVAILABLE_TOKENS') : '' + ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? buildKeyNotFoundHTML('TELEGRAM_AVAILABLE_TOKENS') : '' } ${ Object.keys(result).map((id) => ` @@ -75,7 +75,7 @@ async function loadChatHistory(request) { } // 处理Telegram回调 -async function telegramWebhookAction(request) { +async function telegramWebhook(request) { const resp = await handleMessage(request); return resp || new Response('NOT HANDLED', {status: 200}); } @@ -90,11 +90,11 @@ async function defaultIndexAction() {

You must >>>>> click here <<<<< to bind the webhook.


${ - ENV.API_KEY ? '' : keyNotfoundRender('API_KEY') + ENV.API_KEY ? '' : buildKeyNotFoundHTML('API_KEY') }

After binding the webhook, you can use the following commands to control the bot:

${ - commandsHelp().map((item) => `

${item.command} - ${item.description}

`).join('') + commandsDocument().map((item) => `

${item.command} - ${item.description}

`).join('') }

You can get bot information by visiting the following URL:

@@ -142,7 +142,7 @@ export async function handleRequest(request) { } if (pathname.startsWith(`/telegram`) && pathname.endsWith(`/webhook`)) { try { - const resp = await telegramWebhookAction(request); + const resp = await telegramWebhook(request); if (resp.status === 200) { return resp; } else { diff --git a/src/telegram.js b/src/telegram.js index af732f3f..8fcb7ab4 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -20,18 +20,18 @@ async function sendMessage(message, token, context) { // 发送消息到Telegram export async function sendMessageToTelegram(message, token, context) { - console.log("发送消息:\n",message) - let botToken = token || SHARE_CONTEXT.currentBotToken; - let chatContext = context || CURRENT_CHAT_CONTEXT - if(message.length<=4096){ - return await sendMessage(message,botToken,chatContext) + console.log('发送消息:\n', message); + const botToken = token || SHARE_CONTEXT.currentBotToken; + const chatContext = context || CURRENT_CHAT_CONTEXT; + if (message.length<=4096) { + return await sendMessage(message, botToken, chatContext); } - console.log("消息将分段发送") - const limit = 4000 + console.log('消息将分段发送'); + const limit = 4000; chatContext.parse_mode = 'HTML'; for (let i = 0; i < string.length; i += limit) { - let msg = message.slice(i, i + limit) - await sendMessage(`
\n${msg}\n
`, botToken, chatContext) + const msg = message.slice(i, i + limit); + await sendMessage(`
\n${msg}\n
`, botToken, chatContext); } return new Response('MESSAGE BATCH SEND', {status: 200}); } diff --git a/src/utils.js b/src/utils.js index 468716e6..eec309d5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -65,39 +65,6 @@ export function renderHTML(body) { `; } -/** - * 重试方法 - * - * @param {Function} fn 异步方法 - * @param {int} maxAttemptCount 最大重试次数 - * @param {int} retryInterval 间隔时间ms,默认100ms - * @return {Promise} - */ -export async function retry(fn, maxAttemptCount, retryInterval = 100) { - for (let i = 0; i < maxAttemptCount; i++) { - try { - return await fn(); - } catch (error) { - if (i === maxAttemptCount - 1) { - throw error; - } - await new Promise((resolve) => setTimeout(resolve, retryInterval)); - } - } -} - -export async function catchWithDefault(defaultValue, fn) { - try { - const res = fn(); - if (res instanceof Promise) { - return await res; - } - return res; - } catch (e) { - return defaultValue; - } -} - export function errorToString(e) { return JSON.stringify({ message: e.message, From c7600148479d2105ee95dbe5a931bbd932714587 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 18:05:14 +0800 Subject: [PATCH 22/32] =?UTF-8?q?fix:=20inline=5Fkeyboard=20=E5=9B=9E?= =?UTF-8?q?=E8=B0=83BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 25 ++++++++++++------------- dist/timestamp | 2 +- src/message.js | 21 ++++++++++----------- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 84c28bc0..a4221bb1 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "aa15edc", "timestamp": 1678440309} +{"sha": "7124573", "timestamp": 1678442549} diff --git a/dist/index.js b/dist/index.js index 581d27f5..5df81144 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678440309, + BUILD_TIMESTAMP: 1678442549, // 当前版本 commit id - BUILD_VERSION: "aa15edc", + BUILD_VERSION: "7124573", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -951,20 +951,20 @@ async function msgChatWithOpenAI(message) { history.push({ role: "assistant", content: answer }); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - const replyMarkup = {}; if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === "private") { + const replyMarkup = {}; replyMarkup.inline_keyboard = [[ { text: "\u7EE7\u7EED", - callback_data: `#continue#${message.message_id}` + callback_data: `#continue` }, { text: "\u7ED3\u675F", - callback_data: `#end#${message.message_id}` + callback_data: `#end` } ]]; + CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; } - CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -1011,6 +1011,7 @@ async function msgProcessByChatType(message) { } async function loadMessage(request) { const raw = await request.json(); + console.log(raw); if (ENV.DEV_MODE) { setTimeout(() => { DATABASE.put(`log:${(/* @__PURE__ */ new Date()).toISOString()}`, JSON.stringify(raw), { expirationTtl: 600 }).catch(console.error); @@ -1019,15 +1020,13 @@ async function loadMessage(request) { if (raw.message) { return raw.message; } else if (raw.callback_query && raw.callback_query.message) { - let messageId = null; + const messageId = raw.callback_query.message?.message_id; const chatId = raw.callback_query.message?.chat?.id; const data = raw.callback_query.data; - if (data.startsWith("#continue#")) { - messageId = data.split("#")[2]; - raw.callback_query.message = "\u7EE7\u7EED"; - } else if (data.startsWith("#end#")) { - messageId = data.split("#")[2]; - raw.callback_query.message = "/new"; + if (data.startsWith("#continue")) { + raw.callback_query.message.text = "\u7EE7\u7EED"; + } else if (data.startsWith("#end")) { + raw.callback_query.message.text = "/new"; } if (messageId && chatId) { setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); diff --git a/dist/timestamp b/dist/timestamp index dc157602..1e55bb61 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678440309 +1678442549 diff --git a/src/message.js b/src/message.js index 1fd5e46f..b0964a09 100644 --- a/src/message.js +++ b/src/message.js @@ -169,20 +169,20 @@ async function msgChatWithOpenAI(message) { history.push({role: 'assistant', content: answer}); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - const replyMarkup = { }; if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === 'private') { + const replyMarkup = { }; replyMarkup.inline_keyboard = [[ { text: '继续', - callback_data: `#continue#${message.message_id}`, + callback_data: `#continue`, }, { text: '结束', - callback_data: `#end#${message.message_id}`, + callback_data: `#end`, }, ]]; + CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; } - CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -233,6 +233,7 @@ export async function msgProcessByChatType(message) { // Loader async function loadMessage(request) { const raw = await request.json(); + console.log(raw); if (ENV.DEV_MODE) { setTimeout(() => { DATABASE.put(`log:${new Date().toISOString()}`, JSON.stringify(raw), {expirationTtl: 600}).catch(console.error); @@ -241,15 +242,13 @@ async function loadMessage(request) { if (raw.message) { return raw.message; } else if (raw.callback_query && raw.callback_query.message) { - let messageId = null; + const messageId = raw.callback_query.message?.message_id; const chatId = raw.callback_query.message?.chat?.id; const data = raw.callback_query.data; - if (data.startsWith('#continue#')) { - messageId = data.split('#')[2]; - raw.callback_query.message = '继续'; - } else if (data.startsWith('#end#')) { - messageId = data.split('#')[2]; - raw.callback_query.message = '/new'; + if (data.startsWith('#continue')) { + raw.callback_query.message.text = '继续'; + } else if (data.startsWith('#end')) { + raw.callback_query.message.text = '/new'; } if (messageId && chatId) { setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); From 78c59e78d31c6f8218c0d7841af2e6cbc3bad653 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 18:16:24 +0800 Subject: [PATCH 23/32] =?UTF-8?q?feat:=20inline=5Fkeyboard=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E8=81=8A=E5=A4=A9=E7=B1=BB=E5=9E=8B=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 8 ++++---- dist/timestamp | 2 +- src/env.js | 2 +- src/message.js | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index a4221bb1..cdbdc1e0 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "7124573", "timestamp": 1678442549} +{"sha": "c760014", "timestamp": 1678442956} diff --git a/dist/index.js b/dist/index.js index 5df81144..716ef1ac 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678442549, + BUILD_TIMESTAMP: 1678442956, // 当前版本 commit id - BUILD_VERSION: "7124573", + BUILD_VERSION: "c760014", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -42,7 +42,7 @@ var ENV = { // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: false + INLINE_KEYBOARD_ENABLE: ["private", "group", "supergroup"] }; var CONST = { PASSWORD_KEY: "chat_history_password", @@ -951,7 +951,7 @@ async function msgChatWithOpenAI(message) { history.push({ role: "assistant", content: answer }); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === "private") { + if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { const replyMarkup = {}; replyMarkup.inline_keyboard = [[ { diff --git a/dist/timestamp b/dist/timestamp index 1e55bb61..e2911942 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678442549 +1678442956 diff --git a/src/env.js b/src/env.js index 2a27aefc..58543ec7 100644 --- a/src/env.js +++ b/src/env.js @@ -42,7 +42,7 @@ export const ENV = { // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: false, + INLINE_KEYBOARD_ENABLE: ['private'], }; export const CONST = { diff --git a/src/message.js b/src/message.js index b0964a09..51b57ef0 100644 --- a/src/message.js +++ b/src/message.js @@ -169,7 +169,7 @@ async function msgChatWithOpenAI(message) { history.push({role: 'assistant', content: answer}); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === 'private') { + if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { const replyMarkup = { }; replyMarkup.inline_keyboard = [[ { From b5fd9770a51d4f957c2e58feb6e7bfa6cadf0a08 Mon Sep 17 00:00:00 2001 From: TBXark Date: Fri, 10 Mar 2023 18:31:58 +0800 Subject: [PATCH 24/32] =?UTF-8?q?feat:=20=E5=86=85=E8=81=94=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E8=8C=83=E5=9B=B4=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 12 +++++++++--- dist/timestamp | 2 +- src/context.js | 1 + src/env.js | 2 +- src/message.js | 4 ++++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index cdbdc1e0..c8db4096 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "c760014", "timestamp": 1678442956} +{"sha": "78c59e7", "timestamp": 1678444109} diff --git a/dist/index.js b/dist/index.js index 716ef1ac..3ef2c4f1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678442956, + BUILD_TIMESTAMP: 1678444109, // 当前版本 commit id - BUILD_VERSION: "c760014", + BUILD_VERSION: "78c59e7", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -122,8 +122,10 @@ var SHARE_CONTEXT = { // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id - speakerId: null + speakerId: null, // 发言人 id + fromInlineKeyboard: false + // 是否来自内联键盘 }; function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; @@ -883,6 +885,9 @@ async function msgHandleGroupMessage(message) { const botName = SHARE_CONTEXT.currentBotName; if (botName) { let mentioned = false; + if (SHARE_CONTEXT.fromInlineKeyboard) { + mentioned = true; + } if (message.reply_to_message) { if (message.reply_to_message.from.username === botName) { mentioned = true; @@ -1031,6 +1036,7 @@ async function loadMessage(request) { if (messageId && chatId) { setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); } + SHARE_CONTEXT.fromInlineKeyboard = true; return raw.callback_query.message; } else { throw new Error("Invalid message"); diff --git a/dist/timestamp b/dist/timestamp index e2911942..33e70324 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678442956 +1678444109 diff --git a/src/context.js b/src/context.js index 57b514d6..6412a17c 100644 --- a/src/context.js +++ b/src/context.js @@ -27,6 +27,7 @@ export const SHARE_CONTEXT = { chatType: null, // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id speakerId: null, // 发言人 id + fromInlineKeyboard: false, // 是否来自内联键盘 }; diff --git a/src/env.js b/src/env.js index 58543ec7..32d1f56f 100644 --- a/src/env.js +++ b/src/env.js @@ -42,7 +42,7 @@ export const ENV = { // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: ['private'], + INLINE_KEYBOARD_ENABLE: ['private', 'group', 'supergroup'], }; export const CONST = { diff --git a/src/message.js b/src/message.js index 51b57ef0..0536a663 100644 --- a/src/message.js +++ b/src/message.js @@ -93,6 +93,9 @@ async function msgHandleGroupMessage(message) { const botName = SHARE_CONTEXT.currentBotName; if (botName) { let mentioned = false; + if (SHARE_CONTEXT.fromInlineKeyboard) { + mentioned = true; + } // Reply消息 if (message.reply_to_message) { if (message.reply_to_message.from.username === botName) { @@ -253,6 +256,7 @@ async function loadMessage(request) { if (messageId && chatId) { setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); } + SHARE_CONTEXT.fromInlineKeyboard = true; return raw.callback_query.message; } else { throw new Error('Invalid message'); From 5196cd13769512dc51d5a4bca1e2b8e97c76b4bc Mon Sep 17 00:00:00 2001 From: cheivin Date: Sat, 11 Mar 2023 00:12:03 +0800 Subject: [PATCH 25/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0/role=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E7=94=A8=E4=BA=8E=E8=AE=BE=E7=BD=AE=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E4=BA=BA=E6=80=A7=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/command.js | 108 ++++++++++++++++++++++++++++++++++++++++++++++-- src/context.js | 30 +++++++++++--- src/message.js | 69 +++++++++++++++++++++++++++---- src/router.js | 2 +- src/telegram.js | 18 ++++---- 5 files changed, 200 insertions(+), 27 deletions(-) diff --git a/src/command.js b/src/command.js index 3076a9bc..02e54bd6 100644 --- a/src/command.js +++ b/src/command.js @@ -1,6 +1,6 @@ import {sendMessageToTelegram, sendPhotoToTelegram, sendChatActionToTelegram, getChatRole} from './telegram.js'; import {DATABASE, ENV, CONST} from './env.js'; -import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT} from './context.js'; +import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, USER_DEFINE} from './context.js'; import {requestImageFromChatGPT} from './openai.js'; // / -- Command @@ -38,13 +38,13 @@ const commandHandlers = { needAuth: shareModeGroupAuthCheck, }, '/start': { - help: '获取你的ID,并发起新的对话', + help: '获取你的ID, 并发起新的对话', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandCreateNewChatContext, needAuth: defaultGroupAuthCheck, }, '/img': { - help: '生成一张图片', + help: '生成一张图片, 命令完整格式为 `/img 图片描述`, 例如`/img 月光下的沙滩`', scopes: ['all_private_chats', 'all_chat_administrators'], fn: commandGenerateImg, needAuth: shareModeGroupAuthCheck, @@ -73,8 +73,110 @@ const commandHandlers = { fn: commandSystem, needAuth: defaultGroupAuthCheck, }, + '/role': { + help: '设置预设的身份', + scopes: ['all_private_chats', 'all_chat_administrators'], + fn: commandUpdateRole, + needAuth: shareModeGroupAuthCheck, + }, }; +async function commandUpdateRole(message, command, subcommand) { + // 显示 + if (subcommand==='show') { + const size = Object.getOwnPropertyNames(USER_DEFINE.ROLE).length; + if (size===0) { + return sendMessageToTelegram('还未定义任何角色'); + } + let showMsg = `当前已定义的角色如下(${size}):\n`; + for (const role in USER_DEFINE.ROLE) { + if (USER_DEFINE.ROLE.hasOwnProperty(role)) { + showMsg+=`~${role}:\n
`;
+        showMsg+=JSON.stringify(USER_DEFINE.ROLE[role])+'\n';
+        showMsg+='
'; + } + } + CURRENT_CHAT_CONTEXT.parse_mode = 'HTML'; + return sendMessageToTelegram(showMsg); + } + + const helpMsg = '格式错误: 命令完整格式为 `/role 操作`\n'+ + '当前支持以下`操作`:\n'+ + '`/role show` 显示当前定义的角色.\n'+ + '`/role 角色名 del` 删除指定名称的角色.\n'+ + '`/role 角色名 KEY=VALUE` 设置指定角色的配置.\n'+ + ' 目前以下设置项:\n'+ + ' `SYSTEM_INIT_MESSAGE`:初始化消息\n'+ + ' `OPENAI_API_EXTRA_PARAMS`:OpenAI API 额外参数,必须为JSON'; + + const kv = subcommand.indexOf(' '); + if (kv === -1) { + return sendMessageToTelegram(helpMsg); + } + const role = subcommand.slice(0, kv); + const settings = subcommand.slice(kv + 1).trim(); + const skv = settings.indexOf('='); + if (skv === -1) { + if (settings === 'del') { // 删除 + try { + if (USER_DEFINE.ROLE[role]) { + delete USER_DEFINE.ROLE[role]; + await DATABASE.put( + SHARE_CONTEXT.configStoreKey, + JSON.stringify(Object.assign(USER_CONFIG, {USER_DEFINE: USER_DEFINE})), + ); + return sendMessageToTelegram('删除角色成功'); + } + } catch (e) { + return sendMessageToTelegram(`删除角色错误: \`${e.message}\``); + } + } + return sendMessageToTelegram(helpMsg); + } + const key = settings.slice(0, skv); + const value = settings.slice(skv + 1); + + // ROLE结构定义 + if (!USER_DEFINE.ROLE[role]) { + USER_DEFINE.ROLE[role] = { + // 系统初始化消息 + SYSTEM_INIT_MESSAGE: ENV.SYSTEM_INIT_MESSAGE, + // OpenAI API 额外参数 + OPENAI_API_EXTRA_PARAMS: {}, + }; + } + try { + switch (typeof USER_DEFINE.ROLE[role][key]) { + case 'number': + USER_DEFINE.ROLE[role][key] = Number(value); + break; + case 'boolean': + USER_DEFINE.ROLE[role][key] = value === 'true'; + break; + case 'string': + USER_DEFINE.ROLE[role][key] = value; + break; + case 'object': + const object = JSON.parse(value); + if (typeof object === 'object') { + USER_DEFINE.ROLE[role][key] = object; + break; + } + return sendMessageToTelegram('不支持的配置项或数据类型错误'); + default: + return sendMessageToTelegram('不支持的配置项或数据类型错误'); + } + + await DATABASE.put( + SHARE_CONTEXT.configStoreKey, + JSON.stringify(Object.assign(USER_CONFIG, {USER_DEFINE: USER_DEFINE})), + ); + return sendMessageToTelegram('更新配置成功'); + } catch (e) { + return sendMessageToTelegram(`配置项格式错误: \`${e.message}\``); + } +} + async function commandGenerateImg(message, command, subcommand) { if (subcommand==='') { return sendMessageToTelegram('请输入图片描述。命令完整格式为 \`/img 狸花猫\`'); diff --git a/src/context.js b/src/context.js index 57b514d6..5456a16d 100644 --- a/src/context.js +++ b/src/context.js @@ -8,6 +8,11 @@ export const USER_CONFIG = { OPENAI_API_EXTRA_PARAMS: {}, }; +export const USER_DEFINE = { + // 自定义角色 + ROLE: {}, +}; + // 当前聊天上下文 export const CURRENT_CHAT_CONTEXT = { chat_id: null, @@ -43,11 +48,15 @@ async function initUserConfig(storeKey) { try { const userConfig = JSON.parse(await DATABASE.get(storeKey)); for (const key in userConfig) { - if ( - USER_CONFIG.hasOwnProperty(key) && - typeof USER_CONFIG[key] === typeof userConfig[key] - ) { - USER_CONFIG[key] = userConfig[key]; + if (key === 'USER_DEFINE' && typeof USER_DEFINE === typeof userConfig[key]) { + initUserDefine(userConfig[key]); + } else { + if ( + USER_CONFIG.hasOwnProperty(key) && + typeof USER_CONFIG[key] === typeof userConfig[key] + ) { + USER_CONFIG[key] = userConfig[key]; + } } } } catch (e) { @@ -55,6 +64,17 @@ async function initUserConfig(storeKey) { } } +function initUserDefine(userDefine) { + for (const key in userDefine) { + if ( + USER_DEFINE.hasOwnProperty(key) && + typeof USER_DEFINE[key] === typeof userDefine[key] + ) { + USER_DEFINE[key] = userDefine[key]; + } + } +} + async function initShareContext(message, request) { const {pathname} = new URL(request.url); const token = pathname.match( diff --git a/src/message.js b/src/message.js index c135554e..c0bc2419 100644 --- a/src/message.js +++ b/src/message.js @@ -1,5 +1,5 @@ import {ENV, DATABASE, CONST} from './env.js'; -import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; +import {SHARE_CONTEXT, USER_CONFIG, USER_DEFINE, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; import {sendMessageToTelegram, sendChatActionToTelegram, deleteMessageInlineKeyboard} from './telegram.js'; import {sendMessageToChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; @@ -153,19 +153,61 @@ async function msgHandleCommand(message) { return await handleCommandMessage(message); } +// 响应身份角色扮演 +async function msgHandleRole(message) { + if (!message.text.startsWith('~')) { + return null; + } + message.text = message.text.slice(1); + const kv = message.text.indexOf(' '); + if (kv === -1) { + return null; + } + const role = message.text.slice(0, kv); + const msg = message.text.slice(kv + 1).trim(); + // 存在角色就替换USER_CONFIG + if (USER_DEFINE.ROLE.hasOwnProperty(role)) { + SHARE_CONTEXT.ROLE=role; + message.text = msg; + const roleConfig = USER_DEFINE.ROLE[role]; + for (const key in roleConfig) { + if ( + USER_CONFIG.hasOwnProperty(key) && + typeof USER_CONFIG[key] === typeof roleConfig[key] + ) { + USER_CONFIG[key] = roleConfig[key]; + } + } + } +} +/** + * 你的回复遵守以下规则 + * {如果我发送"/喵娘",你扮演喵状态并忽略其他所有身份,每次回复都是态度扭扭捏捏爱撒娇,经常在回复中劝人躺平、回家种地务农,认为所有人都是善良纯真,并以"咕噜喵~"结尾} + * {如果我发送"/翻译",你进入翻译状态并忽略其他所有身份,将中文翻译为英文,如果不是中文则全部翻译为中文,提供两个答案,①字面意思直接翻译不讲逻辑,②是流畅通顺合逻辑的版本} + * {如果我发送"/老板",你持续进入老板状态并忽略其他所有身份,你的态度看不起任何人,你完全不用任何敬语词组,你的性格自私刻薄虚伪可恨体现在回复文字里,以"加油韭菜"结尾} + */ + // 聊天 async function msgChatWithOpenAI(message) { try { - console.log("提问消息:"+message.text||"") + console.log('提问消息:'+message.text||''); const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram('typing').catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; - const {real: history, fake: fakeHistory} = await loadHistory(historyKey); + let {real: history, fake: fakeHistory, original: original} = await loadHistory(historyKey); + + console.log('历史消息1:', JSON.stringify(fakeHistory || history)); + history = JSON.parse(JSON.stringify(history)); + history.map((item)=>{ + item.cosplay=undefined; + }); + console.log('历史消息2:', JSON.stringify(fakeHistory || history)); + const answer = await sendMessageToChatGPT(message.text, fakeHistory || history); if (!historyDisable) { - history.push({role: 'user', content: message.text || ''}); - history.push({role: 'assistant', content: answer}); - await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + original.push({role: 'user', content: message.text || '', cosplay: SHARE_CONTEXT.ROLE || ''}); + original.push({role: 'assistant', content: answer, cosplay: SHARE_CONTEXT.ROLE || ''}); + await DATABASE.put(historyKey, JSON.stringify(original)).catch(console.error); } const replyMarkup = { }; if (ENV.INLINE_KEYBOARD_ENABLE && SHARE_CONTEXT.chatType === 'private') { @@ -194,16 +236,19 @@ export async function processMessageByChatType(message) { msgFilterWhiteList, msgFilterNonTextMessage, msgHandleCommand, + msgHandleRole, ], 'group': [ msgHandleGroupMessage, msgFilterWhiteList, msgHandleCommand, + msgHandleRole, ], 'supergroup': [ msgHandleGroupMessage, msgFilterWhiteList, msgHandleCommand, + msgHandleRole, ], }; if (!handlerMap.hasOwnProperty(SHARE_CONTEXT.chatType)) { @@ -262,7 +307,7 @@ async function loadHistory(key) { const initMessage = {role: 'system', content: USER_CONFIG.SYSTEM_INIT_MESSAGE}; const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; if (historyDisable) { - return {real: [initMessage]}; + return {real: [initMessage], original: [initMessage]}; } let history = []; try { @@ -273,6 +318,12 @@ async function loadHistory(key) { if (!history || !Array.isArray(history) || history.length === 0) { history = []; } + const original = history; + // 按身份过滤 + if (SHARE_CONTEXT.ROLE) { + history = history.filter((chat) => SHARE_CONTEXT.ROLE === chat.cosplay); + } + if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { // 历史记录超出长度需要裁剪 if (history.length > ENV.MAX_HISTORY_LENGTH) { @@ -312,9 +363,9 @@ async function loadHistory(key) { ...fake[0], role: ENV.SYSTEM_INIT_MESSAGE_ROLE, }; - return {real: history, fake}; + return {real: history, fake, original: original}; } - return {real: history}; + return {real: history, original: original}; } export async function handleMessage(request) { diff --git a/src/router.js b/src/router.js index a94599f6..51785138 100644 --- a/src/router.js +++ b/src/router.js @@ -35,7 +35,7 @@ async function bindWebHookAction(request) {

ChatGPT-Telegram-Workers

${domain}

${ - ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender('TELEGRAM_AVAILABLE_TOKENS') : '' + ENV.TELEGRAM_AVAILABLE_TOKENS.length === 0 ? keyNotfoundRender('TELEGRAM_AVAILABLE_TOKENS') : '' } ${ Object.keys(result).map((id) => ` diff --git a/src/telegram.js b/src/telegram.js index af732f3f..8fcb7ab4 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -20,18 +20,18 @@ async function sendMessage(message, token, context) { // 发送消息到Telegram export async function sendMessageToTelegram(message, token, context) { - console.log("发送消息:\n",message) - let botToken = token || SHARE_CONTEXT.currentBotToken; - let chatContext = context || CURRENT_CHAT_CONTEXT - if(message.length<=4096){ - return await sendMessage(message,botToken,chatContext) + console.log('发送消息:\n', message); + const botToken = token || SHARE_CONTEXT.currentBotToken; + const chatContext = context || CURRENT_CHAT_CONTEXT; + if (message.length<=4096) { + return await sendMessage(message, botToken, chatContext); } - console.log("消息将分段发送") - const limit = 4000 + console.log('消息将分段发送'); + const limit = 4000; chatContext.parse_mode = 'HTML'; for (let i = 0; i < string.length; i += limit) { - let msg = message.slice(i, i + limit) - await sendMessage(`
\n${msg}\n
`, botToken, chatContext) + const msg = message.slice(i, i + limit); + await sendMessage(`
\n${msg}\n
`, botToken, chatContext); } return new Response('MESSAGE BATCH SEND', {status: 200}); } From aa799af20ff8d13157d1f6ebf1dd68b1226832ce Mon Sep 17 00:00:00 2001 From: cheivin Date: Sat, 11 Mar 2023 12:18:19 +0800 Subject: [PATCH 26/32] =?UTF-8?q?merge:=20=E6=89=8B=E5=8A=A8=E5=90=88?= =?UTF-8?q?=E5=B9=B6role=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/message.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/message.js b/src/message.js index ad1272f7..21f27adf 100644 --- a/src/message.js +++ b/src/message.js @@ -93,9 +93,6 @@ async function msgHandleGroupMessage(message) { const botName = SHARE_CONTEXT.currentBotName; if (botName) { let mentioned = false; - if (SHARE_CONTEXT.fromInlineKeyboard) { - mentioned = true; - } // Reply消息 if (message.reply_to_message) { if (message.reply_to_message.from.username === botName) { From 4cacd325c4fd78a335a0ba71df7f81a850665677 Mon Sep 17 00:00:00 2001 From: TBXark Date: Sat, 11 Mar 2023 16:28:34 +0800 Subject: [PATCH 27/32] =?UTF-8?q?fix:=20=E5=B1=8F=E8=94=BDinline=20keyboar?= =?UTF-8?q?d=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 93 +++++++++++++-------------------------------- dist/timestamp | 2 +- proxy/kv.js | 0 proxy/openai.js | 8 ++++ proxy/telegram.js | 8 ++++ src/context.js | 11 +++--- src/env.js | 6 ++- src/message.js | 67 ++++++++++++++++---------------- src/openai.js | 4 +- src/router.js | 1 + src/telegram.js | 16 ++++---- 12 files changed, 100 insertions(+), 118 deletions(-) create mode 100644 proxy/kv.js create mode 100644 proxy/openai.js create mode 100644 proxy/telegram.js diff --git a/dist/buildinfo.json b/dist/buildinfo.json index c8db4096..59fa8dda 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "78c59e7", "timestamp": 1678444109} +{"sha": "b5fd977", "timestamp": 1678523181} diff --git a/dist/index.js b/dist/index.js index 3ef2c4f1..340ad698 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678444109, + BUILD_TIMESTAMP: 1678523181, // 当前版本 commit id - BUILD_VERSION: "78c59e7", + BUILD_VERSION: "b5fd977", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -42,7 +42,10 @@ var ENV = { // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: ["private", "group", "supergroup"] + INLINE_KEYBOARD_ENABLE: [], + // DEBUG 专用 + TELEGRAM_API_DOMAIN: "https://api.telegram.org", + OPENAI_API_DOMAIN: "https://api.openai.com" }; var CONST = { PASSWORD_KEY: "chat_history_password", @@ -122,10 +125,8 @@ var SHARE_CONTEXT = { // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id - speakerId: null, + speakerId: null // 发言人 id - fromInlineKeyboard: false - // 是否来自内联键盘 }; function initChatContext(chatId, replyToMessageId) { CURRENT_CHAT_CONTEXT.chat_id = chatId; @@ -146,7 +147,7 @@ async function initUserConfig(storeKey) { console.error(e); } } -async function initShareContext(message, request) { +function initTelegramContext(request) { const { pathname } = new URL(request.url); const token = pathname.match( /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/ @@ -157,10 +158,12 @@ async function initShareContext(message, request) { } SHARE_CONTEXT.currentBotToken = token; SHARE_CONTEXT.currentBotId = token.split(":")[0]; - SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; } +} +async function initShareContext(message) { + SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; const id = message?.chat?.id; if (id === void 0 || id === null) { throw new Error("Chat id not found"); @@ -187,13 +190,13 @@ async function initShareContext(message, request) { SHARE_CONTEXT.chatId = message.chat.id; SHARE_CONTEXT.speakerId = message.from.id || message.chat.id; } -async function initContext(message, request) { +async function initContext(message) { console.log(ENV); const chatId = message?.chat?.id; const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; initChatContext(chatId, replyId); console.log(CURRENT_CHAT_CONTEXT); - await initShareContext(message, request); + await initShareContext(message); console.log(SHARE_CONTEXT); await initUserConfig(SHARE_CONTEXT.configStoreKey); console.log(USER_CONFIG); @@ -202,7 +205,7 @@ async function initContext(message, request) { // src/telegram.js async function sendMessage(message, token, context) { return await fetch( - `https://api.telegram.org/bot${token}/sendMessage`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendMessage`, { method: "POST", headers: { @@ -236,7 +239,7 @@ ${msg} async function sendPhotoToTelegram(url, token, context) { const chatContext = Object.assign(context || CURRENT_CHAT_CONTEXT, { parse_mode: null }); return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, { method: "POST", headers: { @@ -251,7 +254,7 @@ async function sendPhotoToTelegram(url, token, context) { } async function sendChatActionToTelegram(action, token) { return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendChatAction`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/sendChatAction`, { method: "POST", headers: { @@ -264,27 +267,9 @@ async function sendChatActionToTelegram(action, token) { } ).then((res) => res.json()); } -async function deleteMessageInlineKeyboard(chatId, messageId, token) { - return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/editMessageReplyMarkup`, - { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - chat_id: chatId, - message_id: messageId, - reply_markup: { - inline_keyboard: [] - } - }) - } - ).then((res) => res.json()); -} async function bindTelegramWebHook(token, url) { return await fetch( - `https://api.telegram.org/bot${token}/setWebhook`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/setWebhook`, { method: "POST", headers: { @@ -327,7 +312,7 @@ async function getChatRole(id) { async function getChatAdminister(chatId, token) { try { const resp = await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/getChatAdministrators`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/getChatAdministrators`, { method: "POST", headers: { @@ -346,7 +331,7 @@ async function getChatAdminister(chatId, token) { } async function getBot(token) { const resp = await fetch( - `https://api.telegram.org/bot${token}/getMe`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getMe`, { method: "POST", headers: { @@ -376,7 +361,7 @@ async function requestCompletionsFromChatGPT(message, history) { ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, messages: [...history || [], { role: "user", content: message }] }; - const resp = await fetch("https://api.openai.com/v1/chat/completions", { + const resp = await fetch(`${ENV.OPENAI_API_DOMAIN}/v1/chat/completions`, { method: "POST", headers: { "Content-Type": "application/json", @@ -397,7 +382,7 @@ async function requestImageFromOpenAI(prompt) { n: 1, size: "512x512" }; - const resp = await fetch("https://api.openai.com/v1/images/generations", { + const resp = await fetch(`${ENV.OPENAI_API_DOMAIN}/v1/images/generations`, { method: "POST", headers: { "Content-Type": "application/json", @@ -885,9 +870,6 @@ async function msgHandleGroupMessage(message) { const botName = SHARE_CONTEXT.currentBotName; if (botName) { let mentioned = false; - if (SHARE_CONTEXT.fromInlineKeyboard) { - mentioned = true; - } if (message.reply_to_message) { if (message.reply_to_message.from.username === botName) { mentioned = true; @@ -956,20 +938,6 @@ async function msgChatWithOpenAI(message) { history.push({ role: "assistant", content: answer }); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { - const replyMarkup = {}; - replyMarkup.inline_keyboard = [[ - { - text: "\u7EE7\u7EED", - callback_data: `#continue` - }, - { - text: "\u7ED3\u675F", - callback_data: `#end` - } - ]]; - CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; - } return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -1016,7 +984,7 @@ async function msgProcessByChatType(message) { } async function loadMessage(request) { const raw = await request.json(); - console.log(raw); + console.log(JSON.stringify(raw)); if (ENV.DEV_MODE) { setTimeout(() => { DATABASE.put(`log:${(/* @__PURE__ */ new Date()).toISOString()}`, JSON.stringify(raw), { expirationTtl: 600 }).catch(console.error); @@ -1025,19 +993,7 @@ async function loadMessage(request) { if (raw.message) { return raw.message; } else if (raw.callback_query && raw.callback_query.message) { - const messageId = raw.callback_query.message?.message_id; - const chatId = raw.callback_query.message?.chat?.id; - const data = raw.callback_query.data; - if (data.startsWith("#continue")) { - raw.callback_query.message.text = "\u7EE7\u7EED"; - } else if (data.startsWith("#end")) { - raw.callback_query.message.text = "/new"; - } - if (messageId && chatId) { - setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); - } - SHARE_CONTEXT.fromInlineKeyboard = true; - return raw.callback_query.message; + return null; } else { throw new Error("Invalid message"); } @@ -1098,6 +1054,7 @@ async function loadHistory(key) { return { real: history }; } async function handleMessage(request) { + initTelegramContext(request); const message = await loadMessage(request); const handlers = [ msgInitChatContext, @@ -1118,6 +1075,7 @@ async function handleMessage(request) { return result; } } catch (e) { + console.error(e); return new Response(errorToString(e), { status: 500 }); } } @@ -1251,6 +1209,7 @@ async function handleRequest(request) { } }); } } catch (e) { + console.error(e); return new Response(errorToString(e), { status: 200 }); } } diff --git a/dist/timestamp b/dist/timestamp index 33e70324..b6ddcdf5 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678444109 +1678523181 diff --git a/proxy/kv.js b/proxy/kv.js new file mode 100644 index 00000000..e69de29b diff --git a/proxy/openai.js b/proxy/openai.js new file mode 100644 index 00000000..4dd244a7 --- /dev/null +++ b/proxy/openai.js @@ -0,0 +1,8 @@ +export default { + async fetch(request, env) { + const url = new URL(request.url); + url.hostname = "api.openai.com"; + const newRequest = new Request(url, request); + return await fetch(newRequest); + }, +}; diff --git a/proxy/telegram.js b/proxy/telegram.js new file mode 100644 index 00000000..d5bc5045 --- /dev/null +++ b/proxy/telegram.js @@ -0,0 +1,8 @@ +export default { + async fetch(request, env) { + const url = new URL(request.url); + url.hostname = "api.telegram.org"; + const newRequest = new Request(url, request); + return await fetch(newRequest); + }, +}; diff --git a/src/context.js b/src/context.js index 6412a17c..62d79afb 100644 --- a/src/context.js +++ b/src/context.js @@ -27,7 +27,6 @@ export const SHARE_CONTEXT = { chatType: null, // 会话场景, private/group/supergroup 等, 来源 message.chat.type chatId: null, // 会话 id, private 场景为发言人 id, group/supergroup 场景为群组 id speakerId: null, // 发言人 id - fromInlineKeyboard: false, // 是否来自内联键盘 }; @@ -56,7 +55,7 @@ async function initUserConfig(storeKey) { } } -async function initShareContext(message, request) { +export function initTelegramContext(request) { const {pathname} = new URL(request.url); const token = pathname.match( /^\/telegram\/(\d+:[A-Za-z0-9_-]{35})\/webhook/, @@ -68,11 +67,13 @@ async function initShareContext(message, request) { SHARE_CONTEXT.currentBotToken = token; SHARE_CONTEXT.currentBotId = token.split(':')[0]; - SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; if (ENV.TELEGRAM_BOT_NAME.length > telegramIndex) { SHARE_CONTEXT.currentBotName = ENV.TELEGRAM_BOT_NAME[telegramIndex]; } +} +async function initShareContext(message) { + SHARE_CONTEXT.usageKey = `usage:${SHARE_CONTEXT.currentBotId}`; const id = message?.chat?.id; if (id === undefined || id === null) { throw new Error('Chat id not found'); @@ -120,14 +121,14 @@ async function initShareContext(message, request) { } -export async function initContext(message, request) { +export async function initContext(message) { // 按顺序初始化上下文 console.log(ENV); const chatId = message?.chat?.id; const replyId = CONST.GROUP_TYPES.includes(message.chat?.type) ? message.message_id : null; initChatContext(chatId, replyId); console.log(CURRENT_CHAT_CONTEXT); - await initShareContext(message, request); + await initShareContext(message); console.log(SHARE_CONTEXT); await initUserConfig(SHARE_CONTEXT.configStoreKey); console.log(USER_CONFIG); diff --git a/src/env.js b/src/env.js index 32d1f56f..a01199fb 100644 --- a/src/env.js +++ b/src/env.js @@ -42,7 +42,11 @@ export const ENV = { // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: ['private', 'group', 'supergroup'], + INLINE_KEYBOARD_ENABLE: [], + + // DEBUG 专用 + TELEGRAM_API_DOMAIN: 'https://api.telegram.org', + OPENAI_API_DOMAIN: 'https://api.openai.com', }; export const CONST = { diff --git a/src/message.js b/src/message.js index 0536a663..d3de99b6 100644 --- a/src/message.js +++ b/src/message.js @@ -1,5 +1,5 @@ import {ENV, DATABASE, CONST} from './env.js'; -import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext} from './context.js'; +import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, initContext, initTelegramContext} from './context.js'; import {sendMessageToTelegram, sendChatActionToTelegram, deleteMessageInlineKeyboard} from './telegram.js'; import {requestCompletionsFromChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; @@ -93,11 +93,8 @@ async function msgHandleGroupMessage(message) { const botName = SHARE_CONTEXT.currentBotName; if (botName) { let mentioned = false; - if (SHARE_CONTEXT.fromInlineKeyboard) { - mentioned = true; - } // Reply消息 - if (message.reply_to_message) { + if (message.reply_to_message ) { if (message.reply_to_message.from.username === botName) { mentioned = true; } @@ -172,20 +169,20 @@ async function msgChatWithOpenAI(message) { history.push({role: 'assistant', content: answer}); await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); } - if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { - const replyMarkup = { }; - replyMarkup.inline_keyboard = [[ - { - text: '继续', - callback_data: `#continue`, - }, - { - text: '结束', - callback_data: `#end`, - }, - ]]; - CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; - } + // if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { + // const replyMarkup = { }; + // replyMarkup.inline_keyboard = [[ + // { + // text: '继续', + // callback_data: `#continue`, + // }, + // { + // text: '结束', + // callback_data: `#end`, + // }, + // ]]; + // CURRENT_CHAT_CONTEXT.reply_markup = replyMarkup; + // } return sendMessageToTelegram(answer); } catch (e) { return sendMessageToTelegram(`ERROR:CHAT: ${e.message}`); @@ -236,7 +233,7 @@ export async function msgProcessByChatType(message) { // Loader async function loadMessage(request) { const raw = await request.json(); - console.log(raw); + console.log(JSON.stringify(raw)); if (ENV.DEV_MODE) { setTimeout(() => { DATABASE.put(`log:${new Date().toISOString()}`, JSON.stringify(raw), {expirationTtl: 600}).catch(console.error); @@ -245,19 +242,21 @@ async function loadMessage(request) { if (raw.message) { return raw.message; } else if (raw.callback_query && raw.callback_query.message) { - const messageId = raw.callback_query.message?.message_id; - const chatId = raw.callback_query.message?.chat?.id; - const data = raw.callback_query.data; - if (data.startsWith('#continue')) { - raw.callback_query.message.text = '继续'; - } else if (data.startsWith('#end')) { - raw.callback_query.message.text = '/new'; - } - if (messageId && chatId) { - setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); - } - SHARE_CONTEXT.fromInlineKeyboard = true; - return raw.callback_query.message; + return null + // const messageId = raw.callback_query.message?.message_id; + // const chatId = raw.callback_query.message?.chat?.id; + // const data = raw.callback_query.data; + + // if (data.startsWith('#continue')) { + // raw.callback_query.message.text = '继续'; + // } else if (data.startsWith('#end')) { + // raw.callback_query.message.text = '/new'; + // } + // if (messageId && chatId) { + // setTimeout(() => deleteMessageInlineKeyboard(chatId, messageId).catch(console.error), 0); + // } + // SHARE_CONTEXT.fromInlineKeyboard = true; + // return raw.callback_query.message; } else { throw new Error('Invalid message'); } @@ -324,6 +323,7 @@ async function loadHistory(key) { } export async function handleMessage(request) { + initTelegramContext(request); const message = await loadMessage(request); // 消息处理中间件 @@ -342,6 +342,7 @@ export async function handleMessage(request) { return result; } } catch (e) { + console.error(e) return new Response(errorToString(e), {status: 500}); } } diff --git a/src/openai.js b/src/openai.js index 19f91ffe..50121ea7 100644 --- a/src/openai.js +++ b/src/openai.js @@ -8,7 +8,7 @@ export async function requestCompletionsFromChatGPT(message, history) { ...USER_CONFIG.OPENAI_API_EXTRA_PARAMS, messages: [...(history || []), {role: 'user', content: message}], }; - const resp = await fetch('https://api.openai.com/v1/chat/completions', { + const resp = await fetch(`${ENV.OPENAI_API_DOMAIN}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -30,7 +30,7 @@ export async function requestImageFromOpenAI(prompt) { n: 1, size: '512x512', }; - const resp = await fetch('https://api.openai.com/v1/images/generations', { + const resp = await fetch(`${ENV.OPENAI_API_DOMAIN}/v1/images/generations`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/src/router.js b/src/router.js index a7f3221b..6ae207e5 100644 --- a/src/router.js +++ b/src/router.js @@ -153,6 +153,7 @@ export async function handleRequest(request) { }}); } } catch (e) { + console.error(e); return new Response(errorToString(e), {status: 200}); } } diff --git a/src/telegram.js b/src/telegram.js index 8fcb7ab4..95365800 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -1,10 +1,10 @@ -import {DATABASE} from './env.js'; +import {DATABASE, ENV} from './env.js'; import {CURRENT_CHAT_CONTEXT, SHARE_CONTEXT} from './context.js'; // 发送消息到Telegram async function sendMessage(message, token, context) { return await fetch( - `https://api.telegram.org/bot${token}/sendMessage`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/sendMessage`, { method: 'POST', headers: { @@ -40,7 +40,7 @@ export async function sendMessageToTelegram(message, token, context) { export async function sendPhotoToTelegram(url, token, context) { const chatContext = Object.assign((context || CURRENT_CHAT_CONTEXT), {parse_mode: null}); return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/sendPhoto`, { method: 'POST', headers: { @@ -57,7 +57,7 @@ export async function sendPhotoToTelegram(url, token, context) { // 发送聊天动作到TG export async function sendChatActionToTelegram(action, token) { return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/sendChatAction`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/sendChatAction`, { method: 'POST', headers: { @@ -73,7 +73,7 @@ export async function sendChatActionToTelegram(action, token) { export async function deleteMessageInlineKeyboard(chatId, messageId, token) { return await fetch( - `https://api.telegram.org/bot${token || SHARE_CONTEXT.currentBotToken}/editMessageReplyMarkup`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token || SHARE_CONTEXT.currentBotToken}/editMessageReplyMarkup`, { method: 'POST', headers: { @@ -92,7 +92,7 @@ export async function deleteMessageInlineKeyboard(chatId, messageId, token) { export async function bindTelegramWebHook(token, url) { return await fetch( - `https://api.telegram.org/bot${token}/setWebhook`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/setWebhook`, { method: 'POST', headers: { @@ -140,7 +140,7 @@ export async function getChatRole(id) { export async function getChatAdminister(chatId, token) { try { const resp = await fetch( - `https://api.telegram.org/bot${ + `${ENV.TELEGRAM_API_DOMAIN}/bot${ token || SHARE_CONTEXT.currentBotToken }/getChatAdministrators`, { @@ -163,7 +163,7 @@ export async function getChatAdminister(chatId, token) { // 获取机器人信息 export async function getBot(token) { const resp = await fetch( - `https://api.telegram.org/bot${token}/getMe`, + `${ENV.TELEGRAM_API_DOMAIN}/bot${token}/getMe`, { method: 'POST', headers: { From c33293dc129a14d69e5baa10718c6aeb3775d14b Mon Sep 17 00:00:00 2001 From: TBXark Date: Sat, 11 Mar 2023 16:31:16 +0800 Subject: [PATCH 28/32] =?UTF-8?q?fix:=20msgInitChatContext=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E7=AD=BE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 10 +++++----- dist/timestamp | 2 +- src/message.js | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 59fa8dda..34ffa52d 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "b5fd977", "timestamp": 1678523181} +{"sha": "4cacd32", "timestamp": 1678523412} diff --git a/dist/index.js b/dist/index.js index 340ad698..8bff4523 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678523181, + BUILD_TIMESTAMP: 1678523412, // 当前版本 commit id - BUILD_VERSION: "b5fd977", + BUILD_VERSION: "4cacd32", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -806,9 +806,9 @@ function errorToString(e) { // src/message.js var MAX_TOKEN_LENGTH = 2048; -async function msgInitChatContext(message, request) { +async function msgInitChatContext(message) { try { - await initContext(message, request); + await initContext(message); } catch (e) { return new Response(errorToString(e), { status: 200 }); } @@ -1070,7 +1070,7 @@ async function handleMessage(request) { ]; for (const handler of handlers) { try { - const result = await handler(message, request); + const result = await handler(message); if (result && result instanceof Response) { return result; } diff --git a/dist/timestamp b/dist/timestamp index b6ddcdf5..4cd715e0 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678523181 +1678523412 diff --git a/src/message.js b/src/message.js index d3de99b6..32e4805d 100644 --- a/src/message.js +++ b/src/message.js @@ -10,9 +10,9 @@ const MAX_TOKEN_LENGTH = 2048; // Middleware // 初始化聊天上下文 -async function msgInitChatContext(message, request) { +async function msgInitChatContext(message) { try { - await initContext(message, request); + await initContext(message); } catch (e) { return new Response(errorToString(e), {status: 200}); } @@ -337,7 +337,7 @@ export async function handleMessage(request) { for (const handler of handlers) { try { - const result = await handler(message, request); + const result = await handler(message); if (result && result instanceof Response) { return result; } From 865d7a7b012bd90fdb246f425e2a1566bd3dc6ae Mon Sep 17 00:00:00 2001 From: cheivin Date: Sat, 11 Mar 2023 21:20:52 +0800 Subject: [PATCH 29/32] =?UTF-8?q?build:=20=E6=9E=84=E5=BB=BA=E5=B8=A6?= =?UTF-8?q?=E6=9C=89role=E6=8C=87=E4=BB=A4=E7=9A=84=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dist/buildinfo.json | 2 +- dist/index.js | 170 +++++++++++++++++++++++++++++++++++++++----- dist/timestamp | 2 +- 3 files changed, 156 insertions(+), 18 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index 34ffa52d..e6504ea4 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "4cacd32", "timestamp": 1678523412} +{"sha": "3b2f8dd", "timestamp": 1678540516} diff --git a/dist/index.js b/dist/index.js index 8bff4523..0aecc1bb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,9 +30,9 @@ var ENV = { // 开发模式 DEV_MODE: false, // 当前版本 - BUILD_TIMESTAMP: 1678523412, + BUILD_TIMESTAMP: 1678540516, // 当前版本 commit id - BUILD_VERSION: "4cacd32", + BUILD_VERSION: "3b2f8dd", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -100,6 +100,10 @@ var USER_CONFIG = { // OpenAI API 额外参数 OPENAI_API_EXTRA_PARAMS: {} }; +var USER_DEFINE = { + // 自定义角色 + ROLE: {} +}; var CURRENT_CHAT_CONTEXT = { chat_id: null, reply_to_message_id: null, @@ -139,14 +143,25 @@ async function initUserConfig(storeKey) { try { const userConfig = JSON.parse(await DATABASE.get(storeKey)); for (const key in userConfig) { - if (USER_CONFIG.hasOwnProperty(key) && typeof USER_CONFIG[key] === typeof userConfig[key]) { - USER_CONFIG[key] = userConfig[key]; + if (key === "USER_DEFINE" && typeof USER_DEFINE === typeof userConfig[key]) { + initUserDefine(userConfig[key]); + } else { + if (USER_CONFIG.hasOwnProperty(key) && typeof USER_CONFIG[key] === typeof userConfig[key]) { + USER_CONFIG[key] = userConfig[key]; + } } } } catch (e) { console.error(e); } } +function initUserDefine(userDefine) { + for (const key in userDefine) { + if (USER_DEFINE.hasOwnProperty(key) && typeof USER_DEFINE[key] === typeof userDefine[key]) { + USER_DEFINE[key] = userDefine[key]; + } + } +} function initTelegramContext(request) { const { pathname } = new URL(request.url); const token = pathname.match( @@ -449,13 +464,13 @@ var commandHandlers = { needAuth: commandAuthCheck.shareModeGroup }, "/start": { - help: "\u83B7\u53D6\u4F60\u7684ID\uFF0C\u5E76\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", + help: "\u83B7\u53D6\u4F60\u7684ID, \u5E76\u53D1\u8D77\u65B0\u7684\u5BF9\u8BDD", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandCreateNewChatContext, needAuth: commandAuthCheck.default }, "/img": { - help: "\u751F\u6210\u4E00\u5F20\u56FE\u7247", + help: "\u751F\u6210\u4E00\u5F20\u56FE\u7247, \u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A `/img \u56FE\u7247\u63CF\u8FF0`, \u4F8B\u5982`/img \u6708\u5149\u4E0B\u7684\u6C99\u6EE9`", scopes: ["all_private_chats", "all_chat_administrators"], fn: commandGenerateImg, needAuth: commandAuthCheck.shareModeGroup @@ -483,8 +498,98 @@ var commandHandlers = { scopes: ["all_private_chats", "all_chat_administrators"], fn: commandSystem, needAuth: commandAuthCheck.default + }, + "/role": { + help: "\u8BBE\u7F6E\u9884\u8BBE\u7684\u8EAB\u4EFD", + scopes: ["all_private_chats", "all_chat_administrators"], + fn: commandUpdateRole, + needAuth: commandAuthCheck.shareModeGroup } }; +async function commandUpdateRole(message, command, subcommand) { + if (subcommand === "show") { + const size = Object.getOwnPropertyNames(USER_DEFINE.ROLE).length; + if (size === 0) { + return sendMessageToTelegram("\u8FD8\u672A\u5B9A\u4E49\u4EFB\u4F55\u89D2\u8272"); + } + let showMsg = `\u5F53\u524D\u5DF2\u5B9A\u4E49\u7684\u89D2\u8272\u5982\u4E0B(${size}): +`; + for (const role2 in USER_DEFINE.ROLE) { + if (USER_DEFINE.ROLE.hasOwnProperty(role2)) { + showMsg += `~${role2}: +
`;
+        showMsg += JSON.stringify(USER_DEFINE.ROLE[role2]) + "\n";
+        showMsg += "
"; + } + } + CURRENT_CHAT_CONTEXT.parse_mode = "HTML"; + return sendMessageToTelegram(showMsg); + } + const helpMsg = "\u683C\u5F0F\u9519\u8BEF: \u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A `/role \u64CD\u4F5C`\n\u5F53\u524D\u652F\u6301\u4EE5\u4E0B`\u64CD\u4F5C`:\n`/role show` \u663E\u793A\u5F53\u524D\u5B9A\u4E49\u7684\u89D2\u8272.\n`/role \u89D2\u8272\u540D del` \u5220\u9664\u6307\u5B9A\u540D\u79F0\u7684\u89D2\u8272.\n`/role \u89D2\u8272\u540D KEY=VALUE` \u8BBE\u7F6E\u6307\u5B9A\u89D2\u8272\u7684\u914D\u7F6E.\n \u76EE\u524D\u4EE5\u4E0B\u8BBE\u7F6E\u9879:\n `SYSTEM_INIT_MESSAGE`:\u521D\u59CB\u5316\u6D88\u606F\n `OPENAI_API_EXTRA_PARAMS`:OpenAI API \u989D\u5916\u53C2\u6570\uFF0C\u5FC5\u987B\u4E3AJSON"; + const kv = subcommand.indexOf(" "); + if (kv === -1) { + return sendMessageToTelegram(helpMsg); + } + const role = subcommand.slice(0, kv); + const settings = subcommand.slice(kv + 1).trim(); + const skv = settings.indexOf("="); + if (skv === -1) { + if (settings === "del") { + try { + if (USER_DEFINE.ROLE[role]) { + delete USER_DEFINE.ROLE[role]; + await DATABASE.put( + SHARE_CONTEXT.configStoreKey, + JSON.stringify(Object.assign(USER_CONFIG, { USER_DEFINE })) + ); + return sendMessageToTelegram("\u5220\u9664\u89D2\u8272\u6210\u529F"); + } + } catch (e) { + return sendMessageToTelegram(`\u5220\u9664\u89D2\u8272\u9519\u8BEF: \`${e.message}\``); + } + } + return sendMessageToTelegram(helpMsg); + } + const key = settings.slice(0, skv); + const value = settings.slice(skv + 1); + if (!USER_DEFINE.ROLE[role]) { + USER_DEFINE.ROLE[role] = { + // 系统初始化消息 + SYSTEM_INIT_MESSAGE: ENV.SYSTEM_INIT_MESSAGE, + // OpenAI API 额外参数 + OPENAI_API_EXTRA_PARAMS: {} + }; + } + try { + switch (typeof USER_DEFINE.ROLE[role][key]) { + case "number": + USER_DEFINE.ROLE[role][key] = Number(value); + break; + case "boolean": + USER_DEFINE.ROLE[role][key] = value === "true"; + break; + case "string": + USER_DEFINE.ROLE[role][key] = value; + break; + case "object": + const object = JSON.parse(value); + if (typeof object === "object") { + USER_DEFINE.ROLE[role][key] = object; + break; + } + return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF"); + default: + return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF"); + } + await DATABASE.put( + SHARE_CONTEXT.configStoreKey, + JSON.stringify(Object.assign(USER_CONFIG, { USER_DEFINE })) + ); + return sendMessageToTelegram("\u66F4\u65B0\u914D\u7F6E\u6210\u529F"); + } catch (e) { + return sendMessageToTelegram(`\u914D\u7F6E\u9879\u683C\u5F0F\u9519\u8BEF: \`${e.message}\``); + } +} async function commandGenerateImg(message, command, subcommand) { if (subcommand === "") { return sendMessageToTelegram("\u8BF7\u8F93\u5165\u56FE\u7247\u63CF\u8FF0\u3002\u547D\u4EE4\u5B8C\u6574\u683C\u5F0F\u4E3A `/img \u72F8\u82B1\u732B`"); @@ -925,18 +1030,44 @@ async function msgHandleGroupMessage(message) { async function msgHandleCommand(message) { return await handleCommandMessage(message); } +async function msgHandleRole(message) { + if (!message.text.startsWith("~")) { + return null; + } + message.text = message.text.slice(1); + const kv = message.text.indexOf(" "); + if (kv === -1) { + return null; + } + const role = message.text.slice(0, kv); + const msg = message.text.slice(kv + 1).trim(); + if (USER_DEFINE.ROLE.hasOwnProperty(role)) { + SHARE_CONTEXT.ROLE = role; + message.text = msg; + const roleConfig = USER_DEFINE.ROLE[role]; + for (const key in roleConfig) { + if (USER_CONFIG.hasOwnProperty(key) && typeof USER_CONFIG[key] === typeof roleConfig[key]) { + USER_CONFIG[key] = roleConfig[key]; + } + } + } +} async function msgChatWithOpenAI(message) { try { console.log("\u63D0\u95EE\u6D88\u606F:" + message.text || ""); const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; setTimeout(() => sendChatActionToTelegram("typing").catch(console.error), 0); const historyKey = SHARE_CONTEXT.chatHistoryKey; - const { real: history, fake: fakeHistory } = await loadHistory(historyKey); + let { real: history, fake: fakeHistory, original } = await loadHistory(historyKey); + history = JSON.parse(JSON.stringify(history)); + history.map((item) => { + item.cosplay = void 0; + }); const answer = await requestCompletionsFromChatGPT(message.text, fakeHistory || history); if (!historyDisable) { - history.push({ role: "user", content: message.text || "" }); - history.push({ role: "assistant", content: answer }); - await DATABASE.put(historyKey, JSON.stringify(history)).catch(console.error); + original.push({ role: "user", content: message.text || "", cosplay: SHARE_CONTEXT.ROLE || "" }); + original.push({ role: "assistant", content: answer, cosplay: SHARE_CONTEXT.ROLE || "" }); + await DATABASE.put(historyKey, JSON.stringify(original)).catch(console.error); } return sendMessageToTelegram(answer); } catch (e) { @@ -948,17 +1079,20 @@ async function msgProcessByChatType(message) { "private": [ msgFilterWhiteList, msgFilterNonTextMessage, - msgHandleCommand + msgHandleCommand, + msgHandleRole ], "group": [ msgHandleGroupMessage, msgFilterWhiteList, - msgHandleCommand + msgHandleCommand, + msgHandleRole ], "supergroup": [ msgHandleGroupMessage, msgFilterWhiteList, - msgHandleCommand + msgHandleCommand, + msgHandleRole ] }; if (!handlerMap.hasOwnProperty(SHARE_CONTEXT.chatType)) { @@ -1002,7 +1136,7 @@ async function loadHistory(key) { const initMessage = { role: "system", content: USER_CONFIG.SYSTEM_INIT_MESSAGE }; const historyDisable = ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH <= 0; if (historyDisable) { - return { real: [initMessage] }; + return { real: [initMessage], original: [initMessage] }; } let history = []; try { @@ -1013,6 +1147,10 @@ async function loadHistory(key) { if (!history || !Array.isArray(history) || history.length === 0) { history = []; } + const original = history; + if (SHARE_CONTEXT.ROLE) { + history = history.filter((chat) => SHARE_CONTEXT.ROLE === chat.cosplay); + } if (ENV.AUTO_TRIM_HISTORY && ENV.MAX_HISTORY_LENGTH > 0) { if (history.length > ENV.MAX_HISTORY_LENGTH) { history = history.splice(history.length - ENV.MAX_HISTORY_LENGTH); @@ -1049,9 +1187,9 @@ async function loadHistory(key) { ...fake[0], role: ENV.SYSTEM_INIT_MESSAGE_ROLE }; - return { real: history, fake }; + return { real: history, fake, original }; } - return { real: history }; + return { real: history, original }; } async function handleMessage(request) { initTelegramContext(request); diff --git a/dist/timestamp b/dist/timestamp index 4cd715e0..7f3f27c8 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678523412 +1678540516 From 0cbb4ceccec6cc729953d2e37b07429524e082bc Mon Sep 17 00:00:00 2001 From: cheivin Date: Sat, 11 Mar 2023 22:22:59 +0800 Subject: [PATCH 30/32] =?UTF-8?q?fix:=20=E5=88=86=E6=AE=B5=E5=8F=91?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/telegram.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/telegram.js b/src/telegram.js index 95365800..d0a27d89 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -29,7 +29,7 @@ export async function sendMessageToTelegram(message, token, context) { console.log('消息将分段发送'); const limit = 4000; chatContext.parse_mode = 'HTML'; - for (let i = 0; i < string.length; i += limit) { + for (let i = 0; i < message.length; i += limit) { const msg = message.slice(i, i + limit); await sendMessage(`
\n${msg}\n
`, botToken, chatContext); } From f0e969465605b87e894e81c000e15d282083fd70 Mon Sep 17 00:00:00 2001 From: TBXark Date: Sat, 11 Mar 2023 22:32:50 +0800 Subject: [PATCH 31/32] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0=E7=9A=84=E5=88=86?= =?UTF-8?q?=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- dist/buildinfo.json | 2 +- dist/index.js | 24 +++++++++++---------- dist/timestamp | 2 +- doc/CONFIG.md | 4 ++-- src/command.js | 49 +++++-------------------------------------- src/env.js | 30 ++++++++++++++++---------- src/message.js | 6 ++++-- src/utils.js | 24 +++++++++++++++++++++ wrangler-example.toml | 6 ++++-- 10 files changed, 74 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 322b5000..b144813d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ ## 已知问题 - ~~群消息只能管理员调用bot~~ -- 长消息被Telegram截断 +- ~~长消息被Telegram截断~~ ## 更新日志 - v1.3.0 diff --git a/dist/buildinfo.json b/dist/buildinfo.json index e6504ea4..aaf19fd1 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "3b2f8dd", "timestamp": 1678540516} +{"sha": "865d7a7", "timestamp": 1678544073} diff --git a/dist/index.js b/dist/index.js index 0aecc1bb..ec9863da 100644 --- a/dist/index.js +++ b/dist/index.js @@ -25,14 +25,6 @@ var ENV = { AUTO_TRIM_HISTORY: true, // 最大历史记录长度 MAX_HISTORY_LENGTH: 20, - // 调试模式 - DEBUG_MODE: false, - // 开发模式 - DEV_MODE: false, - // 当前版本 - BUILD_TIMESTAMP: 1678540516, - // 当前版本 commit id - BUILD_VERSION: "3b2f8dd", // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: "\u4F60\u662F\u4E00\u4E2A\u5F97\u529B\u7684\u52A9\u624B", // 全局默认初始化消息角色 @@ -41,9 +33,19 @@ var ENV = { ENABLE_USAGE_STATISTICS: true, // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], + // 检查更新的分支 + UPDATE_BRANCH: "master", + // 当前版本 + BUILD_TIMESTAMP: 1678544073, + // 当前版本 commit id + BUILD_VERSION: "865d7a7", + // DEBUG 专用 + // 调试模式 + DEBUG_MODE: false, + // 开发模式 + DEV_MODE: false, // Inline keyboard: 实验性功能请勿开启 INLINE_KEYBOARD_ENABLE: [], - // DEBUG 专用 TELEGRAM_API_DOMAIN: "https://api.telegram.org", OPENAI_API_DOMAIN: "https://api.openai.com" }; @@ -680,8 +682,8 @@ async function commandFetchUpdate(message, command, subcommand) { ts: ENV.BUILD_TIMESTAMP, sha: ENV.BUILD_VERSION }; - const ts = "https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/master/dist/timestamp"; - const info = "https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/master/dist/buildinfo.json"; + const ts = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/timestamp`; + const info = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/buildinfo.json`; let online = await fetch(info, config).then((r) => r.json()).catch(() => null); if (!online) { online = await fetch(ts).then((r) => r.text()).then((ts2) => ({ ts: Number(ts2.trim()), sha: "unknown" })).catch(() => ({ ts: 0, sha: "unknown" })); diff --git a/dist/timestamp b/dist/timestamp index 7f3f27c8..75831174 100644 --- a/dist/timestamp +++ b/dist/timestamp @@ -1 +1 @@ -1678540516 +1678544073 diff --git a/doc/CONFIG.md b/doc/CONFIG.md index dcece04d..8297c2ea 100644 --- a/doc/CONFIG.md +++ b/doc/CONFIG.md @@ -21,8 +21,8 @@ |CHAT_MODEL|open ai 模型选择 |`gpt-3.5-turbo`|| |SYSTEM_INIT_MESSAGE|系统初始化信息|`你是一个得力的助手`|默认机器人设定| |SYSTEM_INIT_MESSAGE_ROLE|系统初始化信息角色|`system`|默认机器人设定| -|ENABLE_USAGE_STATISTICS|开启使用统计|`true`|开启后,每次调用API都会记录到KV,可以通过`/usage`查看| -|HIDE_COMMAND_BUTTONS|隐藏指令按钮|`null`|把想要隐藏的按钮写入用逗号分开`/start,/system`, 记得带上斜杠| +|ENABLE_USAGE_STATISTICS|开启使用统计|`false`|开启后,每次调用API都会记录到KV,可以通过`/usage`查看| +|HIDE_COMMAND_BUTTONS|隐藏指令按钮|`null`|把想要隐藏的按钮写入用逗号分开`/start,/system`, 记得带上斜杠,修改之后得重新`init`| |DEBUG_MODE|调试模式|`false`|目前可以把最新一条消息保存到KV方便调试| ### 群组配置 diff --git a/src/command.js b/src/command.js index daa2db3a..d2d0ca63 100644 --- a/src/command.js +++ b/src/command.js @@ -2,6 +2,7 @@ import {sendMessageToTelegram, sendPhotoToTelegram, sendChatActionToTelegram, ge import {DATABASE, ENV, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, USER_DEFINE} from './context.js'; import {requestImageFromOpenAI} from './openai.js'; +import { mergeConfig } from './utils.js'; const commandAuthCheck = { default: function() { @@ -144,27 +145,7 @@ async function commandUpdateRole(message, command, subcommand) { }; } try { - switch (typeof USER_DEFINE.ROLE[role][key]) { - case 'number': - USER_DEFINE.ROLE[role][key] = Number(value); - break; - case 'boolean': - USER_DEFINE.ROLE[role][key] = value === 'true'; - break; - case 'string': - USER_DEFINE.ROLE[role][key] = value; - break; - case 'object': - const object = JSON.parse(value); - if (typeof object === 'object') { - USER_DEFINE.ROLE[role][key] = object; - break; - } - return sendMessageToTelegram('不支持的配置项或数据类型错误'); - default: - return sendMessageToTelegram('不支持的配置项或数据类型错误'); - } - + mergeConfig(USER_DEFINE.ROLE[role], key, value); await DATABASE.put( SHARE_CONTEXT.configStoreKey, JSON.stringify(Object.assign(USER_CONFIG, {USER_DEFINE: USER_DEFINE})), @@ -235,26 +216,7 @@ async function commandUpdateUserConfig(message, command, subcommand) { const key = subcommand.slice(0, kv); const value = subcommand.slice(kv + 1); try { - switch (typeof USER_CONFIG[key]) { - case 'number': - USER_CONFIG[key] = Number(value); - break; - case 'boolean': - USER_CONFIG[key] = value === 'true'; - break; - case 'string': - USER_CONFIG[key] = value; - break; - case 'object': - const object = JSON.parse(value); - if (typeof object === 'object') { - USER_CONFIG[key] = object; - break; - } - return sendMessageToTelegram('不支持的配置项或数据类型错误'); - default: - return sendMessageToTelegram('不支持的配置项或数据类型错误'); - } + mergeConfig(USER_CONFIG, key, value) await DATABASE.put( SHARE_CONTEXT.configStoreKey, JSON.stringify(USER_CONFIG), @@ -275,9 +237,8 @@ async function commandFetchUpdate(message, command, subcommand) { ts: ENV.BUILD_TIMESTAMP, sha: ENV.BUILD_VERSION, }; - - const ts = 'https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/master/dist/timestamp'; - const info = 'https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/master/dist/buildinfo.json'; + const ts = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/timestamp`; + const info = `https://raw.githubusercontent.com/TBXark/ChatGPT-Telegram-Workers/${ENV.UPDATE_BRANCH}/dist/buildinfo.json`; let online = await fetch(info, config) .then((r) => r.json()) .catch(() => null); diff --git a/src/env.js b/src/env.js index a01199fb..e5436348 100644 --- a/src/env.js +++ b/src/env.js @@ -7,44 +7,52 @@ export const ENV = { API_KEY: null, // OpenAI的模型名称 CHAT_MODEL: 'gpt-3.5-turbo', + // 允许访问的Telegram Token, 设置时以逗号分隔 TELEGRAM_AVAILABLE_TOKENS: [], // 允许访问的Telegram Token 对应的Bot Name, 设置时以逗号分隔 TELEGRAM_BOT_NAME: [], + // 允许所有人使用 I_AM_A_GENEROUS_PERSON: false, // 白名单 CHAT_WHITE_LIST: [], // 群组白名单 CHAT_GROUP_WHITE_LIST: [], + // 群组机器人开关 GROUP_CHAT_BOT_ENABLE: true, // 群组机器人共享模式,关闭后,一个群组只有一个会话和配置。开启的话群组的每个人都有自己的会话上下文 GROUP_CHAT_BOT_SHARE_MODE: false, + // 为了避免4096字符限制,将消息删减 AUTO_TRIM_HISTORY: true, // 最大历史记录长度 MAX_HISTORY_LENGTH: 20, - // 调试模式 - DEBUG_MODE: false, - // 开发模式 - DEV_MODE: false, - // 当前版本 - BUILD_TIMESTAMP: process.env.BUILD_TIMESTAMP || 0, - // 当前版本 commit id - BUILD_VERSION: process.env.BUILD_VERSION || '', + // 全局默认初始化消息 SYSTEM_INIT_MESSAGE: '你是一个得力的助手', // 全局默认初始化消息角色 SYSTEM_INIT_MESSAGE_ROLE: 'system', // 是否开启使用统计 - ENABLE_USAGE_STATISTICS: true, + ENABLE_USAGE_STATISTICS: false, // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], - // Inline keyboard: 实验性功能请勿开启 - INLINE_KEYBOARD_ENABLE: [], + + // 检查更新的分支 + UPDATE_BRANCH: 'master', + // 当前版本 + BUILD_TIMESTAMP: process.env.BUILD_TIMESTAMP || 0, + // 当前版本 commit id + BUILD_VERSION: process.env.BUILD_VERSION || '', // DEBUG 专用 + // 调试模式 + DEBUG_MODE: false, + // 开发模式 + DEV_MODE: false, + // Inline keyboard: 实验性功能请勿开启 + INLINE_KEYBOARD_ENABLE: [], TELEGRAM_API_DOMAIN: 'https://api.telegram.org', OPENAI_API_DOMAIN: 'https://api.openai.com', }; diff --git a/src/message.js b/src/message.js index 1c7d1bff..10a45d6e 100644 --- a/src/message.js +++ b/src/message.js @@ -1,6 +1,6 @@ import {ENV, DATABASE, CONST} from './env.js'; import {SHARE_CONTEXT, USER_CONFIG, USER_DEFINE, CURRENT_CHAT_CONTEXT, initContext, initTelegramContext} from './context.js'; -import {sendMessageToTelegram, sendChatActionToTelegram, deleteMessageInlineKeyboard} from './telegram.js'; +import {sendMessageToTelegram, sendChatActionToTelegram} from './telegram.js'; import {requestCompletionsFromChatGPT} from './openai.js'; import {handleCommandMessage} from './command.js'; import {errorToString} from './utils.js'; @@ -209,6 +209,7 @@ async function msgChatWithOpenAI(message) { original.push({role: 'assistant', content: answer, cosplay: SHARE_CONTEXT.ROLE || ''}); await DATABASE.put(historyKey, JSON.stringify(original)).catch(console.error); } + /* inline keyboard 实验性代码 */ // if (SHARE_CONTEXT.chatType && ENV.INLINE_KEYBOARD_ENABLE.includes(SHARE_CONTEXT.chatType)) { // const replyMarkup = { }; // replyMarkup.inline_keyboard = [[ @@ -286,6 +287,7 @@ async function loadMessage(request) { return raw.message; } else if (raw.callback_query && raw.callback_query.message) { return null; + /* inline keyboard 实验性代码 */ // const messageId = raw.callback_query.message?.message_id; // const chatId = raw.callback_query.message?.chat?.id; // const data = raw.callback_query.data; @@ -391,7 +393,7 @@ export async function handleMessage(request) { return result; } } catch (e) { - console.error(e) + console.error(e); return new Response(errorToString(e), {status: 500}); } } diff --git a/src/utils.js b/src/utils.js index eec309d5..d54e393a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -71,3 +71,27 @@ export function errorToString(e) { stack: e.stack, }); } + + +export function mergeConfig(config, key, value) { + switch (typeof config[key]) { + case 'number': + config[key] = Number(value); + break; + case 'boolean': + config[key] = value === 'true'; + break; + case 'string': + config[key] = value; + break; + case 'object': + const object = JSON.parse(value); + if (typeof object === 'object') { + config[key] = object; + break; + } + throw new Error('不支持的配置项或数据类型错误'); + default: + throw new Error('不支持的配置项或数据类型错误'); + } +} \ No newline at end of file diff --git a/wrangler-example.toml b/wrangler-example.toml index 6c9d8c6d..4db56d6c 100644 --- a/wrangler-example.toml +++ b/wrangler-example.toml @@ -13,10 +13,11 @@ kv_namespaces = [ [vars] -# 具体参数使用请查看README.md +# 更多参数使用请查看README.md # 没有注释的参数为必填项 # 写了参数的选项为该参数的默认值 # 要使用前面有#的属性请去掉#号 +# 所有变量必须为字符串,多个参数的值之间用逗号隔开 # 基本配置 API_KEY = "sk-" @@ -27,9 +28,10 @@ CHAT_WHITE_LIST = "" # MAX_HISTORY_LENGTH = "20" # DEBUG_MODE = "false" # CHAT_MODEL = "gpt-3.5-turbo" -# 群组相关配置 +# 群组相关配置 # GROUP_CHAT_BOT_ENABLE = "true" # TELEGRAM_BOT_NAME = "" # GROUP_CHAT_BOT_SHARE_MODE = "false" # CHAT_GROUP_WHITE_LIST = "false" + From 595dca36347fc88a90da9b9a72f8d84e7b06576c Mon Sep 17 00:00:00 2001 From: TBXark Date: Sat, 11 Mar 2023 22:58:23 +0800 Subject: [PATCH 32/32] build: 1.3.0 pre-release (4) --- dist/buildinfo.json | 2 +- dist/index.js | 214 ++++++++++++++++++++------------------------ dist/timestamp | 2 +- src/command.js | 6 +- src/utils.js | 2 +- 5 files changed, 105 insertions(+), 121 deletions(-) diff --git a/dist/buildinfo.json b/dist/buildinfo.json index aaf19fd1..18a4d4fa 100644 --- a/dist/buildinfo.json +++ b/dist/buildinfo.json @@ -1 +1 @@ -{"sha": "865d7a7", "timestamp": 1678544073} +{"sha": "94c81f1", "timestamp": 1678546663} diff --git a/dist/index.js b/dist/index.js index ec9863da..2401a347 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30,15 +30,15 @@ var ENV = { // 全局默认初始化消息角色 SYSTEM_INIT_MESSAGE_ROLE: "system", // 是否开启使用统计 - ENABLE_USAGE_STATISTICS: true, + ENABLE_USAGE_STATISTICS: false, // 隐藏部分命令按钮 HIDE_COMMAND_BUTTONS: [], // 检查更新的分支 UPDATE_BRANCH: "master", // 当前版本 - BUILD_TIMESTAMP: 1678544073, + BUILD_TIMESTAMP: 1678546663, // 当前版本 commit id - BUILD_VERSION: "865d7a7", + BUILD_VERSION: "94c81f1", // DEBUG 专用 // 调试模式 DEBUG_MODE: false, @@ -245,7 +245,7 @@ async function sendMessageToTelegram(message, token, context) { console.log("\u6D88\u606F\u5C06\u5206\u6BB5\u53D1\u9001"); const limit = 4e3; chatContext.parse_mode = "HTML"; - for (let i = 0; i < string.length; i += limit) { + for (let i = 0; i < message.length; i += limit) { const msg = message.slice(i, i + limit); await sendMessage(`
 ${msg}
@@ -435,6 +435,98 @@ async function updateBotUsage(usage) {
   await DATABASE.put(SHARE_CONTEXT.usageKey, JSON.stringify(dbValue));
 }
 
+// src/utils.js
+function randomString(length) {
+  const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  let result = "";
+  for (let i = length; i > 0; --i)
+    result += chars[Math.floor(Math.random() * chars.length)];
+  return result;
+}
+async function historyPassword() {
+  let password = await DATABASE.get(CONST.PASSWORD_KEY);
+  if (password === null) {
+    password = randomString(32);
+    await DATABASE.put(CONST.PASSWORD_KEY, password);
+  }
+  return password;
+}
+function renderHTML(body) {
+  return `
+  
+  
+    ChatGPT-Telegram-Workers
+    
+    
+    
+    
+    
+  
+  
+    ${body}
+  
+
+  `;
+}
+function errorToString(e) {
+  return JSON.stringify({
+    message: e.message,
+    stack: e.stack
+  });
+}
+function mergeConfig(config, key, value) {
+  switch (typeof config[key]) {
+    case "number":
+      config[key] = Number(value);
+      break;
+    case "boolean":
+      config[key] = value === "true";
+      break;
+    case "string":
+      config[key] = value;
+      break;
+    case "object":
+      const object = JSON.parse(value);
+      if (typeof object === "object") {
+        config[key] = object;
+        break;
+      }
+      throw new Error("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
+    default:
+      throw new Error("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
+  }
+}
+
 // src/command.js
 var commandAuthCheck = {
   default: function() {
@@ -503,7 +595,7 @@ var commandHandlers = {
   },
   "/role": {
     help: "\u8BBE\u7F6E\u9884\u8BBE\u7684\u8EAB\u4EFD",
-    scopes: ["all_private_chats", "all_chat_administrators"],
+    scopes: ["all_private_chats"],
     fn: commandUpdateRole,
     needAuth: commandAuthCheck.shareModeGroup
   }
@@ -563,26 +655,7 @@ async function commandUpdateRole(message, command, subcommand) {
     };
   }
   try {
-    switch (typeof USER_DEFINE.ROLE[role][key]) {
-      case "number":
-        USER_DEFINE.ROLE[role][key] = Number(value);
-        break;
-      case "boolean":
-        USER_DEFINE.ROLE[role][key] = value === "true";
-        break;
-      case "string":
-        USER_DEFINE.ROLE[role][key] = value;
-        break;
-      case "object":
-        const object = JSON.parse(value);
-        if (typeof object === "object") {
-          USER_DEFINE.ROLE[role][key] = object;
-          break;
-        }
-        return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
-      default:
-        return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
-    }
+    mergeConfig(USER_DEFINE.ROLE[role], key, value);
     await DATABASE.put(
       SHARE_CONTEXT.configStoreKey,
       JSON.stringify(Object.assign(USER_CONFIG, { USER_DEFINE }))
@@ -643,26 +716,7 @@ async function commandUpdateUserConfig(message, command, subcommand) {
   const key = subcommand.slice(0, kv);
   const value = subcommand.slice(kv + 1);
   try {
-    switch (typeof USER_CONFIG[key]) {
-      case "number":
-        USER_CONFIG[key] = Number(value);
-        break;
-      case "boolean":
-        USER_CONFIG[key] = value === "true";
-        break;
-      case "string":
-        USER_CONFIG[key] = value;
-        break;
-      case "object":
-        const object = JSON.parse(value);
-        if (typeof object === "object") {
-          USER_CONFIG[key] = object;
-          break;
-        }
-        return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
-      default:
-        return sendMessageToTelegram("\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u9879\u6216\u6570\u636E\u7C7B\u578B\u9519\u8BEF");
-    }
+    mergeConfig(USER_CONFIG, key, value);
     await DATABASE.put(
       SHARE_CONTEXT.configStoreKey,
       JSON.stringify(USER_CONFIG)
@@ -841,76 +895,6 @@ function commandsDocument() {
   });
 }
 
-// src/utils.js
-function randomString(length) {
-  const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-  let result = "";
-  for (let i = length; i > 0; --i)
-    result += chars[Math.floor(Math.random() * chars.length)];
-  return result;
-}
-async function historyPassword() {
-  let password = await DATABASE.get(CONST.PASSWORD_KEY);
-  if (password === null) {
-    password = randomString(32);
-    await DATABASE.put(CONST.PASSWORD_KEY, password);
-  }
-  return password;
-}
-function renderHTML(body) {
-  return `
-  
-  
-    ChatGPT-Telegram-Workers
-    
-    
-    
-    
-    
-  
-  
-    ${body}
-  
-
-  `;
-}
-function errorToString(e) {
-  return JSON.stringify({
-    message: e.message,
-    stack: e.stack
-  });
-}
-
 // src/message.js
 var MAX_TOKEN_LENGTH = 2048;
 async function msgInitChatContext(message) {
diff --git a/dist/timestamp b/dist/timestamp
index 75831174..690d0679 100644
--- a/dist/timestamp
+++ b/dist/timestamp
@@ -1 +1 @@
-1678544073
+1678546663
diff --git a/src/command.js b/src/command.js
index d2d0ca63..b79dfa78 100644
--- a/src/command.js
+++ b/src/command.js
@@ -2,7 +2,7 @@ import {sendMessageToTelegram, sendPhotoToTelegram, sendChatActionToTelegram, ge
 import {DATABASE, ENV, CONST} from './env.js';
 import {SHARE_CONTEXT, USER_CONFIG, CURRENT_CHAT_CONTEXT, USER_DEFINE} from './context.js';
 import {requestImageFromOpenAI} from './openai.js';
-import { mergeConfig } from './utils.js';
+import {mergeConfig} from './utils.js';
 
 const commandAuthCheck = {
   default: function() {
@@ -74,7 +74,7 @@ const commandHandlers = {
   },
   '/role': {
     help: '设置预设的身份',
-    scopes: ['all_private_chats', 'all_chat_administrators'],
+    scopes: ['all_private_chats'],
     fn: commandUpdateRole,
     needAuth: commandAuthCheck.shareModeGroup,
   },
@@ -216,7 +216,7 @@ async function commandUpdateUserConfig(message, command, subcommand) {
   const key = subcommand.slice(0, kv);
   const value = subcommand.slice(kv + 1);
   try {
-    mergeConfig(USER_CONFIG, key, value)
+    mergeConfig(USER_CONFIG, key, value);
     await DATABASE.put(
         SHARE_CONTEXT.configStoreKey,
         JSON.stringify(USER_CONFIG),
diff --git a/src/utils.js b/src/utils.js
index d54e393a..c90ef293 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -94,4 +94,4 @@ export function mergeConfig(config, key, value) {
     default:
       throw new Error('不支持的配置项或数据类型错误');
   }
-}
\ No newline at end of file
+}