#!/usr/bin/env python3 """ Add Accent Labels to JSON Filenames Renames individual JSON files to include detected accent types in the filename. """ import json import os import shutil from pathlib import Path import argparse import logging from typing import Dict, List def setup_logging(verbose: bool = False): """Setup logging configuration""" level = logging.DEBUG if verbose else logging.INFO logging.basicConfig(level=level, format="%(asctime)s - %(levelname)s - %(message)s") def get_accent_types_from_record(record: Dict) -> List[str]: """ Extract accent types from record's accent analysis Args: record: JSON record with _accent_analysis field Returns: List of detected accent types """ accent_analysis = record.get("_accent_analysis", {}) found_accents = accent_analysis.get("found_accents", {}) return list(found_accents.keys()) def format_accent_string(accents: List[str]) -> str: """ Format list of accents into a clean filename-safe string Args: accents: List of accent names Returns: Formatted accent string for filename """ if not accents: return "no_accent" # Clean and format accent names formatted_accents = [] for accent in accents: # Convert to title case and replace underscores clean_accent = accent.replace("_", "-").title() formatted_accents.append(clean_accent) # Join multiple accents with plus sign return "+".join(formatted_accents) def rename_files_with_accents( input_dir: str, output_dir: str = None, copy_mode: bool = True, dry_run: bool = False ) -> Dict[str, int]: """ Rename JSON files to include detected accent types Args: input_dir: Directory containing JSON files with accent analysis output_dir: Output directory (None = rename in place) copy_mode: If True, copy files; if False, move files dry_run: If True, show what would be done without actually doing it Returns: Dictionary with statistics """ input_path = Path(input_dir) if not input_path.exists(): raise FileNotFoundError(f"Input directory not found: {input_dir}") # Setup output directory if output_dir: output_path = Path(output_dir) output_path.mkdir(parents=True, exist_ok=True) else: output_path = input_path copy_mode = False # Must move if same directory logging.info(f"Processing files in: {input_dir}") logging.info(f"Output directory: {output_path}") logging.info(f"Mode: {'COPY' if copy_mode else 'MOVE'}") logging.info(f"Dry run: {dry_run}") # Statistics stats = {"processed": 0, "renamed": 0, "no_accents": 0, "errors": 0, "multiple_accents": 0} # Find all JSON files json_files = list(input_path.glob("*.json")) if not json_files: logging.warning(f"No JSON files found in {input_dir}") return stats logging.info(f"Found {len(json_files)} JSON files to process") for json_file in json_files: try: stats["processed"] += 1 # Read and parse JSON with open(json_file, "r") as f: record = json.load(f) # Extract accent types accents = get_accent_types_from_record(record) if not accents: stats["no_accents"] += 1 logging.debug(f"No accents found in: {json_file.name}") continue if len(accents) > 1: stats["multiple_accents"] += 1 # Format accent string accent_string = format_accent_string(accents) # Create new filename original_stem = json_file.stem # Remove existing prefix if present (e.g., "accent_test_001_") if original_stem.startswith("accent_test_"): parts = original_stem.split("_", 3) # ['accent', 'test', '001', 'record_id'] if len(parts) >= 4: clean_stem = parts[3] # Just the record ID index_part = parts[2] # The sequence number else: clean_stem = original_stem index_part = "000" else: clean_stem = original_stem index_part = f"{stats['processed']:03d}" # Build new filename with accent new_filename = f"accent_{index_part}_{accent_string}_{clean_stem}.json" new_file_path = output_path / new_filename # Log the operation operation = "COPY" if copy_mode else "MOVE" logging.info(f"{operation}: {json_file.name} -> {new_filename}") logging.debug(f" Detected accents: {', '.join(accents)}") if not dry_run: if copy_mode: shutil.copy2(json_file, new_file_path) else: shutil.move(str(json_file), str(new_file_path)) stats["renamed"] += 1 except Exception as e: stats["errors"] += 1 logging.error(f"Error processing {json_file.name}: {e}") continue # Print summary logging.info("\n" + "=" * 50) logging.info("RENAMING SUMMARY") logging.info("=" * 50) logging.info(f"Files processed: {stats['processed']}") logging.info(f"Files renamed: {stats['renamed']}") logging.info(f"Files with no accents: {stats['no_accents']}") logging.info(f"Files with multiple accents: {stats['multiple_accents']}") logging.info(f"Errors: {stats['errors']}") return stats def main(): parser = argparse.ArgumentParser( description="Rename JSON files to include detected accent types in filename", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: # Rename files in place (move) python add_accents_to_filenames.py --input-dir /path/to/accent_files/ # Copy files to new directory with accent names python add_accents_to_filenames.py --input-dir /path/to/source/ --output-dir /path/to/renamed/ --copy # Preview what would be done (dry run) python add_accents_to_filenames.py --input-dir /path/to/files/ --dry-run Filename Format: accent_001_Scottish_record_id.json accent_002_German+Bavarian_record_id.json (multiple accents) accent_003_Australian_record_id.json """, ) parser.add_argument( "--input-dir", "-i", type=str, required=True, help="Directory containing JSON files with accent analysis", ) parser.add_argument( "--output-dir", "-o", type=str, default=None, help="Output directory for renamed files (default: rename in place)", ) parser.add_argument( "--copy", action="store_true", help="Copy files instead of moving them (default: move)" ) parser.add_argument( "--dry-run", action="store_true", help="Show what would be done without actually doing it" ) parser.add_argument("--verbose", "-v", action="store_true", help="Verbose logging") args = parser.parse_args() setup_logging(args.verbose) try: stats = rename_files_with_accents( input_dir=args.input_dir, output_dir=args.output_dir, copy_mode=args.copy, dry_run=args.dry_run, ) if args.dry_run: print(f"\nšŸ” DRY RUN COMPLETE - No files were actually modified") else: print(f"\nāœ… Successfully processed {stats['processed']} files") print(f"šŸ“ Renamed {stats['renamed']} files with accent labels") if stats["errors"] > 0: print(f"āš ļø {stats['errors']} errors occurred") return 1 return 0 except Exception as e: logging.error(f"Script failed: {e}") return 1 if __name__ == "__main__": exit(main())