import io import logging import traceback from aiogram.filters import Command from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.types import * from aiogram import Router, F, Bot from models.Asset import Asset, AssetType from models.Character import Character from repos.dao import DAO router = Router() class States(StatesGroup): char_wait_name = State() char_wait_bio = State() @router.message(F.document, Command("add_char")) async def add_char(message: Message, state: FSMContext, dao: DAO): if not message.document.mime_type.startswith("image/"): await message.answer("❌ Пожалуйста, отправьте файл изображения (png/jpg).") return await state.set_data({"photo": message.document.file_id}) await state.set_state(States.char_wait_name) await message.answer("Кайф, теперь напиши ее имя") @router.message(States.char_wait_name) async def new_char_name(message: Message, state: FSMContext, dao: DAO): data = await state.get_data() data["name"] = message.text await state.set_data(data) await state.set_state(States.char_wait_bio) await message.answer("А теперь напиши био. Хоть чуть чуть.") # 3. Хендлер био (Финал) @router.message(States.char_wait_bio, F.text) async def new_char_bio(message: Message, state: FSMContext, dao: DAO, bot: Bot): # Получаем все накопленные данные data = await state.get_data() file_id = data["photo"] name = data["name"] bio = message.text wait_msg = await message.answer("💾 Сохраняю персонажа...") try: # ВОТ ТУТ скачиваем файл (прямо перед сохранением) file_io = await bot.download(file_id) # photo_bytes = file_io.getvalue() # Получаем байты # Создаем модель char = Character( id=None, name=name, character_image_data=file_io.read(), character_image_tg_id=None, character_image_doc_tg_id=file_id, character_bio=bio ) file_io.close() # Сохраняем через DAO await dao.chars.add_character(char) file_info = await bot.get_file(char.character_image_doc_tg_id) file_bytes = await bot.download_file(file_info.file_path) file_io = file_bytes.read() avatar_asset = await dao.assets.create_asset( Asset(name="avatar.png", type=AssetType.IMAGE, linked_char_id=str(char.id), data=file_io, tg_doc_file_id=file_id)) char.avatar_image = avatar_asset.link # Отправляем подтверждение # Используем байты для отправки обратно photo_msg = await message.answer_photo( photo=BufferedInputFile(file_io, filename="char.jpg") if not char.character_image_tg_id else char.character_image_tg_id, caption=( "🎉 Персонаж создан!\n\n" f"👤 Имя: {char.name}\n" f"📝 Био: {char.character_bio}" ) ) file_bytes.close() char.character_image_tg_id = photo_msg.photo[0].file_id await dao.chars.update_char(char.id, char) await wait_msg.delete() # Сбрасываем состояние await state.clear() except Exception as e: logging.error(e) await wait_msg.edit_text(f"❌ Ошибка при сохранении: {e}") # Не сбрасываем стейт, даем возможность попробовать ввести био снова или начать заново @router.message(Command("chars")) async def get_chars(message: Message, state: FSMContext, dao: DAO): wait_msg = await message.answer("Ищем персонажей") chars = await dao.chars.get_all_characters() keyboards = [] if len(chars) > 0: for char in chars: keyboards.append(InlineKeyboardButton(text=char.name, callback_data=f'char_info_{char.id}')) keyboard = InlineKeyboardMarkup(inline_keyboard=[keyboards]) else: keyboard = InlineKeyboardMarkup( inline_keyboard=[[InlineKeyboardButton(text="Персонажей нет", callback_data=f'no_chars')]]) await message.answer("Сейчас есть такие персонажи:", reply_markup=keyboard) await wait_msg.delete() @router.callback_query(F.data.startswith("char_info_")) async def get_char_info(callback_query: CallbackQuery, state: FSMContext, dao: DAO, bot: Bot): await callback_query.message.delete() wait_msg = await callback_query.message.answer("Ищем инфу о персонаже") char = await dao.chars.get_character(callback_query.data.split("_")[-1]) if char is None: await callback_query.message.answer("Информация о персонаже не найдена") await get_chars(callback_query.message, state, dao) await wait_msg.delete() return keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text="Запросить фото в документе", callback_data=f'char_photo_file_{char.id}')]]) photo_msg = await callback_query.message.answer_photo( photo=char.character_image_tg_id, caption=f"👤 Имя: {char.name}\n" f"📝 Био: {char.character_bio}", reply_markup=keyboard) await wait_msg.delete() @router.callback_query(F.data.startswith("char_photo_file")) async def get_char_info_photo_file(callback_query: CallbackQuery, state: FSMContext, dao: DAO): char = await dao.chars.get_character(callback_query.data.split("_")[-1]) await callback_query.message.answer_document(char.character_image_doc_tg_id) # 4. Хендлер-помощник (если отправили команду без файла) @router.message(Command("add_char")) async def add_char_help(message: Message): await message.answer( "ℹ️ **Как добавить персонажа:**\n" "Прикрепите фото (файлом/документом) и добавьте в подпись команду `/add_char`." )