Files
igny8/backend/igny8_core/business/automation/models.py

144 lines
7.4 KiB
Python

"""
Automation Models
Tracks automation runs and configuration
"""
from django.db import models
from django.utils import timezone
from igny8_core.auth.models import Account, Site
class AutomationConfig(models.Model):
"""Per-site automation configuration"""
FREQUENCY_CHOICES = [
('daily', 'Daily'),
('weekly', 'Weekly'),
('monthly', 'Monthly'),
]
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='automation_configs')
site = models.OneToOneField(Site, on_delete=models.CASCADE, related_name='automation_config')
is_enabled = models.BooleanField(default=False, help_text="Whether scheduled automation is active")
frequency = models.CharField(max_length=20, choices=FREQUENCY_CHOICES, default='daily')
scheduled_time = models.TimeField(default='02:00', help_text="Time to run (e.g., 02:00)")
# Stage processing toggles
stage_1_enabled = models.BooleanField(default=True, help_text="Process Stage 1: Keywords → Clusters")
stage_2_enabled = models.BooleanField(default=True, help_text="Process Stage 2: Clusters → Ideas")
stage_3_enabled = models.BooleanField(default=True, help_text="Process Stage 3: Ideas → Tasks")
stage_4_enabled = models.BooleanField(default=True, help_text="Process Stage 4: Tasks → Content")
stage_5_enabled = models.BooleanField(default=True, help_text="Process Stage 5: Content → Image Prompts")
stage_6_enabled = models.BooleanField(default=True, help_text="Process Stage 6: Image Prompts → Images")
stage_7_enabled = models.BooleanField(default=True, help_text="Process Stage 7: Review → Published")
# Batch sizes per stage
stage_1_batch_size = models.IntegerField(default=50, help_text="Keywords per batch")
stage_2_batch_size = models.IntegerField(default=1, help_text="Clusters at a time")
stage_3_batch_size = models.IntegerField(default=20, help_text="Ideas per batch")
stage_4_batch_size = models.IntegerField(default=1, help_text="Tasks - sequential")
stage_5_batch_size = models.IntegerField(default=1, help_text="Content at a time")
stage_6_batch_size = models.IntegerField(default=1, help_text="Images - sequential")
# Delay configuration (in seconds)
within_stage_delay = models.IntegerField(default=3, help_text="Delay between batches within a stage (seconds)")
between_stage_delay = models.IntegerField(default=5, help_text="Delay between stage transitions (seconds)")
# Per-run item limits (0 = unlimited, processes all available)
# These prevent runaway automation and control resource usage
max_keywords_per_run = models.IntegerField(default=0, help_text="Max keywords to process in stage 1 (0=unlimited)")
max_clusters_per_run = models.IntegerField(default=0, help_text="Max clusters to process in stage 2 (0=unlimited)")
max_ideas_per_run = models.IntegerField(default=0, help_text="Max ideas to process in stage 3 (0=unlimited)")
max_tasks_per_run = models.IntegerField(default=0, help_text="Max tasks to process in stage 4 (0=unlimited)")
max_content_per_run = models.IntegerField(default=0, help_text="Max content pieces for image prompts in stage 5 (0=unlimited)")
max_images_per_run = models.IntegerField(default=0, help_text="Max images to generate in stage 6 (0=unlimited)")
max_approvals_per_run = models.IntegerField(default=0, help_text="Max content pieces to auto-approve in stage 7 (0=unlimited)")
# Credit budget limit per run (0 = use site's full credit balance)
max_credits_per_run = models.IntegerField(default=0, help_text="Max credits to use per run (0=unlimited)")
last_run_at = models.DateTimeField(null=True, blank=True)
next_run_at = models.DateTimeField(null=True, blank=True, help_text="Calculated based on frequency")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'igny8_automation_configs'
verbose_name = 'Automation Config'
verbose_name_plural = 'Automation Configs'
indexes = [
models.Index(fields=['is_enabled', 'next_run_at']),
models.Index(fields=['account', 'site']),
]
def __str__(self):
return f"Automation Config: {self.site.domain} ({self.frequency})"
class AutomationRun(models.Model):
"""Tracks each automation execution"""
TRIGGER_TYPE_CHOICES = [
('manual', 'Manual'),
('scheduled', 'Scheduled'),
]
STATUS_CHOICES = [
('running', 'Running'),
('paused', 'Paused'),
('cancelled', 'Cancelled'),
('completed', 'Completed'),
('failed', 'Failed'),
]
run_id = models.CharField(max_length=100, unique=True, db_index=True, help_text="Format: run_20251203_140523_manual")
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='automation_runs')
site = models.ForeignKey(Site, on_delete=models.CASCADE, related_name='automation_runs')
trigger_type = models.CharField(max_length=20, choices=TRIGGER_TYPE_CHOICES)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='running', db_index=True)
current_stage = models.IntegerField(default=1, help_text="Current stage number (1-7)")
# Pause/Resume tracking
paused_at = models.DateTimeField(null=True, blank=True, help_text="When automation was paused")
resumed_at = models.DateTimeField(null=True, blank=True, help_text="When automation was last resumed")
cancelled_at = models.DateTimeField(null=True, blank=True, help_text="When automation was cancelled")
started_at = models.DateTimeField(auto_now_add=True, db_index=True)
completed_at = models.DateTimeField(null=True, blank=True)
total_credits_used = models.IntegerField(default=0)
# Initial queue snapshot - captured at run start for accurate progress tracking
initial_snapshot = models.JSONField(
default=dict,
blank=True,
help_text="Snapshot of initial queue sizes: {stage_1_initial, stage_2_initial, ..., total_initial_items}"
)
# JSON results per stage
stage_1_result = models.JSONField(null=True, blank=True, help_text="{keywords_processed, clusters_created, batches}")
stage_2_result = models.JSONField(null=True, blank=True, help_text="{clusters_processed, ideas_created}")
stage_3_result = models.JSONField(null=True, blank=True, help_text="{ideas_processed, tasks_created}")
stage_4_result = models.JSONField(null=True, blank=True, help_text="{tasks_processed, content_created, total_words}")
stage_5_result = models.JSONField(null=True, blank=True, help_text="{content_processed, prompts_created}")
stage_6_result = models.JSONField(null=True, blank=True, help_text="{images_processed, images_generated}")
stage_7_result = models.JSONField(null=True, blank=True, help_text="{ready_for_review}")
error_message = models.TextField(null=True, blank=True)
class Meta:
db_table = 'igny8_automation_runs'
verbose_name = 'Automation Run'
verbose_name_plural = 'Automation Runs'
ordering = ['-started_at']
indexes = [
models.Index(fields=['site', '-started_at']),
models.Index(fields=['status', '-started_at']),
models.Index(fields=['account', '-started_at']),
]
def __str__(self):
return f"{self.run_id} - {self.site.domain} ({self.status})"