image s imsages images model fixes new model see dream

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-10 13:16:05 +00:00
parent 6fb0411f56
commit 854b3efd45
9 changed files with 582 additions and 66 deletions

View File

@@ -1028,9 +1028,18 @@ class AICore:
print(f"[AI][{function_name}] Using Nano Banana config: resolution=1k (no width/height)")
elif runware_model.startswith('bytedance:'):
# Seedream 4.5 (bytedance:seedream@4.5) - High quality ByteDance model
# Uses basic format with just width/height - no steps, CFGScale, or special providerSettings needed
# Just use the base inference_task as-is
print(f"[AI][{function_name}] Using Seedream 4.5 config: basic format, width={width}, height={height}")
# Uses basic format - no steps, CFGScale, negativePrompt, or special providerSettings needed
# Remove negativePrompt as it's not supported
if 'negativePrompt' in inference_task:
del inference_task['negativePrompt']
# Enforce minimum size for Seedream (min 3,686,400 pixels ~ 1920x1920)
current_pixels = width * height
if current_pixels < 3686400:
# Use default Seedream square size
inference_task['width'] = 2048
inference_task['height'] = 2048
width, height = 2048, 2048
print(f"[AI][{function_name}] Using Seedream 4.5 config: basic format (no negativePrompt), width={inference_task['width']}, height={inference_task['height']}")
elif runware_model.startswith('runware:'):
# Hi Dream Full (runware:97@1) - General diffusion, steps 20, CFGScale 7
inference_task['steps'] = 20

View File

