feat(migrations): Rename indexes and update global integration settings fields for improved clarity and functionality
feat(admin): Add API monitoring, debug console, and system health templates for enhanced admin interface docs: Add AI system cleanup summary and audit report detailing architecture, token management, and recommendations docs: Introduce credits and tokens system guide outlining configuration, data flow, and monitoring strategies
This commit is contained in:
@@ -11,7 +11,12 @@ from .settings_models import (
|
||||
|
||||
|
||||
class AIPrompt(AccountBaseModel):
|
||||
"""AI Prompt templates for various AI operations"""
|
||||
"""
|
||||
Account-specific AI Prompt templates.
|
||||
Stores global default in default_prompt, current value in prompt_value.
|
||||
When user saves an override, prompt_value changes but default_prompt stays.
|
||||
Reset copies default_prompt back to prompt_value.
|
||||
"""
|
||||
|
||||
PROMPT_TYPE_CHOICES = [
|
||||
('clustering', 'Clustering'),
|
||||
@@ -28,8 +33,15 @@ class AIPrompt(AccountBaseModel):
|
||||
]
|
||||
|
||||
prompt_type = models.CharField(max_length=50, choices=PROMPT_TYPE_CHOICES, db_index=True)
|
||||
prompt_value = models.TextField(help_text="The prompt template text")
|
||||
default_prompt = models.TextField(help_text="Default prompt value (for reset)")
|
||||
prompt_value = models.TextField(help_text="Current prompt text (customized or default)")
|
||||
default_prompt = models.TextField(
|
||||
blank=True,
|
||||
help_text="Global default prompt - used for reset to default"
|
||||
)
|
||||
is_customized = models.BooleanField(
|
||||
default=False,
|
||||
help_text="True if account customized the prompt, False if using global default"
|
||||
)
|
||||
is_active = models.BooleanField(default=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
@@ -41,24 +53,77 @@ class AIPrompt(AccountBaseModel):
|
||||
indexes = [
|
||||
models.Index(fields=['prompt_type']),
|
||||
models.Index(fields=['account', 'prompt_type']),
|
||||
models.Index(fields=['is_customized']),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_effective_prompt(cls, account, prompt_type):
|
||||
"""
|
||||
Get the effective prompt for an account.
|
||||
Returns account-specific prompt if exists and customized.
|
||||
Otherwise returns global default.
|
||||
"""
|
||||
from .global_settings_models import GlobalAIPrompt
|
||||
|
||||
# Try to get account-specific prompt
|
||||
try:
|
||||
account_prompt = cls.objects.get(account=account, prompt_type=prompt_type, is_active=True)
|
||||
# If customized, use account's version
|
||||
if account_prompt.is_customized:
|
||||
return account_prompt.prompt_value
|
||||
# If not customized, use default_prompt from account record or global
|
||||
return account_prompt.default_prompt or account_prompt.prompt_value
|
||||
except cls.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Fallback to global prompt
|
||||
try:
|
||||
global_prompt = GlobalAIPrompt.objects.get(prompt_type=prompt_type, is_active=True)
|
||||
return global_prompt.prompt_value
|
||||
except GlobalAIPrompt.DoesNotExist:
|
||||
return None
|
||||
|
||||
def reset_to_default(self):
|
||||
"""Reset prompt to global default"""
|
||||
if self.default_prompt:
|
||||
self.prompt_value = self.default_prompt
|
||||
self.is_customized = False
|
||||
self.save()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_prompt_type_display()}"
|
||||
status = "Custom" if self.is_customized else "Default"
|
||||
return f"{self.get_prompt_type_display()} ({status})"
|
||||
|
||||
|
||||
class IntegrationSettings(AccountBaseModel):
|
||||
"""Integration settings for OpenAI, Runware, GSC, etc."""
|
||||
"""
|
||||
Per-account integration settings overrides.
|
||||
|
||||
IMPORTANT: This model stores ONLY model selection and parameter overrides.
|
||||
API keys are NEVER stored here - they come from GlobalIntegrationSettings.
|
||||
|
||||
Free plan: Cannot create overrides, must use global defaults
|
||||
Starter/Growth/Scale plans: Can override model, temperature, tokens, image settings
|
||||
|
||||
NULL values in config mean "use global default"
|
||||
"""
|
||||
|
||||
INTEGRATION_TYPE_CHOICES = [
|
||||
('openai', 'OpenAI'),
|
||||
('dalle', 'DALL-E'),
|
||||
('anthropic', 'Anthropic'),
|
||||
('runware', 'Runware'),
|
||||
('gsc', 'Google Search Console'),
|
||||
('image_generation', 'Image Generation Service'),
|
||||
]
|
||||
|
||||
integration_type = models.CharField(max_length=50, choices=INTEGRATION_TYPE_CHOICES, db_index=True)
|
||||
config = models.JSONField(default=dict, help_text="Integration configuration (API keys, settings, etc.)")
|
||||
config = models.JSONField(
|
||||
default=dict,
|
||||
help_text=(
|
||||
"Model and parameter overrides only. Fields: model, temperature, max_tokens, "
|
||||
"image_size, image_quality, etc. NULL = use global default. "
|
||||
"NEVER store API keys here."
|
||||
)
|
||||
)
|
||||
is_active = models.BooleanField(default=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
@@ -80,6 +145,7 @@ class IntegrationSettings(AccountBaseModel):
|
||||
class AuthorProfile(AccountBaseModel):
|
||||
"""
|
||||
Writing style profiles - tone, language, structure templates.
|
||||
Can be cloned from global templates or created from scratch.
|
||||
Examples: "SaaS B2B Informative", "E-commerce Product Descriptions", etc.
|
||||
"""
|
||||
name = models.CharField(max_length=255, help_text="Profile name (e.g., 'SaaS B2B Informative')")
|
||||
@@ -93,6 +159,18 @@ class AuthorProfile(AccountBaseModel):
|
||||
default=dict,
|
||||
help_text="Structure template defining content sections and their order"
|
||||
)
|
||||
is_custom = models.BooleanField(
|
||||
default=False,
|
||||
help_text="True if created by account, False if cloned from global template"
|
||||
)
|
||||
cloned_from = models.ForeignKey(
|
||||
'system.GlobalAuthorProfile',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='cloned_instances',
|
||||
help_text="Reference to the global template this was cloned from"
|
||||
)
|
||||
is_active = models.BooleanField(default=True, db_index=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
@@ -105,16 +183,19 @@ class AuthorProfile(AccountBaseModel):
|
||||
indexes = [
|
||||
models.Index(fields=['account', 'is_active']),
|
||||
models.Index(fields=['name']),
|
||||
models.Index(fields=['is_custom']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
account = getattr(self, 'account', None)
|
||||
return f"{self.name} ({account.name if account else 'No Account'})"
|
||||
status = "Custom" if self.is_custom else "Template"
|
||||
return f"{self.name} ({status}) - {account.name if account else 'No Account'}"
|
||||
|
||||
|
||||
class Strategy(AccountBaseModel):
|
||||
"""
|
||||
Defined content strategies per sector, integrating prompt types, section logic, etc.
|
||||
Can be cloned from global templates or created from scratch.
|
||||
Links together prompts, author profiles, and sector-specific content strategies.
|
||||
"""
|
||||
name = models.CharField(max_length=255, help_text="Strategy name")
|
||||
@@ -135,6 +216,18 @@ class Strategy(AccountBaseModel):
|
||||
default=dict,
|
||||
help_text="Section logic configuration defining content structure and flow"
|
||||
)
|
||||
is_custom = models.BooleanField(
|
||||
default=False,
|
||||
help_text="True if created by account, False if cloned from global template"
|
||||
)
|
||||
cloned_from = models.ForeignKey(
|
||||
'system.GlobalStrategy',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='cloned_instances',
|
||||
help_text="Reference to the global template this was cloned from"
|
||||
)
|
||||
is_active = models.BooleanField(default=True, db_index=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
@@ -148,8 +241,10 @@ class Strategy(AccountBaseModel):
|
||||
models.Index(fields=['account', 'is_active']),
|
||||
models.Index(fields=['account', 'sector']),
|
||||
models.Index(fields=['name']),
|
||||
models.Index(fields=['is_custom']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
sector_name = self.sector.name if self.sector else 'Global'
|
||||
return f"{self.name} ({sector_name})"
|
||||
status = "Custom" if self.is_custom else "Template"
|
||||
return f"{self.name} ({status}) - {sector_name}"
|
||||
|
||||
Reference in New Issue
Block a user