Files
baiyue-logistics-chat/logistics_chat/ai_client.py
T
ouyangxq 805675f8db 重构物流客服模块并完善会话接待工作台
- 拆分应用工厂、业务服务与路由,保留原有 HTTP/SSE 和存储入口
- 分离页面资源,重排客服工作台并完善响应式导航、草稿和附件交互
- 整理维护脚本、请求示例和贡献指南,移除启动脚本中的密钥配置
- 上传文件改为仅本地保留,补充隔离的后端与前端回归验证

验证:46 项 Python 测试通过,含 14 个已有子测试;12 个 Node 前端场景通过。
2026-10-29 10:59:29 +08:00

62 lines
2.8 KiB
Python

"""DeepSeek HTTP calls; callers retain their streaming/compression/followup deadlines."""
import json
import re
import requests
from requests.exceptions import RequestException, Timeout
from .config import get_setting
def post_completion(body, *, timeout, stream=False):
return requests.post(
get_setting('MODEL_URL'),
headers={'Authorization': f"Bearer {get_setting('DEEPSEEK_API_KEY')}",
'Content-Type': 'application/json'},
json=body, stream=stream, timeout=timeout,
)
EN_COMPRESS_RULE = '原文是英文,压缩后的结果必须仍然使用英文(English),不得翻译成中文。'
def has_chinese(t):
return any(('一' <= ch <= '龥' for ch in t))
def compress_answer(text, limit=get_setting('MAX_ANSWER_CHARS')):
"""回答超长时,让模型压缩到规定字数内;失败则原样返回"""
if len(text) <= limit:
return text
try:
body = {'model': get_setting('MODEL_NAME'), 'messages': [{'role': 'system', 'content': (EN_COMPRESS_RULE if has_chinese(text) is False else '') + f'你是文字精简助手。把用户给的内容压缩到 {limit} 字以内(必须严格满足,超出即为不合格),必须保留所有数字、金额、时效和渠道名称,删除重复表述、客套话和次要说明,结构保持不变。'}, {'role': 'user', 'content': text}], 'stream': False, 'max_tokens': 800}
r = post_completion(body, timeout=(5, 30))
if r.status_code == 200:
short = r.json()['choices'][0]['message']['content'].strip()
print(f'[压缩] {len(text)} 字 -> {len(short)} 字')
return short
print(f'[压缩失败] 状态码 {r.status_code}')
except Exception as e:
print(f'[压缩异常] {e}')
return text
def gen_followups(user_msg, answer_text):
"""根据本轮问答,生成 3 个客户可能接着问的问题(失败返回空列表,不影响主流程)"""
if not get_setting('DEEPSEEK_API_KEY'):
return []
try:
body = {'model': get_setting('MODEL_NAME'), 'messages': [{'role': 'system', 'content': '你是物流客服助手。根据用户问题和你的回答,生成3个客户最可能接着问的简短问题(每个不超过20字),只输出JSON字符串数组,不要任何解释。'}, {'role': 'user', 'content': f'用户问:{user_msg}\n你的回答:{answer_text[:500]}\n\n请生成3个追问:'}], 'stream': False, 'max_tokens': 200}
r = post_completion(body, timeout=(5, 15))
if r.status_code != 200:
return []
text = r.json()['choices'][0]['message']['content'].strip()
m = re.search('\\[.*\\]', text, re.S)
if m:
arr = json.loads(m.group(0))
return [str(x).strip() for x in arr if str(x).strip()][:3]
except Exception:
pass
return []