import pandas as pd import json import os import pickle from datetime import datetime, timedelta from sqlalchemy import create_engine, text from sqlalchemy.exc import SQLAlchemyError class DataManager: def __init__(self, cache_dir='data_cache'): self.cache_dir = cache_dir self.current_data = None self.current_filters = None # Buat directory cache jika belum ada os.makedirs(cache_dir, exist_ok=True) def get_cache_file_path(self, start_date, end_date): """Generate nama file cache berdasarkan filter tanggal""" if start_date and end_date: filename = f"data_{start_date}_to_{end_date}.pkl" elif start_date: filename = f"data_{start_date}_to_latest.pkl" elif end_date: filename = f"data_earliest_to_{end_date}.pkl" else: filename = "data_all.pkl" return os.path.join(self.cache_dir, filename) def is_cache_valid(self, file_path, max_age_hours=24): """Cek apakah cache masih valid berdasarkan waktu""" if not os.path.exists(file_path): return False file_time = datetime.fromtimestamp(os.path.getmtime(file_path)) return (datetime.now() - file_time) < timedelta(hours=max_age_hours) def save_to_cache(self, df, start_date=None, end_date=None): """Simpan data ke cache""" try: cache_file = self.get_cache_file_path(start_date, end_date) # Simpan data dan metadata cache_data = { 'data': df, 'filters': { 'start_date': start_date, 'end_date': end_date }, 'timestamp': datetime.now(), 'data_shape': df.shape, 'columns': list(df.columns) } with open(cache_file, 'wb') as f: pickle.dump(cache_data, f) print(f"✅ Data saved to cache: {cache_file}") return True except Exception as e: print(f"❌ Error saving cache: {e}") return False def load_from_cache(self, start_date=None, end_date=None): """Load data dari cache""" try: cache_file = self.get_cache_file_path(start_date, end_date) if not os.path.exists(cache_file): return None if not self.is_cache_valid(cache_file): print("⚠️ Cache expired, will fetch new data") return None with open(cache_file, 'rb') as f: cache_data = pickle.load(f) print(f"✅ Data loaded from cache: {cache_file}") print(f"📊 Cache info: {cache_data['data_shape']} rows, from {cache_data['timestamp']}") return cache_data['data'] except Exception as e: print(f"❌ Error loading cache: {e}") return None def get_cached_data_info(self): """Get informasi tentang data yang ada di cache""" cache_files = [f for f in os.listdir(self.cache_dir) if f.endswith('.pkl')] cache_info = [] for file in cache_files: file_path = os.path.join(self.cache_dir, file) file_time = datetime.fromtimestamp(os.path.getmtime(file_path)) try: with open(file_path, 'rb') as f: cache_data = pickle.load(f) cache_info.append({ 'filename': file, 'data_shape': cache_data.get('data_shape', 'Unknown'), 'timestamp': file_time, 'filters': cache_data.get('filters', {}), 'columns': cache_data.get('columns', []) }) except: cache_info.append({ 'filename': file, 'data_shape': 'Corrupted', 'timestamp': file_time, 'filters': {}, 'columns': [] }) return cache_info def clear_cache(self): """Hapus semua file cache""" try: cache_files = [f for f in os.listdir(self.cache_dir) if f.endswith('.pkl')] for file in cache_files: os.remove(os.path.join(self.cache_dir, file)) print(f"✅ Cleared {len(cache_files)} cache files") return True except Exception as e: print(f"❌ Error clearing cache: {e}") return False # Singleton instance data_manager = DataManager()