From cd28ba0fbd9921302d36b1930bdca7763e5954a2 Mon Sep 17 00:00:00 2001 From: polina Date: Mon, 22 Dec 2025 08:26:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=B1=D0=BE=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tg_bot/infrastructure/telegram/__init__.py | 0 tg_bot/infrastructure/telegram/bot.py | 51 ++++++++++++ .../telegram/handlers/__init__.py | 0 .../telegram/handlers/help_handler.py | 82 +++++++++++++++++++ .../telegram/handlers/start_handler.py | 70 ++++++++++++++++ .../telegram/handlers/stats_handler.py | 65 +++++++++++++++ tg_bot/main.py | 43 ++++++++++ 7 files changed, 311 insertions(+) create mode 100644 tg_bot/infrastructure/telegram/__init__.py create mode 100644 tg_bot/infrastructure/telegram/bot.py create mode 100644 tg_bot/infrastructure/telegram/handlers/__init__.py create mode 100644 tg_bot/infrastructure/telegram/handlers/help_handler.py create mode 100644 tg_bot/infrastructure/telegram/handlers/start_handler.py create mode 100644 tg_bot/infrastructure/telegram/handlers/stats_handler.py create mode 100644 tg_bot/main.py diff --git a/tg_bot/infrastructure/telegram/__init__.py b/tg_bot/infrastructure/telegram/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tg_bot/infrastructure/telegram/bot.py b/tg_bot/infrastructure/telegram/bot.py new file mode 100644 index 0000000..9f7a44b --- /dev/null +++ b/tg_bot/infrastructure/telegram/bot.py @@ -0,0 +1,51 @@ +import logging +from aiogram import Bot, Dispatcher +from aiogram.enums import ParseMode +from aiogram.client.default import DefaultBotProperties + +from tg_bot.config.settings import settings +from tg_bot.infrastructure.telegram.handlers import ( + start_handler, + help_handler, + stats_handler +) + +logger = logging.getLogger(__name__) + + +async def create_bot() -> tuple[Bot, Dispatcher]: + bot = Bot( + token=settings.TELEGRAM_BOT_TOKEN, + default=DefaultBotProperties(parse_mode=ParseMode.HTML) + ) + dp = Dispatcher() + dp.include_router(start_handler.router) + dp.include_router(help_handler.router) + dp.include_router(stats_handler.router) + return bot, dp + + +async def start_bot(): + try: + bot, dp = await create_bot() + + try: + webhook_info = await bot.get_webhook_info() + if webhook_info.url: + await bot.delete_webhook(drop_pending_updates=True) + except Exception: + pass + print("=" * 50) + print("Telegram бот запускается") + print(f"Бот: @vibelawyer_bot") + print(f"Лимит: {settings.FREE_QUESTIONS_LIMIT} вопросов") + print(f"Команды: /start, /help, /buy, /stats, /mycollections, /search") + print("=" * 50) + + await dp.start_polling(bot, drop_pending_updates=True) + + except Exception as e: + logger.error(f"Ошибка запуска: {e}") + raise + finally: + await bot.session.close() \ No newline at end of file diff --git a/tg_bot/infrastructure/telegram/handlers/__init__.py b/tg_bot/infrastructure/telegram/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tg_bot/infrastructure/telegram/handlers/help_handler.py b/tg_bot/infrastructure/telegram/handlers/help_handler.py new file mode 100644 index 0000000..8a92920 --- /dev/null +++ b/tg_bot/infrastructure/telegram/handlers/help_handler.py @@ -0,0 +1,82 @@ + +from aiogram import Router, types +from aiogram.filters import Command +from aiogram.types import Message + +from tg_bot.config.settings import settings + +router = Router() + + +@router.message(Command("help")) +async def cmd_help(message: Message): + help_text = ( + f"VibeLawyerBot - помощь\n\n" + + f"Основные команды:\n" + f"• /start - начать работу с ботом\n" + f"• /help - показать это сообщение\n" + f"• /buy - купить подписку\n" + f"• /stats - статистика и лимиты\n" + f"• /mypayments - история платежей\n\n" + f"Работа с коллекциями:\n" + f"• /mycollections - показать мои коллекции документов\n" + f"• /search - поиск документов в коллекции\n\n" + + f"Как работает бот:\n" + f"1. У вас есть {settings.FREE_QUESTIONS_LIMIT} бесплатных вопросов\n" + f"2. Бот ищет ответы в ваших коллекциях документов\n" + f"3. После исчерпания лимита нужна подписка\n" + f"4. Подписка даёт неограниченный доступ\n\n" + f"О коллекциях:\n" + f"• Администратор загружает документы в коллекции\n" + f"• Вам предоставляется доступ к коллекциям\n" + f"• При задаче вопроса бот ищет ответы в ваших коллекциях\n" + f"• Используйте /mycollections для просмотра коллекций\n\n" + + f"Оплата (тестовый режим):\n" + f"• Безопасно через ЮKассу\n" + f"• Сразу после оплаты доступ открывается\n" + f"• Тестовые карты для проверки:\n" + f" Успешная оплата: 5555 5555 5555 4477\n" + f" Срок: любой будущий (напр. 12/30)\n" + f" CVV: любой 3 цифры (напр. 123)\n\n" + f" Отказ в оплате: 5555 5555 5555 4445\n" + f" Срок: любой будущий\n" + f" CVV: любой 3 цифры\n\n" + f"• Поддержка: @vibelawyer_support\n\n" + + f"Задавайте юридические вопросы, и бот поможет с ответами!" + ) + + await message.answer(help_text, parse_mode="HTML") + + +@router.message(Command("testcards")) +async def cmd_testcards(message: Message): + testcards_text = ( + f"Тестовые банковские карты для оплаты\n\n" + + f"Для тестирования оплаты используйте:\n\n" + + f"Карта для успешной оплаты:\n" + f"• Номер: 5555 5555 5555 4477\n" + f"• Срок действия: ЛЮБОЙ будущий (например: 12/30)\n" + f"• CVV код: ЛЮБЫЕ 3 цифры (например: 123)\n" + f"• Результат: Оплата пройдёт успешно\n\n" + + f"Карта для отказа в оплате:\n" + f"• Номер: 5555 5555 5555 4445\n" + f"• Срок действия: ЛЮБОЙ будущий\n" + f"• CVV код: ЛЮБЫЕ 3 цифры\n" + f"• Результат: Оплата будет отклонена\n\n" + + f"Важно:\n" + f"• Это тестовые карты, реальные деньги не списываются\n" + f"• Используются только для проверки работы оплаты\n" + f"• После успешной тестовой оплаты premium активируется\n\n" + + f"Для оплаты подписки используйте команду /buy" + ) + + await message.answer(testcards_text, parse_mode="HTML") diff --git a/tg_bot/infrastructure/telegram/handlers/start_handler.py b/tg_bot/infrastructure/telegram/handlers/start_handler.py new file mode 100644 index 0000000..71be4c8 --- /dev/null +++ b/tg_bot/infrastructure/telegram/handlers/start_handler.py @@ -0,0 +1,70 @@ +from aiogram import Router, types +from aiogram.filters import Command +from aiogram.types import Message +from datetime import datetime + +from tg_bot.config.settings import settings +from tg_bot.infrastructure.database.database import SessionLocal +from tg_bot.infrastructure.database.models import UserModel + +router = Router() + +@router.message(Command("start")) +async def cmd_start(message: Message): + + user_id = message.from_user.id + username = message.from_user.username or "" + first_name = message.from_user.first_name or "" + last_name = message.from_user.last_name or "" + session = SessionLocal() + try: + user = session.query(UserModel).filter_by( + telegram_id=str(user_id) + ).first() + + if not user: + user = UserModel( + telegram_id=str(user_id), + username=username, + first_name=first_name, + last_name=last_name + ) + session.add(user) + session.commit() + print(f"Новый пользователь: {user_id}") + else: + user.username = username + user.first_name = first_name + user.last_name = last_name + session.commit() + + except Exception as e: + print(f"Ошибка сохранения пользователя: {e}") + session.rollback() + finally: + session.close() + welcome_text = ( + f"Привет, {first_name}!\n\n" + f"Я VibeLawyerBot - ваш помощник в юридических вопросах.\n\n" + + f"Как я работаю:\n" + f"1. Администратор загружает документы в коллекции\n" + f"2. Вы задаёте вопрос на любую юридическую тему\n" + f"3. Я ищу ответы в ваших коллекциях документов\n" + f"4. Даю развернутый ответ на основе найденных документов\n" + f"5. Первые {settings.FREE_QUESTIONS_LIMIT} вопросов - бесплатно\n" + f"6. Для продолжения нужна подписка (/buy)\n\n" + + f"Основные команды:\n" + f"• /help - подробная помощь\n" + f"• /buy - купить подписку\n" + f"• /stats - ваша статистика\n" + f"• /mypayments - история платежей\n" + f"• /mycollections - мои коллекции документов\n" + f"• /search - поиск в коллекции\n\n" + + f"Готовы начать? Просто напишите ваш вопрос!\n\n" + f"Для получения полного доступа используйте /buy" + ) + + await message.answer(welcome_text, parse_mode="HTML") diff --git a/tg_bot/infrastructure/telegram/handlers/stats_handler.py b/tg_bot/infrastructure/telegram/handlers/stats_handler.py new file mode 100644 index 0000000..3ce7534 --- /dev/null +++ b/tg_bot/infrastructure/telegram/handlers/stats_handler.py @@ -0,0 +1,65 @@ + +from aiogram import Router, types +from aiogram.filters import Command +from aiogram.types import Message + +from tg_bot.config.settings import settings +from tg_bot.infrastructure.database.database import SessionLocal +from tg_bot.infrastructure.database.models import UserModel + +router = Router() + + +@router.message(Command("stats")) +async def cmd_stats(message: Message): + user_id = message.from_user.id + + session = SessionLocal() + try: + user = session.query(UserModel).filter_by( + telegram_id=str(user_id) + ).first() + + if user: + stats_text = ( + f"Ваша статистика\n\n" + f"Основное:\n" + f"• ID: {user_id}\n" + f"• Premium: {'Да' if user.is_premium else 'Нет'}\n" + f"• Вопросов использовано: {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n\n" + ) + + if user.is_premium: + stats_text += ( + f"Premium статус:\n" + f"• Активен до: {user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}\n" + f"• Лимит вопросов: безлимитно\n\n" + ) + else: + remaining = max(0, settings.FREE_QUESTIONS_LIMIT - user.questions_used) + stats_text += ( + f"Бесплатный доступ:\n" + f"• Осталось вопросов: {remaining}\n" + f"• Для безлимита: /buy\n\n" + ) + + else: + stats_text = ( + f"Добро пожаловать!\n\n" + f"Вы новый пользователь.\n" + f"• Ваш ID: {user_id}\n" + f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n" + f"• Для начала работы просто задайте вопрос!\n\n" + f"Используйте /buy для получения полного доступа" + ) + + await message.answer(stats_text, parse_mode="HTML") + + except Exception as e: + await message.answer( + f"Ошибка получения статистики\n\n" + f"Попробуйте позже.", + parse_mode="HTML" + ) + finally: + session.close() diff --git a/tg_bot/main.py b/tg_bot/main.py new file mode 100644 index 0000000..fa162e7 --- /dev/null +++ b/tg_bot/main.py @@ -0,0 +1,43 @@ +import asyncio +import logging +import sys +import os + +current_dir = os.path.dirname(os.path.abspath(__file__)) +parent_dir = os.path.dirname(current_dir) +sys.path.insert(0, parent_dir) + +from tg_bot.config.settings import settings + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(settings.LOG_FILE), + logging.StreamHandler() + ] +) +logger = logging.getLogger("vibelawyer_bot") + + +async def main(): + logger.info("=" * 50) + logger.info(f"Запуск {settings.APP_NAME} v{settings.VERSION}") + logger.info(f"Режим: {'РАЗРАБОТКА' if settings.DEBUG else 'ПРОДАКШН'}") + logger.info(f"Лимит вопросов: {settings.FREE_QUESTIONS_LIMIT}") + logger.info("=" * 50) + + try: + from tg_bot.infrastructure.telegram.bot import start_bot + await start_bot() + + except KeyboardInterrupt: + logger.info("Бот остановлен пользователем") + print("\nБот остановлен") + except Exception as e: + logger.error(f"Ошибка запуска: {e}") + print(f"Ошибка запуска: {e}") + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file