71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
|
|
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()
|