jdesiree commited on
Commit
2bf0c65
·
verified ·
1 Parent(s): fac58fc

Update metrics.py

Browse files
Files changed (1) hide show
  1. metrics.py +0 -200
metrics.py CHANGED
@@ -1,200 +0,0 @@
1
- import time
2
- import json
3
- from datetime import datetime
4
- from dataclasses import dataclass
5
- from typing import List, Optional
6
- import threading
7
-
8
- @dataclass
9
- class InteractionMetric:
10
- """Single interaction metrics"""
11
- timestamp: str
12
- query_length: int
13
- response_time: float
14
- input_tokens: int
15
- output_tokens: int
16
- total_tokens: int
17
- streaming_chunks: int
18
- provider_latency: float
19
- error_occurred: bool
20
- error_message: Optional[str] = None
21
-
22
- class MimirMetrics:
23
- """Metrics collection and analysis for Mimir"""
24
-
25
- def __init__(self, save_file: str = "Mimir_metrics.json"):
26
- self.metrics: List[InteractionMetric] = []
27
- self.save_file = save_file
28
- self.lock = threading.Lock() # Thread-safe for concurrent requests
29
-
30
- # Load existing metrics if file exists
31
- self.load_metrics()
32
-
33
- def start_timing(self) -> dict:
34
- """Start timing an interaction - returns timing context"""
35
- return {
36
- 'start_time': time.time(),
37
- 'provider_start': None,
38
- 'chunk_count': 0,
39
- 'chunks_timing': []
40
- }
41
-
42
- def mark_provider_start(self, timing_context: dict):
43
- """Mark when provider API call starts"""
44
- timing_context['provider_start'] = time.time()
45
-
46
- def mark_provider_end(self, timing_context: dict):
47
- """Mark when provider API call ends and calculate latency"""
48
- if timing_context['provider_start']:
49
- timing_context['provider_latency'] = time.time() - timing_context['provider_start']
50
- else:
51
- timing_context['provider_latency'] = 0.0
52
-
53
- def record_chunk(self, timing_context: dict):
54
- """Record a streaming chunk"""
55
- timing_context['chunk_count'] += 1
56
- timing_context['chunks_timing'].append(time.time())
57
-
58
- def count_tokens(self, text: str) -> int:
59
- """Simple token counting (approximation)"""
60
- # Rough approximation: 1 token ≈ 4 characters for most models
61
- return len(text) // 4
62
-
63
- def log_interaction(self,
64
- query: str,
65
- response: str,
66
- timing_context: dict,
67
- error_occurred: bool = False,
68
- error_message: str = None):
69
- """Log a complete interaction with all metrics"""
70
-
71
- end_time = time.time()
72
- response_time = end_time - timing_context['start_time']
73
-
74
- # Count tokens
75
- input_tokens = self.count_tokens(query)
76
- output_tokens = self.count_tokens(response)
77
- total_tokens = input_tokens + output_tokens
78
-
79
- # Get provider latency
80
- provider_latency = timing_context.get('provider_latency', 0.0)
81
-
82
- # Create metric record
83
- metric = InteractionMetric(
84
- timestamp=datetime.now().isoformat(),
85
- query_length=len(query),
86
- response_time=response_time,
87
- input_tokens=input_tokens,
88
- output_tokens=output_tokens,
89
- total_tokens=total_tokens,
90
- streaming_chunks=timing_context['chunk_count'],
91
- provider_latency=provider_latency,
92
- error_occurred=error_occurred,
93
- error_message=error_message
94
- )
95
-
96
- # Thread-safe append
97
- with self.lock:
98
- self.metrics.append(metric)
99
-
100
- # Auto-save every 10 interactions
101
- if len(self.metrics) % 2 == 0:
102
- self.save_metrics()
103
-
104
- def save_metrics(self):
105
- """Save metrics to JSON file"""
106
- try:
107
- with self.lock:
108
- data = [
109
- {
110
- 'timestamp': m.timestamp,
111
- 'query_length': m.query_length,
112
- 'response_time': m.response_time,
113
- 'input_tokens': m.input_tokens,
114
- 'output_tokens': m.output_tokens,
115
- 'total_tokens': m.total_tokens,
116
- 'streaming_chunks': m.streaming_chunks,
117
- 'provider_latency': m.provider_latency,
118
- 'error_occurred': m.error_occurred,
119
- 'error_message': m.error_message
120
- }
121
- for m in self.metrics
122
- ]
123
-
124
- with open(self.save_file, 'w') as f:
125
- json.dump(data, f, indent=2)
126
-
127
- except Exception as e:
128
- print(f"Error saving metrics: {e}")
129
-
130
- def load_metrics(self):
131
- """Load existing metrics from file"""
132
- try:
133
- with open(self.save_file, 'r') as f:
134
- data = json.load(f)
135
-
136
- self.metrics = [
137
- InteractionMetric(**item) for item in data
138
- ]
139
-
140
- except FileNotFoundError:
141
- # File doesn't exist yet, start fresh
142
- self.metrics = []
143
- except Exception as e:
144
- print(f"Error loading metrics: {e}")
145
- self.metrics = []
146
-
147
- def get_summary_stats(self) -> dict:
148
- """Get summary statistics"""
149
- if not self.metrics:
150
- return {"message": "No metrics recorded yet"}
151
-
152
- response_times = [m.response_time for m in self.metrics]
153
- provider_latencies = [m.provider_latency for m in self.metrics]
154
- token_counts = [m.total_tokens for m in self.metrics]
155
- chunk_counts = [m.streaming_chunks for m in self.metrics]
156
- error_count = sum(1 for m in self.metrics if m.error_occurred)
157
-
158
- return {
159
- "total_interactions": len(self.metrics),
160
- "error_rate": (error_count / len(self.metrics)) * 100,
161
- "avg_response_time": sum(response_times) / len(response_times),
162
- "avg_provider_latency": sum(provider_latencies) / len(provider_latencies),
163
- "avg_tokens": sum(token_counts) / len(token_counts),
164
- "avg_chunks": sum(chunk_counts) / len(chunk_counts),
165
- }
166
-
167
- def export_csv(self, filename: str = None):
168
- """Export metrics to CSV format"""
169
- if filename is None:
170
- filename = f"Mimir_metrics_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
171
-
172
- try:
173
- import csv
174
-
175
- with open(filename, 'w', newline='') as csvfile:
176
- fieldnames = [
177
- 'timestamp', 'query_length', 'response_time',
178
- 'input_tokens', 'output_tokens', 'total_tokens',
179
- 'streaming_chunks', 'provider_latency', 'error_occurred'
180
- ]
181
- writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
182
- writer.writeheader()
183
-
184
- for metric in self.metrics:
185
- writer.writerow({
186
- 'timestamp': metric.timestamp,
187
- 'query_length': metric.query_length,
188
- 'response_time': metric.response_time,
189
- 'input_tokens': metric.input_tokens,
190
- 'output_tokens': metric.output_tokens,
191
- 'total_tokens': metric.total_tokens,
192
- 'streaming_chunks': metric.streaming_chunks,
193
- 'provider_latency': metric.provider_latency,
194
- 'error_occurred': metric.error_occurred
195
- })
196
-
197
- return f"Metrics exported to {filename}"
198
-
199
- except Exception as e:
200
- return f"Error exporting CSV: {e}"