feat: 优化 FAQ 处理和系统稳定性

- 添加本地 FAQ 库快速路径(问候语等社交响应)
- 修复 Chatwoot 重启循环问题(PID 文件清理)
- 添加 LLM 响应缓存(Redis 缓存,提升性能)
- 添加智能推理模式(根据查询复杂度自动启用)
- 添加订单卡片消息功能(Chatwoot 富媒体)
- 增加 LLM 超时时间至 60 秒

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
wangliang
2026-01-20 14:51:30 +08:00
parent c4e97cf312
commit 6b6172d8f0
8 changed files with 684 additions and 18 deletions

View File

@@ -141,32 +141,89 @@ class ChatwootClient:
content_attributes: dict[str, Any]
) -> dict[str, Any]:
"""Send a rich message (cards, buttons, etc.)
Args:
conversation_id: Conversation ID
content: Fallback text content
content_type: Rich content type (cards, input_select, etc.)
content_attributes: Rich content attributes
Returns:
Created message data
"""
client = await self._get_client()
payload = {
"content": content,
"message_type": MessageType.OUTGOING.value,
"content_type": content_type,
"content_attributes": content_attributes
}
response = await client.post(
f"/conversations/{conversation_id}/messages",
json=payload
)
response.raise_for_status()
return response.json()
async def send_order_card(
self,
conversation_id: int,
order_data: dict[str, Any],
actions: list[dict[str, Any]]
) -> dict[str, Any]:
"""发送订单卡片消息Markdown 文本 + 操作按钮)
Args:
conversation_id: 会话 ID
order_data: 订单数据,包含:
- order_id: 订单号
- status: 订单状态
- status_text: 状态文本
- created_at: 下单时间(可选)
- items: 商品列表(可选)
- total_amount: 总金额
- shipping_fee: 运费(可选)
- logistics: 物流信息(可选)
- remark: 备注(可选)
actions: 操作按钮配置列表,每个按钮包含:
- type: "link""postback"
- text: 按钮文字
- uri: 链接地址type=link 时必需)
- payload: 回传数据type=postback 时必需)
Returns:
发送结果
Example:
>>> order_data = {
... "order_id": "123456789",
... "status": "shipped",
... "status_text": "已发货",
... "total_amount": "1058.00",
... "items": [...]
... }
>>> actions = [
... {"type": "link", "text": "查看详情", "uri": "https://..."},
... {"type": "postback", "text": "联系客服", "payload": "CONTACT_SUPPORT"}
... ]
>>> await chatwoot.send_order_card(123, order_data, actions)
"""
# 生成 Markdown 内容
markdown_content = format_order_card_markdown(order_data)
# 生成按钮卡片
buttons = create_action_buttons(actions)
# 发送富媒体消息
return await self.send_rich_message(
conversation_id=conversation_id,
content=markdown_content,
content_type="cards",
content_attributes=buttons
)
# ============ Conversations ============
@@ -342,6 +399,130 @@ class ChatwootClient:
return data.get("payload", [])
# ============ Helper Functions ============
def format_order_card_markdown(order_data: dict[str, Any]) -> str:
"""格式化订单信息为 Markdown 卡片
Args:
order_data: 订单数据,包含订单号、状态、商品、金额、物流等信息
Returns:
格式化的 Markdown 字符串
Example:
>>> order = {
... "order_id": "123456789",
... "status": "shipped",
... "status_text": "已发货",
... "created_at": "2023-10-27 14:30",
... "items": [...],
... "total_amount": "1058.00",
... "shipping_fee": "0.00",
... "logistics": {...}
... }
>>> markdown = format_order_card_markdown(order)
"""
# 订单状态 emoji 映射
status_emoji = {
"pending": "",
"paid": "💰",
"processing": "⚙️",
"shipped": "📦",
"delivered": "",
"completed": "",
"cancelled": "",
"refunded": "💸",
"failed": "⚠️",
}
# 获取状态文本和 emoji
status = order_data.get("status", "unknown")
status_text = order_data.get("status_text", status)
emoji = status_emoji.get(status, "📦")
lines = [
f"{emoji} **订单状态:{status_text}**",
f"📝 **订单号:** `{order_data.get('order_id', '')}`",
]
# 添加下单时间(如果有)
if order_data.get("created_at"):
lines.append(f"📅 **下单时间:** {order_data['created_at']}")
lines.append("") # 空行
lines.append("**商品详情**")
# 添加商品列表
items = order_data.get("items", [])
if items:
for item in items:
name = item.get("name", "未知商品")
quantity = item.get("quantity", 1)
price = item.get("price", "0.00")
# 可选:添加图片链接
image_markdown = ""
if item.get("image_url"):
image_markdown = f" [图片]({item['image_url']})"
lines.append(f"▫️{image_markdown} {name} × {quantity} ¥{price}")
else:
lines.append("▫️ 无商品信息")
# 添加金额信息
lines.extend([
"",
f"💰 **实付:** ¥{order_data.get('total_amount', '0.00')} (含运费 ¥{order_data.get('shipping_fee', '0.00')})"
])
# 添加物流信息(如果有)
logistics = order_data.get("logistics")
if logistics:
lines.extend([
"",
"🚚 **物流信息**",
f"承运商:{logistics.get('carrier', '未知')}",
f"单号:{logistics.get('tracking_number', '未知')}",
"*点击单号可复制跟踪*"
])
# 添加备注(如果有)
if order_data.get("remark"):
lines.extend([
"",
f"📋 **备注:** {order_data['remark']}"
])
return "\n".join(lines)
def create_action_buttons(actions: list[dict[str, Any]]) -> dict[str, Any]:
"""创建 Chatwoot 操作按钮卡片
Args:
actions: 按钮配置列表,每个按钮包含:
- type: "link""postback"
- text: 按钮文字
- uri: 链接地址type=link 时)
- payload: 回传数据type=postback 时)
Returns:
符合 Chatwoot content_attributes 格式的字典
Example:
>>> actions = [
... {"type": "link", "text": "查看详情", "uri": "https://example.com"},
... {"type": "postback", "text": "联系客服", "payload": "CONTACT_SUPPORT"}
... ]
>>> buttons = create_action_buttons(actions)
"""
return {
"items": [{
"title": "操作",
"actions": actions
}]
}
# Global Chatwoot client instance
chatwoot_client: Optional[ChatwootClient] = None