Skip to content

Commit

Permalink
chore: optimize logic of the /set command.
Browse files Browse the repository at this point in the history
feat: add judgment for whitelist users in inlineQuery.

chore: optimize the prompt message after tg message send failed.
  • Loading branch information
adolphnov committed Nov 25, 2024
1 parent 7f92d44 commit 0bcfaca
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 40 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@google-cloud/vertexai": "^1.9.0",
"@navetacandra/ddg": "^0.0.6",
"@rollup/plugin-node-resolve": "^15.3.0",
"@types/fluent-ffmpeg": "^2.1.27",
"@types/node": "^22.9.3",
"@types/node-cron": "^3.0.11",
"@types/react": "^18.3.12",
Expand All @@ -75,6 +76,7 @@
"ai": "^4.0.3",
"eslint": "^9.15.0",
"eslint-plugin-format": "^0.1.2",
"fluent-ffmpeg": "^2.1.3",
"gts": "^6.0.2",
"openai": "^4.73.0",
"react-dom": "^18.3.1",
Expand Down
2 changes: 1 addition & 1 deletion src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function customInfo(config: AgentUserConfig): string {
MAPPING_KEY: config.MAPPING_KEY,
MAPPING_VALUE: config.MAPPING_VALUE,
USE_TOOLS: config.USE_TOOLS.join(','),
SUPPORT_PLUGINS: [...Object.keys(ENV.PLUGINS_FUNCTION), ...Object.keys(tools)].join('|'),
SUPPORT_PLUGINS: Object.keys({ ...ENV.PLUGINS_FUNCTION, ...tools }).join('|'),
CHAT_TRIGGER_PERFIX: ENV.CHAT_TRIGGER_PERFIX,
MESSAGE_REPLACER: Object.keys(ENV.MESSAGE_REPLACER).join('|'),
MAX_STEPS: config.MAX_STEPS,
Expand Down
2 changes: 1 addition & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ export class DefineKeys {
}

export class ExtraUserConfig {
MAPPING_KEY = '-p:SYSTEM_INIT_MESSAGE|-n:MAX_HISTORY_LENGTH|-a:AI_PROVIDER|-ai:AI_IMAGE_PROVIDER|-m:CHAT_MODEL|-md:CURRENT_MODE|-v:OPENAI_VISION_MODEL|-t:OPENAI_TTS_MODEL|-ex:OPENAI_API_EXTRA_PARAMS|-mk:MAPPING_KEY|-mv:MAPPING_VALUE|-asap:FUNCTION_REPLY_ASAP|-tm:TOOL_MODEL|-tool:USE_TOOLS|-oli:IMAGE_MODEL|-vs:VERTEX_SEARCH_GROUNDING';
MAPPING_KEY = '-p:SYSTEM_INIT_MESSAGE|-n:MAX_HISTORY_LENGTH|-a:AI_PROVIDER|-ai:AI_IMAGE_PROVIDER|-m:CHAT_MODEL|-md:CURRENT_MODE|-v:OPENAI_VISION_MODEL|-t:OPENAI_TTS_MODEL|-ex:OPENAI_API_EXTRA_PARAMS|-mk:MAPPING_KEY|-mv:MAPPING_VALUE|-asap:FUNCTION_REPLY_ASAP|-tm:TOOL_MODEL|-tool:USE_TOOLS|-oli:IMAGE_MODEL|-th:TEXT_HANDLE_TYPE|-to:TEXT_OUTPUT|-ah:AUDIO_HANDLE_TYPE|-ao:AUDIO_OUTPUT|-act:AUDIO_CONTAINS_TEXT';
// /set command mapping value, separated by |, : separates multiple relationships
MAPPING_VALUE = '';
// MAPPING_VALUE = "cson:claude-3-5-sonnet-20240620|haiku:claude-3-haiku-20240307|g4m:gpt-4o-mini|g4:gpt-4o|rp+:command-r-plus";
Expand Down
16 changes: 11 additions & 5 deletions src/telegram/command/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,11 @@ export class SetCommandHandler implements CommandHandler {
context: WorkerContext,
sender: MessageSender,
): Promise<string | Response> {
let key = keys[flag] || (Object.keys(context.USER_CONFIG).includes(flag.slice(1)) ? flag.slice(1) : null);
let key = keys[flag]
|| (Object.values(keys).includes(flag.slice(1))
|| Object.keys(context.USER_CONFIG).includes(flag.slice(1))
? flag.slice(1)
: null);
let mappedValue = values[value] ?? value;

if (!key) {
Expand Down Expand Up @@ -521,10 +525,12 @@ export class SetCommandHandler implements CommandHandler {
if (typeof context.USER_CONFIG[key] === 'boolean') {
mappedValue = typeof mappedValue === 'boolean' ? mappedValue : mappedValue === 'true';
}

context.USER_CONFIG[key] = mappedValue;
if (!context.USER_CONFIG.DEFINE_KEYS.includes(key)) {
// 如果设置的值为空,则使用默认值
context.USER_CONFIG[key] = mappedValue || ENV.USER_CONFIG[key];
if (!context.USER_CONFIG.DEFINE_KEYS.includes(key) && mappedValue) {
context.USER_CONFIG.DEFINE_KEYS.push(key);
} else if (!mappedValue) {
context.USER_CONFIG.DEFINE_KEYS = context.USER_CONFIG.DEFINE_KEYS.filter(k => k !== key);
}
log.info(`/set ${key} ${(JSON.stringify(mappedValue) || value).substring(0, 100)}...`);
return key;
Expand Down Expand Up @@ -665,7 +671,7 @@ export class InlineCommandHandler implements CommandHandler {
label: 'Tools',
data: 'INLINE_FUNCTION_TOOLS',
config_key: 'USE_TOOLS',
available_values: [...new Set([...Object.keys(tools), ...Object.keys(ENV.PLUGINS_FUNCTION)])],
available_values: Object.keys({ ...ENV.PLUGINS_FUNCTION, ...tools }),
},
};
};
Expand Down
31 changes: 11 additions & 20 deletions src/telegram/handler/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ENV } from '../../config/env';
import { clearLog, getLog, logSingleton } from '../../log/logDecortor';
import { log } from '../../log/logger';
import { sendToolResult } from '../../tools';
import { imageToBase64String, renderBase64DataURI } from '../../utils/image';
import { imageToBase64String } from '../../utils/image';
import { createTelegramBotAPI } from '../api';
import { escape } from '../utils/md2tgmd';
import { MessageSender, sendAction, TelegraphSender } from '../utils/send';
Expand Down Expand Up @@ -88,10 +88,10 @@ export class ChatHandler implements MessageHandler<WorkerContext> {
await workflow(context, message, params);
return null;
} catch (e) {
console.error('Error:', e);
log.error((e as Error).stack);
const sender = context.MIDDLE_CONTEXT.sender ?? MessageSender.from(context.SHARE_CONTEXT.botToken, message);
const filtered = (e as Error).message.replace(context.SHARE_CONTEXT.botToken, '[REDACTED]');
return sender.sendRichText(`<pre>Error: ${filtered.substring(0, 4000)}</pre>`, 'HTML');
return sender.sendRichText(`<pre>Error: ${filtered.substring(0, 2000)}</pre>`, 'HTML');
}
};

Expand Down Expand Up @@ -204,13 +204,13 @@ export function OnStreamHander(sender: MessageSender | ChosenInlineSender, conte
}

if (!resp.ok) {
log.error(`send message failed: ${resp.status} ${resp.statusText}`);
log.error(`send message failed: ${resp.status} ${await resp.json().then(j => j.description)}`);
sentError = true;
log.error(`send message failed: ${escape(data.split('\n'))}`);
return sentPromise = sender.sendPlainText(text);
}
} catch (e) {
console.error(e);
log.error((e as Error).stack);
}
};

