1189 lines
43 KiB
Python
1189 lines
43 KiB
Python
![]() |
import os
|
|||
|
import sys
|
|||
|
import json
|
|||
|
import logging
|
|||
|
import traceback
|
|||
|
import requests
|
|||
|
from datetime import datetime
|
|||
|
import django
|
|||
|
from django.db import transaction
|
|||
|
from django.contrib.auth import get_user_model
|
|||
|
import time
|
|||
|
|
|||
|
# 设置Django环境
|
|||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'role_based_system.settings')
|
|||
|
django.setup()
|
|||
|
|
|||
|
import lark_oapi as lark
|
|||
|
from lark_oapi.api.bitable.v1 import *
|
|||
|
from user_management.models import (
|
|||
|
FeishuCreator, KnowledgeBase, UserGoal,
|
|||
|
GmailTalentMapping, ChatHistory, ConversationSummary
|
|||
|
)
|
|||
|
from django.conf import settings
|
|||
|
from user_management.gmail_integration import GmailIntegration
|
|||
|
from feishu.feishu import sync_to_knowledge_base
|
|||
|
|
|||
|
logger = logging.getLogger(__name__)
|
|||
|
|
|||
|
def get_tenant_access_token(app_id, app_secret):
|
|||
|
"""
|
|||
|
获取飞书应用的tenant_access_token
|
|||
|
"""
|
|||
|
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
|||
|
headers = {
|
|||
|
"Content-Type": "application/json"
|
|||
|
}
|
|||
|
data = {
|
|||
|
"app_id": app_id,
|
|||
|
"app_secret": app_secret
|
|||
|
}
|
|||
|
|
|||
|
try:
|
|||
|
response = requests.post(url, json=data, headers=headers)
|
|||
|
response_json = response.json()
|
|||
|
|
|||
|
if response.status_code == 200 and response_json.get("code") == 0:
|
|||
|
return {
|
|||
|
"status": "success",
|
|||
|
"access_token": response_json.get("tenant_access_token"),
|
|||
|
"expire": response_json.get("expire")
|
|||
|
}
|
|||
|
else:
|
|||
|
logging.error(f"获取tenant_access_token失败: {response_json}")
|
|||
|
return {
|
|||
|
"status": "error",
|
|||
|
"message": response_json.get("msg", "未知错误")
|
|||
|
}
|
|||
|
except Exception as e:
|
|||
|
logging.error(f"获取tenant_access_token异常: {str(e)}")
|
|||
|
return {
|
|||
|
"status": "error",
|
|||
|
"message": str(e)
|
|||
|
}
|
|||
|
|
|||
|
def fetch_table_records(app_token, table_id, view_id, access_token=None, app_id=None, app_secret=None):
|
|||
|
"""
|
|||
|
从飞书多维表格获取记录
|
|||
|
|
|||
|
参数:
|
|||
|
app_token: 应用ID
|
|||
|
table_id: 表格ID
|
|||
|
view_id: 视图ID
|
|||
|
access_token: 访问令牌(可选,如果提供则直接使用)
|
|||
|
app_id: 应用ID(可选,用于自动获取token)
|
|||
|
app_secret: 应用密钥(可选,用于自动获取token)
|
|||
|
"""
|
|||
|
# 如果没有提供access_token但提供了app_id和app_secret,则自动获取
|
|||
|
if not access_token and app_id and app_secret:
|
|||
|
token_result = get_tenant_access_token(app_id, app_secret)
|
|||
|
if token_result["status"] == "success":
|
|||
|
access_token = token_result["access_token"]
|
|||
|
else:
|
|||
|
logging.error(f"无法获取访问令牌: {token_result['message']}")
|
|||
|
return []
|
|||
|
|
|||
|
total_records = []
|
|||
|
page_token = None
|
|||
|
page_size = 20
|
|||
|
|
|||
|
try:
|
|||
|
# 初始化客户端
|
|||
|
client = lark.Client.builder() \
|
|||
|
.enable_set_token(True) \
|
|||
|
.log_level(lark.LogLevel.DEBUG) \
|
|||
|
.build()
|
|||
|
|
|||
|
logger.info(f"开始从飞书表格获取数据: app_token={app_token}, table_id={table_id}, view_id={view_id}")
|
|||
|
|
|||
|
# 尝试两种方法获取记录
|
|||
|
# 方法1: 使用list接口
|
|||
|
list_success = False
|
|||
|
try:
|
|||
|
while True:
|
|||
|
try:
|
|||
|
# 构造请求对象
|
|||
|
builder = ListAppTableRecordRequest.builder() \
|
|||
|
.app_token(app_token) \
|
|||
|
.table_id(table_id) \
|
|||
|
.page_size(page_size) \
|
|||
|
.view_id(view_id)
|
|||
|
|
|||
|
# 如果有page_token,添加到请求中
|
|||
|
if page_token:
|
|||
|
builder = builder.page_token(page_token)
|
|||
|
|
|||
|
# 构建完整请求
|
|||
|
request = builder.build()
|
|||
|
|
|||
|
logger.debug(f"发送list请求,page_token: {page_token}")
|
|||
|
|
|||
|
# 发起请求
|
|||
|
option = lark.RequestOption.builder().user_access_token(access_token).build()
|
|||
|
response = client.bitable.v1.app_table_record.list(request, option)
|
|||
|
|
|||
|
if not response.success():
|
|||
|
logger.error(f"list请求失败: {response.code}, {response.msg}")
|
|||
|
break
|
|||
|
|
|||
|
# 获取当前页记录
|
|||
|
current_records = response.data.items
|
|||
|
if not current_records:
|
|||
|
logger.info("没有更多记录")
|
|||
|
break
|
|||
|
|
|||
|
total_records.extend(current_records)
|
|||
|
list_success = True
|
|||
|
|
|||
|
# 解析响应数据获取分页信息
|
|||
|
response_data = json.loads(response.raw.content)
|
|||
|
has_more = response_data["data"].get("has_more", False)
|
|||
|
total = response_data["data"].get("total", 0)
|
|||
|
logger.info(f"list方法获取到 {len(current_records)} 条记录,当前总计: {len(total_records)}/{total} 条")
|
|||
|
|
|||
|
# 获取下一页token
|
|||
|
page_token = response_data["data"].get("page_token")
|
|||
|
if not page_token or not has_more:
|
|||
|
logger.info("list方法已获取所有数据")
|
|||
|
break
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"list方法获取记录时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
list_success = False
|
|||
|
break
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"list方法整体出错: {str(e)}")
|
|||
|
list_success = False
|
|||
|
|
|||
|
# 如果list方法失败,尝试search方法
|
|||
|
if not list_success or not total_records:
|
|||
|
logger.info("尝试使用search方法获取数据...")
|
|||
|
page_token = None
|
|||
|
total_records = []
|
|||
|
|
|||
|
while True:
|
|||
|
try:
|
|||
|
# 构造search请求对象
|
|||
|
request = SearchAppTableRecordRequest.builder() \
|
|||
|
.app_token(app_token) \
|
|||
|
.table_id(table_id) \
|
|||
|
.page_size(page_size)
|
|||
|
|
|||
|
# 如果有page_token,添加到请求中
|
|||
|
if page_token:
|
|||
|
request = request.page_token(page_token)
|
|||
|
|
|||
|
# 添加请求体 - 可以根据需要添加过滤条件
|
|||
|
request = request.request_body(
|
|||
|
SearchAppTableRecordRequestBody.builder().build()
|
|||
|
).build()
|
|||
|
|
|||
|
logger.debug(f"发送search请求,page_token: {page_token}")
|
|||
|
|
|||
|
# 发起请求
|
|||
|
option = lark.RequestOption.builder().user_access_token(access_token).build()
|
|||
|
response = client.bitable.v1.app_table_record.search(request, option)
|
|||
|
|
|||
|
if not response.success():
|
|||
|
logger.error(f"search请求失败: {response.code}, {response.msg}")
|
|||
|
break
|
|||
|
|
|||
|
# 获取当前页记录
|
|||
|
current_records = response.data.items
|
|||
|
if not current_records:
|
|||
|
logger.info("search方法没有更多记录")
|
|||
|
break
|
|||
|
|
|||
|
total_records.extend(current_records)
|
|||
|
|
|||
|
# 解析响应数据获取分页信息
|
|||
|
response_data = json.loads(response.raw.content)
|
|||
|
has_more = response_data["data"].get("has_more", False)
|
|||
|
total = response_data["data"].get("total", 0)
|
|||
|
logger.info(f"search方法获取到 {len(current_records)} 条记录,当前总计: {len(total_records)}/{total} 条")
|
|||
|
|
|||
|
# 获取下一页token
|
|||
|
page_token = response_data["data"].get("page_token")
|
|||
|
if not page_token or not has_more:
|
|||
|
logger.info("search方法已获取所有数据")
|
|||
|
break
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"search方法获取记录时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
break
|
|||
|
|
|||
|
logger.info(f"最终获取到 {len(total_records)} 条记录")
|
|||
|
return total_records
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"获取飞书表格记录时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return []
|
|||
|
|
|||
|
def extract_field_value(field_value):
|
|||
|
"""
|
|||
|
提取字段值
|
|||
|
|
|||
|
参数:
|
|||
|
field_value: 飞书返回的字段值
|
|||
|
|
|||
|
返回:
|
|||
|
任意类型: 提取后的值
|
|||
|
"""
|
|||
|
if isinstance(field_value, list):
|
|||
|
if field_value and isinstance(field_value[0], dict):
|
|||
|
return field_value[0].get('text', '')
|
|||
|
elif isinstance(field_value, dict):
|
|||
|
if 'text' in field_value:
|
|||
|
return field_value['text']
|
|||
|
elif 'link' in field_value:
|
|||
|
return field_value['link']
|
|||
|
elif 'link_record_ids' in field_value:
|
|||
|
return ''
|
|||
|
return field_value
|
|||
|
|
|||
|
def find_duplicate_email_creators(records):
|
|||
|
"""
|
|||
|
查找记录中重复邮箱的创作者
|
|||
|
|
|||
|
参数:
|
|||
|
records: 飞书记录列表
|
|||
|
|
|||
|
返回:
|
|||
|
dict: 以邮箱为键,记录列表为值的字典
|
|||
|
"""
|
|||
|
email_map = {}
|
|||
|
|
|||
|
for record in records:
|
|||
|
fields = record.fields
|
|||
|
email = extract_field_value(fields.get('邮箱', ''))
|
|||
|
|
|||
|
if email:
|
|||
|
if email not in email_map:
|
|||
|
email_map[email] = []
|
|||
|
email_map[email].append(record)
|
|||
|
|
|||
|
# 过滤出现次数>1的邮箱
|
|||
|
duplicate_emails = {email: records for email, records in email_map.items() if len(records) > 1}
|
|||
|
|
|||
|
logger.info(f"发现 {len(duplicate_emails)} 个重复邮箱")
|
|||
|
return duplicate_emails
|
|||
|
|
|||
|
def create_or_update_knowledge_base(email, user=None):
|
|||
|
"""
|
|||
|
为创作者创建或更新知识库
|
|||
|
|
|||
|
参数:
|
|||
|
email: 创作者邮箱
|
|||
|
user: 用户对象,默认为None(将选择一个组长)
|
|||
|
|
|||
|
返回:
|
|||
|
tuple: (KnowledgeBase对象, 是否新创建)
|
|||
|
"""
|
|||
|
# 优先使用给定的用户,否则获取一个组长用户
|
|||
|
if not user:
|
|||
|
User = get_user_model()
|
|||
|
user = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not user:
|
|||
|
logger.error("未找到组长用户,无法创建知识库")
|
|||
|
return None, False
|
|||
|
|
|||
|
# 首先查找创作者
|
|||
|
creator = FeishuCreator.objects.filter(email=email).first()
|
|||
|
|
|||
|
if not creator:
|
|||
|
logger.error(f"找不到邮箱为 {email} 的创作者")
|
|||
|
return None, False
|
|||
|
|
|||
|
# 使用sync_to_knowledge_base函数创建知识库
|
|||
|
kb, created = sync_to_knowledge_base(creator_id=creator.id)
|
|||
|
|
|||
|
if kb:
|
|||
|
logger.info(f"邮箱 {email} 的知识库{'已创建' if created else '已存在'}: {kb.id}")
|
|||
|
else:
|
|||
|
logger.error(f"为邮箱 {email} 创建知识库失败")
|
|||
|
|
|||
|
return kb, created
|
|||
|
|
|||
|
def set_user_goal(user, email, goal_content):
|
|||
|
"""
|
|||
|
设置用户总目标
|
|||
|
|
|||
|
参数:
|
|||
|
user: 用户对象
|
|||
|
email: 创作者邮箱
|
|||
|
goal_content: 目标内容
|
|||
|
|
|||
|
返回:
|
|||
|
dict: 包含操作结果和目标信息
|
|||
|
"""
|
|||
|
try:
|
|||
|
# 创建Gmail集成实例
|
|||
|
gmail_integration = GmailIntegration(user)
|
|||
|
|
|||
|
# 设置总目标
|
|||
|
result = gmail_integration.manage_user_goal(goal_content)
|
|||
|
|
|||
|
if result['status'] == 'success':
|
|||
|
logger.info(f"为用户 {user.username} 设置总目标成功: {result['action']}")
|
|||
|
return result
|
|||
|
else:
|
|||
|
logger.error(f"为用户 {user.username} 设置总目标失败: {result.get('message', 'Unknown error')}")
|
|||
|
return result
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"设置用户总目标时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': str(e)
|
|||
|
}
|
|||
|
|
|||
|
def create_chat_with_ai(user, talent_email, goal_content):
|
|||
|
"""
|
|||
|
创建与AI的聊天会话
|
|||
|
|
|||
|
参数:
|
|||
|
user: 用户对象
|
|||
|
talent_email: 达人邮箱
|
|||
|
goal_content: 目标内容
|
|||
|
|
|||
|
返回:
|
|||
|
dict: 操作结果
|
|||
|
"""
|
|||
|
try:
|
|||
|
# 1. 获取或创建知识库
|
|||
|
kb, kb_created = create_or_update_knowledge_base(talent_email, user)
|
|||
|
if not kb:
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"为邮箱 {talent_email} 创建知识库失败"
|
|||
|
}
|
|||
|
|
|||
|
# 2. 设置用户总目标
|
|||
|
goal_result = set_user_goal(user, talent_email, goal_content)
|
|||
|
if goal_result['status'] != 'success':
|
|||
|
return goal_result
|
|||
|
|
|||
|
# 3. 检查是否已有对应的Gmail映射关系
|
|||
|
mapping = GmailTalentMapping.objects.filter(
|
|||
|
user=user,
|
|||
|
talent_email=talent_email,
|
|||
|
is_active=True
|
|||
|
).first()
|
|||
|
|
|||
|
if not mapping:
|
|||
|
# 创建映射关系
|
|||
|
mapping = GmailTalentMapping.objects.create(
|
|||
|
user=user,
|
|||
|
talent_email=talent_email,
|
|||
|
knowledge_base=kb,
|
|||
|
conversation_id=f"feishu_ai_{kb.id}",
|
|||
|
is_active=True
|
|||
|
)
|
|||
|
logger.info(f"创建新的Gmail映射: {talent_email} -> {kb.id}")
|
|||
|
elif mapping.knowledge_base_id != kb.id:
|
|||
|
# 更新现有映射关系
|
|||
|
mapping.knowledge_base = kb
|
|||
|
mapping.save()
|
|||
|
logger.info(f"更新Gmail映射: {talent_email} -> {kb.id}")
|
|||
|
|
|||
|
return {
|
|||
|
'status': 'success',
|
|||
|
'action': 'create',
|
|||
|
'knowledge_base': {
|
|||
|
'id': str(kb.id),
|
|||
|
'name': kb.name,
|
|||
|
'created': kb_created
|
|||
|
},
|
|||
|
'goal': goal_result.get('goal'),
|
|||
|
'mapping': {
|
|||
|
'id': str(mapping.id),
|
|||
|
'conversation_id': mapping.conversation_id
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"创建AI聊天时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': str(e)
|
|||
|
}
|
|||
|
|
|||
|
def process_duplicate_emails(duplicate_emails, goal_content=None):
|
|||
|
"""
|
|||
|
处理重复邮箱记录
|
|||
|
|
|||
|
参数:
|
|||
|
duplicate_emails: 重复邮箱记录字典
|
|||
|
goal_content: 目标内容模板,可包含{email}和{handle}占位符
|
|||
|
|
|||
|
返回:
|
|||
|
dict: 处理结果统计
|
|||
|
"""
|
|||
|
if not goal_content:
|
|||
|
goal_content = "与达人{handle}建立联系并了解其账号情况,处理合作需求,最终目标是达成合作并签约。"
|
|||
|
|
|||
|
User = get_user_model()
|
|||
|
leader = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not leader:
|
|||
|
logger.error("未找到组长用户,无法处理重复邮箱")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': "未找到组长用户"
|
|||
|
}
|
|||
|
|
|||
|
results = {
|
|||
|
'total': len(duplicate_emails),
|
|||
|
'success': 0,
|
|||
|
'failure': 0,
|
|||
|
'details': []
|
|||
|
}
|
|||
|
|
|||
|
for email, records in duplicate_emails.items():
|
|||
|
try:
|
|||
|
# 获取一个Handle作为示例
|
|||
|
handle = extract_field_value(records[0].fields.get('Handle', email.split('@')[0]))
|
|||
|
|
|||
|
# 格式化目标内容
|
|||
|
formatted_goal = goal_content.format(email=email, handle=handle)
|
|||
|
|
|||
|
# 创建AI聊天
|
|||
|
result = create_chat_with_ai(leader, email, formatted_goal)
|
|||
|
|
|||
|
if result['status'] == 'success':
|
|||
|
results['success'] += 1
|
|||
|
logger.info(f"成功为邮箱 {email} 创建AI聊天")
|
|||
|
else:
|
|||
|
results['failure'] += 1
|
|||
|
logger.error(f"为邮箱 {email} 创建AI聊天失败: {result.get('message', 'Unknown error')}")
|
|||
|
|
|||
|
results['details'].append({
|
|||
|
'email': email,
|
|||
|
'handle': handle,
|
|||
|
'status': result['status'],
|
|||
|
'message': result.get('message', '')
|
|||
|
})
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
results['failure'] += 1
|
|||
|
logger.error(f"处理邮箱 {email} 时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
results['details'].append({
|
|||
|
'email': email,
|
|||
|
'status': 'error',
|
|||
|
'message': str(e)
|
|||
|
})
|
|||
|
|
|||
|
return results
|
|||
|
|
|||
|
def generate_ai_response(conversation_history, user_goal):
|
|||
|
"""
|
|||
|
调用DeepSeek API生成AI响应
|
|||
|
|
|||
|
参数:
|
|||
|
conversation_history: 对话历史
|
|||
|
user_goal: 用户总目标
|
|||
|
|
|||
|
返回:
|
|||
|
str: AI响应内容
|
|||
|
"""
|
|||
|
try:
|
|||
|
# 使用有效的API密钥
|
|||
|
api_key = "sk-xqbujijjqqmlmlvkhvxeogqjtzslnhdtqxqgiyuhwpoqcjvf"
|
|||
|
# 如果上面的密钥不正确,可以尝试从环境变量或数据库中获取
|
|||
|
# 从Django设置中获取密钥
|
|||
|
if hasattr(settings, 'DEEPSEEK_API_KEY') and settings.DEEPSEEK_API_KEY:
|
|||
|
api_key = settings.DEEPSEEK_API_KEY
|
|||
|
|
|||
|
url = "https://api.siliconflow.cn/v1/chat/completions"
|
|||
|
|
|||
|
# 系统消息指定AI助手的角色和总目标
|
|||
|
system_message = {
|
|||
|
"role": "system",
|
|||
|
"content": f"""你是一位专业的电商客服和达人助手。你的任务是与达人进行对话,帮助实现以下总目标:
|
|||
|
|
|||
|
{user_goal}
|
|||
|
|
|||
|
你应该主动推进对话,引导达人朝着目标方向发展。每次回复应该简洁明了,专业且有帮助。
|
|||
|
如果你认为总目标已经达成,请在回复的最后一行添加标记: [目标已达成]"""
|
|||
|
}
|
|||
|
|
|||
|
messages = [system_message]
|
|||
|
|
|||
|
# 添加对话历史,但限制消息数量避免超出token限制
|
|||
|
# 如果对话历史太长,可能需要进一步处理或分割
|
|||
|
if len(conversation_history) > 20:
|
|||
|
# 选取关键消息:第一条、最后几条以及中间的一些重要消息
|
|||
|
selected_messages = (
|
|||
|
conversation_history[:2] + # 前两条
|
|||
|
conversation_history[len(conversation_history)//2-2:len(conversation_history)//2+2] + # 中间四条
|
|||
|
conversation_history[-12:] # 最后12条
|
|||
|
)
|
|||
|
messages.extend(selected_messages)
|
|||
|
else:
|
|||
|
messages.extend(conversation_history)
|
|||
|
|
|||
|
# 构建API请求
|
|||
|
payload = {
|
|||
|
"model": "deepseek-ai/DeepSeek-V3",
|
|||
|
"messages": messages,
|
|||
|
"stream": False,
|
|||
|
"max_tokens": 1500, # 增加token上限以容纳完整回复
|
|||
|
"temperature": 0.3, # 降低随机性,使回复更加确定性
|
|||
|
"top_p": 0.9,
|
|||
|
"top_k": 50,
|
|||
|
"frequency_penalty": 0.5,
|
|||
|
"presence_penalty": 0.2,
|
|||
|
"n": 1,
|
|||
|
"stop": [],
|
|||
|
"response_format": {
|
|||
|
"type": "text"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
headers = {
|
|||
|
"Content-Type": "application/json",
|
|||
|
"Authorization": f"Bearer {api_key}"
|
|||
|
}
|
|||
|
|
|||
|
logger.info("开始调用DeepSeek API生成对话回复")
|
|||
|
response = requests.post(url, json=payload, headers=headers)
|
|||
|
|
|||
|
if response.status_code != 200:
|
|||
|
logger.error(f"DeepSeek API调用失败: {response.status_code}, {response.text}")
|
|||
|
return None
|
|||
|
|
|||
|
result = response.json()
|
|||
|
logger.debug(f"DeepSeek API返回: {result}")
|
|||
|
|
|||
|
# 提取回复内容
|
|||
|
if 'choices' in result and len(result['choices']) > 0:
|
|||
|
reply = result['choices'][0]['message']['content']
|
|||
|
# 如果返回的内容为空,直接返回None
|
|||
|
if not reply or reply.strip() == '':
|
|||
|
logger.warning("DeepSeek API返回的回复内容为空")
|
|||
|
return None
|
|||
|
return reply
|
|||
|
|
|||
|
logger.warning(f"DeepSeek API返回格式异常: {result}")
|
|||
|
return None
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"调用DeepSeek API生成回复失败: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return None
|
|||
|
|
|||
|
def check_goal_achieved(response):
|
|||
|
"""
|
|||
|
检查目标是否已达成
|
|||
|
|
|||
|
参数:
|
|||
|
response: AI的回复内容
|
|||
|
|
|||
|
返回:
|
|||
|
bool: 是否达成目标
|
|||
|
"""
|
|||
|
if not response:
|
|||
|
return False
|
|||
|
|
|||
|
# 检查回复中是否包含目标达成标记
|
|||
|
goal_markers = [
|
|||
|
"[目标已达成]",
|
|||
|
"【目标已达成】",
|
|||
|
"目标已达成",
|
|||
|
"已达成目标"
|
|||
|
]
|
|||
|
|
|||
|
for marker in goal_markers:
|
|||
|
if marker in response:
|
|||
|
logger.info(f"检测到目标达成标记: {marker}")
|
|||
|
return True
|
|||
|
|
|||
|
return False
|
|||
|
|
|||
|
def auto_chat_session(user, talent_email, max_turns=10):
|
|||
|
"""
|
|||
|
执行自动聊天会话
|
|||
|
|
|||
|
参数:
|
|||
|
user: 用户对象
|
|||
|
talent_email: 达人邮箱
|
|||
|
max_turns: 最大对话轮次,默认10轮
|
|||
|
|
|||
|
返回:
|
|||
|
dict: 会话结果
|
|||
|
"""
|
|||
|
try:
|
|||
|
# 1. 获取用户目标
|
|||
|
gmail_integration = GmailIntegration(user)
|
|||
|
goal_result = gmail_integration.manage_user_goal()
|
|||
|
|
|||
|
if goal_result['status'] != 'success' or not goal_result.get('goal'):
|
|||
|
logger.error(f"获取用户目标失败: {goal_result.get('message', 'No goal found')}")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': "无法获取用户总目标"
|
|||
|
}
|
|||
|
|
|||
|
user_goal = goal_result['goal']['content']
|
|||
|
|
|||
|
# 2. 获取Gmail映射关系
|
|||
|
mapping = GmailTalentMapping.objects.filter(
|
|||
|
user=user,
|
|||
|
talent_email=talent_email,
|
|||
|
is_active=True
|
|||
|
).first()
|
|||
|
|
|||
|
if not mapping:
|
|||
|
logger.error(f"找不到与邮箱 {talent_email} 的映射关系")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"找不到与邮箱 {talent_email} 的映射关系"
|
|||
|
}
|
|||
|
|
|||
|
kb = mapping.knowledge_base
|
|||
|
conversation_id = mapping.conversation_id
|
|||
|
|
|||
|
# 3. 获取现有对话历史
|
|||
|
chat_messages = ChatHistory.objects.filter(
|
|||
|
user=user,
|
|||
|
knowledge_base=kb,
|
|||
|
conversation_id=conversation_id,
|
|||
|
is_deleted=False
|
|||
|
).order_by('created_at')
|
|||
|
|
|||
|
conversation_history = []
|
|||
|
for msg in chat_messages:
|
|||
|
conversation_history.append({
|
|||
|
"role": msg.role,
|
|||
|
"content": msg.content
|
|||
|
})
|
|||
|
|
|||
|
# 如果没有对话历史,添加一条系统消息作为开始
|
|||
|
if not conversation_history:
|
|||
|
# 创建一条初始的系统消息
|
|||
|
system_msg = ChatHistory.objects.create(
|
|||
|
user=user,
|
|||
|
knowledge_base=kb,
|
|||
|
conversation_id=conversation_id,
|
|||
|
role='system',
|
|||
|
content=f"与达人 {talent_email} 的对话开始。总目标: {user_goal}"
|
|||
|
)
|
|||
|
|
|||
|
conversation_history.append({
|
|||
|
"role": "system",
|
|||
|
"content": system_msg.content
|
|||
|
})
|
|||
|
|
|||
|
# 发送第一封邮件来开始对话
|
|||
|
first_subject = "关于合作的洽谈"
|
|||
|
first_content = f"您好,\n\n我是{user.username},我们正在寻找合适的达人合作伙伴,注意到您的账号非常适合我们的产品。\n\n请问您有兴趣了解更多关于我们合作的细节吗?\n\n期待您的回复。\n\n祝好,\n{user.username}"
|
|||
|
|
|||
|
# 记录首次发送消息到对话历史
|
|||
|
initial_msg = ChatHistory.objects.create(
|
|||
|
user=user,
|
|||
|
knowledge_base=kb,
|
|||
|
conversation_id=conversation_id,
|
|||
|
role='assistant',
|
|||
|
content=first_content
|
|||
|
)
|
|||
|
|
|||
|
conversation_history.append({
|
|||
|
"role": "assistant",
|
|||
|
"content": initial_msg.content
|
|||
|
})
|
|||
|
|
|||
|
# 实际发送邮件
|
|||
|
email_result = gmail_integration.send_email(
|
|||
|
to_email=talent_email,
|
|||
|
subject=first_subject,
|
|||
|
body=first_content,
|
|||
|
conversation_id=conversation_id
|
|||
|
)
|
|||
|
|
|||
|
if email_result['status'] != 'success':
|
|||
|
logger.error(f"发送首次邮件失败: {email_result.get('message', 'Unknown error')}")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"发送首次邮件失败: {email_result.get('message', 'Unknown error')}"
|
|||
|
}
|
|||
|
|
|||
|
logger.info(f"已发送首次邮件到 {talent_email}")
|
|||
|
|
|||
|
# 首次邮件发送后,直接返回不进行后续对话,等待达人回复
|
|||
|
return {
|
|||
|
'status': 'success',
|
|||
|
'message': '已发送首次邮件,等待达人回复',
|
|||
|
'turns_completed': 1,
|
|||
|
'goal_achieved': False,
|
|||
|
'email_sent': True,
|
|||
|
'conversation_id': conversation_id
|
|||
|
}
|
|||
|
|
|||
|
# 4. 检查最新消息是否来自达人(user),如果是,才进行回复
|
|||
|
last_message = chat_messages.last()
|
|||
|
if last_message and last_message.role == 'user':
|
|||
|
# 有达人回复,生成AI回复并发送邮件
|
|||
|
# 生成AI回复
|
|||
|
ai_response = generate_ai_response(conversation_history, user_goal)
|
|||
|
|
|||
|
if not ai_response:
|
|||
|
logger.error("生成AI回复失败")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': '生成AI回复失败'
|
|||
|
}
|
|||
|
|
|||
|
# 检查目标是否已达成
|
|||
|
goal_achieved = check_goal_achieved(ai_response)
|
|||
|
|
|||
|
# 保存AI回复到对话历史
|
|||
|
ai_msg = ChatHistory.objects.create(
|
|||
|
user=user,
|
|||
|
knowledge_base=kb,
|
|||
|
conversation_id=conversation_id,
|
|||
|
role='assistant',
|
|||
|
content=ai_response
|
|||
|
)
|
|||
|
|
|||
|
# 使用最近的主题作为回复主题
|
|||
|
subject = "回复: " + (last_message.subject if hasattr(last_message, 'subject') and last_message.subject else "关于合作的洽谈")
|
|||
|
|
|||
|
# 实际发送邮件
|
|||
|
email_result = gmail_integration.send_email(
|
|||
|
to_email=talent_email,
|
|||
|
subject=subject,
|
|||
|
body=ai_response,
|
|||
|
conversation_id=conversation_id
|
|||
|
)
|
|||
|
|
|||
|
if email_result['status'] != 'success':
|
|||
|
logger.error(f"发送邮件回复失败: {email_result.get('message', 'Unknown error')}")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"发送邮件回复失败: {email_result.get('message', 'Unknown error')}"
|
|||
|
}
|
|||
|
|
|||
|
# 如果目标已达成,发送通知
|
|||
|
if goal_achieved:
|
|||
|
send_goal_achieved_notification(user, talent_email, conversation_id)
|
|||
|
# 生成对话总结
|
|||
|
summary_result = gmail_integration.generate_conversation_summary(talent_email)
|
|||
|
summary_status = "success" if summary_result.get('status') == 'success' else "failed"
|
|||
|
else:
|
|||
|
summary_status = "not_needed"
|
|||
|
|
|||
|
return {
|
|||
|
'status': 'success',
|
|||
|
'turns_completed': 1,
|
|||
|
'goal_achieved': goal_achieved,
|
|||
|
'summary_status': summary_status,
|
|||
|
'email_sent': True,
|
|||
|
'conversation_id': conversation_id
|
|||
|
}
|
|||
|
else:
|
|||
|
# 没有新的达人回复,不需要回复
|
|||
|
return {
|
|||
|
'status': 'success',
|
|||
|
'message': '没有新的达人回复,不需要回复',
|
|||
|
'turns_completed': 0,
|
|||
|
'goal_achieved': False,
|
|||
|
'email_sent': False,
|
|||
|
'conversation_id': conversation_id
|
|||
|
}
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"自动聊天会话出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': str(e)
|
|||
|
}
|
|||
|
|
|||
|
def simulate_user_reply(ai_response, turn_count):
|
|||
|
"""
|
|||
|
模拟用户回复
|
|||
|
|
|||
|
参数:
|
|||
|
ai_response: AI的回复内容
|
|||
|
turn_count: 当前对话轮次
|
|||
|
|
|||
|
返回:
|
|||
|
str: 模拟的用户回复
|
|||
|
"""
|
|||
|
# 根据对话轮次和AI回复生成不同的回复模板
|
|||
|
if turn_count == 0:
|
|||
|
return "你好,很高兴认识你。我对你提到的合作很感兴趣,能详细说说你们公司的情况吗?"
|
|||
|
|
|||
|
if "价格" in ai_response or "报价" in ai_response:
|
|||
|
return "价格是我比较关注的,你们能提供什么样的价格方案?我希望能有一个灵活的合作模式。"
|
|||
|
|
|||
|
if "合作模式" in ai_response or "合作方式" in ai_response:
|
|||
|
return "这种合作模式听起来不错。我目前的粉丝群体主要是25-35岁的女性,她们对美妆和生活方式类产品比较感兴趣。你觉得这和你们的产品匹配吗?"
|
|||
|
|
|||
|
if "产品" in ai_response:
|
|||
|
return "产品听起来很不错。我想了解一下发货和售后是如何处理的?这对我的粉丝体验很重要。"
|
|||
|
|
|||
|
if "合同" in ai_response or "协议" in ai_response:
|
|||
|
return "我对合同条款没有太大问题,但希望能保持一定的创作自由度。什么时候可以开始合作?"
|
|||
|
|
|||
|
# 默认回复
|
|||
|
return "这些信息很有帮助,谢谢。我需要再考虑一下,有什么其他你想告诉我的吗?"
|
|||
|
|
|||
|
def send_goal_achieved_notification(user, talent_email, conversation_id):
|
|||
|
"""
|
|||
|
发送目标达成通知
|
|||
|
|
|||
|
参数:
|
|||
|
user: 用户对象
|
|||
|
talent_email: 达人邮箱
|
|||
|
conversation_id: 对话ID
|
|||
|
"""
|
|||
|
try:
|
|||
|
from user_management.models import Notification
|
|||
|
|
|||
|
# 创建通知
|
|||
|
notification = Notification.objects.create(
|
|||
|
type='system_notice',
|
|||
|
title=f"目标已达成 - {talent_email}",
|
|||
|
content=f"与达人 {talent_email} 的自动对话已达成总目标。请查看对话详情并进行后续处理。",
|
|||
|
sender=user, # 这里发送者设为当前用户
|
|||
|
receiver=user, # 通知发给当前用户
|
|||
|
related_resource=conversation_id
|
|||
|
)
|
|||
|
|
|||
|
logger.info(f"已创建目标达成通知: {notification.id}")
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"发送目标达成通知失败: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
|
|||
|
def print_help():
|
|||
|
"""打印帮助信息"""
|
|||
|
print("飞书多维表格自动AI对话工具")
|
|||
|
print("=======================")
|
|||
|
print("\n可用命令:")
|
|||
|
print(" 1. 从飞书读取表格并处理重复邮箱:")
|
|||
|
print(" python feishu_ai_chat.py process_table --app_token 应用TOKEN --table_id 表格ID --view_id 视图ID --access_token 访问令牌")
|
|||
|
print()
|
|||
|
print(" 2. 为指定邮箱执行自动对话:")
|
|||
|
print(" python feishu_ai_chat.py auto_chat --email 达人邮箱 [--turns 对话轮数]")
|
|||
|
print()
|
|||
|
print(" 3. 设置用户总目标:")
|
|||
|
print(" python feishu_ai_chat.py set_goal --email 达人邮箱 --goal \"总目标内容\"")
|
|||
|
print()
|
|||
|
print(" 4. 检查目标完成状态:")
|
|||
|
print(" python feishu_ai_chat.py check_goal --email 达人邮箱")
|
|||
|
print()
|
|||
|
print(" 5. 帮助信息:")
|
|||
|
print(" python feishu_ai_chat.py help")
|
|||
|
print()
|
|||
|
print("示例:")
|
|||
|
print(" python feishu_ai_chat.py process_table --table_id tblcck2za8GZBliz --view_id vewSOIsmxc")
|
|||
|
print(" python feishu_ai_chat.py auto_chat --email example@gmail.com --turns 5")
|
|||
|
print()
|
|||
|
|
|||
|
def handle_process_table(args):
|
|||
|
"""处理飞书表格命令"""
|
|||
|
import argparse
|
|||
|
parser = argparse.ArgumentParser(description='处理飞书表格')
|
|||
|
parser.add_argument('--app_token', default="XYE6bMQUOaZ5y5svj4vcWohGnmg", help='飞书应用TOKEN')
|
|||
|
parser.add_argument('--table_id', required=True, help='表格ID')
|
|||
|
parser.add_argument('--view_id', required=True, help='视图ID')
|
|||
|
parser.add_argument('--access_token', default=None, help='用户访问令牌')
|
|||
|
parser.add_argument('--app_id', default="cli_a5c97daacb9e500d", help='应用ID')
|
|||
|
parser.add_argument('--app_secret', default="fdVeOCLXmuIHZVmSV0VbJh9wd0Kq1o5y", help='应用密钥')
|
|||
|
parser.add_argument('--goal_template', default="与达人{handle}(邮箱:{email})建立联系并了解其账号情况,评估合作潜力,处理合作需求,最终目标是达成合作并签约。", help='目标内容模板')
|
|||
|
parser.add_argument('--auto_chat', action='store_true', help='是否自动执行AI对话')
|
|||
|
parser.add_argument('--turns', type=int, default=5, help='自动对话轮次')
|
|||
|
|
|||
|
params = parser.parse_args(args)
|
|||
|
|
|||
|
# 从飞书表格获取记录
|
|||
|
records = fetch_table_records(
|
|||
|
params.app_token,
|
|||
|
params.table_id,
|
|||
|
params.view_id,
|
|||
|
params.access_token,
|
|||
|
params.app_id,
|
|||
|
params.app_secret
|
|||
|
)
|
|||
|
|
|||
|
if not records:
|
|||
|
logger.error("未获取到任何记录")
|
|||
|
return
|
|||
|
|
|||
|
# 查找重复邮箱的创作者
|
|||
|
duplicate_emails = find_duplicate_email_creators(records)
|
|||
|
|
|||
|
if not duplicate_emails:
|
|||
|
logger.info("未发现重复邮箱")
|
|||
|
return
|
|||
|
|
|||
|
logger.info(f"发现 {len(duplicate_emails)} 个重复邮箱,开始处理...")
|
|||
|
|
|||
|
# 处理重复邮箱记录
|
|||
|
results = process_duplicate_emails(duplicate_emails, params.goal_template)
|
|||
|
|
|||
|
# 打印处理结果
|
|||
|
logger.info(f"处理完成: 总计 {results['total']} 个邮箱,成功 {results['success']} 个,失败 {results['failure']} 个")
|
|||
|
|
|||
|
# 如果需要自动对话
|
|||
|
if params.auto_chat:
|
|||
|
# 获取组长用户
|
|||
|
User = get_user_model()
|
|||
|
leader = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not leader:
|
|||
|
logger.error("未找到组长用户,无法进行自动对话")
|
|||
|
return
|
|||
|
|
|||
|
# 为每个成功创建的记录执行自动对话
|
|||
|
chat_results = []
|
|||
|
for detail in results['details']:
|
|||
|
if detail['status'] == 'success':
|
|||
|
email = detail['email']
|
|||
|
logger.info(f"开始为邮箱 {email} 执行自动对话...")
|
|||
|
|
|||
|
chat_result = auto_chat_session(leader, email, max_turns=params.turns)
|
|||
|
chat_results.append({
|
|||
|
'email': email,
|
|||
|
'result': chat_result
|
|||
|
})
|
|||
|
|
|||
|
logger.info(f"邮箱 {email} 自动对话完成: {chat_result['status']}")
|
|||
|
|
|||
|
# 打印对话结果
|
|||
|
logger.info(f"自动对话完成: 总计 {len(chat_results)} 个对话")
|
|||
|
for chat in chat_results:
|
|||
|
result = chat['result']
|
|||
|
if result['status'] == 'success':
|
|||
|
logger.info(f"邮箱 {chat['email']} 对话成功,轮次: {result['turns_completed']},目标达成: {result['goal_achieved']}")
|
|||
|
else:
|
|||
|
logger.info(f"邮箱 {chat['email']} 对话失败: {result.get('message', 'Unknown error')}")
|
|||
|
|
|||
|
def handle_auto_chat(args):
|
|||
|
"""处理自动对话命令"""
|
|||
|
import argparse
|
|||
|
parser = argparse.ArgumentParser(description='执行自动对话')
|
|||
|
parser.add_argument('--email', required=True, help='达人邮箱')
|
|||
|
parser.add_argument('--force_send', action='store_true', help='是否强制发送新邮件')
|
|||
|
parser.add_argument('--subject', help='邮件主题(仅当force_send=true时使用)')
|
|||
|
parser.add_argument('--content', help='邮件内容(仅当force_send=true时使用)')
|
|||
|
|
|||
|
params = parser.parse_args(args)
|
|||
|
|
|||
|
# 获取组长用户
|
|||
|
User = get_user_model()
|
|||
|
leader = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not leader:
|
|||
|
logger.error("未找到组长用户,无法进行自动对话")
|
|||
|
return
|
|||
|
|
|||
|
# 如果是强制发送模式
|
|||
|
if params.force_send:
|
|||
|
if not params.content:
|
|||
|
logger.error("当force_send=true时,必须提供content参数")
|
|||
|
return
|
|||
|
|
|||
|
try:
|
|||
|
# 获取知识库映射
|
|||
|
mapping = GmailTalentMapping.objects.filter(
|
|||
|
user=leader,
|
|||
|
talent_email=params.email,
|
|||
|
is_active=True
|
|||
|
).first()
|
|||
|
|
|||
|
if not mapping:
|
|||
|
logger.error(f"找不到与邮箱 {params.email} 的映射关系")
|
|||
|
return
|
|||
|
|
|||
|
# 创建Gmail集成实例
|
|||
|
gmail_integration = GmailIntegration(leader)
|
|||
|
|
|||
|
# 直接发送邮件
|
|||
|
mail_subject = params.subject if params.subject else "关于合作的洽谈"
|
|||
|
mail_result = gmail_integration.send_email(
|
|||
|
to_email=params.email,
|
|||
|
subject=mail_subject,
|
|||
|
body=params.content,
|
|||
|
conversation_id=mapping.conversation_id
|
|||
|
)
|
|||
|
|
|||
|
if mail_result['status'] != 'success':
|
|||
|
logger.error(f"邮件发送失败: {mail_result.get('message', 'Unknown error')}")
|
|||
|
return
|
|||
|
|
|||
|
# 保存发送的内容到对话历史
|
|||
|
ChatHistory.objects.create(
|
|||
|
user=leader,
|
|||
|
knowledge_base=mapping.knowledge_base,
|
|||
|
conversation_id=mapping.conversation_id,
|
|||
|
role='assistant',
|
|||
|
content=params.content
|
|||
|
)
|
|||
|
|
|||
|
logger.info(f"已强制发送邮件到 {params.email}")
|
|||
|
return {
|
|||
|
'status': 'success',
|
|||
|
'message': f"已强制发送邮件到 {params.email}",
|
|||
|
'email_sent': True,
|
|||
|
'conversation_id': mapping.conversation_id
|
|||
|
}
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
logger.error(f"强制发送邮件时出错: {str(e)}")
|
|||
|
logger.error(traceback.format_exc())
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': str(e)
|
|||
|
}
|
|||
|
|
|||
|
# 执行自动对话
|
|||
|
result = auto_chat_session(leader, params.email)
|
|||
|
|
|||
|
# 打印结果
|
|||
|
if result['status'] == 'success':
|
|||
|
if result.get('email_sent'):
|
|||
|
logger.info(f"自动对话成功,已发送邮件到 {params.email}")
|
|||
|
else:
|
|||
|
logger.info(f"没有新的达人回复,不需要发送邮件")
|
|||
|
else:
|
|||
|
logger.error(f"自动对话失败: {result.get('message', 'Unknown error')}")
|
|||
|
|
|||
|
return result
|
|||
|
|
|||
|
def handle_set_goal(args):
|
|||
|
"""处理设置目标命令"""
|
|||
|
import argparse
|
|||
|
parser = argparse.ArgumentParser(description='设置用户总目标')
|
|||
|
parser.add_argument('--email', required=True, help='达人邮箱')
|
|||
|
parser.add_argument('--goal', required=True, help='目标内容')
|
|||
|
|
|||
|
params = parser.parse_args(args)
|
|||
|
|
|||
|
# 获取组长用户
|
|||
|
User = get_user_model()
|
|||
|
leader = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not leader:
|
|||
|
logger.error("未找到组长用户,无法设置目标")
|
|||
|
return
|
|||
|
|
|||
|
# 设置总目标
|
|||
|
gmail_integration = GmailIntegration(leader)
|
|||
|
result = gmail_integration.manage_user_goal(params.goal)
|
|||
|
|
|||
|
# 打印结果
|
|||
|
if result['status'] == 'success':
|
|||
|
logger.info(f"设置总目标成功: {result['action']}")
|
|||
|
else:
|
|||
|
logger.error(f"设置总目标失败: {result.get('message', 'Unknown error')}")
|
|||
|
|
|||
|
return result
|
|||
|
|
|||
|
def handle_check_goal(args):
|
|||
|
"""处理检查目标完成状态命令"""
|
|||
|
import argparse
|
|||
|
parser = argparse.ArgumentParser(description='检查目标完成状态')
|
|||
|
parser.add_argument('--email', required=True, help='达人邮箱')
|
|||
|
|
|||
|
params = parser.parse_args(args)
|
|||
|
|
|||
|
# 获取组长用户
|
|||
|
User = get_user_model()
|
|||
|
leader = User.objects.filter(role='leader').first()
|
|||
|
|
|||
|
if not leader:
|
|||
|
logger.error("未找到组长用户,无法检查目标")
|
|||
|
return
|
|||
|
|
|||
|
# 查找Gmail映射关系
|
|||
|
mapping = GmailTalentMapping.objects.filter(
|
|||
|
user=leader,
|
|||
|
talent_email=params.email,
|
|||
|
is_active=True
|
|||
|
).first()
|
|||
|
|
|||
|
if not mapping:
|
|||
|
logger.error(f"找不到与邮箱 {params.email} 的映射关系")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"找不到与邮箱 {params.email} 的映射关系"
|
|||
|
}
|
|||
|
|
|||
|
# 获取对话历史中最后的AI回复
|
|||
|
last_ai_message = ChatHistory.objects.filter(
|
|||
|
user=leader,
|
|||
|
knowledge_base=mapping.knowledge_base,
|
|||
|
conversation_id=mapping.conversation_id,
|
|||
|
role='assistant',
|
|||
|
is_deleted=False
|
|||
|
).order_by('-created_at').first()
|
|||
|
|
|||
|
if not last_ai_message:
|
|||
|
logger.error(f"找不到与邮箱 {params.email} 的对话历史")
|
|||
|
return {
|
|||
|
'status': 'error',
|
|||
|
'message': f"找不到与邮箱 {params.email} 的对话历史"
|
|||
|
}
|
|||
|
|
|||
|
# 检查目标是否已达成
|
|||
|
goal_achieved = check_goal_achieved(last_ai_message.content)
|
|||
|
|
|||
|
# 获取对话总结
|
|||
|
summary = ConversationSummary.objects.filter(
|
|||
|
user=leader,
|
|||
|
talent_email=params.email,
|
|||
|
is_active=True
|
|||
|
).order_by('-updated_at').first()
|
|||
|
|
|||
|
result = {
|
|||
|
'status': 'success',
|
|||
|
'email': params.email,
|
|||
|
'goal_achieved': goal_achieved,
|
|||
|
'last_message_time': last_ai_message.created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|||
|
'summary': summary.summary if summary else None
|
|||
|
}
|
|||
|
|
|||
|
# 打印结果
|
|||
|
logger.info(f"目标状态检查结果:")
|
|||
|
logger.info(f"邮箱: {params.email}")
|
|||
|
logger.info(f"目标达成: {goal_achieved}")
|
|||
|
logger.info(f"最后消息时间: {result['last_message_time']}")
|
|||
|
|
|||
|
return result
|
|||
|
|
|||
|
def main():
|
|||
|
"""命令行入口函数"""
|
|||
|
import sys
|
|||
|
|
|||
|
if len(sys.argv) < 2 or sys.argv[1] == 'help':
|
|||
|
print_help()
|
|||
|
return
|
|||
|
|
|||
|
command = sys.argv[1]
|
|||
|
args = sys.argv[2:]
|
|||
|
|
|||
|
if command == 'process_table':
|
|||
|
handle_process_table(args)
|
|||
|
elif command == 'auto_chat':
|
|||
|
handle_auto_chat(args)
|
|||
|
elif command == 'set_goal':
|
|||
|
handle_set_goal(args)
|
|||
|
elif command == 'check_goal':
|
|||
|
handle_check_goal(args)
|
|||
|
else:
|
|||
|
print(f"未知命令: {command}")
|
|||
|
print_help()
|
|||
|
|
|||
|
if __name__ == "__main__":
|
|||
|
main()
|