File size: 6,079 Bytes
5539560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import pandas as pd
from datetime import datetime
import json
from typing import List, Dict
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.tracers import BaseTracer
from dataclasses import dataclass, asdict
import plotly.express as px
import streamlit as st

@dataclass
class ChatAnalysis:
    timestamp: str
    user_input: str
    bot_response: str
    context: str
    kb_version: str
    response_time: float
    tokens_used: int
    context_relevance_score: float

class ChatAnalyzer(BaseTracer):
    def __init__(self):
        super().__init__()
        self.analyses: List[ChatAnalysis] = []
        
    def load_logs(self, log_file_path: str) -> List[Dict]:
        """Загрузка и парсинг логов чата из JSON файла"""
        logs = []
        with open(log_file_path, 'r', encoding='utf-8') as f:
            for line in f:
                try:
                    logs.append(json.loads(line.strip()))
                except json.JSONDecodeError:
                    continue
        return logs

    def analyze_interaction(self, log_entry: Dict) -> ChatAnalysis:
        """Анализ одного взаимодействия в чате"""
        # Расчет базовых метрик
        timestamp = datetime.fromisoformat(log_entry["timestamp"])
        
        # Расчет времени ответа (можно заменить на реальную логику измерения)
        response_time = len(log_entry["bot_response"]) * 0.01  # Простая аппроксимация
        
        # Подсчет использованных токенов (заменить на реальный подсчет)
        tokens_used = len(log_entry["bot_response"].split()) + len(log_entry["user_input"].split())
        
        # Расчет релевантности контекста
        context_relevance = self._calculate_context_relevance(
            log_entry["user_input"],
            log_entry["context"],
            log_entry["bot_response"]
        )
        
        return ChatAnalysis(
            timestamp=timestamp.isoformat(),
            user_input=log_entry["user_input"],
            bot_response=log_entry["bot_response"],
            context=log_entry["context"],
            kb_version=log_entry["kb_version"],
            response_time=response_time,
            tokens_used=tokens_used,
            context_relevance_score=context_relevance
        )

    def _calculate_context_relevance(self, query: str, context: str, response: str) -> float:
        """Расчет оценки релевантности между запросом и предоставленным контекстом"""
        # Простая реализация - можно заменить на более сложную систему оценки
        query_terms = set(query.lower().split())
        context_terms = set(context.lower().split())
        response_terms = set(response.lower().split())
        
        query_context_overlap = len(query_terms & context_terms)
        context_response_overlap = len(context_terms & response_terms)
        
        if not query_terms or not context_terms:
            return 0.0
            
        return (query_context_overlap + context_response_overlap) / (len(query_terms) + len(context_terms))

    def create_analysis_dashboard(self):
        """Создание дашборда анализа чата в Streamlit"""
        st.title("Панель анализа чата")
        
        # Преобразование анализа в DataFrame
        df = pd.DataFrame([asdict(a) for a in self.analyses])
        
        # Базовая статистика
        st.header("Обзор")
        col1, col2, col3, col4 = st.columns(4)
        with col1:
            st.metric("Всего взаимодействий", len(df))
        with col2:
            st.metric("Среднее время ответа", f"{df['response_time'].mean():.2f}с")
        with col3:
            st.metric("Средняя релевантность контекста", f"{df['context_relevance_score'].mean():.2%}")
        with col4:
            st.metric("Всего использовано токенов", df['tokens_used'].sum())
            
        # Анализ временных рядов
        st.header("Тренды взаимодействий")
        df['timestamp'] = pd.to_datetime(df['timestamp'])
        fig = px.line(df, x='timestamp', y='response_time', title='Время ответа с течением времени')
        st.plotly_chart(fig)
        
        # Распределение релевантности контекста
        fig = px.histogram(df, x='context_relevance_score', 
                         title='Распределение оценок релевантности контекста',
                         nbins=20)
        st.plotly_chart(fig)
        
        # Детальные логи
        st.header("Детальные логи взаимодействий")
        st.dataframe(df)

def setup_chat_analysis():
    """Инициализация и настройка системы анализа чата"""
    analyzer = ChatAnalyzer()
    
    # Добавление к существующему логированию
    def enhanced_log_interaction(user_input: str, bot_response: str, context: str):
        # Ваш существующий код логирования
        log_interaction(user_input, bot_response, context)
        
        # Добавление анализа
        log_entry = {
            "timestamp": datetime.now().isoformat(),
            "user_input": user_input,
            "bot_response": bot_response,
            "context": context,
            "kb_version": st.session_state.kb_info['version']
        }
        analysis = analyzer.analyze_interaction(log_entry)
        analyzer.analyses.append(analysis)
    
    return analyzer, enhanced_log_interaction