@@ -187,22 +187,42 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
logger.info("[process_image_generation_queue] Step 1: Loading image generation settings")
from igny8_core.modules.system.ai_settings import AISettings
from igny8_core.ai.model_registry import ModelRegistry
from igny8_core.business.billing.models import AIModelConfig
# Get effective settings
image_type = AISettings.get_effective_image_style(account)
image_format = 'webp' # Default format
# Get default image model from database
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
provider = model_config.provider if model_config else 'openai'
model = default_model
# Get user's selected quality tier (from account settings)
quality_tier = AISettings.get_effective_quality_tier(account)
logger.info(f"[process_image_generation_queue] User's quality tier: {quality_tier}")
# Find image model based on quality tier (DYNAMIC from database)
model_config = None
if quality_tier:
model_config = AIModelConfig.objects.filter(
model_type='image',
quality_tier=quality_tier,
is_active=True
).first()
# Fallback to default image model if no tier match
if not model_config:
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
# Set provider and model from database config
if model_config:
provider = model_config.provider or 'openai'
model = model_config.model_name
else:
# Ultimate fallback (should never happen if database is configured)
logger.warning("[process_image_generation_queue] No image model found in database, using fallback")
provider = 'openai'
model = 'dall-e-3'
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 AIModelConfig")
# Style to prompt enhancement mapping
# These style descriptors are added to the image prompt for better results
@@ -225,25 +245,23 @@ def process_image_generation_queue(self, image_ids: list, account_id: int = None
style_description = STYLE_PROMPT_MAP.get(image_type, STYLE_PROMPT_MAP.get('photorealistic'))
logger.info(f"[process_image_generation_queue] Style: {image_type} -> prompt enhancement: {style_description[:50]}...")
# Model-specific landscape sizes (square is always 1024x1024)
# For Runware models - based on Runware documentation for optimal results per model
# For OpenAI DALL-E 3 - uses 1792x1024 for landscape
MODEL_LANDSCAPE_SIZES = {
'runware:97@1': '1280x768', # Hi Dream Full landscape
'bria:10@1': '1344x768', # Bria 3.2 landscape (16:9)
'google:4@2': '1376x768', # Nano Banana landscape (16:9)
'dall-e-3': '1792x1024', # DALL-E 3 landscape
'dall-e-2': '1024x1024', # DALL-E 2 only supports square
}
DEFAULT_SQUARE_SIZE = '1024x1024'
# Get model-specific landscape size for featured images
model_landscape_size = MODEL_LANDSCAPE_SIZES.get(model, '1792x1024' if provider == 'openai' else '1280x768')
# Load image sizes from AIModelConfig (DYNAMIC from database)
# model_config was loaded above based on quality tier
if model_config:
# Get sizes from database (single source of truth)
model_landscape_size = model_config.landscape_size or '1792x1024'
model_square_size = model_config.square_size or '1024x1024'
logger.info(f"[process_image_generation_queue] Loaded sizes from AIModelConfig: landscape={model_landscape_size}, square={model_square_size}")
else:
# Fallback sizes if no model config (should never happen)
model_landscape_size = '1792x1024'
model_square_size = '1024x1024'
logger.warning(f"[process_image_generation_queue] No model config, using fallback sizes")
# Featured image always uses model-specific landscape size
featured_image_size = model_landscape_size
# In-article images: alternating square/landscape based on position (handled in image loop)
in_article_square_size = DEFAULT_SQUARE_SIZE
in_article_square_size = model_square_size
in_article_landscape_size = model_landscape_size
logger.info(f"[process_image_generation_queue] Settings loaded:")

View File

@@ -0,0 +1,38 @@
# Generated by Django 5.2.10 on 2026-01-10 12:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('billing', '0031_add_seedream_model'),
]
operations = [
migrations.AddField(
model_name='historicalaimodelconfig',
name='landscape_size',
field=models.CharField(blank=True, help_text="Landscape image size for this model (e.g., '1792x1024', '1280x768')", max_length=20, null=True),
),
migrations.AddField(
model_name='historicalaimodelconfig',
name='square_size',
field=models.CharField(blank=True, default='1024x1024', help_text="Square image size for this model (e.g., '1024x1024')", max_length=20),
),
migrations.AddField(
model_name='historicalaimodelconfig',
name='valid_sizes',
field=models.JSONField(blank=True, default=list, help_text="List of valid sizes for this model (e.g., ['1024x1024', '1792x1024'])"),
),
migrations.AlterField(
model_name='aimodelconfig',
name='quality_tier',
field=models.CharField(blank=True, choices=[('basic', 'Basic'), ('quality', 'Quality'), ('quality_option2', 'Quality-Option2'), ('premium', 'Premium')], help_text='basic / quality / premium - for image models', max_length=20, null=True),
),
migrations.AlterField(
model_name='historicalaimodelconfig',
name='quality_tier',
field=models.CharField(blank=True, choices=[('basic', 'Basic'), ('quality', 'Quality'), ('quality_option2', 'Quality-Option2'), ('premium', 'Premium')], help_text='basic / quality / premium - for image models', max_length=20, null=True),
),
]

View File

@@ -194,7 +194,7 @@ class SystemAISettings(models.Model):
@classmethod
def get_effective_quality_tier(cls, account=None) -> str:
"""Get quality_tier, checking account override first (from ai_settings key)"""
"""Get quality_tier, checking account override first, then default image model"""
if account:
# Check consolidated ai_settings first
try:
@@ -214,6 +214,21 @@ class SystemAISettings(models.Model):
override = cls._get_account_override(account, 'ai.quality_tier')
if override is not None:
return str(override)
# No account override - get tier from DEFAULT image model (is_default=True)
try:
from igny8_core.business.billing.models import AIModelConfig
default_model = AIModelConfig.objects.filter(
model_type='image',
is_default=True,
is_active=True
).first()
if default_model and default_model.quality_tier:
return default_model.quality_tier
except Exception as e:
logger.debug(f"Could not get default image model tier: {e}")
# Ultimate fallback
return cls.get_instance().default_quality_tier
@staticmethod

View File

