216 lines
9.4 KiB
Python
216 lines
9.4 KiB
Python
from aiogram import Router, types
|
||
from aiogram.types import Message
|
||
from tg_bot.config.settings import settings
|
||
from tg_bot.domain.user_service import UserService, User
|
||
from tg_bot.application.services.rag_service import RAGService
|
||
import re
|
||
|
||
|
||
router = Router()
|
||
rag_service = RAGService()
|
||
user_service = UserService()
|
||
|
||
@router.message()
|
||
async def handle_question(message: Message):
|
||
user_id = message.from_user.id
|
||
question_text = message.text.strip()
|
||
if question_text.startswith('/'):
|
||
return
|
||
|
||
try:
|
||
user = await user_service.get_user_by_telegram_id(user_id)
|
||
|
||
if not user:
|
||
user = await user_service.get_or_create_user(
|
||
user_id,
|
||
message.from_user.username or "",
|
||
message.from_user.first_name or "",
|
||
message.from_user.last_name or ""
|
||
)
|
||
|
||
if user.is_premium:
|
||
await process_premium_question(message, user, question_text)
|
||
|
||
elif user.questions_used < settings.FREE_QUESTIONS_LIMIT:
|
||
await process_free_question(message, user, question_text)
|
||
|
||
else:
|
||
await handle_limit_exceeded(message, user)
|
||
|
||
except Exception as e:
|
||
print(f"Error processing question: {e}")
|
||
await message.answer(
|
||
"Произошла ошибка. Попробуйте позже.",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
|
||
async def process_premium_question(message: Message, user: User, question_text: str):
|
||
await user_service.update_user_questions(int(user.telegram_id))
|
||
user = await user_service.get_user_by_telegram_id(int(user.telegram_id))
|
||
|
||
await message.bot.send_chat_action(message.chat.id, "typing")
|
||
|
||
try:
|
||
rag_result = await rag_service.generate_answer_with_rag(
|
||
question_text,
|
||
str(message.from_user.id)
|
||
)
|
||
|
||
answer = rag_result.get("answer", "Извините, не удалось сгенерировать ответ.")
|
||
sources = rag_result.get("sources", [])
|
||
|
||
# Беседа уже сохранена в бэкенде через API /rag/question
|
||
|
||
import re
|
||
formatted_answer = answer
|
||
formatted_answer = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', formatted_answer)
|
||
formatted_answer = re.sub(r'^(\d+)\.\s+', r'\1. ', formatted_answer, flags=re.MULTILINE)
|
||
formatted_answer = formatted_answer.replace("- ", "• ")
|
||
|
||
response = (
|
||
f"<b>Ваш вопрос:</b>\n"
|
||
f"<i>{question_text[:200]}</i>\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"💬 <b>Ответ:</b>\n\n"
|
||
f"{formatted_answer}\n\n"
|
||
)
|
||
|
||
if sources:
|
||
response += f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
response += f"📚 <b>Источники:</b>\n"
|
||
for idx, source in enumerate(sources[:5], 1):
|
||
title = source.get('title', 'Без названия')
|
||
try:
|
||
from urllib.parse import unquote
|
||
decoded = unquote(title)
|
||
if decoded != title or '%' in title:
|
||
title = decoded
|
||
except:
|
||
pass
|
||
response += f" {idx}. {title}\n"
|
||
response += "\n<i>💡 Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||
|
||
response += (
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"✨ <b>Статус:</b> Premium (вопросов безлимитно)\n"
|
||
f"📊 <b>Всего вопросов:</b> {user.questions_used}"
|
||
)
|
||
|
||
except Exception as e:
|
||
print(f"Error generating answer: {e}")
|
||
response = (
|
||
f"<b>Ваш вопрос:</b>\n"
|
||
f"<i>{question_text[:200]}</i>\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"❌ <b>Ошибка при генерации ответа.</b>\n"
|
||
f"Попробуйте позже.\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"✨ <b>Статус:</b> Premium\n"
|
||
f"📊 <b>Всего вопросов:</b> {user.questions_used}"
|
||
)
|
||
|
||
await message.answer(response, parse_mode="HTML")
|
||
|
||
|
||
async def process_free_question(message: Message, user: User, question_text: str):
|
||
await user_service.update_user_questions(int(user.telegram_id))
|
||
user = await user_service.get_user_by_telegram_id(int(user.telegram_id))
|
||
remaining = settings.FREE_QUESTIONS_LIMIT - user.questions_used
|
||
|
||
await message.bot.send_chat_action(message.chat.id, "typing")
|
||
|
||
try:
|
||
rag_result = await rag_service.generate_answer_with_rag(
|
||
question_text,
|
||
str(message.from_user.id)
|
||
)
|
||
|
||
answer = rag_result.get("answer", "Извините, не удалось сгенерировать ответ.")
|
||
sources = rag_result.get("sources", [])
|
||
|
||
# Уже все сохранили через /rag/question
|
||
|
||
formatted_answer = answer
|
||
formatted_answer = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', formatted_answer)
|
||
formatted_answer = re.sub(r'^(\d+)\.\s+', r'\1. ', formatted_answer, flags=re.MULTILINE)
|
||
formatted_answer = formatted_answer.replace("- ", "• ")
|
||
response = (
|
||
f"<b>Ваш вопрос:</b>\n"
|
||
f"<i>{question_text[:200]}</i>\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"💬 <b>Ответ:</b>\n\n"
|
||
f"{formatted_answer}\n\n"
|
||
)
|
||
|
||
if sources:
|
||
response += f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
response += f"📚 <b>Источники:</b>\n"
|
||
for idx, source in enumerate(sources[:5], 1):
|
||
title = source.get('title', 'Без названия')
|
||
try:
|
||
from urllib.parse import unquote
|
||
decoded = unquote(title)
|
||
if decoded != title or '%' in title:
|
||
title = decoded
|
||
except:
|
||
pass
|
||
response += f" {idx}. {title}\n"
|
||
response += "\n<i>💡 Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||
|
||
response += (
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"📊 <b>Статус:</b> Бесплатный доступ\n"
|
||
f"📈 <b>Использовано вопросов:</b> {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n"
|
||
f"🎯 <b>Осталось бесплатных:</b> {remaining}\n\n"
|
||
)
|
||
|
||
if remaining <= 3 and remaining > 0:
|
||
response += f"⚠️ <i>Осталось мало вопросов! Для продолжения используйте /buy</i>\n\n"
|
||
|
||
response += f"💎 <i>Для безлимитного доступа: /buy</i>"
|
||
|
||
except Exception as e:
|
||
print(f"Error generating answer: {e}")
|
||
response = (
|
||
f"<b>Ваш вопрос:</b>\n"
|
||
f"<i>{question_text[:200]}</i>\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"❌ <b>Ошибка при генерации ответа.</b>\n"
|
||
f"Попробуйте позже.\n\n"
|
||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||
f"📊 <b>Статус:</b> Бесплатный доступ\n"
|
||
f"📈 <b>Использовано вопросов:</b> {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n"
|
||
f"🎯 <b>Осталось бесплатных:</b> {remaining}\n\n"
|
||
f"💎 <i>Для безлимитного доступа: /buy</i>"
|
||
)
|
||
|
||
await message.answer(response, parse_mode="HTML")
|
||
|
||
|
||
#Сново сохраняется в /rag/question
|
||
|
||
|
||
async def handle_limit_exceeded(message: Message, user: User):
|
||
response = (
|
||
f"<b>Лимит бесплатных вопросов исчерпан!</b>\n\n"
|
||
|
||
f"<b>Ваша статистика:</b>\n"
|
||
f"• Использовано вопросов: {user.questions_used}\n"
|
||
f"• Бесплатный лимит: {settings.FREE_QUESTIONS_LIMIT}\n\n"
|
||
|
||
f"<b>Что делать дальше?</b>\n"
|
||
f"1. Купите подписку командой /buy\n"
|
||
f"2. Получите неограниченный доступ к вопросам\n"
|
||
f"3. Продолжайте использовать бот без ограничений\n\n"
|
||
|
||
f"<b>Подписка включает:</b>\n"
|
||
f"• Неограниченное количество вопросов\n"
|
||
f"• Приоритетную обработку\n"
|
||
f"• Доступ ко всем функциям\n\n"
|
||
|
||
f"<b>Нажмите /buy чтобы продолжить</b>"
|
||
)
|
||
|
||
await message.answer(response, parse_mode="HTML")
|