All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m13s
- IP138 在线 API + ip2region 离线库双通道归属地解析,60 秒熔断降级 - 5 条异常检测规则:地区不对/不可能旅行/频繁登录/团队遍地开花/海外IP太杂 - 飞书 interactive 卡片告警(红色严重/橙色警告),含辅助指标 - R2 自动封禁用户、R4 自动封禁团队,封禁即踢下线 - 系统设置页全局配置 + 团队详情页独立阈值覆盖 - 安全日志页面 + 管理员修改密码入口 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
4.9 KiB
Python
92 lines
4.9 KiB
Python
import uuid
|
|
from django.db import models
|
|
from django.conf import settings
|
|
|
|
|
|
class GenerationRecord(models.Model):
|
|
"""Video generation call record."""
|
|
MODE_CHOICES = [
|
|
('universal', '全能参考'),
|
|
('keyframe', '首尾帧'),
|
|
]
|
|
MODEL_CHOICES = [
|
|
('seedance_2.0', 'AirDrama'),
|
|
('seedance_2.0_fast', 'AirDrama Fast'),
|
|
]
|
|
STATUS_CHOICES = [
|
|
('queued', '排队中'),
|
|
('processing', '生成中'),
|
|
('completed', '已完成'),
|
|
('failed', '失败'),
|
|
]
|
|
|
|
user = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.CASCADE,
|
|
related_name='generation_records',
|
|
verbose_name='用户',
|
|
)
|
|
task_id = models.UUIDField(default=uuid.uuid4, unique=True, verbose_name='任务ID')
|
|
ark_task_id = models.CharField(max_length=100, blank=True, default='', verbose_name='火山ARK任务ID')
|
|
prompt = models.TextField(blank=True, verbose_name='提示词')
|
|
mode = models.CharField(max_length=20, choices=MODE_CHOICES, verbose_name='创作模式')
|
|
model = models.CharField(max_length=30, choices=MODEL_CHOICES, verbose_name='模型')
|
|
aspect_ratio = models.CharField(max_length=10, verbose_name='宽高比')
|
|
duration = models.IntegerField(verbose_name='视频时长(秒)')
|
|
seconds_consumed = models.FloatField(default=0, verbose_name='消费秒数')
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='queued', verbose_name='状态')
|
|
result_url = models.CharField(max_length=1000, blank=True, default='', verbose_name='生成结果URL')
|
|
error_message = models.TextField(blank=True, default='', verbose_name='错误信息')
|
|
reference_urls = models.JSONField(default=list, blank=True, verbose_name='参考素材信息')
|
|
created_at = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='创建时间')
|
|
|
|
class Meta:
|
|
verbose_name = '生成记录'
|
|
verbose_name_plural = '生成记录'
|
|
ordering = ['-created_at']
|
|
indexes = [
|
|
models.Index(fields=['user', 'created_at']),
|
|
]
|
|
|
|
def __str__(self):
|
|
return f'{self.user.username} - {self.task_id}'
|
|
|
|
|
|
class QuotaConfig(models.Model):
|
|
"""Global quota configuration (singleton) — Phase 3: seconds + announcement + anomaly detection."""
|
|
default_daily_seconds_limit = models.IntegerField(default=600, verbose_name='默认每日秒数上限')
|
|
default_monthly_seconds_limit = models.IntegerField(default=6000, verbose_name='默认每月秒数上限')
|
|
announcement = models.TextField(blank=True, default='', verbose_name='系统公告')
|
|
announcement_enabled = models.BooleanField(default=False, verbose_name='启用公告')
|
|
max_desktop_sessions = models.IntegerField(default=1, verbose_name='每用户最大桌面端会话数')
|
|
max_mobile_sessions = models.IntegerField(default=0, verbose_name='每用户最大移动端会话数')
|
|
# ── 异常检测全局默认配置 ──
|
|
anomaly_detection_enabled = models.BooleanField(default=False, verbose_name='异常检测总开关')
|
|
r1_enabled_default = models.BooleanField(default=True, verbose_name='R1 默认开关')
|
|
r2_enabled_default = models.BooleanField(default=True, verbose_name='R2 默认开关')
|
|
r2_window_seconds = models.IntegerField(default=3600, verbose_name='R2 默认时间窗口(秒)')
|
|
r3_enabled_default = models.BooleanField(default=True, verbose_name='R3 默认开关')
|
|
r3_window_seconds = models.IntegerField(default=3600, verbose_name='R3 默认时间窗口(秒)')
|
|
r3_max_count = models.IntegerField(default=10, verbose_name='R3 默认最大登录次数')
|
|
r4_enabled_default = models.BooleanField(default=True, verbose_name='R4 默认开关')
|
|
r4_window_seconds = models.IntegerField(default=3600, verbose_name='R4 默认时间窗口(秒)')
|
|
r4_city_count = models.IntegerField(default=5, verbose_name='R4 默认预期外城市数')
|
|
r5_enabled_default = models.BooleanField(default=True, verbose_name='R5 默认开关')
|
|
r5_days = models.IntegerField(default=7, verbose_name='R5 默认统计天数')
|
|
r5_country_count = models.IntegerField(default=10, verbose_name='R5 默认海外国家数')
|
|
feishu_alert_mobiles = models.CharField(max_length=500, blank=True, default='', verbose_name='飞书告警接收人手机号')
|
|
sms_alert_mobiles = models.CharField(max_length=500, blank=True, default='', verbose_name='短信告警手机号(预留)')
|
|
alert_cooldown_seconds = models.IntegerField(default=1800, verbose_name='告警冷却时间(秒)')
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
class Meta:
|
|
verbose_name = '系统配置'
|
|
verbose_name_plural = '系统配置'
|
|
|
|
def save(self, *args, **kwargs):
|
|
self.pk = 1
|
|
super().save(*args, **kwargs)
|
|
|
|
def __str__(self):
|
|
return f'全局配额: {self.default_daily_seconds_limit}s/日, {self.default_monthly_seconds_limit}s/月'
|