Spaces:
Sleeping
Sleeping
Commit ·
631984e
1
Parent(s): fe5790f
reranked top 15 + reranking all together
Browse files- index_retriever.py +18 -30
- utils.py +1 -89
index_retriever.py
CHANGED
|
@@ -22,12 +22,12 @@ def create_query_engine(vector_index):
|
|
| 22 |
vector_retriever = VectorIndexRetriever(
|
| 23 |
index=vector_index,
|
| 24 |
similarity_top_k=30,
|
| 25 |
-
similarity_cutoff=0.
|
| 26 |
)
|
| 27 |
|
| 28 |
hybrid_retriever = QueryFusionRetriever(
|
| 29 |
[vector_retriever, bm25_retriever],
|
| 30 |
-
similarity_top_k=
|
| 31 |
num_queries=1
|
| 32 |
)
|
| 33 |
|
|
@@ -52,37 +52,25 @@ def create_query_engine(vector_index):
|
|
| 52 |
def rerank_nodes(query, nodes, reranker, top_k=15):
|
| 53 |
if not nodes or not reranker:
|
| 54 |
return nodes[:top_k]
|
| 55 |
-
|
| 56 |
try:
|
| 57 |
log_message(f"Переранжирую {len(nodes)} узлов")
|
| 58 |
-
|
| 59 |
-
#
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
#
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
scores = reranker.predict(pairs)
|
| 73 |
-
scored_nodes = list(zip(text_nodes, scores))
|
| 74 |
-
scored_nodes.sort(key=lambda x: x[1], reverse=True)
|
| 75 |
-
reranked_text_nodes = [node for node, score in scored_nodes]
|
| 76 |
-
else:
|
| 77 |
-
reranked_text_nodes = []
|
| 78 |
-
|
| 79 |
-
# Combine: priority nodes first, then reranked text nodes
|
| 80 |
-
final_nodes = priority_nodes + reranked_text_nodes
|
| 81 |
-
result = final_nodes[:top_k]
|
| 82 |
-
|
| 83 |
-
log_message(f"Возвращаю {len(priority_nodes)} приоритетных узлов и {len(result) - len(priority_nodes)} текстовых узлов")
|
| 84 |
return result
|
| 85 |
-
|
| 86 |
except Exception as e:
|
| 87 |
log_message(f"Ошибка переранжировки: {str(e)}")
|
| 88 |
return nodes[:top_k]
|
|
|
|
| 22 |
vector_retriever = VectorIndexRetriever(
|
| 23 |
index=vector_index,
|
| 24 |
similarity_top_k=30,
|
| 25 |
+
similarity_cutoff=0.7
|
| 26 |
)
|
| 27 |
|
| 28 |
hybrid_retriever = QueryFusionRetriever(
|
| 29 |
[vector_retriever, bm25_retriever],
|
| 30 |
+
similarity_top_k=30,
|
| 31 |
num_queries=1
|
| 32 |
)
|
| 33 |
|
|
|
|
| 52 |
def rerank_nodes(query, nodes, reranker, top_k=15):
|
| 53 |
if not nodes or not reranker:
|
| 54 |
return nodes[:top_k]
|
| 55 |
+
|
| 56 |
try:
|
| 57 |
log_message(f"Переранжирую {len(nodes)} узлов")
|
| 58 |
+
|
| 59 |
+
# Prepare pairs for reranker: use node.text for all types
|
| 60 |
+
pairs = [[query, node.text] for node in nodes]
|
| 61 |
+
|
| 62 |
+
# Get scores for all nodes
|
| 63 |
+
scores = reranker.predict(pairs)
|
| 64 |
+
scored_nodes = list(zip(nodes, scores))
|
| 65 |
+
|
| 66 |
+
# Sort all nodes by score descending
|
| 67 |
+
scored_nodes.sort(key=lambda x: x[1], reverse=True)
|
| 68 |
+
reranked_nodes = [node for node, score in scored_nodes]
|
| 69 |
+
|
| 70 |
+
result = reranked_nodes[:top_k]
|
| 71 |
+
log_message(f"Возвращаю топ-{top_k} узлов после совместной переранжировки")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
return result
|
| 73 |
+
|
| 74 |
except Exception as e:
|
| 75 |
log_message(f"Ошибка переранжировки: {str(e)}")
|
| 76 |
return nodes[:top_k]
|
utils.py
CHANGED
|
@@ -105,94 +105,6 @@ def format_context_for_llm(nodes):
|
|
| 105 |
|
| 106 |
return "\n".join(context_parts)
|
| 107 |
|
| 108 |
-
def answer_question(question, query_engine, reranker, current_model, chunks_df=None):
|
| 109 |
-
if query_engine is None:
|
| 110 |
-
return "<div style='background-color: #e53e3e; color: white; padding: 20px; border-radius: 10px;'>Система не инициализирована</div>", ""
|
| 111 |
-
|
| 112 |
-
try:
|
| 113 |
-
log_message(f"Получен вопрос: {question}")
|
| 114 |
-
start_time = time.time()
|
| 115 |
-
|
| 116 |
-
# Извлечение узлов
|
| 117 |
-
retrieved_nodes = query_engine.retriever.retrieve(question)
|
| 118 |
-
log_message(f"Извлечено {len(retrieved_nodes)} узлов")
|
| 119 |
-
|
| 120 |
-
# ДЕТАЛЬНОЕ ЛОГИРОВАНИЕ ИСТОЧНИКОВ
|
| 121 |
-
log_message("=== ДЕТАЛЬНАЯ ИНФОРМАЦИЯ О НАЙДЕННЫХ УЗЛАХ ===")
|
| 122 |
-
for i, node in enumerate(retrieved_nodes):
|
| 123 |
-
log_message(f"Узел {i+1}:")
|
| 124 |
-
log_message(f" Документ: {node.metadata.get('document_id', 'unknown')}")
|
| 125 |
-
log_message(f" Тип: {node.metadata.get('type', 'unknown')}")
|
| 126 |
-
log_message(f" Раздел: {node.metadata.get('section_id', 'unknown')}")
|
| 127 |
-
log_message(f" Текст (первые 400 символов): {node.text[:400]}...")
|
| 128 |
-
log_message(f" Метаданные: {node.metadata}")
|
| 129 |
-
|
| 130 |
-
# Переранжировка
|
| 131 |
-
reranked_nodes = rerank_nodes(question, retrieved_nodes, reranker, top_k=10)
|
| 132 |
-
|
| 133 |
-
log_message("=== УЗЛЫ ПОСЛЕ ПЕРЕРАНЖИРОВКИ ===")
|
| 134 |
-
for i, node in enumerate(reranked_nodes):
|
| 135 |
-
log_message(f"Переранжированный узел {i+1}:")
|
| 136 |
-
log_message(f" Документ: {node.metadata.get('document_id', 'unknown')}")
|
| 137 |
-
log_message(f" Тип: {node.metadata.get('type', 'unknown')}")
|
| 138 |
-
log_message(f" Раздел: {node.metadata.get('section_id', 'unknown')}")
|
| 139 |
-
log_message(f" Полный текст: {node.text}")
|
| 140 |
-
|
| 141 |
-
formatted_context = format_context_for_llm(reranked_nodes)
|
| 142 |
-
log_message(f"ПОЛНЫЙ КОНТЕКСТ ДЛЯ LLM:\n{formatted_context}")
|
| 143 |
-
|
| 144 |
-
enhanced_question = f"""
|
| 145 |
-
Контекст из базы данных:
|
| 146 |
-
{formatted_context}
|
| 147 |
-
|
| 148 |
-
Вопрос пользователя: {question}"""
|
| 149 |
-
|
| 150 |
-
response = query_engine.query(enhanced_question)
|
| 151 |
-
|
| 152 |
-
log_message(f"ОТВЕТ LLM: {response.response}")
|
| 153 |
-
|
| 154 |
-
end_time = time.time()
|
| 155 |
-
processing_time = end_time - start_time
|
| 156 |
-
|
| 157 |
-
log_message(f"Обработка завершена за {processing_time:.2f} секунд")
|
| 158 |
-
|
| 159 |
-
sources_html = generate_sources_html(reranked_nodes, chunks_df)
|
| 160 |
-
|
| 161 |
-
answer_with_time = f"""<div style='background-color: #2d3748; color: white; padding: 20px; border-radius: 10px; margin-bottom: 10px;'>
|
| 162 |
-
<h3 style='color: #63b3ed; margin-top: 0;'>Ответ (Модель: {current_model}):</h3>
|
| 163 |
-
<div style='line-height: 1.6; font-size: 16px;'>{response.response}</div>
|
| 164 |
-
<div style='margin-top: 15px; padding-top: 10px; border-top: 1px solid #4a5568; font-size: 14px; color: #a0aec0;'>
|
| 165 |
-
Время обработки: {processing_time:.2f} секунд
|
| 166 |
-
</div>
|
| 167 |
-
</div>"""
|
| 168 |
-
|
| 169 |
-
chunk_info = []
|
| 170 |
-
for node in reranked_nodes:
|
| 171 |
-
metadata = node.metadata if hasattr(node, 'metadata') else {}
|
| 172 |
-
chunk_info.append({
|
| 173 |
-
'document_id': metadata.get('document_id', 'unknown'),
|
| 174 |
-
'section_id': metadata.get('section_id', metadata.get('section', 'unknown')),
|
| 175 |
-
'section_path': metadata.get('section_path', ''),
|
| 176 |
-
'section_text': metadata.get('section_text', ''),
|
| 177 |
-
'level': metadata.get('level', ''),
|
| 178 |
-
'parent_section': metadata.get('parent_section', ''),
|
| 179 |
-
'parent_title': metadata.get('parent_title', ''),
|
| 180 |
-
'type': metadata.get('type', 'text'),
|
| 181 |
-
'table_number': metadata.get('table_number', ''),
|
| 182 |
-
'image_number': metadata.get('image_number', ''),
|
| 183 |
-
'chunk_size': len(node.text),
|
| 184 |
-
'chunk_text': node.text
|
| 185 |
-
})
|
| 186 |
-
from app import create_chunks_display_html
|
| 187 |
-
chunks_html = create_chunks_display_html(chunk_info)
|
| 188 |
-
|
| 189 |
-
return answer_with_time, sources_html, chunks_html
|
| 190 |
-
|
| 191 |
-
except Exception as e:
|
| 192 |
-
log_message(f"Ошибка обработки вопроса: {str(e)}")
|
| 193 |
-
error_msg = f"<div style='background-color: #e53e3e; color: white; padding: 20px; border-radius: 10px;'>Ошибка обработки вопроса: {str(e)}</div>"
|
| 194 |
-
return error_msg, ""
|
| 195 |
-
|
| 196 |
|
| 197 |
def get_llm_model(model_name):
|
| 198 |
try:
|
|
@@ -377,7 +289,7 @@ def answer_question(question, query_engine, reranker, current_model, chunks_df=N
|
|
| 377 |
start_time = time.time()
|
| 378 |
|
| 379 |
retrieved_nodes = query_engine.retriever.retrieve(question)
|
| 380 |
-
reranked_nodes = rerank_nodes(question, retrieved_nodes, reranker, top_k=
|
| 381 |
|
| 382 |
formatted_context = format_context_for_llm(reranked_nodes)
|
| 383 |
|
|
|
|
| 105 |
|
| 106 |
return "\n".join(context_parts)
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
def get_llm_model(model_name):
|
| 110 |
try:
|
|
|
|
| 289 |
start_time = time.time()
|
| 290 |
|
| 291 |
retrieved_nodes = query_engine.retriever.retrieve(question)
|
| 292 |
+
reranked_nodes = rerank_nodes(question, retrieved_nodes, reranker, top_k=15)
|
| 293 |
|
| 294 |
formatted_context = format_context_for_llm(reranked_nodes)
|
| 295 |
|