from django.db import models from django.contrib.auth import get_user_model import uuid User = get_user_model() class Meeting(models.Model): """会议室模型""" STATUS_CHOICES = [ ('pending', '待开始'), ('active', '进行中'), ('ended', '已结束'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) topic = models.CharField(max_length=200, verbose_name='会议主题') host = models.ForeignKey(User, on_delete=models.CASCADE, related_name='hosted_meetings') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') invite_code = models.CharField(max_length=20, unique=True, verbose_name='邀请码') created_at = models.DateTimeField(auto_now_add=True) started_at = models.DateTimeField(null=True, blank=True) ended_at = models.DateTimeField(null=True, blank=True) expires_at = models.DateTimeField(null=True, blank=True, verbose_name="过期时间") # 主持龙虾(负责生成会议纪要) host_agent_id = models.CharField(max_length=100, null=True, blank=True, verbose_name='主持 Agent ID') host_instance_id = models.CharField(max_length=100, null=True, blank=True, verbose_name='主持实例 ID') minutes_generated = models.BooleanField(default=False, verbose_name='纪要已生成') minutes_uploaded_at = models.DateTimeField(null=True, blank=True, verbose_name='纪要上传时间') class Meta: db_table = 'meetings' verbose_name = '会议室' verbose_name_plural = '会议室' ordering = ['-created_at'] def __str__(self): return f"{self.topic} ({self.host.username})" def save(self, *args, **kwargs): if not self.invite_code: self.invite_code = uuid.uuid4().hex[:8].upper() super().save(*args, **kwargs) class Participant(models.Model): """参会者模型""" AGENT_TYPE_CHOICES = [ ('human', '人类'), ('openclaw', 'OpenClaw Agent'), ('other', '其他 AI'), ] meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE, related_name='participants') user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE) # Agent 信息 agent_type = models.CharField(max_length=20, choices=AGENT_TYPE_CHOICES) agent_id = models.CharField(max_length=100, null=True, blank=True) agent_name = models.CharField(max_length=100, verbose_name='Agent 名称') agent_emoji = models.CharField(max_length=10, default='🤖', verbose_name='Agent 表情') # 显示信息 nickname = models.CharField(max_length=100, verbose_name='昵称') is_host = models.BooleanField(default=False) joined_at = models.DateTimeField(auto_now_add=True) left_at = models.DateTimeField(null=True, blank=True) # API 认证(Agent 用) api_key = models.CharField(max_length=255, null=True, blank=True) class Meta: db_table = 'participants' verbose_name = '参会者' verbose_name_plural = '参会者' indexes = [ models.Index(fields=['meeting', 'agent_id']), models.Index(fields=['agent_type', 'meeting']), ] def __str__(self): return f"{self.agent_emoji} {self.nickname}" def save(self, *args, **kwargs): if not self.api_key and self.agent_type != 'human': self.api_key = uuid.uuid4().hex super().save(*args, **kwargs) class Message(models.Model): """消息模型""" meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE, related_name='messages') sender = models.ForeignKey(Participant, on_delete=models.CASCADE, related_name='sent_messages') content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) # 信箱机制 is_broadcast = models.BooleanField(default=True, verbose_name='群发消息') requires_response = models.BooleanField(default=False, verbose_name='需要回复') in_reply_to = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, related_name='replies') # 读取状态 read_by = models.ManyToManyField(Participant, related_name='read_messages', blank=True) class Meta: db_table = 'messages' verbose_name = '消息' verbose_name_plural = '消息' ordering = ['created_at'] indexes = [ models.Index(fields=['meeting', 'created_at']), models.Index(fields=['is_broadcast', 'created_at']), ] def __str__(self): return f"{self.sender.nickname}: {self.content[:50]}" class MeetingMinutes(models.Model): """会议纪要模型""" meeting = models.OneToOneField(Meeting, on_delete=models.CASCADE, related_name='minutes') content = models.TextField() generated_at = models.DateTimeField(auto_now_add=True) exported_at = models.DateTimeField(null=True, blank=True) class Meta: db_table = 'meeting_minutes' verbose_name = '会议纪要' verbose_name_plural = '会议纪要' def __str__(self): return f"会议纪要 - {self.meeting.topic}"