fixes for ai and iamge related models bacekedn

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-10 05:11:24 +00:00
parent 0c693dc1cc
commit 975eab46cf
9 changed files with 156 additions and 176 deletions

View File

@@ -1,78 +0,0 @@
# 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),
]

View File

@@ -0,0 +1,15 @@
# Generated manually - Add image size fields to AIModelConfig
from django.db import migrations, models
class Migration(migrations.Migration):
"""Add landscape_size, square_size, and valid_sizes fields to AIModelConfig."""
dependencies = [
('billing', '0029_add_webhook_event_and_manual_reference_constraint'),
]
operations = [
# Fields already added via direct SQL, just mark as noop
# This ensures the model matches the database schema
]

View File

@@ -47,6 +47,12 @@ class SystemAISettings(models.Model):
('hd', 'HD'),
]
QUALITY_TIER_CHOICES = [
('basic', 'Basic'),
('quality', 'Quality'),
('premium', 'Premium'),
]
IMAGE_SIZE_CHOICES = [
('1024x1024', '1024x1024 (Square)'),
('1792x1024', '1792x1024 (Landscape)'),
@@ -70,6 +76,12 @@ class SystemAISettings(models.Model):
choices=IMAGE_STYLE_CHOICES,
help_text="Default image style"
)
default_quality_tier = models.CharField(
max_length=20,
default='basic',
choices=QUALITY_TIER_CHOICES,
help_text="Default quality tier for image generation"
)
image_quality = models.CharField(
max_length=20,
default='standard',
@@ -78,7 +90,11 @@ class SystemAISettings(models.Model):
)
max_images_per_article = models.IntegerField(
default=4,
help_text="Max in-article images (1-8)"
help_text="Default number of in-article images"
)
max_allowed_images = models.IntegerField(
default=8,
help_text="Maximum allowed in-article images (dropdown limit)"
)
image_size = models.CharField(
max_length=20,

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.10 on 2026-01-10 04:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0021_add_smtp_email_settings'),
]
operations = [
migrations.AddField(
model_name='systemaisettings',
name='default_quality_tier',
field=models.CharField(choices=[('basic', 'Basic'), ('quality', 'Quality'), ('premium', 'Premium')], default='basic', help_text='Default quality tier for image generation', max_length=20),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.2.10 on 2026-01-10 04:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('system', '0022_systemaisettings_default_quality_tier_and_more'),
]
operations = [
migrations.AddField(
model_name='systemaisettings',
name='max_allowed_images',
field=models.IntegerField(default=8, help_text='Maximum allowed in-article images (dropdown limit)'),
),
migrations.AlterField(
model_name='systemaisettings',
name='max_images_per_article',
field=models.IntegerField(default=4, help_text='Default number of in-article images'),
),
]

View File

@@ -528,12 +528,17 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
This endpoint returns:
- content_generation: temperature, max_tokens
- image_generation: quality_tiers, selected_tier, styles, selected_style, max_images
Settings are stored in a single AccountSettings record with key='ai_settings'
"""
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
authentication_classes = [JWTAuthentication]
throttle_scope = 'system'
throttle_classes = [DebugScopedRateThrottle]
# Single key for all AI settings per account
AI_SETTINGS_KEY = 'ai_settings'
def _get_account(self, request):
"""Get account from request"""
account = getattr(request, 'account', None)
@@ -543,6 +548,20 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
account = getattr(user, 'account', None)
return account
def _get_account_ai_settings(self, account):
"""Get consolidated AI settings for account, returns dict with all settings"""
if not account:
return {}
setting = AccountSettings.objects.filter(
account=account,
key=self.AI_SETTINGS_KEY
).first()
if setting and setting.value:
return setting.value
return {}
def list(self, request):
"""
GET /api/v1/accounts/settings/ai/
@@ -566,6 +585,9 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
try:
from igny8_core.business.billing.models import AIModelConfig
# Get consolidated account settings
account_settings = self._get_account_ai_settings(account)
# Get quality tiers from AIModelConfig (image models)
quality_tiers = []
for model in AIModelConfig.objects.filter(model_type='image', is_active=True).order_by('credits_per_image'):
@@ -594,21 +616,15 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
for opt in SystemAISettings.IMAGE_STYLE_CHOICES
]
# Get effective settings (SystemAISettings with AccountSettings overrides)
temperature = SystemAISettings.get_effective_temperature(account)
max_tokens = SystemAISettings.get_effective_max_tokens(account)
image_style = SystemAISettings.get_effective_image_style(account)
max_images = SystemAISettings.get_effective_max_images(account)
# Get system defaults
system_defaults = SystemAISettings.get_instance()
# Get selected quality tier from AccountSettings
selected_tier = 'quality' # Default
if account:
tier_setting = AccountSettings.objects.filter(
account=account,
key='ai.image_quality_tier'
).first()
if tier_setting and tier_setting.value: # Model uses 'value' field
selected_tier = tier_setting.value.get('value', 'quality')
# 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()
@@ -641,7 +657,7 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
'styles': styles,
'selected_style': image_style,
'max_images': max_images,
'max_allowed': 8,
'max_allowed': system_defaults.max_allowed_images,
# Image sizes based on selected model
'featured_image_size': featured_image_size,
'landscape_image_size': landscape_image_size,
@@ -665,20 +681,14 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
"""
PUT/POST /api/v1/accounts/settings/ai/
Save account-specific overrides to AccountSettings.
Save account-specific overrides to a single AccountSettings record.
All AI settings are stored in one record with key='ai_settings'.
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,
"image_quality_tier": "premium",
"image_style": "illustration",
"max_images": 6
}
"""
account = self._get_account(request)
@@ -691,44 +701,38 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
try:
data = request.data
saved_keys = []
# Get existing settings or start fresh
existing_settings = self._get_account_ai_settings(account)
# 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'),
}
# Update with new values (only if provided)
if content_gen.get('temperature') is not None:
existing_settings['temperature'] = content_gen['temperature']
if content_gen.get('max_tokens') is not None:
existing_settings['max_tokens'] = content_gen['max_tokens']
# Map request fields to AccountSettings keys
key_mappings = {
'temperature': 'ai.temperature',
'max_tokens': 'ai.max_tokens',
'image_quality_tier': 'ai.image_quality_tier',
'image_style': 'ai.image_style',
'max_images': 'ai.max_images',
}
if image_gen.get('quality_tier') is not None:
existing_settings['quality_tier'] = image_gen['quality_tier']
if image_gen.get('image_style') is not None:
existing_settings['image_style'] = image_gen['image_style']
if image_gen.get('max_images_per_article') is not None:
existing_settings['max_images'] = image_gen['max_images_per_article']
for field, account_key in key_mappings.items():
value = flat_data.get(field)
if value is not None:
AccountSettings.objects.update_or_create(
account=account,
key=account_key,
defaults={'value': {'value': value}} # Model uses 'value' field
)
saved_keys.append(account_key)
# Save as single consolidated record
setting, created = AccountSettings.objects.update_or_create(
account=account,
key=self.AI_SETTINGS_KEY,
defaults={'value': existing_settings}
)
logger.info(f"[ContentGenerationSettings] Saved {saved_keys} for account {account.id}")
logger.info(f"[ContentGenerationSettings] Saved ai_settings for account {account.id}: {existing_settings}")
return success_response(
data={'saved_keys': saved_keys},
data={'settings': existing_settings},
message='AI settings saved successfully',
request=request
)