#!/usr/bin/env python3 """ Regenerate analytics from raw JSON files without re-fetching from API. Useful after fixing parsing logic. """ import argparse import json import sys from pathlib import Path # Add parent directory to path for imports sys.path.insert(0, str(Path(__file__).parent.parent)) from src.analytics.analytics_analyzer import aggregate_analytics, format_json_report, load_api_key_to_email_map from src.analytics.analytics_types import parse_usage_record def load_raw_analytics(raw_dir: Path) -> list: """ Load all raw JSON files from directory and parse into dataclasses. Args: raw_dir: Directory containing raw JSON files (YYYY-MM-DD.json) Returns: List of parsed ClaudeCodeUsageRecord objects """ all_records = [] # Get all JSON files sorted by name (which is date) json_files = sorted(raw_dir.glob('*.json')) print(f'Found {len(json_files)} raw JSON files', file=sys.stderr) for json_file in json_files: date_str = json_file.stem # Filename without .json try: with open(json_file, 'r') as f: response = json.load(f) # Parse each record in the response for record_dict in response.get('data', []): record_dict['date'] = date_str record = parse_usage_record(record_dict) all_records.append(record) except Exception as e: print(f'Warning: Failed to parse {json_file.name}: {e}', file=sys.stderr) continue print(f'Loaded {len(all_records)} total records', file=sys.stderr) return all_records def main() -> None: parser = argparse.ArgumentParser( description='Regenerate analytics from raw JSON files', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: # Regenerate from default raw directory %(prog)s # Specify custom directories %(prog)s --raw-dir output/analytics/raw --output output/analytics/analytics.json # Without time grouping %(prog)s --time-grouping none """, ) parser.add_argument( '--raw-dir', type=Path, default=Path('output/analytics/raw'), help='Directory containing raw JSON files (default: output/analytics/raw)', ) parser.add_argument( '--output', type=Path, default=Path('output/analytics/analytics.json'), help='Output file path (default: output/analytics/analytics.json)', ) parser.add_argument( '--time-grouping', choices=['day', 'month', 'none'], default='day', help='Group by time period (default: day)', ) args = parser.parse_args() # Validate raw directory exists if not args.raw_dir.exists(): print(f'Error: Raw directory not found: {args.raw_dir}', file=sys.stderr) sys.exit(1) try: # Load raw data print(f'Loading raw analytics from {args.raw_dir}...', file=sys.stderr) records = load_raw_analytics(args.raw_dir) if not records: print('Error: No records found in raw directory', file=sys.stderr) sys.exit(1) # Aggregate data print('Aggregating analytics...', file=sys.stderr) time_grouping = None if args.time_grouping == 'none' else args.time_grouping api_key_to_email = load_api_key_to_email_map() actor_data = aggregate_analytics(records, time_grouping, api_key_to_email) print(f'Found data for {len(actor_data)} actors', file=sys.stderr) # Format report report = format_json_report(actor_data, time_grouping) # Write output args.output.parent.mkdir(parents=True, exist_ok=True) with open(args.output, 'w') as f: f.write(report) print(f'✅ Analytics written to {args.output}', file=sys.stderr) except Exception as e: print(f'Error: {e}', file=sys.stderr) import traceback traceback.print_exc() sys.exit(1) if __name__ == '__main__': main()