from django.db import models from apps.accounts.models import User import json import os from django.utils import timezone import uuid class GmailCredential(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='gmail_credentials') email = models.EmailField(unique=True, help_text="Gmail email address") credentials = models.TextField(help_text="Serialized OAuth2 credentials (JSON)") is_default = models.BooleanField(default=False, help_text="Default Gmail account for user") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) is_valid = models.BooleanField(default=True, help_text="Whether the credential is valid") last_history_id = models.CharField(max_length=50, blank=True, null=True, help_text="Last processed Gmail history ID") class Meta: unique_together = ('user', 'email') def set_credentials(self, credentials): self.credentials = json.dumps({ 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'scopes': credentials.scopes }) self.is_valid = True def get_credentials(self): from google.oauth2.credentials import Credentials creds_data = json.loads(self.credentials) return Credentials( token=creds_data['token'], refresh_token=creds_data['refresh_token'], token_uri=creds_data['token_uri'], client_id=creds_data['client_id'], client_secret=creds_data['client_secret'], scopes=creds_data['scopes'] ) def __str__(self): return f"{self.user.username} - {self.email}" class GmailConversation(models.Model): """Gmail对话记录,跟踪用户和达人之间的邮件交互""" user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='gmail_conversations') conversation_id = models.CharField(max_length=100, unique=True, help_text="Unique conversation identifier") user_email = models.EmailField(help_text="User's Gmail address") influencer_email = models.EmailField(help_text="Influencer's email address") title = models.CharField(max_length=255, help_text="Conversation title") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) last_sync_time = models.DateTimeField(null=True, blank=True, help_text="Last time conversation was synced with Gmail") is_active = models.BooleanField(default=True, help_text="Whether this conversation is active") has_sent_greeting = models.BooleanField(default=False, help_text="Whether a greeting message has been sent to this conversation") metadata = models.JSONField(null=True, blank=True, help_text="Additional metadata for the conversation") def __str__(self): return f"{self.user.username}: {self.user_email} - {self.influencer_email}" class Meta: ordering = ['-updated_at'] unique_together = ('user', 'user_email', 'influencer_email') class GmailAttachment(models.Model): """Gmail附件记录""" conversation = models.ForeignKey(GmailConversation, on_delete=models.CASCADE, related_name='attachments') email_message_id = models.CharField(max_length=100, help_text="Gmail邮件ID") attachment_id = models.TextField(help_text="Gmail附件的唯一标识符,可能很长") filename = models.CharField(max_length=255, help_text="原始文件名") file_path = models.CharField(max_length=255, help_text="保存在服务器上的路径") content_type = models.CharField(max_length=100, help_text="MIME类型") size = models.IntegerField(default=0, help_text="文件大小(字节)") sender_email = models.EmailField(help_text="发送者邮箱") chat_message_id = models.CharField(max_length=100, blank=True, null=True, help_text="关联到ChatHistory的消息ID") created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.filename} ({self.size} bytes)" def get_file_extension(self): """获取文件扩展名""" _, ext = os.path.splitext(self.filename) return ext.lower() def get_absolute_url(self): """获取文件URL""" return f"/media/gmail_attachments/{os.path.basename(self.file_path)}" class Meta: ordering = ['-created_at'] class ConversationSummary(models.Model): """Gmail对话摘要模型,用于持久化存储对话摘要""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) conversation = models.OneToOneField('GmailConversation', on_delete=models.CASCADE, related_name='summary') content = models.TextField(verbose_name='摘要内容') last_message_id = models.CharField(max_length=255, verbose_name='最后处理的消息ID或ChatHistory的ID', null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = 'gmail_conversation_summaries' verbose_name = 'Gmail对话摘要' verbose_name_plural = 'Gmail对话摘要' def __str__(self): return f"对话 {self.conversation.id} 摘要" class UserGoal(models.Model): """用户目标模型 - 存储用户设定的沟通或销售目标""" STATUS_CHOICES = [ ('pending', '待处理'), ('in_progress', '进行中'), ('completed', '已完成'), ('failed', '失败') ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='goals') conversation = models.ForeignKey(GmailConversation, on_delete=models.CASCADE, related_name='goals', null=True) description = models.TextField(verbose_name='目标描述') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', verbose_name='目标状态') is_active = models.BooleanField(default=True, verbose_name='是否激活') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) completion_time = models.DateTimeField(null=True, blank=True, verbose_name='完成时间') last_activity_time = models.DateTimeField(null=True, blank=True, verbose_name='最后活动时间') metadata = models.JSONField(default=dict, blank=True, null=True, help_text="存储额外信息") class Meta: db_table = 'user_goals' verbose_name = '用户目标' verbose_name_plural = '用户目标' ordering = ['-updated_at'] def __str__(self): return f"{self.user.username}的目标 - {self.description[:20]}..." def get_conversation_id(self): """获取对话ID""" if self.conversation: return self.conversation.conversation_id return None class AutoReplyConfig(models.Model): """ 自动回复配置模型 - 设置特定用户Gmail与达人Gmail的自动回复规则 """ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='auto_reply_configs') user_email = models.EmailField(help_text="用户Gmail邮箱") influencer_email = models.EmailField(help_text="达人Gmail邮箱") is_enabled = models.BooleanField(default=True, help_text="是否启用自动回复") goal_description = models.TextField(verbose_name='自动回复的目标描述', help_text="AI回复时参考的目标") reply_template = models.TextField(blank=True, null=True, help_text="回复模板(可选,为空则由AI生成)") max_replies = models.IntegerField(default=5, help_text="最大自动回复次数") current_replies = models.IntegerField(default=0, help_text="当前已自动回复次数") last_reply_time = models.DateTimeField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) metadata = models.JSONField(default=dict, blank=True, null=True, help_text="存储额外信息,如已处理的消息ID等") class Meta: db_table = 'gmail_auto_reply_configs' verbose_name = 'Gmail自动回复配置' verbose_name_plural = 'Gmail自动回复配置' unique_together = ('user', 'user_email', 'influencer_email') ordering = ['-updated_at'] def __str__(self): return f"{self.user.username}: {self.user_email} ➔ {self.influencer_email}" def can_reply(self): """检查是否可以继续自动回复""" return self.is_enabled and self.current_replies < self.max_replies def increment_reply_count(self): """增加回复计数并更新时间""" self.current_replies += 1 self.last_reply_time = timezone.now() self.save(update_fields=['current_replies', 'last_reply_time', 'updated_at'])