Untitled

 avatar
unknown
plain_text
a month ago
7.3 kB
2
Indexable
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