celery实现ai回复

This commit is contained in:
wanjia 2025-05-20 18:01:02 +08:00
parent 22e8a672ed
commit 82e418b684
13 changed files with 497 additions and 172 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2025-05-20 09:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('chat', '0002_alter_chathistory_content'),
]
operations = [
migrations.AlterField(
model_name='chathistory',
name='content',
field=models.TextField(),
),
]

View File

@ -0,0 +1,53 @@
# Generated by Django 5.2 on 2025-05-20 09:21
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gmail', '0009_gmailconversation_has_sent_greeting_and_more'),
]
operations = [
migrations.CreateModel(
name='ProcessedPushNotification',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('message_id', models.CharField(help_text='Pub/Sub消息ID', max_length=255, unique=True)),
('email_address', models.EmailField(help_text='通知关联的Gmail邮箱', max_length=254)),
('history_id', models.CharField(help_text='Gmail历史ID', max_length=100)),
('processed_at', models.DateTimeField(auto_now_add=True, help_text='处理时间')),
('is_successful', models.BooleanField(default=True, help_text='处理是否成功')),
('metadata', models.JSONField(blank=True, default=dict, help_text='额外信息')),
],
options={
'verbose_name': '已处理推送通知',
'verbose_name_plural': '已处理推送通知',
'db_table': 'gmail_processed_push_notifications',
'ordering': ['-processed_at'],
'indexes': [models.Index(fields=['message_id'], name='gmail_proce_message_912a0c_idx'), models.Index(fields=['email_address', 'history_id'], name='gmail_proce_email_a_2e3770_idx')],
},
),
migrations.CreateModel(
name='UnmatchedEmail',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('message_id', models.CharField(help_text='Gmail邮件ID', max_length=255, unique=True)),
('user_id', models.IntegerField(help_text='用户ID')),
('user_email', models.EmailField(help_text='用户Gmail邮箱', max_length=254)),
('from_email', models.EmailField(help_text='发件人邮箱', max_length=254)),
('to_email', models.EmailField(help_text='收件人邮箱', max_length=254)),
('subject', models.CharField(blank=True, help_text='邮件主题', max_length=500)),
('processed_at', models.DateTimeField(auto_now_add=True, help_text='处理时间')),
],
options={
'verbose_name': '未匹配邮件',
'verbose_name_plural': '未匹配邮件',
'db_table': 'gmail_unmatched_emails',
'ordering': ['-processed_at'],
'indexes': [models.Index(fields=['message_id'], name='gmail_unmat_message_c1924d_idx'), models.Index(fields=['user_id'], name='gmail_unmat_user_id_ee06fe_idx'), models.Index(fields=['user_email', 'from_email'], name='gmail_unmat_user_em_a096af_idx')],
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2025-05-20 09:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gmail', '0010_processedpushnotification_unmatchedemail'),
]
operations = [
migrations.AlterField(
model_name='unmatchedemail',
name='user_id',
field=models.CharField(help_text='用户ID (UUID字符串形式)', max_length=36),
),
]

View File

@ -183,3 +183,55 @@ class AutoReplyConfig(models.Model):
self.current_replies += 1 self.current_replies += 1
self.last_reply_time = timezone.now() self.last_reply_time = timezone.now()
self.save(update_fields=['current_replies', 'last_reply_time', 'updated_at']) self.save(update_fields=['current_replies', 'last_reply_time', 'updated_at'])
class ProcessedPushNotification(models.Model):
"""
已处理的推送通知记录用于去重防止重复处理同一个通知
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
message_id = models.CharField(max_length=255, unique=True, help_text="Pub/Sub消息ID")
email_address = models.EmailField(help_text="通知关联的Gmail邮箱")
history_id = models.CharField(max_length=100, help_text="Gmail历史ID")
processed_at = models.DateTimeField(auto_now_add=True, help_text="处理时间")
is_successful = models.BooleanField(default=True, help_text="处理是否成功")
metadata = models.JSONField(default=dict, blank=True, help_text="额外信息")
class Meta:
db_table = 'gmail_processed_push_notifications'
verbose_name = '已处理推送通知'
verbose_name_plural = '已处理推送通知'
ordering = ['-processed_at']
indexes = [
models.Index(fields=['message_id']),
models.Index(fields=['email_address', 'history_id']),
]
def __str__(self):
return f"{self.email_address} - {self.history_id} ({self.message_id})"
class UnmatchedEmail(models.Model):
"""
记录未匹配到对话的邮件避免重复处理
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
message_id = models.CharField(max_length=255, unique=True, help_text="Gmail邮件ID")
user_id = models.CharField(max_length=36, help_text="用户ID (UUID字符串形式)")
user_email = models.EmailField(help_text="用户Gmail邮箱")
from_email = models.EmailField(help_text="发件人邮箱")
to_email = models.EmailField(help_text="收件人邮箱")
subject = models.CharField(max_length=500, blank=True, help_text="邮件主题")
processed_at = models.DateTimeField(auto_now_add=True, help_text="处理时间")
class Meta:
db_table = 'gmail_unmatched_emails'
verbose_name = '未匹配邮件'
verbose_name_plural = '未匹配邮件'
ordering = ['-processed_at']
indexes = [
models.Index(fields=['message_id']),
models.Index(fields=['user_id']),
models.Index(fields=['user_email', 'from_email']),
]
def __str__(self):
return f"{self.user_email} - {self.from_email} - {self.subject}"

