From 34938f05885eeb24b7ba52fea6d7004f53d4224e Mon Sep 17 00:00:00 2001 From: JianMiau Date: Wed, 26 Aug 2026 11:50:17 +0800 Subject: [PATCH] =?UTF-8?q?0.2.7=EF=BC=9A=E5=9B=9E=E8=A6=86=E5=88=A5?= =?UTF-8?q?=E4=BA=BA=E5=82=B3=E7=9A=84=E6=AA=94=E6=A1=88=EF=BC=8F=E5=9C=96?= =?UTF-8?q?=E7=89=87=E5=86=8D=20tag=20bot=EF=BC=8C=E4=B9=9F=E6=9C=83?= =?UTF-8?q?=E8=AE=80=E5=88=B0=E9=82=A3=E5=80=8B=E9=99=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- README.md | 2 +- package.json | 2 +- src/bot.js | 23 ++++++++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index db20e8d..f7bdf2f 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ telegram-bot web 前景執行控制台(除錯用) - **私訊**:任何訊息都回應;**群組**:只回應 `@bot` 或回覆 bot 訊息的情況;訊息同時 tag 多個 bot 時只有第一個回應 - **引用**:回覆/圈選引用某則訊息再 tag bot,引用內容會一起送給 AI;只引用不打字就直接把引用當輸入 -- **附件**:圖片、PDF、文字/程式碼檔都會下載給 AI 讀(Telegram Bot 下載上限 20MB;docx/xlsx/zip 等二進位不支援,bot 會回覆說明) +- **附件**:圖片、PDF、文字/程式碼檔都會下載給 AI 讀(Telegram Bot 下載上限 20MB;docx/xlsx/zip 等二進位不支援,bot 會回覆說明);「回覆別人傳的檔案/圖片再 tag bot」也會讀到那個附件(回覆另一隻 bot 傳的檔案除外,Telegram 不給) - **bot 接力**:Telegram 不讓 bot 看到其他 bot 的訊息,所以「回覆 A bot 的回覆 + tag B bot(不打字)」時,B 會改拿同聊天室最近一則我們自家 bot 的發言當輸入(6 小時內) - 對話記憶用到 80% 上下文時自動開新會話(回覆會標示),避免越用越慢 diff --git a/package.json b/package.json index 407151b..fe87552 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "telegram-bot", - "version": "0.2.6", + "version": "0.2.7", "description": "Telegram bot powered by your local AI CLI (OpenAI Codex or Claude Code) — zero-dependency, pm2-managed, with a web console to manage multiple bots", "license": "MIT", "type": "commonjs", diff --git a/src/bot.js b/src/bot.js index 59d5e0b..c9c2ad3 100644 --- a/src/bot.js +++ b/src/bot.js @@ -305,7 +305,7 @@ function startBot(config) { '/status — 查看會話與設定', '/help — 顯示這則說明', '', - '群組中要 @我 或回覆我的訊息才會觸發。可以直接傳圖片(附文字說明)。', + '群組中要 @我 或回覆我的訊息才會觸發。可以直接傳圖片/檔案(附文字說明),或回覆別人傳的檔案再 @我。', ].join('\n'); // 會話 key:獨立模式用 chat id,共用模式所有聊天室用同一把 @@ -320,7 +320,13 @@ function startBot(config) { const chatId = message.chat.id; const sessionKey = sessionKeyOf(chatId); const text = message.text || message.caption || ''; - const attachment = pickAttachment(message); + // 附件:自己這則沒有的話,退而看被回覆的那則(「別人傳檔案 → 回覆它並 tag 我」) + let attachment = pickAttachment(message); + let attachmentFromReply = false; + if (!attachment && message.reply_to_message) { + attachment = pickAttachment(message.reply_to_message); + attachmentFromReply = !!attachment; + } const photo = attachment; // 有任何附件都視同有內容 if (!text && !photo) return; if (!shouldRespond(message)) return; @@ -388,24 +394,31 @@ function startBot(config) { if (attachment) { const meta = [attachment.name && `原檔名 ${attachment.name}`, attachment.mime, attachment.size && `${Math.round(attachment.size / 1024)}KB`] .filter(Boolean).join(','); + const label = attachmentFromReply ? '被回覆訊息的附件' : '附件'; if (attachment.kind === 'unsupported') { - attachmentNote = `\n\n【附件】(${meta})格式不支援(docx/xlsx/zip 等二進位讀不了),回覆時告知使用者,建議貼成文字或轉 PDF`; + attachmentNote = `\n\n【${label}】(${meta})格式不支援(docx/xlsx/zip 等二進位讀不了),回覆時告知使用者,建議貼成文字或轉 PDF`; } else if (attachment.size > TELEGRAM_GETFILE_LIMIT) { - attachmentNote = `\n\n【附件】(${meta})超過 Telegram Bot 下載上限 20MB 無法讀取,回覆時告知使用者`; + attachmentNote = `\n\n【${label}】(${meta})超過 Telegram Bot 下載上限 20MB 無法讀取,回覆時告知使用者`; } else { cleanTmp(); const dest = path.join(config.tmpDir, `${Date.now()}-${attachment.uniqueId}${attachment.ext}`); await t.downloadFile(attachment.fileId, dest); if (attachment.kind === 'image') { images.push(dest); + if (attachmentFromReply) attachmentNote = '\n\n【附圖是使用者回覆的那則訊息裡的圖片】'; } else { files.push(dest); - attachmentNote = `\n\n【附件檔案】${meta ? `(${meta})` : ''}請先用讀檔工具讀取再處理:\n${dest}`; + attachmentNote = `\n\n【${label}檔案】${meta ? `(${meta})` : ''}請先用讀檔工具讀取再處理:\n${dest}`; } } } let fallback = files.length ? '(使用者只傳了檔案,請讀取後依上下文處理)' : '(使用者只傳了圖片,請描述並依上下文處理)'; + if (attachmentFromReply) { + fallback = files.length + ? '(使用者沒打字,只回覆了一則帶檔案的訊息並 tag 我:請讀取該檔案後依上下文處理)' + : '(使用者沒打字,只回覆了一則帶圖片的訊息並 tag 我:請描述該圖片並依上下文處理)'; + } if (quotedOnly && (quoted || !sibling)) { fallback = '(使用者沒有輸入文字,只引用了上面的內容並 tag 我:請直接把引用內容當作這次的輸入來處理)'; } else if (quotedOnly && sibling) {