216 lines
7.6 KiB
Python
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
|