import json from dataclasses import dataclass from pathlib import Path from typing import Any from app.config import settings @dataclass(frozen=True) class Profile: code: str analysis_type: str directory: Path config: dict[str, Any] class ProfileStore: def __init__(self) -> None: self._profiles: dict[str, Profile] = {} def reload(self) -> None: profiles: dict[str, Profile] = {} if settings.profiles_dir.exists(): for path in settings.profiles_dir.rglob("profile.json"): data = json.loads(path.read_text(encoding="utf-8")) code = str(data.get("code", "")).strip() analysis_type = str(data.get("analysisType", "")).strip() if not code or not analysis_type: raise ValueError(f"Invalid profile: {path}") if code in profiles: raise ValueError(f"Duplicate profile code: {code}") profiles[code] = Profile(code, analysis_type, path.parent, data) self._profiles = profiles def get(self, code: str, analysis_type: str) -> Profile: profile = self._profiles.get(code) if profile is None: raise KeyError(f"Analysis profile does not exist: {code}") if profile.analysis_type != analysis_type: raise ValueError( f"Profile {code} is for {profile.analysis_type}, not {analysis_type}" ) return profile def status(self) -> list[dict[str, Any]]: result = [] for profile in self._profiles.values(): ready = True detail = "READY" if profile.analysis_type == "AUDIO_CLASSIFICATION": artifact = artifact_path(profile) ready = artifact.exists() detail = "READY" if ready else "WAITING_FOR_REFERENCE_AUDIO" result.append( { "code": profile.code, "analysisType": profile.analysis_type, "ready": ready, "detail": detail, } ) return result def artifact_path(profile: Profile) -> Path: relative = profile.directory.relative_to(settings.profiles_dir) return settings.artifacts_dir / relative / "audio_features.npz" profile_store = ProfileStore()