""" AI Validators - Consolidated validation logic for all AI functions """ import logging from typing import Dict, Any, Optional from django.utils import timezone logger = logging.getLogger(__name__) def validate_ids(payload: dict, max_items: Optional[int] = None) -> Dict[str, Any]: """ Base validation: checks for 'ids' array. Args: payload: Request payload containing 'ids' array max_items: Maximum number of items allowed (deprecated - no longer enforced) Returns: Dict with 'valid' (bool) and optional 'error' (str) """ ids = payload.get('ids', []) if not ids: return {'valid': False, 'error': 'No IDs provided'} # Removed max_items limit check - no limits enforced return {'valid': True} def validate_keywords_exist(ids: list, account=None) -> Dict[str, Any]: """ Validate that keywords exist in database. Args: ids: List of keyword IDs account: Optional account for filtering Returns: Dict with 'valid' (bool) and optional 'error' (str) """ from igny8_core.modules.planner.models import Keywords queryset = Keywords.objects.filter(id__in=ids) if account: queryset = queryset.filter(account=account) if queryset.count() == 0: return {'valid': False, 'error': 'No keywords found'} return {'valid': True} def validate_cluster_limits(account, operation_type: str = 'cluster') -> Dict[str, Any]: """ Validate plan limits for cluster operations. DISABLED: All limits have been removed. Args: account: Account object operation_type: Type of operation ('cluster', 'idea', etc.) Returns: Dict with 'valid' (bool) - always returns valid """ # All limits removed - always return valid return {'valid': True} def validate_cluster_exists(cluster_id: int, account=None) -> Dict[str, Any]: """ Validate that a cluster exists. Args: cluster_id: Cluster ID account: Optional account for filtering Returns: Dict with 'valid' (bool) and optional 'error' (str) """ from igny8_core.modules.planner.models import Clusters queryset = Clusters.objects.filter(id=cluster_id) if account: queryset = queryset.filter(account=account) if not queryset.exists(): return {'valid': False, 'error': 'Cluster not found'} return {'valid': True} def validate_tasks_exist(task_ids: list, account=None) -> Dict[str, Any]: """ Validate that tasks exist in database. Args: task_ids: List of task IDs account: Optional account for filtering Returns: Dict with 'valid' (bool) and optional 'error' (str) """ from igny8_core.modules.writer.models import Tasks queryset = Tasks.objects.filter(id__in=task_ids) if account: queryset = queryset.filter(account=account) if queryset.count() == 0: return {'valid': False, 'error': 'No tasks found'} return {'valid': True} def validate_api_key(api_key: Optional[str], integration_type: str = 'openai') -> Dict[str, Any]: """ Validate that API key is configured. Args: api_key: API key to validate integration_type: Type of integration ('openai', 'runware') Returns: Dict with 'valid' (bool) and optional 'error' (str) """ if not api_key: return { 'valid': False, 'error': f'{integration_type.upper()} API key not configured' } return {'valid': True} def validate_model(model: str, model_type: str = 'text') -> Dict[str, Any]: """ Validate that model is in supported list using database. Args: model: Model name to validate model_type: Type of model ('text' or 'image') Returns: Dict with 'valid' (bool) and optional 'error' (str) """ try: # Try database first from igny8_core.business.billing.models import AIModelConfig exists = AIModelConfig.objects.filter( model_name=model, model_type=model_type, is_active=True ).exists() if not exists: # Get available models for better error message available = list(AIModelConfig.objects.filter( model_type=model_type, is_active=True ).values_list('model_name', flat=True)) if available: return { 'valid': False, 'error': f'Model "{model}" is not active or not found. Available {model_type} models: {", ".join(available)}' } else: return { 'valid': False, 'error': f'Model "{model}" is not found in database' } return {'valid': True} except Exception: # Fallback to constants if database fails from .constants import MODEL_RATES, VALID_OPENAI_IMAGE_MODELS if model_type == 'text': if model not in MODEL_RATES: return { 'valid': False, 'error': f'Model "{model}" is not in supported models list' } elif model_type == 'image': if model not in VALID_OPENAI_IMAGE_MODELS: return { 'valid': False, 'error': f'Model "{model}" is not valid for OpenAI image generation. Only {", ".join(VALID_OPENAI_IMAGE_MODELS)} are supported.' } return {'valid': True} def validate_image_size(size: str, model: str) -> Dict[str, Any]: """ Validate that image size is valid for the selected model using database. Args: size: Image size (e.g., '1024x1024') model: Model name Returns: Dict with 'valid' (bool) and optional 'error' (str) """ try: # Try database first from igny8_core.business.billing.models import AIModelConfig model_config = AIModelConfig.objects.filter( model_name=model, model_type='image', is_active=True ).first() if model_config: if not model_config.validate_size(size): valid_sizes = model_config.valid_sizes or [] return { 'valid': False, 'error': f'Image size "{size}" is not valid for model "{model}". Valid sizes are: {", ".join(valid_sizes)}' } return {'valid': True} else: return { 'valid': False, 'error': f'Image model "{model}" not found in database' } except Exception: # Fallback to constants if database fails from .constants import VALID_SIZES_BY_MODEL valid_sizes = VALID_SIZES_BY_MODEL.get(model, []) if size not in valid_sizes: return { 'valid': False, 'error': f'Image size "{size}" is not valid for model "{model}". Valid sizes are: {", ".join(valid_sizes)}' } return {'valid': True}