Expand All @@ -235,6 +235,7 @@ export function OnStreamHander(sender: MessageSender | ChosenInlineSender, conte
}
if (sentError || !finalResp.ok) {
(sender as MessageSender).context.sentMessageIds.clear();
log.error(`send message failed: ${finalResp.status} ${await finalResp.json().then(j => j.description)}`);
return sendTelegraph(context!, sender, question || 'Redo Question', text, true);
}
return finalResp;
Expand Down Expand Up @@ -385,10 +386,8 @@ async function handleAudio(
if (isMiddle) {
const voice = await asr(resp as string, context.USER_CONFIG);
ENV.HIDE_MIDDLE_MESSAGE && sender.api.deleteMessage({ chat_id: sender.context.chat_id, message_id: sender.context.message_id! });
return sender.api.sendVoice({
chat_id: sender.context.chat_id,
voice,
});
sendAction(context.SHARE_CONTEXT.botToken, sender.context.chat_id, 'upload_voice');
return sender.sendVoice(voice);
}
return resp;
}
Expand All @@ -407,22 +406,14 @@ async function handleTextToAudio(
text = await chatWithLLM(message, params, context, null, streamSender, true) as string;
!ENV.HIDE_MIDDLE_MESSAGE && streamSender.send('Chat with LLM done');
}
const agent = new ASR();
const audio = await agent.hander(text, context.USER_CONFIG);
// const sendPromise = sender.sendPlainText('Audio generation in progress.');
// sender.update({ message_id: await sendPromise.then(r => r.json()).then(r => r.result.message_id) });
// const mediaParams: Telegram.InputMediaAudio = {
// type: 'audio',
// media: 'attach://file',
// };
const audio = await asr(text, context.USER_CONFIG);
sendAction(context.SHARE_CONTEXT.botToken, sender.context.chat_id, 'upload_voice');
const resp = await sender.sendVoice(audio, context.USER_CONFIG.AUDIO_CONTAINS_TEXT ? text : undefined);
if (resp.ok) {
return sender.api.deleteMessage({ chat_id: sender.context.chat_id, message_id: sender.context.message_id! });
}
log.error(`Failed to send voice message: ${resp.status} ${await resp.text()}`);
throw new Error(`Failed to send voice message: ${resp.status} ${resp.statusText}`);
// return sender.editMessageMedia(mediaParams, undefined, audio);
// log.error(`Failed to send voice message: ${resp.status} ${await resp.text()}`);
throw new Error(`Failed to send voice message: ${resp.status} ${await resp.json().then(j => j.description)}`);
}

