Untitled
import json from datetime import datetime from pathlib import Path from typing import Dict, List, Set, Union class MetricsManager: def __init__(self, storage_path: str = "sorting_metrics.json"): self.storage_path = Path(storage_path) self.metrics = self._load_or_initialize_metrics() def _load_or_initialize_metrics(self) -> dict: """Load existing metrics from file or initialize new metrics structure.""" if self.storage_path.exists(): with open(self.storage_path, 'r') as f: return json.load(f) return { # Basic sorting metrics 'total_items_sorted': 0, 'items_sorted_per_bin': {}, 'sort_timestamps': [], 'fill_levels_per_bin': {}, 'bin_emptying_counts': {}, 'api_vs_local_usage_counts': {'api': 0, 'local': 0}, # Time-based metrics 'daily_usage_counts': {}, 'weekly_usage_counts': {}, 'monthly_usage_counts': {}, 'time_between_sorts': [], 'time_of_day_patterns': {}, 'daily_weekly_monthly_streaks': { 'daily': 0, 'weekly': 0, 'monthly': 0 }, 'time_to_empty_from_90': [], 'fill_rate_per_bin': {}, 'fill_level_balance': {}, # Short-term tracking 'items_last_5_minutes': { 'count': 0, 'timestamps': [] }, 'current_sorting_streak': { 'start_date': None, 'days': 0, 'last_sort_date': None }, # Hour coverage tracking 'hours_sorted': [], 'weekend_streak': { 'count': 0, 'dates': [] }, # Seasonal tracking 'seasonal_counts': { 'summer': 0, 'winter': 0, 'current_season': '', 'season_start': None }, # Environmental impact 'environmental_impact': { 'co2_saved': 0.0, 'trees_saved': 0.0, 'paper_weight_recycled': 0.0, 'plastic_weight_recycled': 0.0, 'organic_weight_processed': 0.0 }, # Fill level history 'fill_level_history': {}, 'balance_tracking': { 'start_date': None, 'days_within_threshold': 0, 'last_check': None }, # Achievement progress 'achievements': {}, # Bin specialization 'bin_specialization': {} } def save(self): """Save current metrics to file.""" # Convert datetime objects to string format metrics_copy = self._prepare_for_serialization(self.metrics) with open(self.storage_path, 'w') as f: json.dump(metrics_copy, f, indent=4) def _prepare_for_serialization(self, data): """Prepare data for JSON serialization by converting datetime objects to strings.""" if isinstance(data, dict): return {k: self._prepare_for_serialization(v) for k, v in data.items()} elif isinstance(data, list): return [self._prepare_for_serialization(item) for item in data] elif isinstance(data, datetime): return data.isoformat() elif isinstance(data, set): return list(data) return data def update_sort_metrics(self, bin_id: str, fill_level: float, classification_method: str): """Update metrics after a new sort.""" current_time = datetime.now() # Update basic metrics self.metrics['total_items_sorted'] += 1 self.metrics['items_sorted_per_bin'][bin_id] = self.metrics['items_sorted_per_bin'].get(bin_id, 0) + 1 self.metrics['sort_timestamps'].append(current_time.isoformat()) self.metrics['fill_levels_per_bin'][bin_id] = fill_level # Update classification method counts self.metrics['api_vs_local_usage_counts'][classification_method] += 1 # Update time-based metrics self._update_time_metrics(current_time) # Update fill level history if bin_id not in self.metrics['fill_level_history']: self.metrics['fill_level_history'][bin_id] = { 'timestamps': [], 'levels': [], 'emptying_timestamps': [] } self.metrics['fill_level_history'][bin_id]['timestamps'].append(current_time.isoformat()) self.metrics['fill_level_history'][bin_id]['levels'].append(fill_level) # Save updates to file self.save() def _update_time_metrics(self, current_time: datetime): """Update time-based metrics.""" date_str = current_time.date().isoformat() week_str = f"{current_time.year}-W{current_time.isocalendar()[1]}" month_str = f"{current_time.year}-{current_time.month:02d}" # Update usage counts self.metrics['daily_usage_counts'][date_str] = self.metrics['daily_usage_counts'].get(date_str, 0) + 1 self.metrics['weekly_usage_counts'][week_str] = self.metrics['weekly_usage_counts'].get(week_str, 0) + 1 self.metrics['monthly_usage_counts'][month_str] = self.metrics['monthly_usage_counts'].get(month_str, 0) + 1 # Update hour coverage hour = current_time.hour if hour not in self.metrics['hours_sorted']: self.metrics['hours_sorted'].append(hour) def get_metrics(self) -> dict: """Return current metrics.""" return self.metrics def update_environmental_impact(self, material_type: str, weight: float): """Update environmental impact metrics based on material type and weight.""" impact_factors = { 'paper': { 'co2_per_kg': 2.6, 'trees_per_kg': 0.017 }, 'plastic': { 'co2_per_kg': 6.0 }, 'organic': { 'co2_per_kg': 0.5 } } if material_type in impact_factors: factors = impact_factors[material_type] self.metrics['environmental_impact']['co2_saved'] += factors.get('co2_per_kg', 0) * weight if material_type == 'paper': self.metrics['environmental_impact']['trees_saved'] += factors['trees_per_kg'] * weight self.metrics['environmental_impact']['paper_weight_recycled'] += weight elif material_type == 'plastic': self.metrics['environmental_impact']['plastic_weight_recycled'] += weight elif material_type == 'organic': self.metrics['environmental_impact']['organic_weight_processed'] += weight self.save()
Leave a Comment