Files
adsassistant/backend_django/adsassistant_backend/api/models.py
2026-03-05 06:55:42 +03:00

99 lines
4.3 KiB
Python

from django.db import models
from django.contrib.auth.models import User
class Brief(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="briefs")
product = models.TextField()
audience = models.TextField()
usp = models.TextField(blank=True, null=True)
benefits = models.JSONField(default=list, blank=True)
constraints = models.TextField(blank=True, null=True)
tone = models.CharField(max_length=120, blank=True, null=True)
formats = models.JSONField(default=list) # client chooses formats
variants_per_format = models.PositiveIntegerField(default=3)
created_at = models.DateTimeField(auto_now_add=True)
class TextVariant(models.Model):
brief = models.ForeignKey(Brief, on_delete=models.CASCADE, related_name="variants")
format = models.CharField(max_length=50)
payload = models.JSONField(default=dict)
placement_tips = models.TextField(blank=True, default="")
expected_effect = models.TextField(blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
class Test(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="tests")
brief = models.ForeignKey(Brief, on_delete=models.CASCADE, related_name="tests")
name = models.CharField(max_length=200, default="Тест")
channel = models.CharField(max_length=120, blank=True, default="")
duration_days = models.PositiveIntegerField(default=3)
sample_size = models.PositiveIntegerField(default=0)
objective = models.CharField(max_length=32, default="leads") # leads|conversions|clicks
status = models.CharField(max_length=20, default="draft")
created_at = models.DateTimeField(auto_now_add=True)
class Segment(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE, related_name="segments")
name = models.CharField(max_length=200)
description = models.TextField(blank=True, default="")
class Assignment(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE, related_name="assignments")
segment = models.ForeignKey(Segment, on_delete=models.CASCADE, related_name="assignments")
variant = models.ForeignKey(TextVariant, on_delete=models.CASCADE, related_name="assignments")
class ResultEntry(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE, related_name="results")
segment = models.ForeignKey(Segment, on_delete=models.CASCADE, related_name="results")
variant = models.ForeignKey(TextVariant, on_delete=models.CASCADE, related_name="results")
date = models.DateField()
impressions = models.PositiveIntegerField(default=0)
clicks = models.PositiveIntegerField(default=0)
conversions = models.PositiveIntegerField(default=0)
leads = models.PositiveIntegerField(default=0)
spend = models.FloatField(default=0.0)
created_at = models.DateTimeField(auto_now_add=True)
class MetricsSnapshot(models.Model):
test = models.OneToOneField(Test, on_delete=models.CASCADE, related_name="snapshot")
ranking = models.JSONField(default=list)
recommendations = models.JSONField(default=list)
created_at = models.DateTimeField(auto_now_add=True)
class OptimizationPolicy(models.Model):
"""User-defined optimization rules for Agent #2.
Supports two modes:
- thresholds: structured KPI + thresholds
- text: free-form query that describes ranking/thresholds
"""
MODE_CHOICES = [
("thresholds", "thresholds"),
("text", "text"),
]
KPI_CHOICES = [
("cpa", "cpa"),
("cpl", "cpl"),
("cpc", "cpc"),
("ctr", "ctr"),
("cr", "cr"),
]
test = models.OneToOneField("Test", on_delete=models.CASCADE, related_name="policy")
mode = models.CharField(max_length=16, choices=MODE_CHOICES, default="thresholds")
# Structured mode
primary_kpi = models.CharField(max_length=8, choices=KPI_CHOICES, default="cpl")
direction = models.CharField(max_length=8, default="min") # min or max
good_threshold = models.FloatField(null=True, blank=True)
ok_threshold = models.FloatField(null=True, blank=True)
min_impressions = models.IntegerField(default=0)
min_clicks = models.IntegerField(default=0)
# Text mode
query_text = models.TextField(blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True)