From 6847b7271e984bfc3998566754169980f04e2b8f Mon Sep 17 00:00:00 2001 From: Markov Andrey Date: Tue, 30 Jun 2026 08:24:50 +0000 Subject: [PATCH] Add new file --- core/rag_api.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 core/rag_api.py diff --git a/core/rag_api.py b/core/rag_api.py new file mode 100644 index 0000000..db4a1bd --- /dev/null +++ b/core/rag_api.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +""" +Единый API-интерфейс для работы с RAG-оркестратором. +Используется ботами для вызова RAG-логики без необходимости +знать внутреннее устройство оркестратора. + +Этот класс является прослойкой (facade) между ботами и RAGOrchestrator. +В будущем он может быть легко заменён на HTTP-клиент, +если оркестратор будет вынесен в отдельный сервис. + +Сейчас этот файл может использоваться для локальной работы, +но в новой архитектуре мы используем RAGClient (HTTP), +поэтому данный класс является опциональным. +""" + +import logging +from typing import Optional, Dict, List, Any + +from core.rag_orchestrator import RAGOrchestrator +from core.services.kb_service import KBService +from core.services.giga_client import GigaClient +from core.services.file_service import FileService +from core.services.postgres_service import PostgresService + +logger = logging.getLogger(__name__) + + +class RAGAPI: + """ + Единый API-интерфейс для RAG-функциональности. + Создаёт и содержит экземпляр RAGOrchestrator. + Предоставляет методы для выполнения запросов и индексации документов. + """ + + def __init__( + self, + db: PostgresService, + qdrant, + embedding, + kb: KBService, + giga: GigaClient, + files: FileService, + config, + default_prompts: Optional[Dict[str, str]] = None + ): + """ + Инициализация API. + + Аргументы: + db: сервис PostgreSQL (PostgresService) + qdrant: сервис Qdrant (QdrantService) + embedding: сервис эмбеддингов (EmbeddingService) + kb: сервис базы знаний (KBService) + giga: клиент GigaChat (GigaClient) + files: сервис файлов (FileService) + config: объект конфигурации (BotConfig) + default_prompts: словарь промптов по умолчанию. + Используется, если в запросе не переданы свои промпты. + """ + self.config = config + self.default_prompts = default_prompts or {} + + # Создаём оркестратор с переданными сервисами + self.orchestrator = RAGOrchestrator( + db=db, + qdrant=qdrant, + embedding=embedding, + kb=kb, + giga=giga, + files=files, + config=config, + default_prompts=self.default_prompts + ) + logger.info("RAGAPI инициализирован") + + async def query( + self, + query: str, + user_jid: str, + room_jid: Optional[str], + prompts: Optional[Dict[str, str]] = None, + intent_override: Optional[str] = None, + last_file_path: Optional[str] = None, + last_file_text: Optional[str] = None, + ) -> Dict[str, Any]: + """ + Выполняет RAG-запрос через оркестратор. + ИСТОРИЯ НЕ ПЕРЕДАЁТСЯ – оркестратор получает её из БД. + """ + try: + if prompts is None: + prompts = self.default_prompts.copy() + + result = await self.orchestrator.process_query( + query=query, + user_jid=user_jid, + room_jid=room_jid, + prompts=prompts, + intent_override=intent_override, + last_file_path=last_file_path, + last_file_text=last_file_text + ) + logger.debug(f"RAGAPI.query успешно выполнен для {user_jid}, intent={result.get('intent')}") + return result + except Exception as e: + logger.error(f"Ошибка в RAGAPI.query: {e}", exc_info=True) + return { + "answer": f"⚠️ Произошла ошибка при обработке запроса: {str(e)}", + "intent": "ERROR", + "context": "", + "sources": [], + "confidence": None, + "error": str(e) + } + + async def index_document( + self, + file_name: str, + file_text: str, + user_jid: str, + room_jid: Optional[str], + is_global: bool = False, + title: Optional[str] = None, + metadata: Optional[Dict] = None, + file_hash: Optional[str] = None, + update_if_exists: bool = True + ) -> Dict[str, Any]: + """Индексирует документ через оркестратор.""" + try: + result = await self.orchestrator.index_document( + file_name=file_name, + file_text=file_text, + user_jid=user_jid, + room_jid=room_jid, + is_global=is_global, + title=title, + metadata=metadata, + file_hash=file_hash, + update_if_exists=update_if_exists + ) + logger.info(f"Документ {file_name} проиндексирован, doc_id={result.get('doc_id')}") + return result + except Exception as e: + logger.error(f"Ошибка в RAGAPI.index_document: {e}", exc_info=True) + return {"doc_id": None, "chunk_count": 0, "error": str(e)} + + def close(self): + """Закрывает ресурсы (если необходимо).""" + logger.debug("RAGAPI закрывается") \ No newline at end of file