LocalScriptsWeb/backend/core/profile_manager.py

216 lines
7.6 KiB
Python

from pathlib import Path
import json
from typing import Dict, Any, List, Optional
from datetime import datetime
class ProfileManager:
"""Manages application profiles"""
DEFAULT_PROFILE = {
"id": "default",
"name": "Default Profile",
"llm_settings": {"model": "gpt-4", "temperature": 0.7, "api_key": ""},
}
def __init__(self, data_dir: Path):
self.data_dir = data_dir
self.profiles_file = data_dir / "profiles.json"
self.schema_file = data_dir / "profile_schema.json"
self.profiles: Dict[str, Dict] = self._load_profiles()
self._schema = self._load_schema()
def _load_schema(self) -> Dict[str, Any]:
"""Load profile schema"""
if self.schema_file.exists():
try:
with open(self.schema_file, "r", encoding="utf-8") as f:
return json.load(f)
except Exception as e:
print(f"Error loading profile schema: {e}")
return {"config_schema": {}}
def _load_profiles(self) -> Dict[str, Dict]:
"""Load all profiles and ensure default profile exists"""
profiles = {}
# Crear perfil por defecto si no existe
default_profile = self._create_default_profile()
try:
if self.profiles_file.exists():
with open(self.profiles_file, "r", encoding="utf-8") as f:
loaded_profiles = json.load(f)
profiles.update(loaded_profiles)
except Exception as e:
print(f"Error loading profiles: {e}")
# Asegurar que existe el perfil por defecto
if "default" not in profiles:
profiles["default"] = default_profile
self._save_profiles(profiles)
return profiles
def _create_default_profile(self) -> Dict[str, Any]:
"""Create default profile"""
profile = self.DEFAULT_PROFILE.copy()
now = datetime.now().isoformat()
profile["created_at"] = now
profile["updated_at"] = now
return profile
def _save_profiles(self, profiles: Optional[Dict] = None):
"""Save all profiles"""
if profiles is None:
profiles = self.profiles
try:
self.profiles_file.parent.mkdir(parents=True, exist_ok=True)
with open(self.profiles_file, "w", encoding="utf-8") as f:
json.dump(profiles, f, indent=4)
except Exception as e:
print(f"Error saving profiles: {e}")
raise
def _validate_profile(self, profile_data: Dict[str, Any]) -> Dict[str, Any]:
"""Validate profile data against schema"""
schema = self._schema.get("config_schema", {})
validated = {}
for key, field_schema in schema.items():
if key in profile_data:
validated[key] = self._validate_field(
key, profile_data[key], field_schema
)
elif field_schema.get("required", False):
raise ValueError(f"Required field '{key}' is missing")
else:
validated[key] = field_schema.get("default")
# Pass through non-schema fields
for key, value in profile_data.items():
if key not in schema:
validated[key] = value
return validated
def _validate_field(
self, key: str, value: Any, field_schema: Dict[str, Any]
) -> Any:
"""Validate a single field value"""
field_type = field_schema.get("type")
if value is None or value == "":
if field_schema.get("required", False):
raise ValueError(f"Field '{key}' is required")
return field_schema.get("default")
try:
if field_type == "string":
return str(value)
elif field_type == "number":
return float(value) if "." in str(value) else int(value)
elif field_type == "boolean":
if isinstance(value, str):
return value.lower() == "true"
return bool(value)
elif field_type == "select":
if value not in field_schema.get("options", []):
raise ValueError(f"Invalid option '{value}' for field '{key}'")
return value
else:
return value
except Exception as e:
raise ValueError(f"Invalid value for field '{key}': {str(e)}")
def get_all_profiles(self) -> List[Dict[str, Any]]:
"""Get all profiles"""
return list(self.profiles.values())
def get_profile(self, profile_id: str) -> Optional[Dict[str, Any]]:
"""Get specific profile with fallback to default"""
profile = self.profiles.get(profile_id)
if not profile and profile_id != "default":
# Si no se encuentra el perfil y no es el perfil por defecto,
# intentar retornar el perfil por defecto
profile = self.profiles.get("default")
if not profile:
# Si tampoco existe el perfil por defecto, crearlo
profile = self._create_default_profile()
self.profiles["default"] = profile
self._save_profiles(self.profiles)
return profile
def create_profile(self, profile_data: Dict[str, Any]) -> Dict[str, Any]:
"""Create new profile"""
if "id" not in profile_data:
raise ValueError("Profile must have an id")
profile_id = profile_data["id"]
if profile_id in self.profiles:
raise ValueError(f"Profile {profile_id} already exists")
# Add timestamps
now = datetime.now().isoformat()
profile_data["created_at"] = now
profile_data["updated_at"] = now
# Validate profile data
validated_data = self._validate_profile(profile_data)
# Save profile
self.profiles[profile_id] = validated_data
self._save_profiles()
return validated_data
def update_profile(
self, profile_id: str, profile_data: Dict[str, Any]
) -> Dict[str, Any]:
"""Update existing profile"""
if profile_id not in self.profiles:
raise ValueError(f"Profile {profile_id} not found")
if profile_id == "default" and "id" in profile_data:
raise ValueError("Cannot change id of default profile")
# Update timestamp
profile_data["updated_at"] = datetime.now().isoformat()
# Validate profile data
validated_data = self._validate_profile(profile_data)
# Update profile
current_profile = self.profiles[profile_id].copy()
current_profile.update(validated_data)
self.profiles[profile_id] = current_profile
self._save_profiles()
return current_profile
def delete_profile(self, profile_id: str):
"""Delete profile"""
if profile_id == "default":
raise ValueError("Cannot delete default profile")
if profile_id not in self.profiles:
raise ValueError(f"Profile {profile_id} not found")
del self.profiles[profile_id]
self._save_profiles()
def get_schema(self) -> Dict[str, Any]:
"""Get profile schema"""
return self._schema
def update_schema(self, schema: Dict[str, Any]):
"""Update profile schema"""
try:
self.schema_file.parent.mkdir(parents=True, exist_ok=True)
with open(self.schema_file, "w", encoding="utf-8") as f:
json.dump(schema, f, indent=4)
self._schema = schema
except Exception as e:
print(f"Error saving schema: {e}")
raise