@@ -793,23 +793,38 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
}
elif integration_type == 'image_generation':
# Model-specific landscape sizes
MODEL_LANDSCAPE_SIZES = {
'runware:97@1': '1280x768',
'bria:10@1': '1344x768',
'google:4@2': '1376x768',
}
from igny8_core.business.billing.models import AIModelConfig
from igny8_core.modules.system.ai_settings import AISettings
# Get default image model from AIModelConfig
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
default_service = model_config.provider if model_config else 'openai'
# Get user's quality tier (from account settings)
quality_tier = AISettings.get_effective_quality_tier(account)
# Find image model based on quality tier (DYNAMIC from database)
model_config = None
if quality_tier:
model_config = AIModelConfig.objects.filter(
model_type='image',
quality_tier=quality_tier,
is_active=True
).first()
# Fallback to default image model
if not model_config:
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
# Extract settings from model config
if model_config:
default_service = model_config.provider or 'openai'
default_model = model_config.model_name
model_landscape_size = model_config.landscape_size or '1792x1024'
model_square_size = model_config.square_size or '1024x1024'
else:
default_service = 'openai'
default_model = 'dall-e-3'
model_landscape_size = MODEL_LANDSCAPE_SIZES.get(default_model, '1280x768')
model_landscape_size = '1792x1024'
model_square_size = '1024x1024'
response_data = {
'id': 'image_generation',
@@ -826,8 +841,11 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
'image_format': 'webp',
'desktop_enabled': True,
'featured_image_size': model_landscape_size,
'in_article_landscape_size': model_landscape_size,
'in_article_square_size': model_square_size,
'desktop_image_size': SystemAISettings.get_effective_image_size(account),
'using_global': True,
'quality_tier': quality_tier,
}
else:
# Other integration types - return empty
@@ -856,9 +874,11 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
1. SystemAISettings (singleton) provides system-wide defaults
2. AccountSettings (key-value) provides per-account overrides
3. API keys come from IntegrationProvider (accounts cannot override API keys)
4. Model config (sizes, etc.) from AIModelConfig (DYNAMIC, single source of truth)
"""
from igny8_core.modules.system.ai_settings import SystemAISettings
from igny8_core.modules.system.ai_settings import SystemAISettings, AISettings
from igny8_core.ai.model_registry import ModelRegistry
from igny8_core.business.billing.models import AIModelConfig
account = getattr(request, 'account', None)
@@ -868,29 +888,36 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
if user and hasattr(user, 'is_authenticated') and user.is_authenticated:
account = getattr(user, 'account', None)
# Model-specific landscape sizes
MODEL_LANDSCAPE_SIZES = {
'runware:97@1': '1280x768', # Hi Dream Full landscape
'bria:10@1': '1344x768', # Bria 3.2 landscape (16:9)
'google:4@2': '1376x768', # Nano Banana landscape (16:9)
'dall-e-3': '1792x1024', # DALL-E 3 landscape
'dall-e-2': '1024x1024', # DALL-E 2 square only
}
try:
# Get default image model from AIModelConfig
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
provider = model_config.provider if model_config else 'openai'
model = default_model
# Get user's quality tier from account settings (DYNAMIC)
quality_tier = AISettings.get_effective_quality_tier(account)
# Find image model based on quality tier (DYNAMIC from database)
model_config = None
if quality_tier:
model_config = AIModelConfig.objects.filter(
model_type='image',
quality_tier=quality_tier,
is_active=True
).first()
# Fallback to default image model
if not model_config:
default_model = ModelRegistry.get_default_model('image')
if default_model:
model_config = ModelRegistry.get_model(default_model)
# Extract settings from model config (SINGLE SOURCE OF TRUTH)
if model_config:
provider = model_config.provider or 'openai'
model = model_config.model_name
model_landscape_size = model_config.landscape_size or '1792x1024'
model_square_size = model_config.square_size or '1024x1024'
else:
provider = 'openai'
model = 'dall-e-3'
# Get model-specific landscape size
model_landscape_size = MODEL_LANDSCAPE_SIZES.get(model, '1280x768')
default_featured_size = model_landscape_size if provider == 'runware' else '1792x1024'
model_landscape_size = '1792x1024'
model_square_size = '1024x1024'
# Get image style from SystemAISettings with AccountSettings overrides
image_style = SystemAISettings.get_effective_image_style(account)
@@ -915,7 +942,7 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
if not image_style or image_style in ['natural', 'vivid']:
image_style = 'photorealistic'
logger.info(f"[get_image_generation_settings] Returning: provider={provider}, model={model}, image_style={image_style}")
logger.info(f"[get_image_generation_settings] Returning: provider={provider}, model={model}, image_style={image_style}, quality_tier={quality_tier}")
return success_response(
data={
@@ -927,8 +954,11 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
'max_in_article_images': SystemAISettings.get_effective_max_images(account),
'image_format': 'webp',
'desktop_enabled': True,
'featured_image_size': default_featured_size,
'featured_image_size': model_landscape_size,
'in_article_landscape_size': model_landscape_size,
'in_article_square_size': model_square_size,
'desktop_image_size': SystemAISettings.get_effective_image_size(account),
'quality_tier': quality_tier,
}
},
request=request

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.2.10 on 2026-01-10 12:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0023_systemaisettings_max_allowed_images_and_more'),
]
operations = [
migrations.AlterField(
model_name='systemaisettings',
name='default_quality_tier',
field=models.CharField(choices=[('basic', 'Basic'), ('quality', 'Quality'), ('quality_option2', 'Quality-Option2'), ('premium', 'Premium')], default='basic', help_text='Default quality tier for image generation', max_length=20),
),
# Removed DeleteModel for AccountIntegrationOverride - table doesn't exist
]

View File

@@ -621,15 +621,20 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
# Get system defaults
system_defaults = SystemAISettings.get_instance()
# Get default image model (is_default=True) - SINGLE SOURCE OF TRUTH
default_image_model = AIModelConfig.get_default_image_model()
# Determine default tier from default model (not hardcoded)
default_tier = default_image_model.quality_tier if default_image_model else 'basic'
# Apply account overrides or use system defaults
temperature = account_settings.get('temperature', system_defaults.temperature)
max_tokens = account_settings.get('max_tokens', system_defaults.max_tokens)
image_style = account_settings.get('image_style', system_defaults.image_style)
max_images = account_settings.get('max_images', system_defaults.max_images_per_article)
selected_tier = account_settings.get('quality_tier', system_defaults.default_quality_tier)
# Get default image model (or model for selected tier)
default_image_model = AIModelConfig.get_default_image_model()
# Get selected tier: account override > default model's tier
selected_tier = account_settings.get('quality_tier') or default_tier
# Try to find model matching selected tier
selected_model = AIModelConfig.objects.filter(

View File

@@ -869,8 +869,17 @@ Make sure each prompt is detailed enough for image generation, describing the vi
del inference_task['height']
inference_task['resolution'] = '1k'
elif runware_model.startswith('bytedance:'):
# Seedream models use basic format - no steps, CFGScale needed
pass
# Seedream models use basic format - no steps, CFGScale, negativePrompt needed
# Also require minimum 3,686,400 pixels (roughly 1920x1920)
if 'negativePrompt' in inference_task:
del inference_task['negativePrompt']
# Enforce minimum size for Seedream (min ~1920x1920, use 2048x2048 for square)
current_pixels = width * height
if current_pixels < 3686400:
# Use default Seedream square size
inference_task['width'] = 2048
inference_task['height'] = 2048
logger.info(f"[AIProcessor.generate_image] Seedream requires min 3.6M pixels, adjusted to 2048x2048")
elif runware_model.startswith('runware:'):
# Hi Dream Full - needs steps and CFGScale
inference_task['steps'] = 30