базовый бот
This commit is contained in:
parent
697644269e
commit
cd28ba0fbd
0
tg_bot/infrastructure/telegram/__init__.py
Normal file
0
tg_bot/infrastructure/telegram/__init__.py
Normal file
51
tg_bot/infrastructure/telegram/bot.py
Normal file
51
tg_bot/infrastructure/telegram/bot.py
Normal file
@ -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()
|
||||||
0
tg_bot/infrastructure/telegram/handlers/__init__.py
Normal file
0
tg_bot/infrastructure/telegram/handlers/__init__.py
Normal file
82
tg_bot/infrastructure/telegram/handlers/help_handler.py
Normal file
82
tg_bot/infrastructure/telegram/handlers/help_handler.py
Normal file
@ -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"<b>VibeLawyerBot - помощь</b>\n\n"
|
||||||
|
|
||||||
|
f"<b>Основные команды:</b>\n"
|
||||||
|
f"• /start - начать работу с ботом\n"
|
||||||
|
f"• /help - показать это сообщение\n"
|
||||||
|
f"• /buy - купить подписку\n"
|
||||||
|
f"• /stats - статистика и лимиты\n"
|
||||||
|
f"• /mypayments - история платежей\n\n"
|
||||||
|
f"<b>Работа с коллекциями:</b>\n"
|
||||||
|
f"• /mycollections - показать мои коллекции документов\n"
|
||||||
|
f"• /search - поиск документов в коллекции\n\n"
|
||||||
|
|
||||||
|
f"<b>Как работает бот:</b>\n"
|
||||||
|
f"1. У вас есть <b>{settings.FREE_QUESTIONS_LIMIT}</b> бесплатных вопросов\n"
|
||||||
|
f"2. Бот ищет ответы в ваших коллекциях документов\n"
|
||||||
|
f"3. После исчерпания лимита нужна подписка\n"
|
||||||
|
f"4. Подписка даёт неограниченный доступ\n\n"
|
||||||
|
f"<b>О коллекциях:</b>\n"
|
||||||
|
f"• Администратор загружает документы в коллекции\n"
|
||||||
|
f"• Вам предоставляется доступ к коллекциям\n"
|
||||||
|
f"• При задаче вопроса бот ищет ответы в ваших коллекциях\n"
|
||||||
|
f"• Используйте /mycollections для просмотра коллекций\n\n"
|
||||||
|
|
||||||
|
f"<b>Оплата (тестовый режим):</b>\n"
|
||||||
|
f"• Безопасно через ЮKассу\n"
|
||||||
|
f"• Сразу после оплаты доступ открывается\n"
|
||||||
|
f"• <b>Тестовые карты для проверки:</b>\n"
|
||||||
|
f" Успешная оплата: <code>5555 5555 5555 4477</code>\n"
|
||||||
|
f" Срок: <b>любой будущий</b> (напр. 12/30)\n"
|
||||||
|
f" CVV: <b>любой 3 цифры</b> (напр. 123)\n\n"
|
||||||
|
f" Отказ в оплате: <code>5555 5555 5555 4445</code>\n"
|
||||||
|
f" Срок: <b>любой будущий</b>\n"
|
||||||
|
f" CVV: <b>любой 3 цифры</b>\n\n"
|
||||||
|
f"• Поддержка: @vibelawyer_support\n\n"
|
||||||
|
|
||||||
|
f"<i>Задавайте юридические вопросы, и бот поможет с ответами!</i>"
|
||||||
|
)
|
||||||
|
|
||||||
|
await message.answer(help_text, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("testcards"))
|
||||||
|
async def cmd_testcards(message: Message):
|
||||||
|
testcards_text = (
|
||||||
|
f"<b>Тестовые банковские карты для оплаты</b>\n\n"
|
||||||
|
|
||||||
|
f"<b>Для тестирования оплаты используйте:</b>\n\n"
|
||||||
|
|
||||||
|
f"<b>Карта для успешной оплаты:</b>\n"
|
||||||
|
f"• Номер: <code>5555 5555 5555 4477</code>\n"
|
||||||
|
f"• Срок действия: <b>ЛЮБОЙ будущий</b> (например: 12/30)\n"
|
||||||
|
f"• CVV код: <b>ЛЮБЫЕ 3 цифры</b> (например: 123)\n"
|
||||||
|
f"• Результат: Оплата пройдёт успешно\n\n"
|
||||||
|
|
||||||
|
f"<b>Карта для отказа в оплате:</b>\n"
|
||||||
|
f"• Номер: <code>5555 5555 5555 4445</code>\n"
|
||||||
|
f"• Срок действия: <b>ЛЮБОЙ будущий</b>\n"
|
||||||
|
f"• CVV код: <b>ЛЮБЫЕ 3 цифры</b>\n"
|
||||||
|
f"• Результат: Оплата будет отклонена\n\n"
|
||||||
|
|
||||||
|
f"<b>Важно:</b>\n"
|
||||||
|
f"• Это тестовые карты, реальные деньги не списываются\n"
|
||||||
|
f"• Используются только для проверки работы оплаты\n"
|
||||||
|
f"• После успешной тестовой оплаты premium активируется\n\n"
|
||||||
|
|
||||||
|
f"Для оплаты подписки используйте команду /buy"
|
||||||
|
)
|
||||||
|
|
||||||
|
await message.answer(testcards_text, parse_mode="HTML")
|
||||||
70
tg_bot/infrastructure/telegram/handlers/start_handler.py
Normal file
70
tg_bot/infrastructure/telegram/handlers/start_handler.py
Normal file
@ -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"<b>Привет, {first_name}!</b>\n\n"
|
||||||
|
f"Я <b>VibeLawyerBot</b> - ваш помощник в юридических вопросах.\n\n"
|
||||||
|
|
||||||
|
f"<b>Как я работаю:</b>\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"<b>Основные команды:</b>\n"
|
||||||
|
f"• /help - подробная помощь\n"
|
||||||
|
f"• /buy - купить подписку\n"
|
||||||
|
f"• /stats - ваша статистика\n"
|
||||||
|
f"• /mypayments - история платежей\n"
|
||||||
|
f"• /mycollections - мои коллекции документов\n"
|
||||||
|
f"• /search - поиск в коллекции\n\n"
|
||||||
|
|
||||||
|
f"<b>Готовы начать?</b> Просто напишите ваш вопрос!\n\n"
|
||||||
|
f"<i>Для получения полного доступа используйте /buy</i>"
|
||||||
|
)
|
||||||
|
|
||||||
|
await message.answer(welcome_text, parse_mode="HTML")
|
||||||
65
tg_bot/infrastructure/telegram/handlers/stats_handler.py
Normal file
65
tg_bot/infrastructure/telegram/handlers/stats_handler.py
Normal file
@ -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"<b>Ваша статистика</b>\n\n"
|
||||||
|
f"<b>Основное:</b>\n"
|
||||||
|
f"• ID: <code>{user_id}</code>\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"<b>Premium статус:</b>\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"<b>Бесплатный доступ:</b>\n"
|
||||||
|
f"• Осталось вопросов: {remaining}\n"
|
||||||
|
f"• Для безлимита: /buy\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
stats_text = (
|
||||||
|
f"<b>Добро пожаловать!</b>\n\n"
|
||||||
|
f"Вы новый пользователь.\n"
|
||||||
|
f"• Ваш ID: <code>{user_id}</code>\n"
|
||||||
|
f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n"
|
||||||
|
f"• Для начала работы просто задайте вопрос!\n\n"
|
||||||
|
f"<i>Используйте /buy для получения полного доступа</i>"
|
||||||
|
)
|
||||||
|
|
||||||
|
await message.answer(stats_text, parse_mode="HTML")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await message.answer(
|
||||||
|
f"<b>Ошибка получения статистики</b>\n\n"
|
||||||
|
f"Попробуйте позже.",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
43
tg_bot/main.py
Normal file
43
tg_bot/main.py
Normal file
@ -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())
|
||||||
Loading…
x
Reference in New Issue
Block a user