python-telegram-bot中Filter.command与Filter.photo组合的消息处理器失效问题
问题描述
正在开发一款图片编辑Telegram机器人,支持通过/crop、/removebg等命令执行各类编辑功能,可接收用户的单张或多张图片并返回编辑后的结果。使用python-telegram-bot库时,发现如下定义的消息处理器无法触发:
dispatcher.add_handler(MessageHandler(Filters.command('crop') & (Filters.photo),crop))
但使用dispatcher.add_handler(MessageHandler(Filters.caption('crop') & (Filters.photo),crop))则可正常工作。然而上传多张图片时,无法给每张图片添加字幕,这在实际操作中不可行。
完整代码如下:
import requests import telegram from io import BytesIO import imgpro import os import cv2 import logging from telegram import Update from removebg import RemoveBg import cv2 import numpy as np from io import BytesIO import os import io, requests, cv2, numpy as np from telegram.ext.callbackcontext import CallbackContext from telegram.ext.messagehandler import MessageHandler from telegram.ext import ( Updater, MessageHandler, CommandHandler, CallbackQueryHandler, CallbackContext, ConversationHandler, PicklePersistence, filters) from telegram.ext.filters import Filters from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ForceReply botToken='bototken' global fileSavePath fileSavePath=".\\trial.jpeg" # Enable logging logging.basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO ) logger = logging.getLogger(__name__) ##########################FUNCTION BLOCK#################################################### def cropImage(filePath,fileSavePath): ## Crop Borders from Images based on hard coded percentage reduction ## ## Useful for removing borders from Night Wear Images with Design Numbers,etc. image = cv2.imdecode(np.frombuffer(filePath.read(), np.uint8), 1) height, width = image.shape[:2] redH=np.round(height*0.05,0) redW=np.round(width*0.11,0) y=0+int(redH) x=0+int(redW) h=height-int(redH) w=width-int(redW) crop_image = image[x:w, y:h] crop_image = image[y:h, x:w] cv2.waitKey(0) cv2.destroyAllWindows() cv2.imwrite(fileSavePath, crop_image) return('crop_image') ############################TELEGRAM BLOCK################################################### def cropb(update, context): #Function to crop borders from photos length = len(update.message.photo) print ('Photos in this message:', length) for n in range(0, length): file = context.bot.get_file(update.message.photo[n].file_id) f = BytesIO(file.download_as_bytearray()) cropImage(f,fileSavePath) update.message.reply_photo(photo=open(".\\trial.jpeg", 'rb')) def crop(update, context): #Funtion to crop borders from 1 photo file = context.bot.get_file(update.message.photo[-1].file_id) file.download('.\\trial2.jpeg') f = BytesIO(file.download_as_bytearray()) cropImage(f,fileSavePath) update.message.reply_photo(photo=open(".\\trial.jpeg", 'rb')) def main(): telegram_bot_token = botToken updater = Updater(token=telegram_bot_token, use_context=True) dispatcher = updater.dispatcher dispatcher.add_handler(MessageHandler(Filters.command('crop') & (Filters.photo),crop)) # dispatcher.add_handler(MessageHandler(Filters.photo, crop)) # dispatcher.add_handler(MessageHandler(Filters.photo, crop)) updater.start_polling() updater.idle() if __name__ == '__main__': main()
解决方案
问题根源
Telegram的消息机制中,/crop这类命令消息属于纯文本消息,而带图片的消息里,命令只能作为图片的**字幕(caption)**存在。Filters.command('crop')只能匹配纯文本的命令消息,无法匹配包含图片+字幕命令的消息,所以原处理器无法触发。
可行方案:使用对话流程处理
通过ConversationHandler先接收用户的命令,再等待用户发送图片,这种方式既支持单张也支持多张图片,无需给每张图片加字幕。
修改后的核心代码如下:
- 定义对话状态
WAITING_FOR_PHOTOS = 1
- 添加对话逻辑函数
def start_crop(update: Update, context: CallbackContext) -> int: update.message.reply_text("请发送需要裁剪的图片,支持单张或多张。") return WAITING_FOR_PHOTOS def handle_crop_photos(update: Update, context: CallbackContext) -> int: photos = update.message.photo if not photos: update.message.reply_text("请发送有效的图片!") return WAITING_FOR_PHOTOS # 批量处理所有图片 for photo in photos: file = context.bot.get_file(photo.file_id) f = BytesIO(file.download_as_bytearray()) cropImage(f, fileSavePath) update.message.reply_photo(photo=open(".\\trial.jpeg", 'rb')) update.message.reply_text("所有图片裁剪完成!") return ConversationHandler.END def cancel(update: Update, context: CallbackContext) -> int: update.message.reply_text("操作已取消。") return ConversationHandler.END
- 更新主函数中的处理器配置
def main(): telegram_bot_token = botToken updater = Updater(token=telegram_bot_token, use_context=True) dispatcher = updater.dispatcher # 添加对话处理器 conv_handler = ConversationHandler( entry_points=[CommandHandler('crop', start_crop)], states={ WAITING_FOR_PHOTOS: [MessageHandler(Filters.photo, handle_crop_photos)], }, fallbacks=[CommandHandler('cancel', cancel)], ) dispatcher.add_handler(conv_handler) updater.start_polling() updater.idle()
方案优势
- 用户只需先发送
/crop命令,再发送任意数量的图片即可完成批量处理,操作流程清晰。 - 避免了给每张图片加字幕的繁琐操作,符合实际使用场景。
内容的提问来源于stack exchange,提问作者Viraj Desai
相关产品推荐
相关产品推荐