export async function sendImages(img: ImageResult, SEND_IMAGE_AS_FILE: boolean, sender: MessageSender, config: AgentUserConfig) {
Expand Down
3 changes: 3 additions & 0 deletions src/telegram/handler/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ export class HandlerCallbackQuery implements CallbackQueryHandler<CallbackQueryC
}

private async checkWhiteList(message: Telegram.Message, context: CallbackQueryContext, api: TelegramBotAPI) {
if (ENV.CHAT_WHITE_LIST.includes(`${message.from?.id}`)) {
return null;
}
const roleList = COMMAND_AUTH_CHECKER.shareModeGroup(message.chat.type);
if (roleList) {
// 获取身份并判断
Expand Down
2 changes: 1 addition & 1 deletion src/telegram/handler/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class AnswerChatInlineQuery implements answerInlineQuery {
return OnStream.end?.(answer);
} catch (e) {
const filtered = (e as Error).message.replace(context.botToken, '[REDACTED]');
return OnStream.end?.(`Error: ${filtered.substring(0, 4000)}`);
return OnStream.end?.(`Error: ${filtered.substring(0, 2000)}`);
}
};

Expand Down
14 changes: 6 additions & 8 deletions src/telegram/utils/send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,12 @@ export class MessageSender {
voice,
caption,
};
if (caption) {
if (['spoiler', 'bold', 'italic', 'underline', 'strikethrough', 'code', 'pre'].includes(ENV.AUDIO_TEXT_FORMAT || '')) {
params.caption_entities = [{
type: ENV.AUDIO_TEXT_FORMAT as Telegram.MessageEntityType,
offset: 0,
length: caption!.length,
}];
}
if (caption && ['spoiler', 'bold', 'italic', 'underline', 'strikethrough', 'code', 'pre'].includes(ENV.AUDIO_TEXT_FORMAT || '')) {
params.caption_entities = [{
type: ENV.AUDIO_TEXT_FORMAT as Telegram.MessageEntityType,
offset: 0,
length: caption.length,
}];
}
if (this.context.reply_to_message_id) {
params.reply_parameters = {
Expand Down
44 changes: 44 additions & 0 deletions src/utils/others/audio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { ReadableStream as WebReadableStream } from 'node:stream/web';
import { Readable, Transform } from 'node:stream';

class Base64Encode extends Transform {
private bufferCache = '';

_transform(chunk: Buffer, encoding: string, callback: () => void) {
this.bufferCache += chunk.toString('base64');
callback();
}

_flush(callback: () => void) {
if (this.bufferCache.length) {
this.push(this.bufferCache);
}
callback();
}
}

async function streamToBase64(audioUrl: string) {
try {
const response = await fetch(audioUrl);
if (!response.ok) {
throw new Error(`Failed to download file: ${response.statusText}`);
}

return new Promise((resolve, reject) => {
const base64EncodeStream = new Base64Encode();
let base64Data = '';

base64EncodeStream.on('data', chunk => base64Data += chunk);
base64EncodeStream.on('end', () => resolve(base64Data));
base64EncodeStream.on('error', reject);

// 将 Web Stream 转换为 Node Stream
Readable.fromWeb(response.body as unknown as WebReadableStream).pipe(base64EncodeStream);
});
} catch (error) {
console.error('Error processing stream:', error);
throw error;
}
}

export { streamToBase64 };
6 changes: 3 additions & 3 deletions wrangler-example.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 这里的 name 改成你自己的workers 的名字
name = 'chatgpt-telegram-workers'
compatibility_date = '2023-10-07'
main = './dist/index.js'
compatibility_date = '2024-09-23'
main = './src/index.ts'
workers_dev = true
compatibility_flags = [ "nodejs_compat" ]

Expand Down Expand Up @@ -89,7 +89,7 @@ GROUP_CHAT_BOT_ENABLE = 'true'

## -- 通用配置 --
##
## AI提供商: auto, openai, azure, workers, gemini, mistral, cohere, anthropic
## AI提供商: auto, openai, azure, workers, gemini, mistral, cohere, anthropic, xai
AI_PROVIDER = 'auto'
## AI图片提供商: auto, openai, azure, workers
AI_IMAGE_PROVIDER = 'auto'
Expand Down
36 changes: 35 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,13 @@
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz"
integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==

"@types/fluent-ffmpeg@^2.1.27":
version "2.1.27"
resolved "https://registry.yarnpkg.com/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.27.tgz#c4eac6fbda30bb6316d2220c8faf54f48db0812d"
integrity sha512-QiDWjihpUhriISNoBi2hJBRUUmoj/BMTYcfz+F+ZM9hHWBYABFAE6hjP/TbCZC0GWwlpa3FzvHH9RzFeRusZ7A==
dependencies:
"@types/node" "*"

"@types/json-schema@^7.0.15", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9":
version "7.0.15"
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
Expand Down Expand Up @@ -1246,7 +1253,7 @@
dependencies:
"@types/node" "*"

"@types/node@*", "@types/node@^22.9.1":
"@types/node@*":
version "22.9.1"
resolved "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz"
integrity sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==
Expand All @@ -1265,6 +1272,13 @@
dependencies:
undici-types "~5.26.4"

"@types/node@^22.9.3":
version "22.9.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.3.tgz#08f3d64b3bc6d74b162d36f60213e8a6704ef2b4"
integrity sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==
dependencies:
undici-types "~6.19.8"

"@types/normalize-package-data@^2.4.0":
version "2.4.4"
resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz"
Expand Down Expand Up @@ -1899,6 +1913,11 @@ async-sema@^3.1.1:
resolved "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz"
integrity sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==

async@^0.2.9:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
integrity sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==

asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
Expand Down Expand Up @@ -3413,6 +3432,14 @@ flatted@^3.2.9:
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz"
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==

fluent-ffmpeg@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz#d6846be257777844249a4adeb320f25326d239f3"
integrity sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==
dependencies:
async "^0.2.9"
which "^1.1.1"

form-data-encoder@1.7.2:
version "1.7.2"
resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz"
Expand Down Expand Up @@ -6434,6 +6461,13 @@ whatwg-url@^5.0.0:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"

which@^1.1.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"

which@^2.0.1, which@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
Expand Down

0 comments on commit 0bcfaca

Please sign in to comment.