import time
import logging
logger = logging.getLogger(__name__)
def log_message(message):
logger.info(message)
print(message, flush=True)
class ChatHandler:
def __init__(self, index_retriever):
self.index_retriever = index_retriever
self.chat_history = []
def format_section_path(self, metadata):
parts = []
section_id = metadata.get('section_id')
if section_id and section_id != 'Unknown':
parts.append(section_id)
subsection_id = metadata.get('subsection_id')
if subsection_id and subsection_id != 'Unknown':
parts.append(subsection_id)
sub_subsection_id = metadata.get('sub_subsection_id')
if sub_subsection_id and sub_subsection_id != 'Unknown':
parts.append(sub_subsection_id)
sub_sub_subsection_id = metadata.get('sub_sub_subsection_id')
if sub_sub_subsection_id and sub_sub_subsection_id != 'Unknown':
parts.append(sub_sub_subsection_id)
return " → ".join(parts) if parts else "Основной раздел"
def generate_sources_html(self, nodes):
html = "
"
html += "
Источники:
"
for i, node in enumerate(nodes):
metadata = node.metadata if hasattr(node, 'metadata') else {}
doc_type = metadata.get('type', 'text')
doc_id = metadata.get('document_id', 'unknown')
html += f"
"
if doc_type == 'text':
section_path = self.format_section_path(metadata)
document_name = metadata.get('document_name', doc_id)
level = metadata.get('level', 'section')
html += f"
📄 {doc_id}
"
html += f"
{document_name}
"
html += f"
📍 {section_path}
"
html += f"
Уровень: {level}
"
elif doc_type == 'table':
table_num = metadata.get('table_number', 'unknown')
section = metadata.get('section', '')
if table_num and table_num != 'unknown':
if not table_num.startswith('№'):
table_num = f"№{table_num}"
html += f"
📊 Таблица {table_num} - {doc_id}
"
else:
html += f"
📊 Таблица - {doc_id}
"
if section:
html += f"
📍 {section}
"
elif doc_type == 'image':
image_num = metadata.get('image_number', 'unknown')
section = metadata.get('section', '')
if image_num and image_num != 'unknown':
if not str(image_num).startswith('№'):
image_num = f"№{image_num}"
html += f"
🖼️ Изображение {image_num} - {doc_id}
"
else:
html += f"
🖼️ Изображение - {doc_id}
"
if section:
html += f"
📍 {section}
"
html += "
"
html += "
"
return html
def answer_question(self, question):
if not self.index_retriever.is_initialized():
return "Система не инициализирована
", ""
try:
log_message(f"Получен вопрос: {question}")
current_model = self.index_retriever.get_current_model()
log_message(f"Используется модель: {current_model}")
start_time = time.time()
retrieved_nodes = self.index_retriever.retrieve_nodes(question)
if not retrieved_nodes:
return "Не удалось найти релевантные документы
", ""
log_message(f"Отправляю запрос в LLM с {len(retrieved_nodes)} узлами")
response = self.index_retriever.query_engine.query(question)
end_time = time.time()
processing_time = end_time - start_time
log_message(f"Обработка завершена за {processing_time:.2f} секунд")
self.chat_history.append({
"question": question,
"answer": response.response,
"model": current_model,
"processing_time": processing_time,
"nodes_count": len(retrieved_nodes)
})
sources_html = self.generate_sources_html(retrieved_nodes)
answer_with_time = f"""
Ответ (Модель: {current_model}):
{response.response}
Время обработки: {processing_time:.2f} секунд | Источников: {len(retrieved_nodes)}
"""
return answer_with_time, sources_html
except Exception as e:
log_message(f"Ошибка обработки вопроса: {str(e)}")
error_msg = f"Ошибка обработки вопроса: {str(e)}
"
return error_msg, ""
def get_chat_history(self):
return self.chat_history
def clear_history(self):
self.chat_history = []
log_message("История чата очищена")
def get_history_html(self):
if not self.chat_history:
return "История пуста
"
html = ""
html += "
История чата:
"
for i, entry in enumerate(reversed(self.chat_history[-10:])):
html += f"
"
html += f"
Вопрос {len(self.chat_history) - i}:
"
html += f"
{entry['question']}
"
html += f"
Ответ ({entry['model']}):
"
html += f"
{entry['answer'][:300]}{'...' if len(entry['answer']) > 300 else ''}
"
html += f"
Время: {entry['processing_time']:.2f}с | Источников: {entry['nodes_count']}
"
html += "
"
html += "
"
return html