Spaces:
Sleeping
Sleeping
File size: 7,601 Bytes
600d58a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | from llama_index.core import VectorStoreIndex, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.google_genai import GoogleGenAI
from llama_index.llms.openai import OpenAI
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.response_synthesizers import get_response_synthesizer, ResponseMode
from llama_index.core.prompts import PromptTemplate
from llama_index.retrievers.bm25 import BM25Retriever
from llama_index.core.retrievers import QueryFusionRetriever
from sentence_transformers import CrossEncoder
import logging
logger = logging.getLogger(__name__)
def log_message(message):
logger.info(message)
print(message, flush=True)
class IndexRetriever:
def __init__(self, config):
self.config = config
self.vector_index = None
self.query_engine = None
self.reranker = None
self.current_model = config.DEFAULT_MODEL
def get_llm_model(self, model_name):
try:
model_config = self.config.AVAILABLE_MODELS.get(model_name)
if not model_config:
log_message(f"Модель {model_name} не найдена, использую модель по умолчанию")
model_config = self.config.AVAILABLE_MODELS[self.config.DEFAULT_MODEL]
if not model_config.get("api_key"):
raise Exception(f"API ключ не найден для модели {model_name}")
if model_config["provider"] == "google":
return GoogleGenAI(
model=model_config["model_name"],
api_key=model_config["api_key"]
)
elif model_config["provider"] == "openai":
return OpenAI(
model=model_config["model_name"],
api_key=model_config["api_key"]
)
else:
raise Exception(f"Неподдерживаемый провайдер: {model_config['provider']}")
except Exception as e:
log_message(f"Ошибка создания модели {model_name}: {str(e)}")
return GoogleGenAI(model="gemini-2.0-flash", api_key=self.config.GOOGLE_API_KEY)
def initialize_models(self, documents):
try:
log_message("Инициализация моделей и индекса")
embed_model = HuggingFaceEmbedding(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
llm = self.get_llm_model(self.current_model)
log_message("Инициализирую переранкер")
self.reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-12-v2')
Settings.embed_model = embed_model
Settings.llm = llm
log_message(f"Строю векторный индекс из {len(documents)} документов")
self.vector_index = VectorStoreIndex.from_documents(documents)
self.create_query_engine()
log_message(f"Модели и индекс успешно инициализированы с моделью: {self.current_model}")
return True
except Exception as e:
log_message(f"Ошибка инициализации моделей: {str(e)}")
return False
def create_query_engine(self):
try:
bm25_retriever = BM25Retriever.from_defaults(
docstore=self.vector_index.docstore,
similarity_top_k=15
)
vector_retriever = VectorIndexRetriever(
index=self.vector_index,
similarity_top_k=20,
similarity_cutoff=0.5
)
hybrid_retriever = QueryFusionRetriever(
[vector_retriever, bm25_retriever],
similarity_top_k=30,
num_queries=1
)
custom_prompt_template = PromptTemplate(self.config.CUSTOM_PROMPT)
response_synthesizer = get_response_synthesizer(
response_mode=ResponseMode.TREE_SUMMARIZE,
text_qa_template=custom_prompt_template
)
self.query_engine = RetrieverQueryEngine(
retriever=hybrid_retriever,
response_synthesizer=response_synthesizer
)
log_message("Query engine успешно создан")
except Exception as e:
log_message(f"Ошибка создания query engine: {str(e)}")
raise
def switch_model(self, model_name):
try:
log_message(f"Переключение на модель: {model_name}")
new_llm = self.get_llm_model(model_name)
Settings.llm = new_llm
if self.vector_index is not None:
self.create_query_engine()
self.current_model = model_name
log_message(f"Модель успешно переключена на: {model_name}")
return f"✅ Модель переключена на: {model_name}"
else:
return "❌ Ошибка: система не инициализирована"
except Exception as e:
error_msg = f"Ошибка переключения модели: {str(e)}"
log_message(error_msg)
return f"❌ {error_msg}"
def rerank_nodes(self, query, nodes, top_k=10):
if not nodes or not self.reranker:
return nodes[:top_k]
try:
log_message(f"Переранжирую {len(nodes)} узлов")
pairs = []
for node in nodes:
pairs.append([query, node.text])
scores = self.reranker.predict(pairs)
scored_nodes = list(zip(nodes, scores))
scored_nodes.sort(key=lambda x: x[1], reverse=True)
reranked_nodes = [node for node, score in scored_nodes[:top_k]]
log_message(f"Возвращаю топ-{len(reranked_nodes)} переранжированных узлов")
return reranked_nodes
except Exception as e:
log_message(f"Ошибка переранжировки: {str(e)}")
return nodes[:top_k]
def retrieve_nodes(self, question):
if self.query_engine is None:
return []
try:
log_message(f"Извлекаю релевантные узлы для вопроса: {question}")
retrieved_nodes = self.query_engine.retriever.retrieve(question)
log_message(f"Извлечено {len(retrieved_nodes)} узлов")
log_message("Применяю переранжировку")
reranked_nodes = self.rerank_nodes(question, retrieved_nodes, top_k=10)
return reranked_nodes
except Exception as e:
log_message(f"Ошибка извлечения узлов: {str(e)}")
return []
def get_current_model(self):
return self.current_model
def is_initialized(self):
return self.query_engine is not None |