Fix image generation: escape JSON in prompt template + GlobalIntegrationSettings fallback

ROOT CAUSES IDENTIFIED:
1. GlobalAIPrompt template had unescaped JSON braces that broke Python's .format()
   - Python treats {...} as placeholders, causing KeyError when rendering
   - Escaped JSON braces to {{...}} while preserving {title}, {content}, {max_images}

2. Image functions hardcoded aws-admin IntegrationSettings which didn't exist
   - Functions failed when aws-admin account had no IntegrationSettings
   - Added GlobalIntegrationSettings fallback for all missing values

CHANGES:
- Fixed GlobalAIPrompt.image_prompt_extraction template in database (escaped JSON)
- Updated generate_image_prompts._get_max_in_article_images() with fallback
- Updated generate_images.prepare_data() with fallback for all image settings
- Updated tasks.process_image_generation_queue() with fallback for config + API keys

TESTED: Template rendering now works, GlobalIntegrationSettings.max_in_article_images=4
This commit is contained in:
IGNY8 VPS (Salman)
2025-12-25 02:09:29 +00:00
parent 5299fd82eb
commit 504d0174f7
3 changed files with 91 additions and 51 deletions

View File

@@ -218,27 +218,35 @@ class GenerateImagePromptsFunction(BaseAIFunction):
# Helper methods # Helper methods
def _get_max_in_article_images(self, account) -> int: def _get_max_in_article_images(self, account) -> int:
"""Get max_in_article_images from AWS account IntegrationSettings only""" """
Get max_in_article_images from settings.
Tries aws-admin IntegrationSettings first, falls back to GlobalIntegrationSettings.
"""
from igny8_core.modules.system.models import IntegrationSettings from igny8_core.modules.system.models import IntegrationSettings
from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings
from igny8_core.auth.models import Account from igny8_core.auth.models import Account
# Only use system account (aws-admin) settings # Try aws-admin IntegrationSettings first (legacy pattern)
system_account = Account.objects.get(slug='aws-admin') try:
settings = IntegrationSettings.objects.get( system_account = Account.objects.get(slug='aws-admin')
account=system_account, settings = IntegrationSettings.objects.get(
integration_type='image_generation', account=system_account,
is_active=True integration_type='image_generation',
) is_active=True
max_images = settings.config.get('max_in_article_images')
if max_images is None:
raise ValueError(
"max_in_article_images not configured in aws-admin image_generation settings. "
"Please set this value in the Integration Settings page."
) )
max_images = settings.config.get('max_in_article_images')
max_images = int(max_images) if max_images is not None:
logger.info(f"Using max_in_article_images={max_images} from aws-admin account") max_images = int(max_images)
logger.info(f"Using max_in_article_images={max_images} from aws-admin IntegrationSettings")
return max_images
except (Account.DoesNotExist, IntegrationSettings.DoesNotExist):
logger.debug("aws-admin IntegrationSettings not found, falling back to GlobalIntegrationSettings")
# Fall back to GlobalIntegrationSettings
global_settings = GlobalIntegrationSettings.get_instance()
max_images = global_settings.max_in_article_images
logger.info(f"Using max_in_article_images={max_images} from GlobalIntegrationSettings")
return max_images return max_images
def _extract_content_elements(self, content: Content, max_images: int) -> Dict: def _extract_content_elements(self, content: Content, max_images: int) -> Dict:

View File

@@ -67,32 +67,42 @@ class GenerateImagesFunction(BaseAIFunction):
if not tasks: if not tasks:
raise ValueError("No tasks found") raise ValueError("No tasks found")
# Get image generation settings from aws-admin account only (global settings) # Get image generation settings
# Try aws-admin IntegrationSettings first (legacy), fall back to GlobalIntegrationSettings
from igny8_core.modules.system.models import IntegrationSettings from igny8_core.modules.system.models import IntegrationSettings
from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings
from igny8_core.auth.models import Account from igny8_core.auth.models import Account
system_account = Account.objects.get(slug='aws-admin') image_settings = {}
integration = IntegrationSettings.objects.get( try:
account=system_account, system_account = Account.objects.get(slug='aws-admin')
integration_type='image_generation', integration = IntegrationSettings.objects.get(
is_active=True account=system_account,
) integration_type='image_generation',
image_settings = integration.config or {} is_active=True
)
image_settings = integration.config or {}
logger.info("Using image settings from aws-admin IntegrationSettings")
except (Account.DoesNotExist, IntegrationSettings.DoesNotExist):
logger.info("aws-admin IntegrationSettings not found, using GlobalIntegrationSettings")
# Extract settings with defaults # Fall back to GlobalIntegrationSettings for missing values
provider = image_settings.get('provider') or image_settings.get('service', 'openai') global_settings = GlobalIntegrationSettings.get_instance()
# Extract settings with defaults from global settings
provider = image_settings.get('provider') or image_settings.get('service') or global_settings.default_image_service
if provider == 'runware': if provider == 'runware':
model = image_settings.get('model') or image_settings.get('runwareModel', 'runware:97@1') model = image_settings.get('model') or image_settings.get('runwareModel') or global_settings.runware_model
else: else:
model = image_settings.get('model', 'dall-e-3') model = image_settings.get('model') or global_settings.dalle_model
return { return {
'tasks': tasks, 'tasks': tasks,
'account': account, 'account': account,
'provider': provider, 'provider': provider,
'model': model, 'model': model,
'image_type': image_settings.get('image_type', 'realistic'), 'image_type': image_settings.get('image_type') or global_settings.image_style,
'max_in_article_images': int(image_settings.get('max_in_article_images')), 'max_in_article_images': int(image_settings.get('max_in_article_images') or global_settings.max_in_article_images),
'desktop_enabled': image_settings.get('desktop_enabled', True), 'desktop_enabled': image_settings.get('desktop_enabled', True),
'mobile_enabled': image_settings.get('mobile_enabled', True), 'mobile_enabled': image_settings.get('mobile_enabled', True),
} }

