Spaces:
Sleeping
Sleeping
| """ | |
| Enhanced utility functions for LabelIt! application with real-time analytics | |
| """ | |
| import json | |
| import os | |
| from PIL import Image | |
| from collections import Counter | |
| # File paths for data storage (compatible with pre-existing folders) | |
| DATA_DIR = 'data' | |
| USERS_FILE = os.path.join(DATA_DIR, 'users.json') | |
| LABELS_FILE = os.path.join(DATA_DIR, 'labels.json') | |
| IMAGES_DIR = os.path.join(DATA_DIR, 'images') | |
| def load_users(): | |
| """Load users from JSON file with error handling for pre-existing files""" | |
| if os.path.exists(USERS_FILE): | |
| try: | |
| with open(USERS_FILE, 'r') as f: | |
| return json.load(f) | |
| except (FileNotFoundError, json.JSONDecodeError, PermissionError): | |
| pass | |
| return {} | |
| def save_users(users): | |
| """Save users to JSON file with error handling for read-only environments""" | |
| if os.path.exists(DATA_DIR): | |
| try: | |
| with open(USERS_FILE, 'w') as f: | |
| json.dump(users, f, indent=2) | |
| except (OSError, PermissionError): | |
| pass | |
| def load_labels(): | |
| """Load labels from JSON file with error handling for pre-existing files""" | |
| if os.path.exists(LABELS_FILE): | |
| try: | |
| with open(LABELS_FILE, 'r') as f: | |
| return json.load(f) | |
| except (FileNotFoundError, json.JSONDecodeError, PermissionError): | |
| pass | |
| return {} | |
| def save_labels(labels): | |
| """Save labels to JSON file with error handling for read-only environments""" | |
| if os.path.exists(DATA_DIR): | |
| try: | |
| with open(LABELS_FILE, 'w') as f: | |
| json.dump(labels, f, indent=2) | |
| except (OSError, PermissionError): | |
| pass | |
| def validate_image(uploaded_file): | |
| """Validate uploaded image file""" | |
| # Check file size (10MB limit) | |
| if uploaded_file.size > 10 * 1024 * 1024: # 10MB in bytes | |
| return { | |
| 'valid': False, | |
| 'error': 'file_too_large' | |
| } | |
| # Check file type | |
| allowed_types = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'] | |
| if uploaded_file.type not in allowed_types: | |
| return { | |
| 'valid': False, | |
| 'error': 'invalid_file_type' | |
| } | |
| # Try to open and verify image | |
| try: | |
| image = Image.open(uploaded_file) | |
| image.verify() | |
| uploaded_file.seek(0) # Reset file pointer | |
| return { | |
| 'valid': True, | |
| 'error': None | |
| } | |
| except Exception: | |
| return { | |
| 'valid': False, | |
| 'error': 'image_processing_error' | |
| } | |
| def get_categories(): | |
| """Get list of available categories""" | |
| return [ | |
| 'Animals', | |
| 'Food', | |
| 'Objects', | |
| 'Nature', | |
| 'People', | |
| 'Transportation' | |
| ] | |
| def calculate_statistics(): | |
| """Calculate comprehensive real-time statistics for the analytics dashboard""" | |
| users = load_users() | |
| labels_data = load_labels() | |
| # Basic counts | |
| total_users = len(users) | |
| total_images = len(labels_data) | |
| # Count total labels across all images | |
| total_labels = 0 | |
| languages_used = set() | |
| language_breakdown = Counter() | |
| category_breakdown = Counter() | |
| # Location-based statistics | |
| images_with_location = 0 | |
| gps_accuracy_breakdown = Counter() | |
| location_methods = Counter() | |
| country_breakdown = Counter() | |
| city_breakdown = Counter() | |
| for entry_data in labels_data.values(): | |
| # Count labels for this image | |
| image_labels = entry_data.get('labels', []) | |
| total_labels += len(image_labels) | |
| # Track languages used | |
| for label in image_labels: | |
| lang = label.get('language', 'unknown') | |
| languages_used.add(lang) | |
| language_breakdown[lang] += 1 | |
| # Track categories | |
| category = entry_data.get('category', 'Unknown') | |
| category_breakdown[category] += 1 | |
| # Track location data | |
| location = entry_data.get('location') | |
| if location and location.get('latitude'): | |
| images_with_location += 1 | |
| # Track location capture method | |
| method = location.get('method', 'Unknown') | |
| location_methods[method] += 1 | |
| # Track GPS accuracy levels | |
| accuracy = location.get('accuracy') | |
| if accuracy is not None: | |
| if accuracy <= 10: | |
| gps_accuracy_breakdown['High'] += 1 | |
| elif accuracy <= 50: | |
| gps_accuracy_breakdown['Medium'] += 1 | |
| else: | |
| gps_accuracy_breakdown['Low'] += 1 | |
| else: | |
| gps_accuracy_breakdown['Unknown'] += 1 | |
| # Track countries and cities | |
| country = location.get('country') | |
| if country: | |
| country_breakdown[country] += 1 | |
| city = location.get('city') | |
| if city: | |
| city_breakdown[city] += 1 | |
| return { | |
| 'total_users': total_users, | |
| 'total_images': total_images, | |
| 'total_labels': total_labels, | |
| 'languages_used': len(languages_used), | |
| 'language_breakdown': dict(language_breakdown), | |
| 'category_breakdown': dict(category_breakdown), | |
| 'images_with_location': images_with_location, | |
| 'gps_accuracy_breakdown': dict(gps_accuracy_breakdown), | |
| 'location_methods': dict(location_methods), | |
| 'country_breakdown': dict(country_breakdown), | |
| 'city_breakdown': dict(city_breakdown) | |
| } | |
| def get_location_accuracy_level(accuracy): | |
| """Determine location accuracy level based on accuracy value""" | |
| if accuracy is None: | |
| return "Unknown", "#95a5a6" | |
| if accuracy <= 10: | |
| return "High", "#27ae60" | |
| elif accuracy <= 50: | |
| return "Medium", "#f39c12" | |
| else: | |
| return "Low", "#e74c3c" | |
| def format_location_display(location_data): | |
| """Format location data for display""" | |
| if not location_data or not location_data.get('lat'): | |
| return "๐ Location not available" | |
| lat = location_data['lat'] | |
| lon = location_data['lon'] | |
| method = location_data.get('method', 'Unknown') | |
| accuracy = location_data.get('accuracy') | |
| # Method icon | |
| method_icons = { | |
| 'GPS': '๐ฐ๏ธ', | |
| 'IP': '๐', | |
| 'Manual': '๐' | |
| } | |
| method_icon = method_icons.get(method, '๐') | |
| # Base location string | |
| location_str = f"{method_icon} {lat:.6f}, {lon:.6f}" | |
| # Add accuracy if available | |
| if accuracy: | |
| level, _ = get_location_accuracy_level(accuracy) | |
| location_str += f" (ยฑ{accuracy:.0f}m - {level} Accuracy)" | |
| # Add city/country if available | |
| if location_data.get('city') and location_data.get('country'): | |
| location_str += f" - {location_data['city']}, {location_data['country']}" | |
| return location_str | |
| def validate_coordinates(lat, lon): | |
| """Validate latitude and longitude coordinates""" | |
| try: | |
| lat = float(lat) | |
| lon = float(lon) | |
| if -90 <= lat <= 90 and -180 <= lon <= 180: | |
| return True, lat, lon | |
| else: | |
| return False, None, None | |
| except (ValueError, TypeError): | |
| return False, None, None | |
| def get_user_contribution_stats(username): | |
| """Get contribution statistics for a specific user""" | |
| labels_data = load_labels() | |
| user_stats = { | |
| 'images_uploaded': 0, | |
| 'labels_added': 0, | |
| 'languages_contributed': set(), | |
| 'categories_contributed': set() | |
| } | |
| for entry_data in labels_data.values(): | |
| # Check if user uploaded this image | |
| if entry_data.get('uploaded_by') == username: | |
| user_stats['images_uploaded'] += 1 | |
| user_stats['categories_contributed'].add(entry_data.get('category', 'Unknown')) | |
| # Check labels added by this user | |
| for label in entry_data.get('labels', []): | |
| if label.get('added_by') == username: | |
| user_stats['labels_added'] += 1 | |
| user_stats['languages_contributed'].add(label.get('language', 'unknown')) | |
| # Convert sets to counts | |
| user_stats['languages_contributed'] = len(user_stats['languages_contributed']) | |
| user_stats['categories_contributed'] = len(user_stats['categories_contributed']) | |
| return user_stats | |