View File

@ -780,6 +780,23 @@ class GmailService:
return True return True
else: else:
logger.info(f"未找到匹配的对话: 用户邮箱={to_email}, 达人邮箱={from_email}") logger.info(f"未找到匹配的对话: 用户邮箱={to_email}, 达人邮箱={from_email}")
# 记录未匹配的邮件,避免重复处理
from apps.gmail.models import UnmatchedEmail
# 检查是否已经记录过
existing = UnmatchedEmail.objects.filter(message_id=msg_id).exists()
if not existing:
# 创建未匹配邮件记录
UnmatchedEmail.objects.create(
message_id=msg_id,
user_id=str(user.id), # 将UUID转换为字符串
user_email=to_email,
from_email=from_email,
to_email=to_email,
subject=subject[:500] # 截取前500个字符避免超出字段长度
)
logger.info(f"已记录未匹配的邮件: {msg_id}")
else: else:
logger.info(f"邮件不是发送给用户的: 发件人={from_email}, 收件人={to_email}, 用户邮箱={user_email}") logger.info(f"邮件不是发送给用户的: 发件人={from_email}, 收件人={to_email}, 用户邮箱={user_email}")

257
apps/gmail/tasks.py Normal file
View File

@ -0,0 +1,257 @@
import logging
import json
import base64
from celery import shared_task
from django.utils import timezone
from .models import GmailCredential, GmailConversation, UserGoal, ProcessedPushNotification, UnmatchedEmail
from .services.gmail_service import GmailService
from .services.goal_service import get_conversation_summary, get_last_message, generate_recommended_reply
from apps.chat.models import ChatHistory
logger = logging.getLogger(__name__)
@shared_task(
bind=True,
max_retries=3,
default_retry_delay=60, # 重试延迟60秒
acks_late=True, # 任务完成后再确认
time_limit=600, # 任务超时限制600秒
soft_time_limit=300 # 软超时限制300秒
)
def process_push_notification(self, message_data, message_id, subscription):
"""
处理Gmail推送通知的Celery任务
Args:
message_data: Base64编码的消息数据
message_id: 消息ID
subscription: 订阅信息
Returns:
bool: 处理是否成功
"""
try:
logger.info(f"开始处理推送通知: {message_id}")
print(f"[Gmail Webhook Task] 处理推送通知: {message_id}")
# 检查是否已处理过该消息
if ProcessedPushNotification.objects.filter(message_id=message_id).exists():
logger.info(f"通知 {message_id} 已处理过,跳过")
print(f"[Gmail Webhook Task] 通知 {message_id} 已处理过,跳过")
return True
# Base64解码消息数据
try:
decoded_data = json.loads(base64.b64decode(message_data).decode('utf-8'))
print(f"[Gmail Webhook Task] 解码后的数据: {decoded_data}")
# 获取Gmail通知关键信息
email_address = decoded_data.get('emailAddress')
history_id = decoded_data.get('historyId')
if not email_address:
logger.error("[Gmail Webhook Task] 错误: 推送数据缺少邮箱地址")
# 记录失败的处理,防止重复处理
ProcessedPushNotification.objects.create(
message_id=message_id,
email_address="unknown",
history_id=history_id or "unknown",
is_successful=False,
metadata=decoded_data
)
return False
# 创建处理记录
notification_record = ProcessedPushNotification.objects.create(
message_id=message_id,
email_address=email_address,
history_id=history_id or "unknown",
metadata=decoded_data
)
# 查找对应的Gmail凭证
credential = GmailCredential.objects.filter(email=email_address, is_valid=True).first()
if not credential:
logger.warning(f"[Gmail Webhook Task] 警告: 未找到对应的Gmail凭证: {email_address}")
notification_record.is_successful = False
notification_record.save()
return False
user = credential.user
logger.info(f"[Gmail Webhook Task] 找到有效凭证: 用户ID {user.id}, 邮箱 {email_address}")
# 处理新邮件
processed_emails = GmailService.process_new_emails(user, credential, history_id)
logger.info(f"[Gmail Webhook Task] 新邮件处理完成,共 {len(processed_emails)}")
# 处理自动回复
if processed_emails:
process_auto_replies.delay(user.id, credential.id, processed_emails)
# 更新凭证的历史ID
if history_id:
credential.last_history_id = history_id
credential.save()
logger.info(f"[Gmail Webhook Task] 已更新凭证历史ID: {history_id}")
# 更新通知记录
notification_record.is_successful = True
notification_record.save()
return True
except Exception as e:
logger.error(f"[Gmail Webhook Task] 解析推送数据失败: {str(e)}")
# 记录失败的处理
ProcessedPushNotification.objects.create(
message_id=message_id,
email_address="error",
history_id="error",
is_successful=False,
metadata={"error": str(e)}
)
# 抛出异常以便Celery可能进行重试
raise self.retry(exc=e, countdown=30)
except Exception as e:
logger.error(f"[Gmail Webhook Task] 处理推送通知失败: {str(e)}")
import traceback
logger.error(traceback.format_exc())
# 尝试重试任务
raise self.retry(exc=e, countdown=60)
@shared_task(
bind=True,
max_retries=2,
default_retry_delay=60,
time_limit=300,
soft_time_limit=240
)
def process_auto_replies(self, user_id, credential_id, email_ids):
"""
处理自动回复的任务
Args:
user_id: 用户ID
credential_id: Gmail凭证ID
email_ids: 需要处理的邮件ID列表
Returns:
bool: 处理是否成功
"""
try:
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.get(id=user_id)
credential = GmailCredential.objects.get(id=credential_id)
logger.info(f"[Auto Reply Task] 开始处理{len(email_ids)}封邮件的自动回复")
# 遍历每个处理过的邮件ID
for email_id in email_ids:
try:
# 通过邮件ID查找对应的聊天记录
chat_msg = ChatHistory.objects.filter(
metadata__gmail_message_id=email_id
).order_by('-created_at').first()
if not chat_msg:
logger.info(f"[Auto Reply Task] 邮件 {email_id} 未找到对应的聊天记录,跳过自动回复")
continue
conversation_id = chat_msg.conversation_id
# 检查对话是否是活跃的
conversation = GmailConversation.objects.filter(
conversation_id=conversation_id,
is_active=True
).first()
if not conversation:
logger.info(f"[Auto Reply Task] 对话 {conversation_id} 不是活跃的,跳过自动回复")
continue
logger.info(f"[Auto Reply Task] 发现活跃对话 {conversation_id},准备自动回复")
# 检查邮件角色,只有达人发送的邮件才自动回复
if chat_msg.role != 'assistant':
logger.info(f"[Auto Reply Task] 邮件 {email_id} 不是达人发送的,跳过自动回复")
continue
# 查找对话的目标
goal = UserGoal.objects.filter(
conversation=conversation,
is_active=True
).first()
if not goal:
logger.info(f"[Auto Reply Task] 对话 {conversation_id} 没有活跃目标,跳过自动回复")
continue
# 获取对话摘要
conversation_summary = get_conversation_summary(conversation_id)
if not conversation_summary:
conversation_summary = "无对话摘要"
# 获取最后一条达人消息
last_message = get_last_message(conversation_id)
if not last_message:
logger.info(f"[Auto Reply Task] 对话 {conversation_id} 没有达人消息,跳过自动回复")
continue
# 生成推荐回复
reply_content, error = generate_recommended_reply(
user=user,
goal_description=goal.description,
conversation_summary=conversation_summary,
last_message=last_message
)
if error:
logger.error(f"[Auto Reply Task] 生成推荐回复失败: {error}")
continue
if not reply_content:
logger.warning(f"[Auto Reply Task] 生成的推荐回复为空")
continue
# 构建回复的主题
subject = chat_msg.metadata.get('subject', '')
reply_subject = f"回复: {subject}" if not subject.startswith('回复:') else subject
# 准备发送自动回复
logger.info(f"[Auto Reply Task] 准备发送自动回复: 从{conversation.user_email}{conversation.influencer_email}")
success, reply_message_id = GmailService.send_email(
user=user,
user_email=conversation.user_email,
to_email=conversation.influencer_email,
subject=reply_subject,
body=reply_content
)
if success:
logger.info(f"[Auto Reply Task] 已成功发送自动回复: {reply_message_id}")
# 更新目标状态
goal.last_activity_time = timezone.now()
if goal.status == 'pending':
goal.status = 'in_progress'
goal.save(update_fields=['last_activity_time', 'status', 'updated_at'])
else:
logger.error(f"[Auto Reply Task] 发送自动回复失败: {reply_message_id}")
except Exception as reply_error:
logger.error(f"[Auto Reply Task] 处理自动回复过程中出错: {str(reply_error)}")
import traceback
logger.error(traceback.format_exc())
return True
except Exception as e:
logger.error(f"[Auto Reply Task] 处理自动回复失败: {str(e)}")
import traceback
logger.error(traceback.format_exc())
raise self.retry(exc=e, countdown=30)

