feat: 增强 Agent 系统和完善项目结构

主要改进:
- Agent 增强: 订单查询、售后支持、客服路由等功能优化
- 新增语言检测和 Token 管理模块
- 改进 Chatwoot webhook 处理和用户标识
- MCP 服务器增强: 订单 MCP 和 Strapi MCP 功能扩展
- 新增商城客户端、知识库、缓存和同步模块
- 添加多语言提示词系统 (YAML)
- 完善项目结构: 整理文档、脚本和测试文件
- 新增调试和测试工具脚本

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
wangliang
2026-01-16 16:28:47 +08:00
parent 0e59f3067e
commit e093995368
48 changed files with 5263 additions and 395 deletions

View File

@@ -0,0 +1,180 @@
"""
Mall API Client for MCP Servers
用于调用商城 API包括订单查询等接口
"""
from typing import Any, Optional
import httpx
from pydantic_settings import BaseSettings
from pydantic import ConfigDict
class MallSettings(BaseSettings):
"""Mall API configuration"""
mall_api_url: Optional[str] = None
mall_api_token: Optional[str] = None
mall_tenant_id: str = "2"
mall_currency_code: str = "EUR"
mall_language_id: str = "1"
mall_source: str = "us.qa1.gaia888.com"
model_config = ConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore"
)
settings = MallSettings()
class MallClient:
"""Async client for Mall API"""
def __init__(
self,
api_url: Optional[str] = None,
api_token: Optional[str] = None,
tenant_id: Optional[str] = None,
currency_code: Optional[str] = None,
language_id: Optional[str] = None,
source: Optional[str] = None
):
self.api_url = (api_url or settings.mall_api_url or "").rstrip("/")
self.api_token = api_token or settings.mall_api_token or ""
self.tenant_id = tenant_id or settings.mall_tenant_id
self.currency_code = currency_code or settings.mall_currency_code
self.language_id = language_id or settings.mall_language_id
self.source = source or settings.mall_source
self._client: Optional[httpx.AsyncClient] = None
async def _get_client(self) -> httpx.AsyncClient:
"""Get or create HTTP client with default headers"""
if self._client is None:
self._client = httpx.AsyncClient(
base_url=self.api_url,
headers={
"Authorization": f"Bearer {self.api_token}",
"Content-Type": "application/json",
"Accept": "application/json",
"Device-Type": "pc",
"tenant-Id": self.tenant_id,
"currency-code": self.currency_code,
"language-id": self.language_id,
"source": self.source,
},
timeout=30.0
)
return self._client
async def close(self):
"""Close HTTP client"""
if self._client:
await self._client.aclose()
self._client = None
async def request(
self,
method: str,
endpoint: str,
params: Optional[dict[str, Any]] = None,
json: Optional[dict[str, Any]] = None,
headers: Optional[dict[str, str]] = None
) -> dict[str, Any]:
"""Make API request and handle response
Args:
method: HTTP method
endpoint: API endpoint (e.g., "/mall/api/order/show")
params: Query parameters
json: JSON body
headers: Additional headers
Returns:
Response data
"""
client = await self._get_client()
# Merge additional headers
request_headers = {}
if headers:
request_headers.update(headers)
response = await client.request(
method=method,
url=endpoint,
params=params,
json=json,
headers=request_headers
)
response.raise_for_status()
data = response.json()
# Mall API 返回格式: {"code": 200, "msg": "success", "result": {...}}
# 检查 API 错误
if data.get("code") != 200:
raise Exception(f"API Error [{data.get('code')}]: {data.get('msg') or data.get('message')}")
# 返回 result 字段或整个 data
return data.get("result", data)
async def get(
self,
endpoint: str,
params: Optional[dict[str, Any]] = None,
**kwargs: Any
) -> dict[str, Any]:
"""GET request"""
return await self.request("GET", endpoint, params=params, **kwargs)
async def post(
self,
endpoint: str,
json: Optional[dict[str, Any]] = None,
**kwargs: Any
) -> dict[str, Any]:
"""POST request"""
return await self.request("POST", endpoint, json=json, **kwargs)
# ============ Order APIs ============
async def get_order_by_id(
self,
order_id: str
) -> dict[str, Any]:
"""Query order by order ID
根据订单号查询订单详情
Args:
order_id: 订单号 (e.g., "202071324")
Returns:
订单详情,包含订单号、状态、商品信息、金额、物流信息等
Order details including order ID, status, items, amount, logistics info, etc.
Example:
>>> client = MallClient()
>>> order = await client.get_order_by_id("202071324")
>>> print(order["order_id"])
"""
try:
result = await self.get(
"/mall/api/order/show",
params={"orderId": order_id}
)
return result
except Exception as e:
raise Exception(f"查询订单失败 (Query order failed): {str(e)}")
# Global Mall client instance
mall_client: Optional[MallClient] = None
def get_mall_client() -> MallClient:
"""Get or create global Mall client instance"""
global mall_client
if mall_client is None:
mall_client = MallClient()
return mall_client