View File

@@ -181,10 +181,13 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
failed = 0 failed = 0
results = [] results = []
# Get image generation settings from IntegrationSettings # Get image generation settings
# Always use system account settings (aws-admin) for global configuration # Try aws-admin IntegrationSettings first (legacy), fall back to GlobalIntegrationSettings
logger.info("[process_image_generation_queue] Step 1: Loading image generation settings from aws-admin") logger.info("[process_image_generation_queue] Step 1: Loading image generation settings")
from igny8_core.auth.models import Account from igny8_core.auth.models import Account
from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings
config = {}
try: try:
system_account = Account.objects.get(slug='aws-admin') system_account = Account.objects.get(slug='aws-admin')
image_settings = IntegrationSettings.objects.get( image_settings = IntegrationSettings.objects.get(
@@ -192,30 +195,35 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
integration_type='image_generation', integration_type='image_generation',
is_active=True is_active=True
) )
logger.info(f"[process_image_generation_queue] Using system account (aws-admin) settings") logger.info(f"[process_image_generation_queue] Using system account (aws-admin) IntegrationSettings")
config = image_settings.config or {} config = image_settings.config or {}
except (Account.DoesNotExist, IntegrationSettings.DoesNotExist): except (Account.DoesNotExist, IntegrationSettings.DoesNotExist):
logger.error("[process_image_generation_queue] ERROR: Image generation settings not found in aws-admin account") logger.info("[process_image_generation_queue] aws-admin IntegrationSettings not found, using GlobalIntegrationSettings")
return {'success': False, 'error': 'Image generation settings not found in aws-admin account'}
except Exception as e: except Exception as e:
logger.error(f"[process_image_generation_queue] ERROR loading image generation settings: {e}", exc_info=True) logger.error(f"[process_image_generation_queue] ERROR loading image generation settings: {e}", exc_info=True)
return {'success': False, 'error': f'Error loading image generation settings: {str(e)}'} return {'success': False, 'error': f'Error loading image generation settings: {str(e)}'}
# Fall back to GlobalIntegrationSettings for missing values
global_settings = GlobalIntegrationSettings.get_instance()
logger.info(f"[process_image_generation_queue] Image generation settings loaded. Config keys: {list(config.keys())}") logger.info(f"[process_image_generation_queue] Image generation settings loaded. Config keys: {list(config.keys())}")
logger.info(f"[process_image_generation_queue] Full config: {config}") logger.info(f"[process_image_generation_queue] Full config: {config}")
# Get provider and model from config (respect user settings) # Get provider and model from config with global fallbacks
provider = config.get('provider', 'openai') provider = config.get('provider') or global_settings.default_image_service
# Get model - try 'model' first, then 'imageModel' as fallback if provider == 'runware':
model = config.get('model') or config.get('imageModel') or 'dall-e-3' model = config.get('model') or config.get('imageModel') or global_settings.runware_model
else:
model = config.get('model') or config.get('imageModel') or global_settings.dalle_model
logger.info(f"[process_image_generation_queue] Using PROVIDER: {provider}, MODEL: {model} from settings") logger.info(f"[process_image_generation_queue] Using PROVIDER: {provider}, MODEL: {model} from settings")
image_type = config.get('image_type', 'realistic') image_type = config.get('image_type') or global_settings.image_style
image_format = config.get('image_format', 'webp') image_format = config.get('image_format', 'webp')
desktop_enabled = config.get('desktop_enabled', True) desktop_enabled = config.get('desktop_enabled', True)
mobile_enabled = config.get('mobile_enabled', True) mobile_enabled = config.get('mobile_enabled', True)
# Get image sizes from config, with fallback defaults # Get image sizes from config, with fallback defaults
featured_image_size = config.get('featured_image_size') or ('1280x832' if provider == 'runware' else '1024x1024') featured_image_size = config.get('featured_image_size') or ('1280x832' if provider == 'runware' else '1024x1024')
desktop_image_size = config.get('desktop_image_size') or '1024x1024' desktop_image_size = config.get('desktop_image_size') or global_settings.desktop_image_size
in_article_image_size = config.get('in_article_image_size') or '512x512' # Default to 512x512 in_article_image_size = config.get('in_article_image_size') or '512x512' # Default to 512x512
logger.info(f"[process_image_generation_queue] Settings loaded:") logger.info(f"[process_image_generation_queue] Settings loaded:")
@@ -228,7 +236,7 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
# Get provider API key (using same approach as test image generation) # Get provider API key (using same approach as test image generation)
# Note: API key is stored as 'apiKey' (camelCase) in IntegrationSettings.config # Note: API key is stored as 'apiKey' (camelCase) in IntegrationSettings.config
# Normal users use system account settings (aws-admin) via fallback # Normal users use system account settings (aws-admin) via fallback, or GlobalIntegrationSettings
logger.info(f"[process_image_generation_queue] Step 2: Loading {provider.upper()} API key") logger.info(f"[process_image_generation_queue] Step 2: Loading {provider.upper()} API key")
try: try:
provider_settings = IntegrationSettings.objects.get( provider_settings = IntegrationSettings.objects.get(
@@ -240,7 +248,6 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
except IntegrationSettings.DoesNotExist: except IntegrationSettings.DoesNotExist:
# Fallback to system account (aws-admin) settings # Fallback to system account (aws-admin) settings
logger.info(f"[process_image_generation_queue] No {provider.upper()} settings for account {account.id}, falling back to system account") logger.info(f"[process_image_generation_queue] No {provider.upper()} settings for account {account.id}, falling back to system account")
from igny8_core.auth.models import Account
try: try:
system_account = Account.objects.get(slug='aws-admin') system_account = Account.objects.get(slug='aws-admin')
provider_settings = IntegrationSettings.objects.get( provider_settings = IntegrationSettings.objects.get(
@@ -250,19 +257,34 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
) )
logger.info(f"[process_image_generation_queue] Using system account (aws-admin) {provider.upper()} settings") logger.info(f"[process_image_generation_queue] Using system account (aws-admin) {provider.upper()} settings")
except (Account.DoesNotExist, IntegrationSettings.DoesNotExist): except (Account.DoesNotExist, IntegrationSettings.DoesNotExist):
logger.error(f"[process_image_generation_queue] ERROR: {provider.upper()} integration settings not found in system account either") # Final fallback: use GlobalIntegrationSettings API key
return {'success': False, 'error': f'{provider.upper()} integration not found or not active'} logger.info(f"[process_image_generation_queue] No {provider.upper()} IntegrationSettings found, will use GlobalIntegrationSettings API key")
provider_settings = None # Signal to use global settings below
except Exception as e:
logger.error(f"[process_image_generation_queue] ERROR getting {provider.upper()} API key from aws-admin: {e}", exc_info=True)
return {'success': False, 'error': f'Error retrieving {provider.upper()} API key: {str(e)}'}
except Exception as e: except Exception as e:
logger.error(f"[process_image_generation_queue] ERROR getting {provider.upper()} API key: {e}", exc_info=True) logger.error(f"[process_image_generation_queue] ERROR getting {provider.upper()} API key: {e}", exc_info=True)
return {'success': False, 'error': f'Error retrieving {provider.upper()} API key: {str(e)}'} return {'success': False, 'error': f'Error retrieving {provider.upper()} API key: {str(e)}'}
# Extract API key from provider settings # Extract API key from provider settings or global settings
logger.info(f"[process_image_generation_queue] {provider.upper()} config keys: {list(provider_settings.config.keys()) if provider_settings.config else 'None'}") if provider_settings:
logger.info(f"[process_image_generation_queue] {provider.upper()} config keys: {list(provider_settings.config.keys()) if provider_settings.config else 'None'}")
api_key = provider_settings.config.get('apiKey') if provider_settings.config else None
else:
# Use GlobalIntegrationSettings API key
logger.info(f"[process_image_generation_queue] Using {provider.upper()} API key from GlobalIntegrationSettings")
if provider == 'runware':
api_key = global_settings.runware_api_key
elif provider == 'openai':
api_key = global_settings.dalle_api_key or global_settings.openai_api_key
else:
api_key = None
api_key = provider_settings.config.get('apiKey') if provider_settings.config else None
if not api_key: if not api_key:
logger.error(f"[process_image_generation_queue] {provider.upper()} API key not found in config") logger.error(f"[process_image_generation_queue] {provider.upper()} API key not found in config or GlobalIntegrationSettings")
logger.error(f"[process_image_generation_queue] {provider.upper()} config: {provider_settings.config}") if provider_settings:
logger.error(f"[process_image_generation_queue] {provider.upper()} config: {provider_settings.config}")
return {'success': False, 'error': f'{provider.upper()} API key not configured'} return {'success': False, 'error': f'{provider.upper()} API key not configured'}
# Log API key presence (but not the actual key for security) # Log API key presence (but not the actual key for security)