View File

@ -932,7 +932,7 @@ class GmailWebhookView(APIView):
def post(self, request): def post(self, request):
""" """
处理POST请求接收Gmail Pub/Sub推送通知 处理POST请求接收Gmail Pub/Sub推送通知
从中获取邮箱地址和历史ID然后保存最新邮件到数据库 将推送通知交给Celery任务队列异步处理
Args: Args:
request: Django REST Framework请求对象包含Pub/Sub消息 request: Django REST Framework请求对象包含Pub/Sub消息
@ -948,8 +948,6 @@ class GmailWebhookView(APIView):
# 打印请求时间和基本信息 # 打印请求时间和基本信息
current_time = timezone.now() current_time = timezone.now()
print(f"接收时间: {current_time.strftime('%Y-%m-%d %H:%M:%S.%f')}") print(f"接收时间: {current_time.strftime('%Y-%m-%d %H:%M:%S.%f')}")
print(f"请求头: {dict(request.headers)}")
print(f"原始数据: {request.data}")
# 解析推送消息 # 解析推送消息
message = request.data.get('message', {}) message = request.data.get('message', {})
@ -968,180 +966,27 @@ class GmailWebhookView(APIView):
'data': None 'data': None
}, status=status.HTTP_400_BAD_REQUEST) }, status=status.HTTP_400_BAD_REQUEST)
# Base64解码消息数据 # 检查该消息是否已处理过
try: from .models import ProcessedPushNotification
decoded_data = json.loads(base64.b64decode(data).decode('utf-8')) if ProcessedPushNotification.objects.filter(message_id=message_id).exists():
print(f"[Gmail Webhook] 解码后的数据: {decoded_data}") print(f"[Gmail Webhook] 通知 {message_id} 已处理过,跳过")
# 获取Gmail通知关键信息
email_address = decoded_data.get('emailAddress')
history_id = decoded_data.get('historyId')
print(f"邮箱地址: {email_address}")
print(f"历史ID: {history_id}")
if not email_address:
print("[Gmail Webhook] 错误: 推送数据缺少邮箱地址")
return Response({
'code': 400,
'message': '推送数据缺少邮箱地址',
'data': None
}, status=status.HTTP_400_BAD_REQUEST)
# 查找对应的Gmail凭证
credential = GmailCredential.objects.filter(email=email_address, is_valid=True).first()
if credential:
user = credential.user
print(f"[Gmail Webhook] 找到有效凭证: 用户ID {user.id}, 邮箱 {email_address}")
# 获取并保存最新邮件
print("[Gmail Webhook] 开始获取最新邮件...")
try:
# 使用GmailService的静态方法处理新邮件
processed_emails = GmailService.process_new_emails(user, credential, history_id)
print(f"[Gmail Webhook] 新邮件处理完成,共 {len(processed_emails)}")
# 处理活跃对话的自动回复
if processed_emails:
print(f"[Gmail Webhook] 开始处理自动回复...")
# 获取刚处理的邮件的对应的对话信息
from apps.gmail.models import GmailConversation, UserGoal
from apps.chat.models import ChatHistory
# 遍历每个处理过的邮件ID
for email_id in processed_emails:
try:
# 通过邮件ID查找对应的聊天记录
chat_msg = ChatHistory.objects.filter(
metadata__gmail_message_id=email_id
).order_by('-created_at').first()
if not chat_msg:
print(f"[Gmail Webhook] 邮件 {email_id} 未找到对应的聊天记录,跳过自动回复")
continue
conversation_id = chat_msg.conversation_id
# 检查对话是否是活跃的
conversation = GmailConversation.objects.filter(
conversation_id=conversation_id,
is_active=True
).first()
if not conversation:
print(f"[Gmail Webhook] 对话 {conversation_id} 不是活跃的,跳过自动回复")
continue
print(f"[Gmail Webhook] 发现活跃对话 {conversation_id},准备自动回复")
# 检查邮件角色,只有达人发送的邮件才自动回复
if chat_msg.role != 'assistant':
print(f"[Gmail Webhook] 邮件 {email_id} 不是达人发送的,跳过自动回复")
continue
# 查找对话的目标
goal = UserGoal.objects.filter(
conversation=conversation,
is_active=True
).first()
if not goal:
print(f"[Gmail Webhook] 对话 {conversation_id} 没有活跃目标,跳过自动回复")
continue
# 获取对话摘要
from apps.gmail.services.goal_service import get_conversation_summary, get_last_message, generate_recommended_reply
conversation_summary = get_conversation_summary(conversation_id)
if not conversation_summary:
conversation_summary = "无对话摘要"
# 获取最后一条达人消息
last_message = get_last_message(conversation_id)
if not last_message:
print(f"[Gmail Webhook] 对话 {conversation_id} 没有达人消息,跳过自动回复")
continue
# 生成推荐回复
reply_content, error = generate_recommended_reply(
user=user,
goal_description=goal.description,
conversation_summary=conversation_summary,
last_message=last_message
)
if error:
print(f"[Gmail Webhook] 生成推荐回复失败: {error}")
continue
if not reply_content:
print(f"[Gmail Webhook] 生成的推荐回复为空")
continue
# 构建回复的主题
subject = chat_msg.metadata.get('subject', '')
reply_subject = f"回复: {subject}" if not subject.startswith('回复:') else subject
# 准备发送自动回复
print(f"[Gmail Webhook] 准备发送自动回复: 从{conversation.user_email}{conversation.influencer_email}")
success, reply_message_id = GmailService.send_email(
user=user,
user_email=conversation.user_email,
to_email=conversation.influencer_email,
subject=reply_subject,
body=reply_content
)
if success:
print(f"[Gmail Webhook] 已成功发送自动回复: {reply_message_id}")
# 更新目标状态
goal.last_activity_time = timezone.now()
if goal.status == 'pending':
goal.status = 'in_progress'
goal.save(update_fields=['last_activity_time', 'status', 'updated_at'])
else:
print(f"[Gmail Webhook] 发送自动回复失败: {reply_message_id}")
except Exception as reply_error:
print(f"[Gmail Webhook] 处理自动回复过程中出错: {str(reply_error)}")
import traceback
print(traceback.format_exc())
# 更新凭证的历史ID移到处理完成后再更新
if history_id:
credential.last_history_id = history_id
credential.save()
print(f"[Gmail Webhook] 已更新凭证历史ID: {history_id}")
except Exception as e:
print(f"[Gmail Webhook] 获取最新邮件失败: {str(e)}")
logger.error(f"获取最新邮件失败: {str(e)}")
import traceback
print(traceback.format_exc())
else:
print(f"[Gmail Webhook] 警告: 未找到对应的Gmail凭证: {email_address}")
logger.warning(f"收到推送通知但未找到对应的Gmail凭证: {email_address}")
except Exception as e:
print(f"[Gmail Webhook] 解析推送数据失败: {str(e)}")
logger.error(f"解析推送数据失败: {str(e)}")
return Response({ return Response({
'code': 400, 'code': 200,
'message': f'解析推送数据失败: {str(e)}', 'message': '通知已处理过,跳过',
'data': None 'data': None
}, status=status.HTTP_400_BAD_REQUEST) })
print("[Gmail Webhook] 推送处理完成") # 将消息提交到Celery任务队列进行异步处理
from .tasks import process_push_notification
process_push_notification.delay(data, message_id, subscription)
print("[Gmail Webhook] 已将推送通知提交到任务队列处理")
print("="*100 + "\n") print("="*100 + "\n")
# 返回成功响应 # 返回成功响应
return Response({ return Response({
'code': 200, 'code': 200,
'message': '推送通知处理成功', 'message': '推送通知已接收并提交到任务队列',
'data': None 'data': None
}) })

