From abeede5f04b3d5a9a4e7c5cb671e587cf43cc887 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Thu, 25 Dec 2025 01:17:41 +0000 Subject: [PATCH] image prompt issues --- .../ai/functions/generate_image_prompts.py | 37 +++--- .../ai/functions/generate_images.py | 31 ++--- backend/igny8_core/ai/prompts.py | 10 +- backend/igny8_core/ai/settings.py | 117 ++++++++++++++++++ .../AI-MODELS-DATABASE-CONFIGURATION-PLAN.md | 0 .../AI-MODELS-IMPLEMENTATION-SUMMARY.md | 0 .../AI-MODELS-VALIDATION-REPORT.md | 0 7 files changed, 150 insertions(+), 45 deletions(-) rename AI-MODELS-DATABASE-CONFIGURATION-PLAN.md => tmp-md-files/AI-MODELS-DATABASE-CONFIGURATION-PLAN.md (100%) rename AI-MODELS-IMPLEMENTATION-SUMMARY.md => tmp-md-files/AI-MODELS-IMPLEMENTATION-SUMMARY.md (100%) rename AI-MODELS-VALIDATION-REPORT.md => tmp-md-files/AI-MODELS-VALIDATION-REPORT.md (100%) diff --git a/backend/igny8_core/ai/functions/generate_image_prompts.py b/backend/igny8_core/ai/functions/generate_image_prompts.py index e8990d20..78edc39c 100644 --- a/backend/igny8_core/ai/functions/generate_image_prompts.py +++ b/backend/igny8_core/ai/functions/generate_image_prompts.py @@ -99,6 +99,7 @@ class GenerateImagePromptsFunction(BaseAIFunction): content_text = self._format_content_for_prompt(extracted) # Get prompt from PromptRegistry - same as other functions + # Provide multiple context key variations for compatibility with different prompt templates prompt = PromptRegistry.get_prompt( function_name='generate_image_prompts', account=account, @@ -106,6 +107,11 @@ class GenerateImagePromptsFunction(BaseAIFunction): 'title': extracted['title'], 'content': content_text, 'max_images': max_images, + 'count': max_images, # Alias for backward compatibility + 'TITLE': extracted['title'], # Uppercase variants + 'CONTENT': content_text, + 'MAX_IMAGES': max_images, + 'COUNT': max_images, } ) @@ -218,28 +224,17 @@ class GenerateImagePromptsFunction(BaseAIFunction): # Helper methods def _get_max_in_article_images(self, account) -> int: - """Get max_in_article_images from AWS account IntegrationSettings only""" - from igny8_core.modules.system.models import IntegrationSettings - from igny8_core.auth.models import Account + """Get max_in_article_images from global settings with optional account override""" + from igny8_core.ai.settings import get_image_generation_config - # Only use system account (aws-admin) settings - system_account = Account.objects.get(slug='aws-admin') - settings = IntegrationSettings.objects.get( - account=system_account, - 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 = int(max_images) - logger.info(f"Using max_in_article_images={max_images} from aws-admin account") - return max_images + try: + config = get_image_generation_config(account) + max_images = config.get('max_in_article_images', 2) # Default to 2 if not set + logger.info(f"Using max_in_article_images={max_images} for account {account.id}") + return max_images + except Exception as e: + logger.warning(f"Failed to get max_in_article_images from settings: {e}. Using default of 2") + return 2 # Fallback default def _extract_content_elements(self, content: Content, max_images: int) -> Dict: """Extract title, intro paragraphs, and H2 headings from content HTML""" diff --git a/backend/igny8_core/ai/functions/generate_images.py b/backend/igny8_core/ai/functions/generate_images.py index f202f4a7..d54248ee 100644 --- a/backend/igny8_core/ai/functions/generate_images.py +++ b/backend/igny8_core/ai/functions/generate_images.py @@ -67,34 +67,23 @@ class GenerateImagesFunction(BaseAIFunction): if not tasks: raise ValueError("No tasks found") - # Get image generation settings from aws-admin account only (global settings) - from igny8_core.modules.system.models import IntegrationSettings - from igny8_core.auth.models import Account + # Get image generation settings from global settings with optional account override + from igny8_core.ai.settings import get_image_generation_config - system_account = Account.objects.get(slug='aws-admin') - integration = IntegrationSettings.objects.get( - account=system_account, - integration_type='image_generation', - is_active=True - ) - image_settings = integration.config or {} - - # Extract settings with defaults - provider = image_settings.get('provider') or image_settings.get('service', 'openai') - if provider == 'runware': - model = image_settings.get('model') or image_settings.get('runwareModel', 'runware:97@1') - else: - model = image_settings.get('model', 'dall-e-3') + image_config = get_image_generation_config(account) + provider = image_config.get('provider', 'openai') + model = image_config.get('model', 'dall-e-3') + max_in_article_images = image_config.get('max_in_article_images', 2) return { 'tasks': tasks, 'account': account, 'provider': provider, 'model': model, - 'image_type': image_settings.get('image_type', 'realistic'), - 'max_in_article_images': int(image_settings.get('max_in_article_images')), - 'desktop_enabled': image_settings.get('desktop_enabled', True), - 'mobile_enabled': image_settings.get('mobile_enabled', True), + 'image_type': image_config.get('style', 'realistic'), + 'max_in_article_images': max_in_article_images, + 'desktop_enabled': True, # Always enabled + 'mobile_enabled': True, # Always enabled } def build_prompt(self, data: Dict, account=None) -> Dict: diff --git a/backend/igny8_core/ai/prompts.py b/backend/igny8_core/ai/prompts.py index 8d021f7c..caa45e80 100644 --- a/backend/igny8_core/ai/prompts.py +++ b/backend/igny8_core/ai/prompts.py @@ -130,20 +130,24 @@ class PromptRegistry: logger.debug(f"Replaced placeholder {placeholder} with {len(str(value))} characters") # Step 2: Try .format() style for {variable} placeholders (if any remain) - # Normalize context keys - convert UPPER to lowercase for .format() + # Normalize context keys - provide both original case, lowercase, and uppercase normalized_context = {} for key, value in context.items(): - # Try both original key and lowercase version + # Add original key normalized_context[key] = value + # Add lowercase version normalized_context[key.lower()] = value + # Add uppercase version + normalized_context[key.upper()] = value # Only try .format() if there are {variable} placeholders if '{' in rendered and '}' in rendered: try: rendered = rendered.format(**normalized_context) + logger.debug(f"Successfully formatted prompt with context keys: {list(context.keys())}") except (KeyError, ValueError, IndexError) as e: # If .format() fails, log warning but keep the [IGNY8_*] replacements - logger.warning(f"Failed to format prompt with .format(): {e}. Using [IGNY8_*] replacements only.") + logger.warning(f"Failed to format prompt with .format(): {e}. Context keys: {list(context.keys())}. Using [IGNY8_*] replacements only.") return rendered diff --git a/backend/igny8_core/ai/settings.py b/backend/igny8_core/ai/settings.py index 55574237..f1376a18 100644 --- a/backend/igny8_core/ai/settings.py +++ b/backend/igny8_core/ai/settings.py @@ -123,3 +123,120 @@ def get_model_config(function_name: str, account) -> Dict[str, Any]: '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." + ) + diff --git a/AI-MODELS-DATABASE-CONFIGURATION-PLAN.md b/tmp-md-files/AI-MODELS-DATABASE-CONFIGURATION-PLAN.md similarity index 100% rename from AI-MODELS-DATABASE-CONFIGURATION-PLAN.md rename to tmp-md-files/AI-MODELS-DATABASE-CONFIGURATION-PLAN.md diff --git a/AI-MODELS-IMPLEMENTATION-SUMMARY.md b/tmp-md-files/AI-MODELS-IMPLEMENTATION-SUMMARY.md similarity index 100% rename from AI-MODELS-IMPLEMENTATION-SUMMARY.md rename to tmp-md-files/AI-MODELS-IMPLEMENTATION-SUMMARY.md diff --git a/AI-MODELS-VALIDATION-REPORT.md b/tmp-md-files/AI-MODELS-VALIDATION-REPORT.md similarity index 100% rename from AI-MODELS-VALIDATION-REPORT.md rename to tmp-md-files/AI-MODELS-VALIDATION-REPORT.md