Compare commits
2 Commits
1b550e6503
...
ef71c67683
| Author | SHA1 | Date | |
|---|---|---|---|
| ef71c67683 | |||
| 570f0b7ea7 |
@ -3,6 +3,7 @@ Use cases для работы с документами
|
||||
"""
|
||||
from uuid import UUID
|
||||
from typing import BinaryIO, Optional
|
||||
import httpx
|
||||
from src.domain.entities.document import Document
|
||||
from src.domain.repositories.document_repository import IDocumentRepository
|
||||
from src.domain.repositories.collection_repository import ICollectionRepository
|
||||
@ -10,6 +11,7 @@ from src.domain.repositories.collection_access_repository import ICollectionAcce
|
||||
from src.application.services.document_parser_service import DocumentParserService
|
||||
from src.application.services.rag_service import RAGService
|
||||
from src.shared.exceptions import NotFoundError, ForbiddenError
|
||||
from src.shared.config import settings
|
||||
|
||||
|
||||
class DocumentUseCases:
|
||||
@ -60,12 +62,34 @@ class DocumentUseCases:
|
||||
)
|
||||
return await self.document_repository.create(document)
|
||||
|
||||
async def _send_telegram_notification(self, telegram_id: str, message: str):
|
||||
"""Отправить уведомление пользователю через Telegram Bot API"""
|
||||
if not settings.TELEGRAM_BOT_TOKEN:
|
||||
return
|
||||
|
||||
try:
|
||||
url = f"https://api.telegram.org/bot{settings.TELEGRAM_BOT_TOKEN}/sendMessage"
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
response = await client.post(
|
||||
url,
|
||||
json={
|
||||
"chat_id": telegram_id,
|
||||
"text": message,
|
||||
"parse_mode": "HTML"
|
||||
}
|
||||
)
|
||||
if response.status_code != 200:
|
||||
print(f"Failed to send Telegram notification: {response.status_code}")
|
||||
except Exception as e:
|
||||
print(f"Error sending Telegram notification: {e}")
|
||||
|
||||
async def upload_and_parse_document(
|
||||
self,
|
||||
collection_id: UUID,
|
||||
file: BinaryIO,
|
||||
filename: str,
|
||||
user_id: UUID
|
||||
user_id: UUID,
|
||||
telegram_id: Optional[str] = None
|
||||
) -> Document:
|
||||
"""Загрузить и распарсить документ, затем автоматически проиндексировать"""
|
||||
collection = await self.collection_repository.get_by_id(collection_id)
|
||||
@ -86,11 +110,37 @@ class DocumentUseCases:
|
||||
)
|
||||
document = await self.document_repository.create(document)
|
||||
|
||||
if self.rag_service:
|
||||
if self.rag_service and telegram_id:
|
||||
try:
|
||||
await self.rag_service.index_document(document)
|
||||
await self._send_telegram_notification(
|
||||
telegram_id,
|
||||
"🔄 <b>Начинаю индексацию документа...</b>\n\n"
|
||||
f"📄 <b>Документ:</b> {title}\n\n"
|
||||
f"Это может занять некоторое время.\n"
|
||||
f"Вы получите уведомление по завершении."
|
||||
)
|
||||
|
||||
chunks = await self.rag_service.index_document(document)
|
||||
|
||||
await self._send_telegram_notification(
|
||||
telegram_id,
|
||||
"✅ <b>Индексация завершена!</b>\n\n"
|
||||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
f"📄 <b>Документ:</b> {title}\n"
|
||||
f"📊 <b>Проиндексировано чанков:</b> {len(chunks)}\n\n"
|
||||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
f"💡 <b>Теперь вы можете задавать вопросы по этому документу!</b>\n"
|
||||
f"Просто напишите ваш вопрос, и я найду ответ на основе загруженного документа."
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Ошибка при автоматической индексации документа {document.document_id}: {e}")
|
||||
if telegram_id:
|
||||
await self._send_telegram_notification(
|
||||
telegram_id,
|
||||
"⚠️ <b>Ошибка при индексации</b>\n\n"
|
||||
f"Документ загружен, но индексация не завершена.\n"
|
||||
f"Ошибка: {str(e)[:200]}"
|
||||
)
|
||||
|
||||
return document
|
||||
|
||||
|
||||
@ -69,7 +69,8 @@ async def upload_document(
|
||||
collection_id=collection_id,
|
||||
file=file.file,
|
||||
filename=file.filename,
|
||||
user_id=current_user.user_id
|
||||
user_id=current_user.user_id,
|
||||
telegram_id=current_user.telegram_id
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@ -360,8 +360,9 @@ async def process_upload_document(message: Message, state: FSMContext):
|
||||
|
||||
if result:
|
||||
await message.answer(
|
||||
f"<b>Документ загружен</b>\n\n"
|
||||
f"Название: <b>{result.get('title', filename)}</b>",
|
||||
f"<b>✅ Документ загружен и добавлен в коллекцию</b>\n\n"
|
||||
f"<b>Название:</b> {result.get('title', filename)}\n\n"
|
||||
f"📄 Документ сейчас индексируется. Вы получите уведомление, когда индексация завершится.\n\n",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
else:
|
||||
|
||||
@ -3,6 +3,8 @@ 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()
|
||||
@ -60,22 +62,37 @@ async def process_premium_question(message: Message, user: User, question_text:
|
||||
|
||||
# Беседа уже сохранена в бэкенде через 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"<b>Ответ:</b>\n{answer}\n\n"
|
||||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
f"💬 <b>Ответ:</b>\n\n"
|
||||
f"{formatted_answer}\n\n"
|
||||
)
|
||||
|
||||
if sources:
|
||||
response += f"<b>Источники:</b>\n"
|
||||
response += f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
response += f"📚 <b>Источники:</b>\n"
|
||||
for idx, source in enumerate(sources[:5], 1):
|
||||
title = source.get('title', 'Без названия')
|
||||
response += f"{idx}. {title}\n"
|
||||
response += "\n<i>Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||||
try:
|
||||
from urllib.parse import unquote
|
||||
title = unquote(title)
|
||||
except:
|
||||
pass
|
||||
response += f" {idx}. {title}\n"
|
||||
response += "\n<i>💡 Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||||
|
||||
response += (
|
||||
f"<b>Статус:</b> Premium (вопросов безлимитно)\n"
|
||||
f"<b>Всего вопросов:</b> {user.questions_used}"
|
||||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
f"✨ <b>Статус:</b> Premium (вопросов безлимитно)\n"
|
||||
f"📊 <b>Всего вопросов:</b> {user.questions_used}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
@ -83,9 +100,12 @@ async def process_premium_question(message: Message, user: User, question_text:
|
||||
response = (
|
||||
f"<b>Ваш вопрос:</b>\n"
|
||||
f"<i>{question_text[:200]}</i>\n\n"
|
||||
f"Ошибка при генерации ответа. Попробуйте позже.\n\n"
|
||||
f"<b>Статус:</b> Premium\n"
|
||||
f"<b>Всего вопросов:</b> {user.questions_used}"
|
||||
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")
|
||||
@ -109,40 +129,56 @@ async def process_free_question(message: Message, user: User, question_text: str
|
||||
|
||||
# Уже все сохранили через /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"<b>Ответ:</b>\n{answer}\n\n"
|
||||
f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
f"💬 <b>Ответ:</b>\n\n"
|
||||
f"{formatted_answer}\n\n"
|
||||
)
|
||||
|
||||
if sources:
|
||||
response += f"<b>Источники:</b>\n"
|
||||
response += f"━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n"
|
||||
response += f"📚 <b>Источники:</b>\n"
|
||||
for idx, source in enumerate(sources[:5], 1):
|
||||
title = source.get('title', 'Без названия')
|
||||
response += f"{idx}. {title}\n"
|
||||
response += "\n<i>Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||||
try:
|
||||
from urllib.parse import unquote
|
||||
title = unquote(title)
|
||||
except:
|
||||
pass
|
||||
response += f" {idx}. {title}\n"
|
||||
response += "\n<i>💡 Используйте /mycollections для просмотра всех коллекций</i>\n\n"
|
||||
|
||||
response += (
|
||||
f"<b>Статус:</b> Бесплатный доступ\n"
|
||||
f"<b>Использовано вопросов:</b> {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n"
|
||||
f"<b>Осталось бесплатных:</b> {remaining}\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"
|
||||
)
|
||||
|
||||
if remaining <= 3 and remaining > 0:
|
||||
response += f"<i>Осталось мало вопросов! Для продолжения используйте /buy</i>\n\n"
|
||||
response += f"⚠️ <i>Осталось мало вопросов! Для продолжения используйте /buy</i>\n\n"
|
||||
|
||||
response += f"<i>Для безлимитного доступа: /buy</i>"
|
||||
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"<b>Использовано вопросов:</b> {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n"
|
||||
f"<b>Осталось бесплатных:</b> {remaining}\n\n"
|
||||
f"<i>Для безлимитного доступа: /buy</i>"
|
||||
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")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user