View File

@ -0,0 +1,17 @@
# Generated by Django 5.2 on 2025-05-20 09:21
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('template', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='template',
name='created_by',
),
]

View File

@ -0,0 +1,7 @@
# 配置Django启动时加载Celery
from __future__ import absolute_import, unicode_literals
# 确保celery app在Django启动时被加载
from .celery import app as celery_app
__all__ = ('celery_app',)

19
daren_project/celery.py Normal file
View File

@ -0,0 +1,19 @@
import os
from celery import Celery
from django.conf import settings
# 设置Django默认settings模块
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'daren_project.settings')
# 创建Celery应用
app = Celery('daren_project')
# 使用Django settings的CELERY_配置值
app.config_from_object('django.conf:settings', namespace='CELERY')
# 自动发现并注册tasks模块中的任务
app.autodiscover_tasks()
@app.task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self.request!r}')

View File

@ -56,6 +56,8 @@ INSTALLED_APPS = [
'apps.operation', 'apps.operation',
'apps.discovery', # 新添加的Discovery应用 'apps.discovery', # 新添加的Discovery应用
'apps.template', # 新添加的Template应用 'apps.template', # 新添加的Template应用
'django_celery_beat', # Celery定时任务
'django_celery_results', # Celery结果存储
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -140,6 +142,7 @@ USE_TZ = True
# 静态文件和模板 # 静态文件和模板
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static'] STATICFILES_DIRS = [BASE_DIR / 'static']
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
@ -192,13 +195,31 @@ PROXY_URL = 'http://127.0.0.1:7890'
# Gmail Pub/Sub相关设置 # Gmail Pub/Sub相关设置
GOOGLE_CLOUD_PROJECT_ID = 'knowledge-454905' # 替换为您的Google Cloud项目ID GOOGLE_CLOUD_PROJECT_ID = 'knowledge-454905'
# 主题名称 # 主题名称
GMAIL_PUBSUB_TOPIC = 'gmail-watch-topic' GMAIL_PUBSUB_TOPIC = 'gmail-watch-topic'
# 设置允许使用Google Pub/Sub的应用列表 # 设置允许使用Google Pub/Sub的应用列表
INSTALLED_APPS += ['google.cloud.pubsub'] INSTALLED_APPS += ['google.cloud.pubsub']
# Celery配置
CELERY_BROKER_URL = 'redis://localhost:6379/0' # 使用Redis作为消息代理
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # 使用Redis存储任务结果
CELERY_ACCEPT_CONTENT = ['json'] # 指定接受的内容类型
CELERY_TASK_SERIALIZER = 'json' # 任务序列化和反序列化使用JSON
CELERY_RESULT_SERIALIZER = 'json' # 结果序列化使用JSON
CELERY_TIMEZONE = 'Asia/Shanghai' # 使用上海时区
CELERY_TASK_TRACK_STARTED = True # 追踪任务的开始状态
CELERY_TASK_TIME_LIMIT = 300 # 任务的hard time limit
CELERY_TASK_SOFT_TIME_LIMIT = 240 # 任务的soft time limit
CELERY_WORKER_MAX_TASKS_PER_CHILD = 500 # 工作进程处理多少个任务后重启
# Windows平台Celery特定设置
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True # 启动时尝试重新连接
CELERY_WORKER_CONCURRENCY = 1 # Windows下使用单进程模式避免权限错误
CELERY_TASK_ALWAYS_EAGER = False # 不要在Django主进程中执行任务
CELERY_BROKER_HEARTBEAT = 0 # 禁用心跳检测解决Windows的问题
FEISHU_APP_ID = "cli_a5c97daacb9e500d" FEISHU_APP_ID = "cli_a5c97daacb9e500d"
FEISHU_APP_SECRET = "fdVeOCLXmuIHZVmSV0VbJh9wd0Kq1o5y" FEISHU_APP_SECRET = "fdVeOCLXmuIHZVmSV0VbJh9wd0Kq1o5y"
FEISHU_DEFAULT_APP_TOKEN = "XYE6bMQUOaZ5y5svj4vcWohGnmg" FEISHU_DEFAULT_APP_TOKEN = "XYE6bMQUOaZ5y5svj4vcWohGnmg"

1
query Normal file
View File

@ -0,0 +1 @@
redis

Binary file not shown.