Как изменить код так, чтобы бот отправлял сообщение с функцией <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, )