Image genartiona dn temaplte design redesign
This commit is contained in:
@@ -816,6 +816,27 @@ class AIModelConfig(models.Model):
|
||||
help_text="basic / quality / premium - for image models"
|
||||
)
|
||||
|
||||
# Image Size Configuration (for image models)
|
||||
landscape_size = models.CharField(
|
||||
max_length=20,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Landscape image size for this model (e.g., '1792x1024', '1280x768')"
|
||||
)
|
||||
|
||||
square_size = models.CharField(
|
||||
max_length=20,
|
||||
default='1024x1024',
|
||||
blank=True,
|
||||
help_text="Square image size for this model (e.g., '1024x1024')"
|
||||
)
|
||||
|
||||
valid_sizes = models.JSONField(
|
||||
default=list,
|
||||
blank=True,
|
||||
help_text="List of valid sizes for this model (e.g., ['1024x1024', '1792x1024'])"
|
||||
)
|
||||
|
||||
# Model Limits
|
||||
max_tokens = models.IntegerField(
|
||||
null=True,
|
||||
@@ -884,6 +905,21 @@ class AIModelConfig(models.Model):
|
||||
model_type='image',
|
||||
is_active=True
|
||||
).order_by('quality_tier', 'model_name')
|
||||
|
||||
def validate_size(self, size: str) -> bool:
|
||||
"""Validate that the given size is valid for this image model"""
|
||||
if not self.valid_sizes:
|
||||
# If no valid_sizes defined, accept common sizes
|
||||
return True
|
||||
return size in self.valid_sizes
|
||||
|
||||
def get_landscape_size(self) -> str:
|
||||
"""Get the landscape size for this model"""
|
||||
return self.landscape_size or '1792x1024'
|
||||
|
||||
def get_square_size(self) -> str:
|
||||
"""Get the square size for this model"""
|
||||
return self.square_size or '1024x1024'
|
||||
|
||||
|
||||
class WebhookEvent(models.Model):
|
||||
|
||||
@@ -800,6 +800,11 @@ class AIModelConfigAdmin(SimpleHistoryAdmin, Igny8ModelAdmin):
|
||||
'description': 'For IMAGE models only',
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Image Model Sizes', {
|
||||
'fields': ('landscape_size', 'square_size', 'valid_sizes'),
|
||||
'description': 'For IMAGE models: specify supported image dimensions',
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Capabilities', {
|
||||
'fields': ('capabilities',),
|
||||
'description': 'JSON: vision, function_calling, json_mode, etc.',
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Generated migration for adding image size fields to AIModelConfig
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def populate_image_sizes(apps, schema_editor):
|
||||
"""Populate image sizes based on model name"""
|
||||
AIModelConfig = apps.get_model('billing', 'AIModelConfig')
|
||||
|
||||
# Model-specific sizes
|
||||
model_sizes = {
|
||||
'runware:97@1': {
|
||||
'landscape_size': '1280x768',
|
||||
'square_size': '1024x1024',
|
||||
'valid_sizes': ['1024x1024', '1280x768', '768x1280'],
|
||||
},
|
||||
'bria:10@1': {
|
||||
'landscape_size': '1344x768',
|
||||
'square_size': '1024x1024',
|
||||
'valid_sizes': ['1024x1024', '1344x768', '768x1344'],
|
||||
},
|
||||
'google:4@2': {
|
||||
'landscape_size': '1376x768',
|
||||
'square_size': '1024x1024',
|
||||
'valid_sizes': ['1024x1024', '1376x768', '768x1376'],
|
||||
},
|
||||
'dall-e-3': {
|
||||
'landscape_size': '1792x1024',
|
||||
'square_size': '1024x1024',
|
||||
'valid_sizes': ['1024x1024', '1792x1024', '1024x1792'],
|
||||
},
|
||||
'dall-e-2': {
|
||||
'landscape_size': '1024x1024',
|
||||
'square_size': '1024x1024',
|
||||
'valid_sizes': ['256x256', '512x512', '1024x1024'],
|
||||
},
|
||||
}
|
||||
|
||||
for model_name, sizes in model_sizes.items():
|
||||
AIModelConfig.objects.filter(
|
||||
model_name=model_name,
|
||||
model_type='image'
|
||||
).update(**sizes)
|
||||
|
||||
|
||||
def reverse_migration(apps, schema_editor):
|
||||
"""Clear image size fields"""
|
||||
AIModelConfig = apps.get_model('billing', 'AIModelConfig')
|
||||
AIModelConfig.objects.filter(model_type='image').update(
|
||||
landscape_size=None,
|
||||
square_size='1024x1024',
|
||||
valid_sizes=[],
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('billing', '0026_populate_aimodel_credits'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='aimodelconfig',
|
||||
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='aimodelconfig',
|
||||
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='aimodelconfig',
|
||||
name='valid_sizes',
|
||||
field=models.JSONField(blank=True, default=list, help_text="List of valid sizes for this model (e.g., ['1024x1024', '1792x1024'])"),
|
||||
),
|
||||
migrations.RunPython(populate_image_sizes, reverse_migration),
|
||||
]
|
||||
@@ -183,8 +183,8 @@ class ContentSettingsViewSet(viewsets.ViewSet):
|
||||
setting = AccountSettings.objects.get(account=account, key=pk)
|
||||
return success_response(data={
|
||||
'key': setting.key,
|
||||
'config': setting.config,
|
||||
'is_active': setting.is_active,
|
||||
'config': setting.value, # Model uses 'value', frontend expects 'config'
|
||||
'is_active': getattr(setting, 'is_active', True),
|
||||
}, request=request)
|
||||
except AccountSettings.DoesNotExist:
|
||||
# Return default settings if not yet saved
|
||||
@@ -234,17 +234,17 @@ class ContentSettingsViewSet(viewsets.ViewSet):
|
||||
# Filter to only valid fields
|
||||
filtered_config = {k: v for k, v in config.items() if k in valid_fields}
|
||||
|
||||
# Get or create setting
|
||||
# Get or create setting - model uses 'value' field
|
||||
setting, created = AccountSettings.objects.update_or_create(
|
||||
account=account,
|
||||
key=pk,
|
||||
defaults={'config': filtered_config, 'is_active': True}
|
||||
defaults={'value': filtered_config}
|
||||
)
|
||||
|
||||
return success_response(data={
|
||||
'key': setting.key,
|
||||
'config': setting.config,
|
||||
'is_active': setting.is_active,
|
||||
'config': setting.value, # Model uses 'value', frontend expects 'config'
|
||||
'is_active': getattr(setting, 'is_active', True),
|
||||
'message': 'Settings saved successfully',
|
||||
}, request=request)
|
||||
|
||||
@@ -607,8 +607,28 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
||||
account=account,
|
||||
key='ai.image_quality_tier'
|
||||
).first()
|
||||
if tier_setting and tier_setting.config:
|
||||
selected_tier = tier_setting.config.get('value', 'quality')
|
||||
if tier_setting and tier_setting.value: # Model uses 'value' field
|
||||
selected_tier = tier_setting.value.get('value', 'quality')
|
||||
|
||||
# Get default image model (or model for selected tier)
|
||||
default_image_model = AIModelConfig.get_default_image_model()
|
||||
|
||||
# Try to find model matching selected tier
|
||||
selected_model = AIModelConfig.objects.filter(
|
||||
model_type='image',
|
||||
quality_tier=selected_tier,
|
||||
is_active=True
|
||||
).first() or default_image_model
|
||||
|
||||
# Get image sizes from the selected model
|
||||
featured_image_size = '1792x1024' # Default
|
||||
landscape_image_size = '1792x1024' # Default
|
||||
square_image_size = '1024x1024' # Default
|
||||
|
||||
if selected_model:
|
||||
landscape_image_size = selected_model.landscape_size or '1792x1024'
|
||||
square_image_size = selected_model.square_size or '1024x1024'
|
||||
featured_image_size = landscape_image_size # Featured uses landscape
|
||||
|
||||
response_data = {
|
||||
'content_generation': {
|
||||
@@ -622,6 +642,12 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
||||
'selected_style': image_style,
|
||||
'max_images': max_images,
|
||||
'max_allowed': 8,
|
||||
# Image sizes based on selected model
|
||||
'featured_image_size': featured_image_size,
|
||||
'landscape_image_size': landscape_image_size,
|
||||
'square_image_size': square_image_size,
|
||||
'model_name': selected_model.model_name if selected_model else None,
|
||||
'model_display_name': selected_model.display_name if selected_model else None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +666,12 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
||||
PUT/POST /api/v1/accounts/settings/ai/
|
||||
|
||||
Save account-specific overrides to AccountSettings.
|
||||
Request body per the plan:
|
||||
Accepts nested structure:
|
||||
{
|
||||
"content_generation": { "temperature": 0.8, "max_tokens": 4096 },
|
||||
"image_generation": { "quality_tier": "premium", "image_style": "illustration", "max_images_per_article": 6 }
|
||||
}
|
||||
Or flat structure:
|
||||
{
|
||||
"temperature": 0.8,
|
||||
"max_tokens": 4096,
|
||||
@@ -662,6 +693,19 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
||||
data = request.data
|
||||
saved_keys = []
|
||||
|
||||
# Handle nested structure from frontend
|
||||
content_gen = data.get('content_generation', {})
|
||||
image_gen = data.get('image_generation', {})
|
||||
|
||||
# Flatten nested structure or use flat keys
|
||||
flat_data = {
|
||||
'temperature': content_gen.get('temperature') if content_gen else data.get('temperature'),
|
||||
'max_tokens': content_gen.get('max_tokens') if content_gen else data.get('max_tokens'),
|
||||
'image_quality_tier': image_gen.get('quality_tier') if image_gen else data.get('image_quality_tier'),
|
||||
'image_style': image_gen.get('image_style') if image_gen else data.get('image_style'),
|
||||
'max_images': image_gen.get('max_images_per_article') if image_gen else data.get('max_images'),
|
||||
}
|
||||
|
||||
# Map request fields to AccountSettings keys
|
||||
key_mappings = {
|
||||
'temperature': 'ai.temperature',
|
||||
@@ -672,11 +716,12 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
||||
}
|
||||
|
||||
for field, account_key in key_mappings.items():
|
||||
if field in data:
|
||||
value = flat_data.get(field)
|
||||
if value is not None:
|
||||
AccountSettings.objects.update_or_create(
|
||||
account=account,
|
||||
key=account_key,
|
||||
defaults={'config': {'value': data[field]}}
|
||||
defaults={'value': {'value': value}} # Model uses 'value' field
|
||||
)
|
||||
saved_keys.append(account_key)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user