""" Data Manager Service Manages the active data file path for model training. Persists configuration to a JSON file so it survives restarts. """ import json import logging from datetime import datetime from pathlib import Path from app.core.config import get_settings logger = logging.getLogger(__name__) CONFIG_FILENAME = "data_config.json" def _config_path() -> Path: """Get path to the data config file.""" settings = get_settings() return settings.artifacts_dir / CONFIG_FILENAME def get_active_data_path() -> Path: """ Get the currently active data file path. Returns custom path if set, otherwise returns default. """ settings = get_settings() config_file = _config_path() if config_file.exists(): try: config = json.loads(config_file.read_text(encoding="utf-8")) custom_path = config.get("active_data_path") if custom_path: custom_path = Path(custom_path) if custom_path.exists(): return custom_path else: logger.warning("Custom data path no longer exists: %s", custom_path) except (json.JSONDecodeError, KeyError) as e: logger.warning("Failed to read data config: %s", e) return settings.data_path def set_active_data_path(path: Path) -> None: """Set the active data file path.""" config_file = _config_path() config_file.parent.mkdir(parents=True, exist_ok=True) config = { "active_data_path": str(path), "updated_at": datetime.now().isoformat(), } config_file.write_text(json.dumps(config, indent=2), encoding="utf-8") logger.info("Updated active data path to: %s", path) def reset_to_default() -> None: """Reset to use the default data file.""" config_file = _config_path() if config_file.exists(): config_file.unlink() logger.info("Reset to default data path") def save_uploaded_file(content: bytes, original_filename: str) -> Path: """ Save uploaded file content to the data/raw directory. Returns the path to the saved file. """ settings = get_settings() upload_dir = settings.root_dir / "data" / "raw" upload_dir.mkdir(parents=True, exist_ok=True) # Generate timestamped filename timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") # Keep original extension suffix = Path(original_filename).suffix or ".csv" filename = f"uploaded_data_{timestamp}{suffix}" file_path = upload_dir / filename file_path.write_bytes(content) logger.info("Saved uploaded file to: %s", file_path) return file_path def get_data_info() -> dict: """Get information about the current data configuration.""" settings = get_settings() active_path = get_active_data_path() default_path = settings.data_path return { "active_path": str(active_path), "active_filename": active_path.name, "active_exists": active_path.exists(), "is_custom": active_path != default_path, "default_path": str(default_path), "default_filename": default_path.name, "default_exists": default_path.exists(), }