Как изменить код так, чтобы бот отправлял сообщение с функцией <b>hadnle_text</b> только один раз, даже если пользователь загрузит несколько фотографий, и при этом сохранял возможность выбирать один из двух вариантов ответа?
Проблема, с которой вы сталкиваетесь, связана с тем, что бот не может корректно обрабатывать несколько сообщений в одном состоянии FSM (Finite State Machine). Когда пользователь отправляет несколько фото, обработчик срабатывает для последнего фото, и предыдущие фото игнорируются. Если вы хотите, чтобы функция `handle_text` срабатывала только один раз при загрузке фотографии, и при этом оставалась возможность выбора между двумя вариантами ответа, вам необходимо использовать подход с временным состоянием или флагом, который будет следить за тем, было ли уже обработано фото. Вот пример того, как можно изменить вашу логику: ```python from aiogram import Bot, Dispatcher, types from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.dispatcher import FSMContext from aiogram.dispatcher import State, StatesGroup from aiogram.utils import executor API_TOKEN = 'YOUR_API_TOKEN' # Инициализация бота и диспетчера bot = Bot(token=API_TOKEN) storage = MemoryStorage() dp = Dispatcher(bot, storage=storage) # Определяем состояния class Form(StatesGroup): waiting_for_photo = State() waiting_for_option = State() @dp.message_handler(commands='start') async def cmd_start(message: types.Message): await message.answer("Пожалуйста, загрузите фото.") await Form.waiting_for_photo.set() @dp.message_handler(content_types=['photo'], state=Form.waiting_for_photo) async def handle_photo(message: types.Message, state: FSMContext): # Сохранение информации о фото photo = message.photo[-1] # Здесь можно добавить дополнительно логику для обработки фото await state.update_data(photo_id=photo.file_id) # Отправляем сообщение с вариантами после первого фото await message.answer("Выберите один из вариантов: \n1. Вариант 1 \n2. Вариант 2") # Переходим к следующему состоянию await Form.waiting_for_option.set() @dp.message_handler(state=Form.waiting_for_option) async def handle_option(message: types.Message, state: FSMContext): user_data = await state.get_data() if message.text == '1': await message.answer("Вы выбрали первый вариант.") elif message.text == '2': await message.answer("Вы выбрали второй вариант.") else: await message.answer("Пожалуйста, выберите 1 или 2.") # Завершение состояния await state.finish() @dp.message_handler(state='*', content_types=types.ContentTypes.ANY) async def catch_all(message: types.Message): await message.answer("Я не понимаю это сообщение.") if __name__ == '__main__': executor.start_polling(dp, skip_updates=True) ``` ### Описание кода: 1. **Состояния FSM**: Мы определяем два состояния: `waiting_for_photo` и `waiting_for_option`. 2. **Обработка фотографий**: В `handle_photo` мы обрабатываем только первое фото и устанавливаем состояние ожидания ответа от пользователя. 3. **Управление состояниями**: После загрузки фотографии мы переходим к следующему состоянию и ждем выбора пользователя. 4. **Завершение FSM**: После обработки выбора мы завершаем сессию с помощью `await state.finish()`, чтобы бот готов был к новым командам. Этот подход позволит вашему боту обрабатывать только одно отправленное фото и затем перейти к выбору варианта без повторной активации состояния для фото.
Следует почитать на счет того как работает медиагруппа в ТГ, 5 фото в одном сообщении = 5 апдейтов.
Я бы ушел от FSM в сторону Callback Data Factory
# ... from aiogram.filters.callback_data import CallbackData class AnswerCallback(CallbackData, prefix='answer'): message_id: int answer_type: str @router.message(F.photo) async def photo_handle(message: Message): await hadnle_text(message) async def hadnle_text(message: Message): builder = InlineKeyboardBuilder() builder.add(InlineKeyboardButton( text="Answer 1", callback_data=AnswerCallback(message_id=message.message_id, answer_type='Answer 1').pack()), InlineKeyboardButton( text="Answer 2", callback_data=AnswerCallback(message_id=message.message_id, answer_type='Answer 2').pack()), ) # Или так # builder.button(text="Answer 1", callback_data=AnswerCallback(message_id=message.message_id, answer_type='answer 1')) # builder.button(text="Answer 2", callback_data=AnswerCallback(message_id=message.message_id, answer_type='answer 2')) await message.answer( f"<b>Выберите кнопку</b>", reply_markup=builder.as_markup() ) @router.callback_query(AnswerCallback.filter()) async def text_state_callback(callback: CallbackQuery, callback_data: AnswerCallback): await bot.send_message( chat_id=callback.message.chat.id, text=callback_data.answer_type, reply_to_message_id=callback_data.message_id, )