lot of messs
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-23 08:40
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0003_globalmodulesettings'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GlobalAIPrompt',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('prompt_type', models.CharField(choices=[('clustering', 'Clustering'), ('ideas', 'Ideas Generation'), ('content_generation', 'Content Generation'), ('image_prompt_extraction', 'Image Prompt Extraction'), ('image_prompt_template', 'Image Prompt Template'), ('negative_prompt', 'Negative Prompt'), ('site_structure_generation', 'Site Structure Generation'), ('product_generation', 'Product Content Generation'), ('service_generation', 'Service Page Generation'), ('taxonomy_generation', 'Taxonomy Generation')], help_text='Type of AI operation this prompt is for', max_length=50, unique=True)),
|
||||
('prompt_value', models.TextField(help_text='Default prompt template')),
|
||||
('description', models.TextField(blank=True, help_text='Description of what this prompt does')),
|
||||
('variables', models.JSONField(blank=True, default=list, help_text='Optional: List of variables used in the prompt (e.g., {keyword}, {industry})')),
|
||||
('is_active', models.BooleanField(db_index=True, default=True)),
|
||||
('version', models.IntegerField(default=1, help_text='Prompt version for tracking changes')),
|
||||
('last_updated', models.DateTimeField(auto_now=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Global AI Prompt',
|
||||
'verbose_name_plural': 'Global AI Prompts',
|
||||
'db_table': 'igny8_global_ai_prompts',
|
||||
'ordering': ['prompt_type'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GlobalAuthorProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(help_text="Profile name (e.g., 'SaaS B2B Professional')", max_length=255, unique=True)),
|
||||
('description', models.TextField(help_text='Description of the writing style')),
|
||||
('tone', models.CharField(help_text="Writing tone (e.g., 'Professional', 'Casual', 'Technical')", max_length=100)),
|
||||
('language', models.CharField(default='en', help_text='Language code', max_length=50)),
|
||||
('structure_template', models.JSONField(default=dict, help_text='Structure template defining content sections')),
|
||||
('category', models.CharField(choices=[('saas', 'SaaS/B2B'), ('ecommerce', 'E-commerce'), ('blog', 'Blog/Publishing'), ('technical', 'Technical'), ('creative', 'Creative'), ('news', 'News/Media'), ('academic', 'Academic')], help_text='Profile category', max_length=50)),
|
||||
('is_active', models.BooleanField(db_index=True, default=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Global Author Profile',
|
||||
'verbose_name_plural': 'Global Author Profiles',
|
||||
'db_table': 'igny8_global_author_profiles',
|
||||
'ordering': ['category', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GlobalStrategy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(help_text='Strategy name', max_length=255, unique=True)),
|
||||
('description', models.TextField(help_text='Description of the content strategy')),
|
||||
('prompt_types', models.JSONField(default=list, help_text='List of prompt types to use')),
|
||||
('section_logic', models.JSONField(default=dict, help_text='Section logic configuration')),
|
||||
('category', models.CharField(choices=[('blog', 'Blog Content'), ('ecommerce', 'E-commerce'), ('saas', 'SaaS/B2B'), ('news', 'News/Media'), ('technical', 'Technical Documentation'), ('marketing', 'Marketing Content')], help_text='Strategy category', max_length=50)),
|
||||
('is_active', models.BooleanField(db_index=True, default=True)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Global Strategy',
|
||||
'verbose_name_plural': 'Global Strategies',
|
||||
'db_table': 'igny8_global_strategies',
|
||||
'ordering': ['category', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GlobalIntegrationSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('openai_api_key', models.CharField(blank=True, help_text='Platform OpenAI API key - used by ALL accounts', max_length=500)),
|
||||
('openai_model', models.CharField(choices=[('gpt-4.1', 'GPT-4.1 - $2.00 / $8.00 per 1M tokens'), ('gpt-4o-mini', 'GPT-4o mini - $0.15 / $0.60 per 1M tokens'), ('gpt-4o', 'GPT-4o - $2.50 / $10.00 per 1M tokens'), ('gpt-4-turbo-preview', 'GPT-4 Turbo Preview - $10.00 / $30.00 per 1M tokens'), ('gpt-5.1', 'GPT-5.1 - $1.25 / $10.00 per 1M tokens (16K)'), ('gpt-5.2', 'GPT-5.2 - $1.75 / $14.00 per 1M tokens (16K)')], default='gpt-4o-mini', help_text='Default text generation model (accounts can override if plan allows)', max_length=100)),
|
||||
('openai_temperature', models.FloatField(default=0.7, help_text='Default temperature 0.0-2.0 (accounts can override if plan allows)')),
|
||||
('openai_max_tokens', models.IntegerField(default=8192, help_text='Default max tokens for responses (accounts can override if plan allows)')),
|
||||
('dalle_api_key', models.CharField(blank=True, help_text='Platform DALL-E API key - used by ALL accounts (can be same as OpenAI)', max_length=500)),
|
||||
('dalle_model', models.CharField(choices=[('dall-e-3', 'DALL·E 3 - $0.040 per image'), ('dall-e-2', 'DALL·E 2 - $0.020 per image')], default='dall-e-3', help_text='Default DALL-E model (accounts can override if plan allows)', max_length=100)),
|
||||
('dalle_size', models.CharField(choices=[('1024x1024', '1024x1024 (Square)'), ('1792x1024', '1792x1024 (Landscape)'), ('1024x1792', '1024x1792 (Portrait)'), ('512x512', '512x512 (Small Square)')], default='1024x1024', help_text='Default image size (accounts can override if plan allows)', max_length=20)),
|
||||
('runware_api_key', models.CharField(blank=True, help_text='Platform Runware API key - used by ALL accounts', max_length=500)),
|
||||
('runware_model', models.CharField(choices=[('runware:97@1', 'Runware 97@1 - Versatile Model'), ('runware:100@1', 'Runware 100@1 - High Quality'), ('runware:101@1', 'Runware 101@1 - Fast Generation')], default='runware:97@1', help_text='Default Runware model (accounts can override if plan allows)', max_length=100)),
|
||||
('default_image_service', models.CharField(choices=[('openai', 'OpenAI DALL-E'), ('runware', 'Runware')], default='openai', help_text='Default image generation service for all accounts (openai=DALL-E, runware=Runware)', max_length=20)),
|
||||
('image_quality', models.CharField(choices=[('standard', 'Standard'), ('hd', 'HD')], default='standard', help_text='Default image quality for all providers (accounts can override if plan allows)', max_length=20)),
|
||||
('image_style', models.CharField(choices=[('vivid', 'Vivid'), ('natural', 'Natural'), ('realistic', 'Realistic'), ('artistic', 'Artistic'), ('cartoon', 'Cartoon')], default='realistic', help_text='Default image style for all providers (accounts can override if plan allows)', max_length=20)),
|
||||
('max_in_article_images', models.IntegerField(default=2, help_text='Default maximum images to generate per article (1-5, accounts can override if plan allows)')),
|
||||
('desktop_image_size', models.CharField(default='1024x1024', help_text='Default desktop image size (accounts can override if plan allows)', max_length=20)),
|
||||
('mobile_image_size', models.CharField(default='512x512', help_text='Default mobile image size (accounts can override if plan allows)', max_length=20)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True)),
|
||||
('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='global_settings_updates', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Global Integration Settings',
|
||||
'verbose_name_plural': 'Global Integration Settings',
|
||||
'db_table': 'igny8_global_integration_settings',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,183 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-23 (custom data migration)
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_model_strings_to_fks(apps, schema_editor):
|
||||
"""Convert CharField model identifiers to ForeignKey references"""
|
||||
GlobalIntegrationSettings = apps.get_model('system', 'GlobalIntegrationSettings')
|
||||
AIModelConfig = apps.get_model('billing', 'AIModelConfig')
|
||||
|
||||
# Get the singleton GlobalIntegrationSettings instance
|
||||
try:
|
||||
settings = GlobalIntegrationSettings.objects.first()
|
||||
if not settings:
|
||||
print(" No GlobalIntegrationSettings found, skipping data migration")
|
||||
return
|
||||
|
||||
# Map openai_model string to AIModelConfig FK
|
||||
if settings.openai_model_old:
|
||||
model_name = settings.openai_model_old
|
||||
# Try to find matching model
|
||||
openai_model = AIModelConfig.objects.filter(
|
||||
model_name=model_name,
|
||||
provider='openai',
|
||||
model_type='text'
|
||||
).first()
|
||||
if openai_model:
|
||||
settings.openai_model_new = openai_model
|
||||
print(f" ✓ Mapped openai_model: {model_name} → {openai_model.id}")
|
||||
else:
|
||||
# Try gpt-4o-mini as fallback
|
||||
openai_model = AIModelConfig.objects.filter(
|
||||
model_name='gpt-4o-mini',
|
||||
provider='openai',
|
||||
model_type='text'
|
||||
).first()
|
||||
if openai_model:
|
||||
settings.openai_model_new = openai_model
|
||||
print(f" ⚠ Could not find {model_name}, using fallback: gpt-4o-mini")
|
||||
|
||||
# Map dalle_model string to AIModelConfig FK
|
||||
if settings.dalle_model_old:
|
||||
model_name = settings.dalle_model_old
|
||||
dalle_model = AIModelConfig.objects.filter(
|
||||
model_name=model_name,
|
||||
provider='openai',
|
||||
model_type='image'
|
||||
).first()
|
||||
if dalle_model:
|
||||
settings.dalle_model_new = dalle_model
|
||||
print(f" ✓ Mapped dalle_model: {model_name} → {dalle_model.id}")
|
||||
else:
|
||||
# Try dall-e-3 as fallback
|
||||
dalle_model = AIModelConfig.objects.filter(
|
||||
model_name='dall-e-3',
|
||||
provider='openai',
|
||||
model_type='image'
|
||||
).first()
|
||||
if dalle_model:
|
||||
settings.dalle_model_new = dalle_model
|
||||
print(f" ⚠ Could not find {model_name}, using fallback: dall-e-3")
|
||||
|
||||
# Map runware_model string to AIModelConfig FK
|
||||
if settings.runware_model_old:
|
||||
model_name = settings.runware_model_old
|
||||
# Runware models might have different naming
|
||||
runware_model = AIModelConfig.objects.filter(
|
||||
provider='runware',
|
||||
model_type='image'
|
||||
).first() # Just get first active Runware model
|
||||
if runware_model:
|
||||
settings.runware_model_new = runware_model
|
||||
print(f" ✓ Mapped runware_model: {model_name} → {runware_model.id}")
|
||||
|
||||
settings.save()
|
||||
print(" ✅ Data migration complete")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ⚠ Error during data migration: {e}")
|
||||
# Don't fail the migration, let admin fix it manually
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('billing', '0019_add_ai_model_config'),
|
||||
('system', '0004_add_global_integration_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Step 1: Add new FK fields with temporary names
|
||||
migrations.AddField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='openai_model_new',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text='Default text generation model (accounts can override if plan allows)',
|
||||
limit_choices_to={'is_active': True, 'model_type': 'text', 'provider': 'openai'},
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name='global_openai_text_model_new',
|
||||
to='billing.aimodelconfig'
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='dalle_model_new',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text='Default DALL-E model (accounts can override if plan allows)',
|
||||
limit_choices_to={'is_active': True, 'model_type': 'image', 'provider': 'openai'},
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name='global_dalle_model_new',
|
||||
to='billing.aimodelconfig'
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='runware_model_new',
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text='Default Runware model (accounts can override if plan allows)',
|
||||
limit_choices_to={'is_active': True, 'model_type': 'image', 'provider': 'runware'},
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name='global_runware_model_new',
|
||||
to='billing.aimodelconfig'
|
||||
),
|
||||
),
|
||||
|
||||
# Step 2: Rename old CharField fields
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='openai_model',
|
||||
new_name='openai_model_old',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='dalle_model',
|
||||
new_name='dalle_model_old',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='runware_model',
|
||||
new_name='runware_model_old',
|
||||
),
|
||||
|
||||
# Step 3: Run data migration
|
||||
migrations.RunPython(migrate_model_strings_to_fks, migrations.RunPython.noop),
|
||||
|
||||
# Step 4: Remove old CharField fields
|
||||
migrations.RemoveField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='openai_model_old',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='dalle_model_old',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='runware_model_old',
|
||||
),
|
||||
|
||||
# Step 5: Rename new FK fields to final names
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='openai_model_new',
|
||||
new_name='openai_model',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='dalle_model_new',
|
||||
new_name='dalle_model',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='globalintegrationsettings',
|
||||
old_name='runware_model_new',
|
||||
new_name='runware_model',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-23 14:24
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('billing', '0020_add_optimizer_publisher_timestamps'),
|
||||
('system', '0005_link_global_settings_to_aimodelconfig'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='globalmodulesettings',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='globalmodulesettings',
|
||||
name='optimizer_enabled',
|
||||
field=models.BooleanField(default=True, help_text='Enable Optimizer module platform-wide'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='globalmodulesettings',
|
||||
name='publisher_enabled',
|
||||
field=models.BooleanField(default=True, help_text='Enable Publisher module platform-wide'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='globalmodulesettings',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='dalle_model',
|
||||
field=models.ForeignKey(blank=True, help_text='Default DALL-E model (accounts can override if plan allows)', limit_choices_to={'is_active': True, 'model_type': 'image', 'provider': 'openai'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='global_dalle_model', to='billing.aimodelconfig'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='openai_model',
|
||||
field=models.ForeignKey(blank=True, help_text='Default text generation model (accounts can override if plan allows)', limit_choices_to={'is_active': True, 'model_type': 'text', 'provider': 'openai'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='global_openai_text_model', to='billing.aimodelconfig'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='globalintegrationsettings',
|
||||
name='runware_model',
|
||||
field=models.ForeignKey(blank=True, help_text='Default Runware model (accounts can override if plan allows)', limit_choices_to={'is_active': True, 'model_type': 'image', 'provider': 'runware'}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='global_runware_model', to='billing.aimodelconfig'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user