添加token
This commit is contained in:
parent
f882c25093
commit
1d5b3eb237
@ -19,7 +19,7 @@ class OfferStatusService:
|
|||||||
:return: 状态字符串
|
:return: 状态字符串
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
url = "http://127.0.0.1:8000/api/operation/negotiations/offer_status/"
|
url = "http://81.69.223.133:58099/api/operation/negotiations/offer_status/"
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'creator_id': str(creator_id),
|
'creator_id': str(creator_id),
|
||||||
|
@ -11,6 +11,7 @@ from rest_framework import viewsets, status
|
|||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from apps.user.authentication import CustomTokenAuthentication
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -30,6 +31,8 @@ from apps.brands.models import Product
|
|||||||
|
|
||||||
client = Client(host="http://localhost:11434")
|
client = Client(host="http://localhost:11434")
|
||||||
class ContentAnalysisAPI(APIView):
|
class ContentAnalysisAPI(APIView):
|
||||||
|
authentication_classes = [CustomTokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
parser_classes = (MultiPartParser, FormParser)
|
parser_classes = (MultiPartParser, FormParser)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
@ -167,79 +170,71 @@ class ContentAnalysisAPI(APIView):
|
|||||||
class NegotiationViewSet(viewsets.ModelViewSet):
|
class NegotiationViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Negotiation.objects.all()
|
queryset = Negotiation.objects.all()
|
||||||
serializer_class = NegotiationSerializer
|
serializer_class = NegotiationSerializer
|
||||||
|
authentication_classes = [CustomTokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
"""创建谈判(事务保护版)"""
|
"""创建谈判并返回包含初始消息的响应"""
|
||||||
try:
|
serializer = self.get_serializer(data=request.data)
|
||||||
# 开启事务:所有数据库操作要么全部成功,要么全部回滚
|
serializer.is_valid(raise_exception=True)
|
||||||
with transaction.atomic():
|
|
||||||
# 1. 验证请求数据
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True) # 自动返回400错误
|
|
||||||
|
|
||||||
creator = serializer.validated_data['creator']
|
# Extract creator and product from validated data
|
||||||
product = serializer.validated_data['product']
|
creator = serializer.validated_data['creator']
|
||||||
|
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, "message": "未找到指定的达人", "data": None},
|
"code": 404,
|
||||||
status=status.HTTP_404_NOT_FOUND
|
"message": "未找到指定的达人",
|
||||||
)
|
"data": None
|
||||||
|
})
|
||||||
|
|
||||||
# 3. 检查商品是否存在
|
# Check if the product exists
|
||||||
if not Product.objects.filter(id=product.id).exists():
|
if not Product.objects.filter(id=product.id).exists():
|
||||||
return Response(
|
return Response({
|
||||||
{"code": 404, "message": "未找到指定的商品", "data": None},
|
"code": 404,
|
||||||
status=status.HTTP_404_NOT_FOUND
|
"message": "未找到指定的商品",
|
||||||
)
|
"data": None
|
||||||
|
})
|
||||||
|
|
||||||
# 4. 检查是否已存在相同谈判
|
# Check if a negotiation already exists for the same creator and product
|
||||||
if Negotiation.objects.filter(creator=creator, product=product).exists():
|
existing_negotiation = Negotiation.objects.filter(creator=creator, product=product).first()
|
||||||
return Response(
|
if existing_negotiation:
|
||||||
{
|
return Response({
|
||||||
"code": 400,
|
"code": 400,
|
||||||
"message": "谈判已存在",
|
"message": "谈判已存在",
|
||||||
"data": {}
|
"data": {
|
||||||
},
|
"negotiation_id": existing_negotiation.id
|
||||||
status=status.HTTP_400_BAD_REQUEST
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
# 5. 创建谈判记录
|
# 1. 创建谈判记录
|
||||||
negotiation = serializer.save()
|
negotiation = serializer.save()
|
||||||
|
|
||||||
# 6. 生成初始消息
|
# 2. 生成并保存初始消息
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
||||||
# 7. 返回成功响应
|
# 4. 构建响应数据
|
||||||
return Response(
|
response_data = {
|
||||||
{
|
"code": 200,
|
||||||
"code": 200,
|
"message": "谈判已创建",
|
||||||
"message": "谈判已创建",
|
"data": {
|
||||||
"data": {
|
"id": message.id,
|
||||||
"id": message.id,
|
**serializer.data,
|
||||||
**serializer.data,
|
"content": initial_message,
|
||||||
"content": initial_message,
|
"created_at": message.created_at
|
||||||
"created_at": message.created_at
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
status=status.HTTP_201_CREATED,
|
|
||||||
headers=self.get_success_headers(serializer.data)
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
headers = self.get_success_headers(serializer.data)
|
||||||
# 记录异常细节(实际生产环境应接入监控系统)
|
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):
|
||||||
@ -441,6 +436,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
|
|||||||
|
|
||||||
🔍 商品详情:
|
🔍 商品详情:
|
||||||
- 名称:{product.name}
|
- 名称:{product.name}
|
||||||
|
- 类目:{product.category}
|
||||||
- 核心卖点:{product.description}
|
- 核心卖点:{product.description}
|
||||||
|
|
||||||
🤝 合作优势:
|
🤝 合作优势:
|
||||||
@ -479,8 +475,8 @@ class NegotiationViewSet(viewsets.ModelViewSet):
|
|||||||
你是作为一个专业的商务谈判专家, 现在正在与达人 {negotiation.creator.name} 进行价格谈判。
|
你是作为一个专业的商务谈判专家, 现在正在与达人 {negotiation.creator.name} 进行价格谈判。
|
||||||
|
|
||||||
当前谈判轮次:{negotiation.current_round}/4
|
当前谈判轮次:{negotiation.current_round}/4
|
||||||
商品参考价格:{negotiation.product.sales_price_min}元
|
商品参考价格:{negotiation.product.max_price}元
|
||||||
商品最低价格:{negotiation.product.sales_price_max}元
|
商品最低价格:{negotiation.product.min_price}元
|
||||||
达人最新回复:
|
达人最新回复:
|
||||||
{history[-1]['content']}
|
{history[-1]['content']}
|
||||||
|
|
||||||
@ -537,8 +533,7 @@ class NegotiationViewSet(viewsets.ModelViewSet):
|
|||||||
# history = self._get_stage_messages(negotiation)
|
# history = self._get_stage_messages(negotiation)
|
||||||
content = f"""
|
content = f"""
|
||||||
当前谈判已进入正式合同的准备阶段。
|
当前谈判已进入正式合同的准备阶段。
|
||||||
|
|
||||||
如果用户继续谈跟价格有关的信息的话,我们就表示已经谈好价格了,无法修改。
|
|
||||||
如果用户表示没有收到合同邮件的话,我们就再次向用户发送合同邮件。
|
如果用户表示没有收到合同邮件的话,我们就再次向用户发送合同邮件。
|
||||||
如果用户表示接受的话,我们引导用户去查看邮件并签署合同。
|
如果用户表示接受的话,我们引导用户去查看邮件并签署合同。
|
||||||
如果用户表示拒绝的话,我们引导用户去查看合同邮件然后在邮件中拒绝签署此合同。
|
如果用户表示拒绝的话,我们引导用户去查看合同邮件然后在邮件中拒绝签署此合同。
|
||||||
@ -605,7 +600,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(
|
||||||
@ -620,15 +615,17 @@ 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
|
||||||
|
|
||||||
|
|
||||||
## 根据接收到的达人列表来查找达人(已弃用)
|
## 根据接收到的达人列表来查找达人(已弃用)
|
||||||
class TopCreatorsAPI(APIView):
|
class TopCreatorsAPI(APIView):
|
||||||
|
authentication_classes = [CustomTokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
# Extract filtering criteria and creator list from the request
|
# Extract filtering criteria and creator list from the request
|
||||||
criteria = request.data.get('criteria', "")
|
criteria = request.data.get('criteria', "")
|
||||||
@ -715,6 +712,8 @@ class TopCreatorsAPI(APIView):
|
|||||||
|
|
||||||
## 生成sql直接查询达人库
|
## 生成sql直接查询达人库
|
||||||
class CreatorSQLSearchAPI(APIView):
|
class CreatorSQLSearchAPI(APIView):
|
||||||
|
authentication_classes = [CustomTokenAuthentication]
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
criteria = request.data.get('criteria', '')
|
criteria = request.data.get('criteria', '')
|
||||||
top_n = int(request.data.get('top_n', 10)) # 默认为10
|
top_n = int(request.data.get('top_n', 10)) # 默认为10
|
||||||
@ -722,48 +721,54 @@ class CreatorSQLSearchAPI(APIView):
|
|||||||
return Response({"error": "缺少筛选条件"}, status=400)
|
return Response({"error": "缺少筛选条件"}, status=400)
|
||||||
|
|
||||||
table_schema = '''
|
table_schema = '''
|
||||||
creator_profiles(
|
feishu_creators(
|
||||||
id bigint 主键,
|
id char(32) 主键,
|
||||||
name varchar(255) 达人名称,
|
record_id varchar(100) 记录ID,
|
||||||
avatar_url text 头像URL,
|
contact_person varchar(50) 联系人姓名,
|
||||||
email varchar(255) 电子邮箱,
|
handle longtext 账号/达人昵称,
|
||||||
instagram varchar(255) Instagram账号,
|
tiktok_url longtext 抖音主页链接,
|
||||||
tiktok_link varchar(255) TikTok链接,
|
fans_count varchar(50) 粉丝数,
|
||||||
location varchar(100) 位置,
|
gmv varchar(100) GMV,
|
||||||
live_schedule varchar(255) 直播时间表,
|
email varchar(254) 邮箱,
|
||||||
category varchar(100) 类别,
|
phone varchar(50) 电话,
|
||||||
e_commerce_level int 电商能力等级,
|
account_type varchar(50) 账号类型,
|
||||||
exposure_level varchar(10) 曝光等级,
|
price_quote longtext 报价,
|
||||||
followers int 粉丝数,
|
response_speed varchar(50) 响应速度,
|
||||||
gmv decimal(12,2) GMV(千美元),
|
cooperation_intention varchar(50) 合作意向,
|
||||||
items_sold decimal(12,2) 售出商品数量,
|
payment_method varchar(50) 支付方式,
|
||||||
avg_video_views int 平均视频浏览量,
|
payment_account varchar(100) 支付账号,
|
||||||
pricing_min decimal(10,2) 最低个人定价,
|
address longtext 地址,
|
||||||
pricing_max decimal(10,2) 最高个人定价,
|
has_ooin varchar(10) 是否有OOIN,
|
||||||
pricing_package varchar(100) 套餐定价,
|
source varchar(100) 数据来源,
|
||||||
collab_count int 合作次数,
|
contact_status varchar(50) 联系状态,
|
||||||
latest_collab varchar(100) 最新合作,
|
cooperation_brands json 合作品牌,
|
||||||
e_commerce_platforms json 电商平台,
|
system_categories varchar(100) 系统分类,
|
||||||
gmv_by_channel json GMV按渠道分布,
|
actual_categories varchar(100) 实际分类,
|
||||||
gmv_by_category json GMV按类别分布,
|
human_categories varchar(100) 人工分类,
|
||||||
mcn varchar(255) MCN机构,
|
creator_base varchar(100) 达人基地,
|
||||||
create_time datetime 创建时间,
|
notes longtext 备注,
|
||||||
update_time datetime 更新时间
|
created_at datetime 创建时间,
|
||||||
|
updated_at datetime 更新时间
|
||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
prompt = f"""
|
prompt = f"""
|
||||||
你是一个SQL专家。下面是MySQL表creator_profiles的结构:
|
你是一个SQL专家。下面是MySQL表feishu_creators的结构:
|
||||||
{table_schema}
|
{table_schema}
|
||||||
|
|
||||||
以下是我对表中每个字段的解释: 方便你写出正确的sql查询语句
|
以下是我对表中每个字段的解释: 方便你写出正确的sql查询语句
|
||||||
请根据以下自然语言筛选条件, 生成一条MySQL的SELECT语句, 查询daren_detail.creator_profiles表(注意一定要写数据库名称.表名称), 返回所有字段。不要加任何解释说明, 只输出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;
|
||||||
|
注意: response_speed 字段有以下几个取值: 1、无回复 2、一般 3、正常 4、积极。请在sql中直接使用上述的某个值就好, 不要进行任何转换。例如: SELECT * FROM daren.feishu_creators WHERE response_speed = '积极'
|
||||||
|
注意: source 字段有以下几个取值: 1. 线下活动 2、TAP后台。请在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="qwen2.5:32b",
|
model="deepseek-r1:70b",
|
||||||
messages=[{'role': 'user', 'content': prompt}],
|
messages=[{'role': 'user', 'content': prompt}],
|
||||||
)
|
)
|
||||||
sql = self._extract_sql(response['message']['content'])
|
sql = self._extract_sql(response['message']['content'])
|
||||||
|
@ -223,6 +223,3 @@ SIMPLE_JWT = {
|
|||||||
'JTI_CLAIM': None, # 不在 token 中包含 JWT ID
|
'JTI_CLAIM': None, # 不在 token 中包含 JWT ID
|
||||||
}
|
}
|
||||||
|
|
||||||
# JWT配置
|
|
||||||
JWT_SECRET_KEY = 'your-secret-key-here' # 建议使用更安全的密钥
|
|
||||||
JWT_EXPIRATION_DELTA = 24 * 60 * 60 # token有效期24小时(秒)
|
|
11
logs/app.log
11
logs/app.log
@ -29,3 +29,14 @@ ERROR 2025-05-20 17:40:33,375 offer_status_service
|
|||||||
ERROR 2025-05-20 17:41:03,425 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
ERROR 2025-05-20 17:41:03,425 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
||||||
ERROR 2025-05-20 17:41:33,477 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
ERROR 2025-05-20 17:41:33,477 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
||||||
ERROR 2025-05-20 17:42:03,529 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
ERROR 2025-05-20 17:42:03,529 offer_status_service 获取谈判状态失败: 不存在与用户id为14和商品id为241a67e0-1c99-44de-a5dd-40622ffa23b6的谈判
|
||||||
|
INFO 2025-05-21 15:11:55,810 status_polling_service 已启动活动 1 的状态轮询,间隔 30 秒
|
||||||
|
INFO 2025-05-21 15:11:55,812 consumers 已启动活动 1 的状态轮询
|
||||||
|
INFO 2025-05-21 15:11:55,813 consumers WebSocket连接已建立: campaign_1
|
||||||
|
ERROR 2025-05-21 15:11:55,860 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:12:25,874 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:12:55,889 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:13:25,904 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:13:55,924 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:14:25,949 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:14:55,967 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
ERROR 2025-05-21 15:15:25,985 offer_status_service 请求谈判状态接口失败: 401
|
||||||
|
Loading…
Reference in New Issue
Block a user