243 lines
9.1 KiB
Python
243 lines
9.1 KiB
Python
"""
|
|
AI Settings - Centralized model configurations and limits
|
|
Uses global settings with optional per-account overrides.
|
|
"""
|
|
from typing import Dict, Any
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Function name aliases (for backward compatibility)
|
|
FUNCTION_ALIASES = {
|
|
"cluster_keywords": "auto_cluster",
|
|
"auto_cluster_keywords": "auto_cluster",
|
|
"auto_generate_ideas": "generate_ideas",
|
|
"auto_generate_content": "generate_content",
|
|
"auto_generate_images": "generate_images",
|
|
}
|
|
|
|
|
|
def get_model_config(function_name: str, account) -> Dict[str, Any]:
|
|
"""
|
|
Get model configuration for AI function.
|
|
|
|
Architecture:
|
|
- API keys: ALWAYS from GlobalIntegrationSettings (platform-wide)
|
|
- Model/params: From IntegrationSettings if account has override, else from global
|
|
- Free plan: Cannot override, uses global defaults
|
|
- Starter/Growth/Scale: Can override model, temperature, max_tokens, etc.
|
|
|
|
Args:
|
|
function_name: Name of the AI function
|
|
account: Account instance (required)
|
|
|
|
Returns:
|
|
dict: Model configuration with 'model', 'max_tokens', 'temperature', 'api_key'
|
|
|
|
Raises:
|
|
ValueError: If account not provided or settings not configured
|
|
"""
|
|
if not account:
|
|
raise ValueError("Account is required for model configuration")
|
|
|
|
# Resolve function alias
|
|
actual_name = FUNCTION_ALIASES.get(function_name, function_name)
|
|
|
|
try:
|
|
from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings
|
|
from igny8_core.modules.system.models import IntegrationSettings
|
|
|
|
# Get global settings (for API keys and defaults)
|
|
global_settings = GlobalIntegrationSettings.get_instance()
|
|
|
|
if not global_settings.openai_api_key:
|
|
raise ValueError(
|
|
"Platform OpenAI API key not configured. "
|
|
"Please configure GlobalIntegrationSettings in Django admin."
|
|
)
|
|
|
|
# Start with global defaults
|
|
model = global_settings.openai_model
|
|
temperature = global_settings.openai_temperature
|
|
max_tokens = global_settings.openai_max_tokens
|
|
api_key = global_settings.openai_api_key # ALWAYS from global
|
|
|
|
# Check if account has overrides (only for Starter/Growth/Scale plans)
|
|
# Free plan users cannot create IntegrationSettings records
|
|
try:
|
|
account_settings = IntegrationSettings.objects.get(
|
|
account=account,
|
|
integration_type='openai',
|
|
is_active=True
|
|
)
|
|
|
|
config = account_settings.config or {}
|
|
|
|
# Override model if specified (NULL = use global)
|
|
if config.get('model'):
|
|
model = config['model']
|
|
|
|
# Override temperature if specified
|
|
if config.get('temperature') is not None:
|
|
temperature = config['temperature']
|
|
|
|
# Override max_tokens if specified
|
|
if config.get('max_tokens'):
|
|
max_tokens = config['max_tokens']
|
|
|
|
except IntegrationSettings.DoesNotExist:
|
|
# No account override, use global defaults (already set above)
|
|
pass
|
|
|
|
except Exception as e:
|
|
logger.error(f"Could not load OpenAI settings for account {account.id}: {e}")
|
|
raise ValueError(
|
|
f"Could not load OpenAI configuration for account {account.id}. "
|
|
f"Please configure GlobalIntegrationSettings."
|
|
)
|
|
|
|
# Validate model is in our supported list (optional validation)
|
|
try:
|
|
from igny8_core.utils.ai_processor import MODEL_RATES
|
|
if model not in MODEL_RATES:
|
|
logger.warning(
|
|
f"Model '{model}' for account {account.id} is not in supported list. "
|
|
f"Supported models: {list(MODEL_RATES.keys())}"
|
|
)
|
|
except ImportError:
|
|
pass
|
|
|
|
# Build response format based on model (JSON mode for supported models)
|
|
response_format = None
|
|
try:
|
|
from igny8_core.ai.constants import JSON_MODE_MODELS
|
|
if model in JSON_MODE_MODELS:
|
|
response_format = {"type": "json_object"}
|
|
except ImportError:
|
|
pass
|
|
|
|
return {
|
|
'model': model,
|
|
'max_tokens': max_tokens,
|
|
'temperature': temperature,
|
|
'response_format': response_format,
|
|
}
|
|
|
|
|
|
def get_image_generation_config(account) -> Dict[str, Any]:
|
|
"""
|
|
Get image generation configuration for AI functions.
|
|
|
|
Architecture:
|
|
- API keys: ALWAYS from GlobalIntegrationSettings (platform-wide)
|
|
- Model/params: From IntegrationSettings if account has override, else from global
|
|
- Supports both OpenAI (DALL-E) and Runware providers
|
|
|
|
Args:
|
|
account: Account instance (required)
|
|
|
|
Returns:
|
|
dict: Image generation configuration with 'provider', 'model', 'api_key',
|
|
'size', 'quality', 'style', 'max_in_article_images'
|
|
|
|
Raises:
|
|
ValueError: If account not provided or settings not configured
|
|
"""
|
|
if not account:
|
|
raise ValueError("Account is required for image generation configuration")
|
|
|
|
try:
|
|
from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings
|
|
from igny8_core.modules.system.models import IntegrationSettings
|
|
|
|
# Get global settings (for API keys and defaults)
|
|
global_settings = GlobalIntegrationSettings.get_instance()
|
|
|
|
# Start with global defaults
|
|
provider = global_settings.default_image_service # 'openai' or 'runware'
|
|
max_in_article_images = global_settings.max_in_article_images
|
|
|
|
if provider == 'runware':
|
|
api_key = global_settings.runware_api_key
|
|
model = global_settings.runware_model
|
|
size = global_settings.desktop_image_size
|
|
quality = global_settings.image_quality
|
|
style = global_settings.image_style
|
|
|
|
if not api_key:
|
|
raise ValueError(
|
|
"Platform Runware API key not configured. "
|
|
"Please configure GlobalIntegrationSettings in Django admin."
|
|
)
|
|
else: # openai/dalle
|
|
api_key = global_settings.dalle_api_key or global_settings.openai_api_key
|
|
model = global_settings.dalle_model
|
|
size = global_settings.dalle_size
|
|
quality = global_settings.image_quality
|
|
style = global_settings.image_style
|
|
|
|
if not api_key:
|
|
raise ValueError(
|
|
"Platform OpenAI/DALL-E API key not configured. "
|
|
"Please configure GlobalIntegrationSettings in Django admin."
|
|
)
|
|
|
|
# Check if account has overrides
|
|
# Try both 'image_generation' and provider-specific types for backward compatibility
|
|
account_settings = None
|
|
for integration_type in ['image_generation', provider, 'dalle', 'runware']:
|
|
try:
|
|
account_settings = IntegrationSettings.objects.get(
|
|
account=account,
|
|
integration_type=integration_type,
|
|
is_active=True
|
|
)
|
|
break
|
|
except IntegrationSettings.DoesNotExist:
|
|
continue
|
|
|
|
if account_settings:
|
|
config = account_settings.config or {}
|
|
|
|
# Override provider if specified
|
|
if config.get('provider') or config.get('service'):
|
|
provider = config.get('provider') or config.get('service')
|
|
|
|
# Override model if specified
|
|
if config.get('model'):
|
|
model = config['model']
|
|
|
|
# Override size if specified
|
|
if config.get('size') or config.get('image_size'):
|
|
size = config.get('size') or config.get('image_size')
|
|
|
|
# Override quality if specified
|
|
if config.get('quality') or config.get('image_quality'):
|
|
quality = config.get('quality') or config.get('image_quality')
|
|
|
|
# Override style if specified
|
|
if config.get('style') or config.get('image_style'):
|
|
style = config.get('style') or config.get('image_style')
|
|
|
|
# Override max_in_article_images if specified
|
|
if config.get('max_in_article_images'):
|
|
max_in_article_images = int(config['max_in_article_images'])
|
|
|
|
return {
|
|
'provider': provider,
|
|
'model': model,
|
|
'api_key': api_key, # ALWAYS from global
|
|
'size': size,
|
|
'quality': quality,
|
|
'style': style,
|
|
'max_in_article_images': max_in_article_images,
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Could not load image generation settings for account {account.id}: {e}")
|
|
raise ValueError(
|
|
f"Could not load image generation configuration for account {account.id}. "
|
|
f"Please configure GlobalIntegrationSettings."
|
|
)
|
|
|