MVP0
This commit is contained in:
98
backend_django/adsassistant_backend/api/models.py
Normal file
98
backend_django/adsassistant_backend/api/models.py
Normal file
@@ -0,0 +1,98 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user