image strugles 2
This commit is contained in:
@@ -1026,11 +1026,19 @@ class AICore:
|
|||||||
del inference_task['height']
|
del inference_task['height']
|
||||||
inference_task['resolution'] = '1k' # Use 1K tier for optimal speed/quality
|
inference_task['resolution'] = '1k' # Use 1K tier for optimal speed/quality
|
||||||
print(f"[AI][{function_name}] Using Nano Banana config: resolution=1k (no width/height)")
|
print(f"[AI][{function_name}] Using Nano Banana config: resolution=1k (no width/height)")
|
||||||
else:
|
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}")
|
||||||
|
elif runware_model.startswith('runware:'):
|
||||||
# Hi Dream Full (runware:97@1) - General diffusion, steps 20, CFGScale 7
|
# Hi Dream Full (runware:97@1) - General diffusion, steps 20, CFGScale 7
|
||||||
inference_task['steps'] = 20
|
inference_task['steps'] = 20
|
||||||
inference_task['CFGScale'] = 7
|
inference_task['CFGScale'] = 7
|
||||||
print(f"[AI][{function_name}] Using Hi Dream Full config: steps=20, CFGScale=7")
|
print(f"[AI][{function_name}] Using Hi Dream Full config: steps=20, CFGScale=7")
|
||||||
|
else:
|
||||||
|
# Unknown model - use basic format without extra parameters
|
||||||
|
print(f"[AI][{function_name}] Using basic format for unknown model: {runware_model}")
|
||||||
|
|
||||||
payload = [
|
payload = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,22 +70,37 @@ class GenerateImagesFunction(BaseAIFunction):
|
|||||||
# Get image generation settings from AISettings (with account overrides)
|
# Get image generation settings from AISettings (with account overrides)
|
||||||
from igny8_core.modules.system.ai_settings import AISettings
|
from igny8_core.modules.system.ai_settings import AISettings
|
||||||
from igny8_core.ai.model_registry import ModelRegistry
|
from igny8_core.ai.model_registry import ModelRegistry
|
||||||
|
from igny8_core.business.billing.models import AIModelConfig
|
||||||
|
|
||||||
# Get effective settings (AISettings + AccountSettings overrides)
|
# Get effective settings (AISettings + AccountSettings overrides)
|
||||||
image_style = AISettings.get_effective_image_style(account)
|
image_style = AISettings.get_effective_image_style(account)
|
||||||
max_images = AISettings.get_effective_max_images(account)
|
max_images = AISettings.get_effective_max_images(account)
|
||||||
|
quality_tier = AISettings.get_effective_quality_tier(account)
|
||||||
|
|
||||||
# Get default image model and provider from database
|
# Get image model based on user's selected quality tier
|
||||||
default_model = ModelRegistry.get_default_model('image')
|
selected_model = None
|
||||||
if default_model:
|
if quality_tier:
|
||||||
model_config = ModelRegistry.get_model(default_model)
|
selected_model = AIModelConfig.objects.filter(
|
||||||
provider = model_config.provider if model_config else 'openai'
|
model_type='image',
|
||||||
model = default_model
|
quality_tier=quality_tier,
|
||||||
|
is_active=True
|
||||||
|
).first()
|
||||||
|
|
||||||
|
# Fall back to default model if no tier match
|
||||||
|
if not selected_model:
|
||||||
|
default_model_name = ModelRegistry.get_default_model('image')
|
||||||
|
if default_model_name:
|
||||||
|
selected_model = ModelRegistry.get_model(default_model_name)
|
||||||
|
|
||||||
|
# Set provider and model from selected model
|
||||||
|
if selected_model:
|
||||||
|
provider = selected_model.provider if selected_model.provider else 'openai'
|
||||||
|
model = selected_model.model_name
|
||||||
else:
|
else:
|
||||||
provider = 'openai'
|
provider = 'openai'
|
||||||
model = 'dall-e-3'
|
model = 'dall-e-3'
|
||||||
|
|
||||||
logger.info(f"Using image settings: provider={provider}, model={model}, style={image_style}, max={max_images}")
|
logger.info(f"Using image settings: provider={provider}, model={model}, tier={quality_tier}, style={image_style}, max={max_images}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'tasks': tasks,
|
'tasks': tasks,
|
||||||
|
|||||||
@@ -736,6 +736,7 @@ class AIModelConfig(models.Model):
|
|||||||
QUALITY_TIER_CHOICES = [
|
QUALITY_TIER_CHOICES = [
|
||||||
('basic', 'Basic'),
|
('basic', 'Basic'),
|
||||||
('quality', 'Quality'),
|
('quality', 'Quality'),
|
||||||
|
('quality_option2', 'Quality-Option2'),
|
||||||
('premium', 'Premium'),
|
('premium', 'Premium'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,42 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
# Fields already added via direct SQL, just mark as noop
|
# Declare the fields in Django schema so migrations can use them
|
||||||
# This ensures the model matches the database schema
|
# These fields already exist in DB, so state_operations syncs Django's understanding
|
||||||
|
migrations.SeparateDatabaseAndState(
|
||||||
|
state_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'])",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
database_operations=[
|
||||||
|
# No DB operations - fields already exist via direct SQL
|
||||||
|
],
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# Generated manually - Add Seedream 4.5 image model and update quality_tier choices
|
||||||
|
from decimal import Decimal
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def add_seedream_model(apps, schema_editor):
|
||||||
|
"""
|
||||||
|
Add ByteDance Seedream 4.5 image model via Runware.
|
||||||
|
|
||||||
|
Model specs:
|
||||||
|
- model: bytedance:seedream@4.5
|
||||||
|
- Square size: 2048x2048
|
||||||
|
- Landscape size: 2304x1728
|
||||||
|
- Quality tier: quality_option2
|
||||||
|
- Credits per image: 5
|
||||||
|
"""
|
||||||
|
AIModelConfig = apps.get_model('billing', 'AIModelConfig')
|
||||||
|
|
||||||
|
AIModelConfig.objects.update_or_create(
|
||||||
|
model_name='bytedance:seedream@4.5',
|
||||||
|
defaults={
|
||||||
|
'display_name': 'Seedream 4.5 - High Quality',
|
||||||
|
'model_type': 'image',
|
||||||
|
'provider': 'runware',
|
||||||
|
'is_default': False,
|
||||||
|
'is_active': True,
|
||||||
|
'credits_per_image': 5,
|
||||||
|
'quality_tier': 'quality_option2',
|
||||||
|
'landscape_size': '2304x1728',
|
||||||
|
'square_size': '2048x2048',
|
||||||
|
'valid_sizes': ['2048x2048', '2304x1728', '2560x1440', '1728x2304', '1440x2560'],
|
||||||
|
'capabilities': {
|
||||||
|
'max_sequential_images': 4,
|
||||||
|
'high_resolution': True,
|
||||||
|
'provider_settings': {
|
||||||
|
'bytedance': {
|
||||||
|
'maxSequentialImages': 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
print("✅ Added Seedream 4.5 image model")
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_migration(apps, schema_editor):
|
||||||
|
"""Remove Seedream model"""
|
||||||
|
AIModelConfig = apps.get_model('billing', 'AIModelConfig')
|
||||||
|
AIModelConfig.objects.filter(model_name='bytedance:seedream@4.5').delete()
|
||||||
|
print("❌ Removed Seedream 4.5 image model")
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
"""Add Seedream 4.5 image model and update quality_tier choices."""
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('billing', '0030_add_aimodel_image_sizes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
# Update quality_tier field choices to include quality_option2
|
||||||
|
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 / quality_option2 / premium - for image models',
|
||||||
|
max_length=20,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# Add the Seedream model
|
||||||
|
migrations.RunPython(add_seedream_model, reverse_migration),
|
||||||
|
]
|
||||||
@@ -50,6 +50,7 @@ class SystemAISettings(models.Model):
|
|||||||
QUALITY_TIER_CHOICES = [
|
QUALITY_TIER_CHOICES = [
|
||||||
('basic', 'Basic'),
|
('basic', 'Basic'),
|
||||||
('quality', 'Quality'),
|
('quality', 'Quality'),
|
||||||
|
('quality_option2', 'Quality-Option2'),
|
||||||
('premium', 'Premium'),
|
('premium', 'Premium'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -191,6 +192,30 @@ class SystemAISettings(models.Model):
|
|||||||
return str(override)
|
return str(override)
|
||||||
return cls.get_instance().image_size
|
return cls.get_instance().image_size
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_effective_quality_tier(cls, account=None) -> str:
|
||||||
|
"""Get quality_tier, checking account override first (from ai_settings key)"""
|
||||||
|
if account:
|
||||||
|
# Check consolidated ai_settings first
|
||||||
|
try:
|
||||||
|
from igny8_core.modules.system.settings_models import AccountSettings
|
||||||
|
setting = AccountSettings.objects.filter(
|
||||||
|
account=account,
|
||||||
|
key='ai_settings'
|
||||||
|
).first()
|
||||||
|
if setting and setting.value:
|
||||||
|
tier = setting.value.get('quality_tier')
|
||||||
|
if tier:
|
||||||
|
return str(tier)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Could not get quality_tier from ai_settings: {e}")
|
||||||
|
|
||||||
|
# Fall back to individual key
|
||||||
|
override = cls._get_account_override(account, 'ai.quality_tier')
|
||||||
|
if override is not None:
|
||||||
|
return str(override)
|
||||||
|
return cls.get_instance().default_quality_tier
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_account_override(account, key: str):
|
def _get_account_override(account, key: str):
|
||||||
"""Get account-specific override from AccountSettings"""
|
"""Get account-specific override from AccountSettings"""
|
||||||
|
|||||||
@@ -594,10 +594,12 @@ class ContentGenerationSettingsViewSet(viewsets.ViewSet):
|
|||||||
tier = model.quality_tier or 'basic'
|
tier = model.quality_tier or 'basic'
|
||||||
# Avoid duplicates
|
# Avoid duplicates
|
||||||
if not any(t['tier'] == tier for t in quality_tiers):
|
if not any(t['tier'] == tier for t in quality_tiers):
|
||||||
|
# Format label: quality_option2 -> "Quality-Option2"
|
||||||
|
tier_label = tier.replace('_', '-').title() if tier else 'Basic'
|
||||||
quality_tiers.append({
|
quality_tiers.append({
|
||||||
'tier': tier,
|
'tier': tier,
|
||||||
'credits': model.credits_per_image or 1,
|
'credits': model.credits_per_image or 1,
|
||||||
'label': tier.title(),
|
'label': tier_label,
|
||||||
'description': f"{model.display_name} quality",
|
'description': f"{model.display_name} quality",
|
||||||
'model': model.model_name,
|
'model': model.model_name,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -845,12 +845,9 @@ Make sure each prompt is detailed enough for image generation, describing the vi
|
|||||||
# Reference: image-generation.php lines 79-97
|
# Reference: image-generation.php lines 79-97
|
||||||
import uuid
|
import uuid
|
||||||
logger.info(f"[AIProcessor.generate_image] Runware API key check: has_key={bool(api_key)}, key_length={len(api_key) if api_key else 0}, key_preview={api_key[:10] + '...' + api_key[-4:] if api_key and len(api_key) > 14 else 'N/A'}")
|
logger.info(f"[AIProcessor.generate_image] Runware API key check: has_key={bool(api_key)}, key_length={len(api_key) if api_key else 0}, key_preview={api_key[:10] + '...' + api_key[-4:] if api_key and len(api_key) > 14 else 'N/A'}")
|
||||||
payload = [
|
|
||||||
{
|
# Build base inference task
|
||||||
'taskType': 'authentication',
|
inference_task = {
|
||||||
'apiKey': api_key
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'taskType': 'imageInference',
|
'taskType': 'imageInference',
|
||||||
'taskUUID': str(uuid.uuid4()),
|
'taskUUID': str(uuid.uuid4()),
|
||||||
'positivePrompt': prompt,
|
'positivePrompt': prompt,
|
||||||
@@ -858,11 +855,36 @@ Make sure each prompt is detailed enough for image generation, describing the vi
|
|||||||
'model': runware_model,
|
'model': runware_model,
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': height,
|
'height': height,
|
||||||
'steps': 30,
|
|
||||||
'CFGScale': 7.5,
|
|
||||||
'numberResults': 1,
|
'numberResults': 1,
|
||||||
'outputFormat': kwargs.get('format', 'webp')
|
'outputFormat': kwargs.get('format', 'webp')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Model-specific parameter configuration
|
||||||
|
if runware_model.startswith('bria:'):
|
||||||
|
# Bria models need steps
|
||||||
|
inference_task['steps'] = 20
|
||||||
|
elif runware_model.startswith('google:'):
|
||||||
|
# Google models use resolution instead of width/height
|
||||||
|
del inference_task['width']
|
||||||
|
del inference_task['height']
|
||||||
|
inference_task['resolution'] = '1k'
|
||||||
|
elif runware_model.startswith('bytedance:'):
|
||||||
|
# Seedream models use basic format - no steps, CFGScale needed
|
||||||
|
pass
|
||||||
|
elif runware_model.startswith('runware:'):
|
||||||
|
# Hi Dream Full - needs steps and CFGScale
|
||||||
|
inference_task['steps'] = 30
|
||||||
|
inference_task['CFGScale'] = 7.5
|
||||||
|
else:
|
||||||
|
# Unknown model - use basic format
|
||||||
|
pass
|
||||||
|
|
||||||
|
payload = [
|
||||||
|
{
|
||||||
|
'taskType': 'authentication',
|
||||||
|
'apiKey': api_key
|
||||||
|
},
|
||||||
|
inference_task
|
||||||
]
|
]
|
||||||
|
|
||||||
logger.info(f"[AIProcessor.generate_image] Runware request payload: model={runware_model}, width={width}, height={height}, prompt_length={len(prompt)}")
|
logger.info(f"[AIProcessor.generate_image] Runware request payload: model={runware_model}, width={width}, height={height}, prompt_length={len(prompt)}")
|
||||||
|
|||||||
1016
docs/plans/COMPREHENSIVE-SYSTEM-FIX-PLAN-JAN-10-2026.md
Normal file
1016
docs/plans/COMPREHENSIVE-SYSTEM-FIX-PLAN-JAN-10-2026.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
|||||||
| Phase | Focus | Priority | Status |
|
| Phase | Focus | Priority | Status |
|
||||||
|-------|-------|----------|--------|
|
|-------|-------|----------|--------|
|
||||||
| **1** | Code Cleanup & Technical Debt | 🔴 Critical | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-1-code-cleanup--technical-debt-) |
|
| **1** | Code Cleanup & Technical Debt | 🔴 Critical | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-1-code-cleanup--technical-debt-) |
|
||||||
| **2** | Content & Template Optimization | 🔴 Critical | ⏳ Pending |
|
| **2** | Content & Template Optimization | 🔴 Critical | ✅ Completed |
|
||||||
| **3** | Pipeline Verification & Testing | 🔴 Critical | ⏳ Pending |
|
| **3** | Pipeline Verification & Testing | 🔴 Critical | ⏳ Pending |
|
||||||
| **4** | Email & Notifications QA |🟡 High | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-4-email--notifications-qa-) |
|
| **4** | Email & Notifications QA |🟡 High | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-4-email--notifications-qa-) |
|
||||||
| **5** | UX Improvements | 🟡 High | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-5-ux-improvements-) |
|
| **5** | UX Improvements | 🟡 High | ✅ Completed - [See Completed File](./FINAL-PRELAUNCH-Completed.md#pre-launch-phase-5-ux-improvements-) |
|
||||||
|
|||||||
Reference in New Issue
Block a user