import asyncio from io import BytesIO from redis.asyncio.client import Redis from aiogram import Router, F from aiogram.fsm.context import FSMContext from aiogram.types import Message, CallbackQuery, BufferedInputFile from aiogram.filters import Command, CommandStart, StateFilter from aiogram_dialog import DialogManager, StartMode from fluentogram import TranslatorHub from database.repositories.user import UserRepository from database.repositories.utils import UtilsRepository from database.models import User import bot.keyboards.inline as inline_kb from bot.states.states import Menu, Settings, Knowledge, Wallet, Input, Balance from bot.utils.send_answer import process_after_photo, process_after_text from bot.utils.funcs_gpt import transcribe_audio, add_file_to_memory from config import TYPE_USAGE, ADMIN_ID, ADMINS_LIST from bot.utils.check_payment import check_payment_sol, check_payment_ton router = Router() DICT_FORMATS = { "doc": "application/msword", "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "md": "text/markdown", "pdf": "application/pdf", "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", 'txt': 'text/plain', 'py': 'text/x-python' } @router.message(CommandStart()) async def start(message: Message, user_repo: UserRepository, state: FSMContext, user: User, i18n): await state.clear() await message.answer(text=i18n.get('start_text'), reply_markup=inline_kb.close_text(i18n.get('close_kb'))) @router.callback_query(F.data.startswith('select_language_')) async def select_language(callback: CallbackQuery, user_repo: UserRepository, user: User, i18n, _translator_hub: TranslatorHub): lang = callback.data.split('_')[2] translator = _translator_hub.get_translator_by_locale(lang) await user_repo.update(user, language=lang) await callback.message.edit_text(text=translator.get('start_text'), reply_markup=inline_kb.close_text(translator.get('close_kb'))) @router.message(Command('help')) async def cmd_help(message: Message, state: FSMContext, i18n): await state.clear() await message.answer(text=i18n.get('cmd_help_text'), reply_markup=inline_kb.close_text(i18n.get('close_kb'))) @router.callback_query(F.data == 'close') async def close(callback: CallbackQuery, utils_repo: UtilsRepository, state: FSMContext, i18n): await state.clear() await callback.message.delete() @router.message(Command('settings')) async def cmd_settings(message: Message, dialog_manager: DialogManager, state: FSMContext): await state.clear() await dialog_manager.start(state=Settings.main, mode=StartMode.RESET_STACK) @router.message(Command('new')) async def cmd_new(message: Message, dialog_manager: DialogManager, state: FSMContext): await state.clear() await dialog_manager.start(state=Menu.new, mode=StartMode.RESET_STACK) @router.message(Command('save')) async def cmd_save(message: Message, state: FSMContext, dialog_manager: DialogManager): await state.clear() await dialog_manager.start(state=Menu.save, mode=StartMode.RESET_STACK) @router.message(Command('delete')) async def cmd_delete(message: Message, state: FSMContext, dialog_manager: DialogManager): await state.clear() await dialog_manager.start(state=Menu.delete, mode=StartMode.RESET_STACK) @router.message(Command('balance')) async def cmd_settings(message: Message, dialog_manager: DialogManager, state: FSMContext): await state.clear() await dialog_manager.start(state=Balance.main, mode=StartMode.RESET_STACK) @router.message(F.text, StateFilter(None)) async def text_input(message: Message, user_repo: UserRepository, utils_repo: UtilsRepository, redis: Redis, user: User, i18n, mcp_server, scheduler): if await redis.get(f'request_{message.from_user.id}'): return if TYPE_USAGE == 'private': if message.from_user.id != ADMIN_ID and message.from_user.id not in ADMINS_LIST: return else: if user.balance_credits <= 0: return await message.answer(i18n.get('warning_text_no_credits')) await redis.set(f'request_{message.from_user.id}', 't', ex=40) mess_to_delete = await message.answer(text=i18n.get('wait_answer_text')) task = asyncio.create_task(process_after_text(message=message, user=user, user_repo=user_repo, utils_repo=utils_repo, redis=redis, i18n=i18n, mess_to_delete=mess_to_delete, mcp_server_1=mcp_server, scheduler=scheduler)) @router.message(F.photo, StateFilter(None)) async def photo_input(message: Message, user_repo: UserRepository, utils_repo: UserRepository, redis: Redis, user: User, i18n, mcp_server, scheduler): if await redis.get(f'request_{message.from_user.id}'): return if TYPE_USAGE == 'private': if message.from_user.id != ADMIN_ID and message.from_user.id not in ADMINS_LIST: return else: if user.balance_credits <= 0: return await message.answer(i18n.get('warning_text_no_credits')) await redis.set(f'request_{message.from_user.id}', 't', ex=40) mess_to_delete = await message.answer(text=i18n.get('wait_answer_text')) task = asyncio.create_task(process_after_photo(message=message, user=user, user_repo=user_repo, utils_repo=utils_repo, redis=redis, i18n=i18n, mess_to_delete=mess_to_delete, mcp_server_1=mcp_server, scheduler=scheduler)) @router.message(F.voice, StateFilter(None)) async def input_voice(message: Message, user_repo: UserRepository, utils_repo: UserRepository, redis: Redis, user: User, i18n, mcp_server, scheduler): if await redis.get(f'request_{message.from_user.id}'): return if TYPE_USAGE == 'private': if message.from_user.id != ADMIN_ID and message.from_user.id not in ADMINS_LIST: return else: if user.balance_credits <= 0: return await message.answer(i18n.get('warning_text_no_credits')) await redis.set(f'request_{message.from_user.id}', 't', ex=40) mess_to_delete = await message.answer(text=i18n.get('wait_answer_text')) voice_id = message.voice.file_id file_path = await message.bot.get_file(file_id=voice_id) file_bytes = (await message.bot.download_file(file_path.file_path)).read() try: text_from_voice = await transcribe_audio(bytes_audio=file_bytes) except Exception as e: await message.answer(text=i18n.get('warning_text_error')) await redis.delete(f'request_{message.from_user.id}') return await mess_to_delete.delete() task = asyncio.create_task( process_after_text(message=message, user=user, user_repo=user_repo, utils_repo=utils_repo, redis=redis, i18n=i18n, mess_to_delete=mess_to_delete, text_from_voice=text_from_voice, mcp_server_1=mcp_server, scheduler=scheduler)) @router.message(F.document, StateFilter(None)) async def input_document(message: Message, user_repo: UserRepository, utils_repo: UserRepository, redis: Redis, user: User, i18n, mcp_server, scheduler): if await redis.get(f'request_{message.from_user.id}'): return if TYPE_USAGE == 'private': if message.from_user.id != ADMIN_ID and message.from_user.id not in ADMINS_LIST: return else: if user.balance_credits <= 0: return await message.answer(i18n.get('warning_text_no_credits')) format_doc = message.document.file_name.split('.')[-1] if format_doc not in DICT_FORMATS: return await message.answer(i18n.get('warning_text_format')) await redis.set(f'request_{message.from_user.id}', 't', ex=40) mess_to_delete = await message.answer(text=i18n.get('wait_answer_text')) file_id = message.document.file_id file_path = await message.bot.get_file(file_id=file_id) file_bytes = (await message.bot.download_file(file_path.file_path)).read() try: await add_file_to_memory(user_repo=user_repo, user=user, file_name=message.document.file_name, file_bytes=file_bytes, mem_type=DICT_FORMATS.get(format_doc)) task = asyncio.create_task( process_after_text(message=message, user=user, user_repo=user_repo, utils_repo=utils_repo, redis=redis, i18n=i18n, mess_to_delete=mess_to_delete, mcp_server_1=mcp_server, constant_text=i18n.get('text_user_upload_file', filename=message.document.file_name), scheduler=scheduler) ) except Exception as e: await message.answer(i18n.get('warning_text_error')) await redis.delete(f'request_{message.from_user.id}') await mess_to_delete.delete() @router.callback_query(F.data.startswith('check_payment_')) async def check_payment(callback: CallbackQuery, user_repo: UserRepository, utils_repo: UtilsRepository, user: User, solana_client, i18n): id_payment = int(callback.data.split('_')[-1]) await callback.answer('') payment = await utils_repo.get_payment(payment_id=id_payment) message = await callback.message.answer(text=i18n.get('wait_check_payment_text')) try: if payment.crypto_currency == 'SOL': is_check = await check_payment_sol(amount=payment.crypto_amount, client=solana_client) else: is_check = await check_payment_ton(amount=payment.crypto_amount) if is_check: await user_repo.add_user_credits(user_id=user.telegram_id, balance_credits=payment.amount_usd * 1000) await utils_repo.update_payment_status(payment_id=payment.id, status='confirmed') await callback.message.delete() return await message.edit_text(text=i18n.get('check_payment_success_text')) except Exception as e: print(e) pass await message.edit_text(text=i18n.get('check_payment_error_text')) @router.callback_query(F.data.startswith('markdown_')) async def md_answer(callback: CallbackQuery, user_repo: UserRepository, user: User, i18n, bot): row_id = int(callback.data.split('_')[-1]) row = await user_repo.get_row_for_md(row_id=row_id) if not row: return await callback.answer(i18n.get('warning_text_no_row_md'), show_alert=True) bio = BytesIO() bio.write(row.content.encode("utf-8")) bio.seek(0) await callback.bot.send_document( chat_id=callback.from_user.id, document=BufferedInputFile(bio.read(), filename=f'{row.id}.md') ) bio.close()