fina autoamtiona adn billing and credits

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-04 15:54:15 +00:00
parent f8a9293196
commit 40dfe20ead
40 changed files with 5680 additions and 18 deletions

View File

@@ -40,6 +40,7 @@ class AutoClusterFunction(BaseAIFunction):
def validate(self, payload: dict, account=None) -> Dict:
"""Custom validation for clustering"""
from igny8_core.ai.validators import validate_ids, validate_keywords_exist
from igny8_core.ai.validators.cluster_validators import validate_minimum_keywords
# Base validation (no max_items limit)
result = validate_ids(payload, max_items=None)
@@ -52,6 +53,21 @@ class AutoClusterFunction(BaseAIFunction):
if not keywords_result['valid']:
return keywords_result
# NEW: Validate minimum keywords (5 required for meaningful clustering)
min_validation = validate_minimum_keywords(
keyword_ids=ids,
account=account,
min_required=5
)
if not min_validation['valid']:
logger.warning(f"[AutoCluster] Validation failed: {min_validation['error']}")
return min_validation
logger.info(
f"[AutoCluster] Validation passed: {min_validation['count']} keywords available (min: {min_validation['required']})"
)
# Removed plan limits check
return {'valid': True}

View File

@@ -0,0 +1,52 @@
"""
AI Validators Package
Shared validation logic for AI functions
"""
from .cluster_validators import validate_minimum_keywords, validate_keyword_selection
# The codebase also contains a module-level file `ai/validators.py` which defines
# common validator helpers (e.g. `validate_ids`). Because there is both a
# package directory `ai/validators/` and a module file `ai/validators.py`, Python
# will resolve `igny8_core.ai.validators` to the package and not the module file.
# To avoid changing many imports across the project, load the module file here
# and re-export the commonly used functions.
import importlib.util
import os
_module_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'validators.py'))
if os.path.exists(_module_path):
spec = importlib.util.spec_from_file_location('igny8_core.ai._validators_module', _module_path)
_validators_mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(_validators_mod)
# Re-export commonly used functions from the module file
validate_ids = getattr(_validators_mod, 'validate_ids', None)
validate_keywords_exist = getattr(_validators_mod, 'validate_keywords_exist', None)
validate_cluster_limits = getattr(_validators_mod, 'validate_cluster_limits', None)
validate_cluster_exists = getattr(_validators_mod, 'validate_cluster_exists', None)
validate_tasks_exist = getattr(_validators_mod, 'validate_tasks_exist', None)
validate_api_key = getattr(_validators_mod, 'validate_api_key', None)
validate_model = getattr(_validators_mod, 'validate_model', None)
validate_image_size = getattr(_validators_mod, 'validate_image_size', None)
else:
# Module file missing - keep names defined if cluster validators provide them
validate_ids = None
validate_keywords_exist = None
validate_cluster_limits = None
validate_cluster_exists = None
validate_tasks_exist = None
validate_api_key = None
validate_model = None
validate_image_size = None
__all__ = [
'validate_minimum_keywords',
'validate_keyword_selection',
'validate_ids',
'validate_keywords_exist',
'validate_cluster_limits',
'validate_cluster_exists',
'validate_tasks_exist',
'validate_api_key',
'validate_model',
'validate_image_size',
]

View File

@@ -0,0 +1,105 @@
"""
Cluster-specific validators
Shared between auto-cluster function and automation pipeline
"""
import logging
from typing import Dict, List
logger = logging.getLogger(__name__)
def validate_minimum_keywords(
keyword_ids: List[int],
account=None,
min_required: int = 5
) -> Dict:
"""
Validate that sufficient keywords are available for clustering
Args:
keyword_ids: List of keyword IDs to cluster
account: Account object for filtering
min_required: Minimum number of keywords required (default: 5)
Returns:
Dict with 'valid' (bool) and 'error' (str) or 'count' (int)
"""
from igny8_core.modules.planner.models import Keywords
# Build queryset
queryset = Keywords.objects.filter(id__in=keyword_ids, status='new')
if account:
queryset = queryset.filter(account=account)
# Count available keywords
count = queryset.count()
# Validate minimum
if count < min_required:
return {
'valid': False,
'error': f'Insufficient keywords for clustering. Need at least {min_required} keywords, but only {count} available.',
'count': count,
'required': min_required
}
return {
'valid': True,
'count': count,
'required': min_required
}
def validate_keyword_selection(
selected_ids: List[int],
available_count: int,
min_required: int = 5
) -> Dict:
"""
Validate keyword selection (for frontend validation)
Args:
selected_ids: List of selected keyword IDs
available_count: Total count of available keywords
min_required: Minimum required
Returns:
Dict with validation result
"""
selected_count = len(selected_ids)
# Check if any keywords selected
if selected_count == 0:
return {
'valid': False,
'error': 'No keywords selected',
'type': 'NO_SELECTION'
}
# Check if enough selected
if selected_count < min_required:
return {
'valid': False,
'error': f'Please select at least {min_required} keywords. Currently selected: {selected_count}',
'type': 'INSUFFICIENT_SELECTION',
'selected': selected_count,
'required': min_required
}
# Check if enough available (even if not all selected)
if available_count < min_required:
return {
'valid': False,
'error': f'Not enough keywords available. Need at least {min_required} keywords, but only {available_count} exist.',
'type': 'INSUFFICIENT_AVAILABLE',
'available': available_count,
'required': min_required
}
return {
'valid': True,
'selected': selected_count,
'available': available_count,
'required': min_required
}