添加token

This commit is contained in:
jlj 2025-05-20 17:54:15 +08:00
commit 409ae78edd

View File

@ -169,67 +169,77 @@ class NegotiationViewSet(viewsets.ModelViewSet):
serializer_class = NegotiationSerializer serializer_class = NegotiationSerializer
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
"""创建谈判并返回包含初始消息的响应""" """创建谈判(事务保护版)"""
serializer = self.get_serializer(data=request.data) try:
serializer.is_valid(raise_exception=True) # 开启事务:所有数据库操作要么全部成功,要么全部回滚
with transaction.atomic():
# 1. 验证请求数据
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) # 自动返回400错误
# Extract creator and product from validated data creator = serializer.validated_data['creator']
creator = serializer.validated_data['creator'] product = serializer.validated_data['product']
product = serializer.validated_data['product']
# 检查该用户是否存在 # 2. 检查达人是否存在
if not CreatorProfile.objects.filter(id=creator.id).exists(): if not CreatorProfile.objects.filter(id=creator.id).exists():
return Response({ return Response(
"code": 404, {"code": 404, "message": "未找到指定的达人", "data": None},
"message": "未找到指定的达人", status=status.HTTP_404_NOT_FOUND
"data": None )
})
# Check if the product exists # 3. 检查商品是否存在
if not Product.objects.filter(id=product.id).exists(): if not Product.objects.filter(id=product.id).exists():
return Response({ return Response(
"code": 404, {"code": 404, "message": "未找到指定的商品", "data": None},
"message": "未找到指定的商品", status=status.HTTP_404_NOT_FOUND
"data": None )
})
# Check if a negotiation already exists for the same creator and product # 4. 检查是否已存在相同谈判
existing_negotiation = Negotiation.objects.filter(creator=creator, product=product).first() if Negotiation.objects.filter(creator=creator, product=product).exists():
if existing_negotiation: return Response(
return Response({ {
"code": 400, "code": 400,
"message": "谈判已存在", "message": "谈判已存在",
"data": { "data": {}
"negotiation_id": existing_negotiation.id },
} status=status.HTTP_400_BAD_REQUEST
}) )
# 1. 创建谈判记录 # 5. 创建谈判记录
negotiation = serializer.save() negotiation = serializer.save()
# 2. 生成并保存初始消息 # 6. 生成初始消息
initial_message = self._generate_welcome_message(negotiation) initial_message = self._generate_welcome_message(negotiation)
message = Message.objects.create( message = Message.objects.create(
negotiation=negotiation, negotiation=negotiation,
role='assistant', role='assistant',
content=initial_message, content=initial_message,
stage=negotiation.status stage=negotiation.status
) )
# 4. 构建响应数据 # 7. 返回成功响应
response_data = { return Response(
"code": 200, {
"message": "谈判已创建", "code": 200,
"data": { "message": "谈判已创建",
"id": message.id, "data": {
**serializer.data, "id": message.id,
"content": initial_message, **serializer.data,
"created_at": message.created_at "content": initial_message,
} "created_at": message.created_at
} }
},
status=status.HTTP_201_CREATED,
headers=self.get_success_headers(serializer.data)
)
headers = self.get_success_headers(serializer.data) except Exception as e:
return Response(response_data, status=status.HTTP_201_CREATED, headers=headers) # 记录异常细节(实际生产环境应接入监控系统)
# logger.error(f"谈判创建失败: {str(e)}", exc_info=True)
return Response(
{"code": 500, "message": "服务器内部错误", "data": None},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
@action(detail=True, methods=['post']) @action(detail=True, methods=['post'])
def chat(self, request, pk=None): def chat(self, request, pk=None):
@ -431,7 +441,6 @@ class NegotiationViewSet(viewsets.ModelViewSet):
🔍 商品详情 🔍 商品详情
- 名称{product.name} - 名称{product.name}
- 类目{product.category}
- 核心卖点{product.description} - 核心卖点{product.description}
🤝 合作优势 🤝 合作优势
@ -470,8 +479,8 @@ class NegotiationViewSet(viewsets.ModelViewSet):
你是作为一个专业的商务谈判专家, 现在正在与达人 {negotiation.creator.name} 进行价格谈判 你是作为一个专业的商务谈判专家, 现在正在与达人 {negotiation.creator.name} 进行价格谈判
当前谈判轮次{negotiation.current_round}/4 当前谈判轮次{negotiation.current_round}/4
商品参考价格{negotiation.product.max_price} 商品参考价格{negotiation.product.sales_price_min}
商品最低价格{negotiation.product.min_price} 商品最低价格{negotiation.product.sales_price_max}
达人最新回复 达人最新回复
{history[-1]['content']} {history[-1]['content']}
@ -525,7 +534,8 @@ class NegotiationViewSet(viewsets.ModelViewSet):
# history = self._get_stage_messages(negotiation) # history = self._get_stage_messages(negotiation)
content = f""" content = f"""
当前谈判已进入正式合同的准备阶段 当前谈判已进入正式合同的准备阶段
如果用户继续谈跟价格有关的信息的话我们就表示已经谈好价格了无法修改
如果用户表示没有收到合同邮件的话我们就再次向用户发送合同邮件 如果用户表示没有收到合同邮件的话我们就再次向用户发送合同邮件
如果用户表示接受的话我们引导用户去查看邮件并签署合同 如果用户表示接受的话我们引导用户去查看邮件并签署合同
如果用户表示拒绝的话我们引导用户去查看合同邮件然后在邮件中拒绝签署此合同 如果用户表示拒绝的话我们引导用户去查看合同邮件然后在邮件中拒绝签署此合同
@ -592,7 +602,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
subject = f"合同文件 - {negotiation.product.name}" subject = f"合同文件 - {negotiation.product.name}"
recipient = '3299361176@qq.com' recipient = '3299361176@qq.com'
if not recipient: if not recipient:
logger.error(f"未找到达人 {negotiation.creator.name} 的邮箱,无法发送合同。") # logger.error(f"未找到达人 {negotiation.creator.name} 的邮箱,无法发送合同。")
return False return False
try: try:
email = EmailMessage( email = EmailMessage(
@ -607,10 +617,10 @@ class NegotiationViewSet(viewsets.ModelViewSet):
email.attach('商品合同.docx', f.read(), email.attach('商品合同.docx', f.read(),
'application/vnd.openxmlformats-officedocument.wordprocessingml.document') 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')
email.send(fail_silently=False) email.send(fail_silently=False)
logger.info(f"合同已发送到 {recipient}") # logger.info(f"合同已发送到 {recipient}")
return True return True
except Exception as e: except Exception as e:
logger.error(f"发送合同邮件失败: {e}") # logger.error(f"发送合同邮件失败: {e}")
return False return False
@ -709,54 +719,48 @@ class CreatorSQLSearchAPI(APIView):
return Response({"error": "缺少筛选条件"}, status=400) return Response({"error": "缺少筛选条件"}, status=400)
table_schema = ''' table_schema = '''
feishu_creators( creator_profiles(
id char(32) 主键, id bigint 主键,
record_id varchar(100) 记录ID, name varchar(255) 达人名称,
contact_person varchar(50) 联系人姓名, avatar_url text 头像URL,
handle longtext 账号/达人昵称, email varchar(255) 电子邮箱,
tiktok_url longtext 抖音主页链接, instagram varchar(255) Instagram账号,
fans_count varchar(50) 粉丝数, tiktok_link varchar(255) TikTok链接,
gmv varchar(100) GMV, location varchar(100) 位置,
email varchar(254) 邮箱, live_schedule varchar(255) 直播时间表,
phone varchar(50) 电话, category varchar(100) 类别,
account_type varchar(50) 账号类型, e_commerce_level int 电商能力等级,
price_quote longtext 报价, exposure_level varchar(10) 曝光等级,
response_speed varchar(50) 响应速度, followers int 粉丝数,
cooperation_intention varchar(50) 合作意向, gmv decimal(12,2) GMV(千美元),
payment_method varchar(50) 支付方式, items_sold decimal(12,2) 售出商品数量,
payment_account varchar(100) 支付账号, avg_video_views int 平均视频浏览量,
address longtext 地址, pricing_min decimal(10,2) 最低个人定价,
has_ooin varchar(10) 是否有OOIN, pricing_max decimal(10,2) 最高个人定价,
source varchar(100) 数据来源, pricing_package varchar(100) 套餐定价,
contact_status varchar(50) 联系状态, collab_count int 合作次数,
cooperation_brands json 合作品牌, latest_collab varchar(100) 最新合作,
system_categories varchar(100) 系统分类, e_commerce_platforms json 电商平台,
actual_categories varchar(100) 实际分类, gmv_by_channel json GMV按渠道分布,
human_categories varchar(100) 人工分类, gmv_by_category json GMV按类别分布,
creator_base varchar(100) 达人基地, mcn varchar(255) MCN机构,
notes longtext 备注, create_time datetime 创建时间,
created_at datetime 创建时间, update_time datetime 更新时间
updated_at datetime 更新时间
) )
''' '''
prompt = f""" prompt = f"""
你是一个SQL专家下面是MySQL表feishu_creators的结构: 你是一个SQL专家下面是MySQL表creator_profiles的结构:
{table_schema} {table_schema}
以下是我对表中每个字段的解释: 方便你写出正确的sql查询语句 以下是我对表中每个字段的解释: 方便你写出正确的sql查询语句
注意: fans_count 字段为字符串可能为纯数字 '1234'也可能带有 K M百万后缀 '9K', '56.5K', '13.2M'请在SQL中将其统一转换为数字后再进行比较, K=1000, M=1000000例如查找粉丝数量大于10000的博主: SELECT * FROM your_table WHERE (CASE WHEN fans_count LIKE '%K' THEN CAST(REPLACE(fans_count, 'K', '') AS DECIMAL(10,2)) * 1000 WHEN fans_count LIKE '%M' THEN CAST(REPLACE(fans_count, 'M', '') AS DECIMAL(10,2)) * 1000000 ELSE CAST(fans_count AS DECIMAL(10,2)) END) > 100000; 请根据以下自然语言筛选条件, 生成一条MySQL的SELECT语句, 查询daren_detail.creator_profiles表(注意一定要写数据库名称.表名称), 返回所有字段不要加任何解释说明, 只输出SQL语句本身
注意: response_speed 字段有以下几个取值: 1无回复 2一般 3正常 4积极请在sql中直接使用上述的某个值就好, 不要进行任何转换例如 SELECT * FROM daren.feishu_creators WHERE response_speed = '积极'
注意: source 字段有以下几个取值: 1. 线下活动 2TAP后台请在sql中直接使用上述的某个值就好, 不要进行任何转换例如: SELECT * FROM daren.feishu_creators WHERE source = 'TAP后台'
注意: system_categories 字段是一个varchar类型的值, 是一个列表形式表示的例如 ['日用百货']['美妆个护,保健'] 这种例如查找'美妆个护'的博主 SELECT * FROM daren.feishu_creators WHERE system_categories LIKE '%美妆个护%';
注意: gmv 字段是一个varchar类型的值, 例如 $86.89$8761.98$15.5K$12.5M 这种例如我要查询gmv大于10000美金的达人: SELECT * FROM daren.feishu_creators WHERE gmv NOT LIKE '$0-%' AND (CASE WHEN gmv LIKE '%K' THEN CAST(SUBSTRING(gmv, 2, LENGTH(gmv) - 2) AS DECIMAL(10,2)) * 1000 WHEN gmv LIKE '%M' THEN CAST(SUBSTRING(gmv, 2, LENGTH(gmv) - 2) AS DECIMAL(10,2)) * 1000000 ELSE CAST(SUBSTRING(gmv, 2) AS DECIMAL(10,2)) END) > 10000;
请根据以下自然语言筛选条件, 生成一条MySQL的SELECT语句, 查询daren.feishu_creators表(注意一定要写数据库名称.表名称), 返回所有字段不要加任何解释说明, 只输出SQL语句本身
筛选条件{criteria} 筛选条件{criteria}
""" """
# 2. 让大模型生成SQL # 2. 让大模型生成SQL
response = client.chat( response = client.chat(
model="deepseek-r1:70b", model="qwen2.5:32b",
messages=[{'role': 'user', 'content': prompt}], messages=[{'role': 'user', 'content': prompt}],
) )
sql = self._extract_sql(response['message']['content']) sql = self._extract_sql(response['message']['content'])