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:
401
docs/test-conversation-id.html
Normal file
401
docs/test-conversation-id.html
Normal file
@@ -0,0 +1,401 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>会话 ID 检查工具</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
.info-box {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-box h3 {
|
||||
margin-top: 0;
|
||||
color: #2196F3;
|
||||
}
|
||||
.data-display {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
.data-label {
|
||||
font-weight: bold;
|
||||
color: #495057;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.data-value {
|
||||
color: #212529;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
word-break: break-all;
|
||||
}
|
||||
button {
|
||||
background: #2196F3;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background: #0b7dda;
|
||||
}
|
||||
button.danger {
|
||||
background: #dc3545;
|
||||
}
|
||||
button.danger:hover {
|
||||
background: #c82333;
|
||||
}
|
||||
.instructions {
|
||||
background: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
padding: 15px 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.instructions ol {
|
||||
margin: 10px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.instructions li {
|
||||
margin: 8px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔍 Chatwoot 会话 ID 检查工具</h1>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>📝 使用说明</h3>
|
||||
<ol>
|
||||
<li>打开浏览器开发者工具(按 F12)</li>
|
||||
<li>切换到 Console(控制台)标签</li>
|
||||
<li>点击下面的"显示会话信息"按钮</li>
|
||||
<li>在 Console 中查看当前的 conversation_id</li>
|
||||
<li>将这个 ID 与 Agent 日志中的 conversation_id 对比</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>🎯 操作按钮</h3>
|
||||
<button onclick="showConversationInfo()">显示会话信息</button>
|
||||
<button onclick="checkWidgetStatus()">检查 Widget 状态</button>
|
||||
<button onclick="checkToken()">检查 Token</button>
|
||||
<button onclick="testOrderAPI()">测试订单 API</button>
|
||||
<button onclick="clearLocalStorage()" class="danger">清除本地存储(重新开始)</button>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📊 信息显示</h3>
|
||||
<div class="data-display">
|
||||
<div class="data-label">Widget SDK 状态:</div>
|
||||
<div class="data-value" id="widgetStatus">未初始化</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">当前会话 ID:</div>
|
||||
<div class="data-value" id="conversationId">未知</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">Token 状态:</div>
|
||||
<div class="data-value" id="tokenStatus">未检查</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">订单 API 测试结果:</div>
|
||||
<div class="data-value" id="orderApiResult">未测试</div>
|
||||
</div>
|
||||
<div class="data-display">
|
||||
<div class="data-label">本地存储数据:</div>
|
||||
<div class="data-value" id="localStorageData">无</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="instructions">
|
||||
<h3>💡 问题排查</h3>
|
||||
<p><strong>如果看不到 AI 回复:</strong></p>
|
||||
<ol>
|
||||
<li>点击"清除本地存储"按钮</li>
|
||||
<li>刷新页面(Ctrl+Shift+R)</li>
|
||||
<li>在右下角聊天窗口重新发送消息</li>
|
||||
<li>查看 Agent 日志: <code>docker logs ai_agent --tail 50</code></li>
|
||||
<li>对比 Console 中的 conversation_id 与日志中的是否一致</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 获取 Cookie 中的 token
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查 Token
|
||||
function checkToken() {
|
||||
console.log('======================================');
|
||||
console.log('Token 检查');
|
||||
console.log('======================================');
|
||||
|
||||
const token = getCookie('token');
|
||||
const tokenStatusDiv = document.getElementById('tokenStatus');
|
||||
|
||||
if (token) {
|
||||
console.log('✅ Token 已找到');
|
||||
console.log('Token 长度:', token.length);
|
||||
console.log('Token 前缀:', token.substring(0, 50) + '...');
|
||||
tokenStatusDiv.textContent = `✅ 已找到 | 长度: ${token.length} | 前缀: ${token.substring(0, 30)}...`;
|
||||
tokenStatusDiv.style.color = '#28a745';
|
||||
} else {
|
||||
console.log('❌ 未找到 Token');
|
||||
console.log('Cookie 名称: token');
|
||||
tokenStatusDiv.textContent = '❌ 未找到 | Cookie 名称: token';
|
||||
tokenStatusDiv.style.color = '#dc3545';
|
||||
}
|
||||
|
||||
console.log('所有 Cookie:', document.cookie);
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
// 测试订单 API
|
||||
async function testOrderAPI() {
|
||||
console.log('======================================');
|
||||
console.log('测试订单 API');
|
||||
console.log('======================================');
|
||||
|
||||
const token = getCookie('token');
|
||||
const resultDiv = document.getElementById('orderApiResult');
|
||||
|
||||
if (!token) {
|
||||
console.error('❌ 未找到 Token,无法调用 API');
|
||||
resultDiv.textContent = '❌ 未找到 Token';
|
||||
resultDiv.style.color = '#dc3545';
|
||||
alert('❌ 未找到 Token,请先确保已登录商城');
|
||||
return;
|
||||
}
|
||||
|
||||
const orderId = '202071324';
|
||||
const apiUrl = `https://apicn.qa1.gaia888.com/mall/api/order/show?orderId=${orderId}`;
|
||||
|
||||
console.log('API URL:', apiUrl);
|
||||
console.log('Authorization:', `Bearer ${token.substring(0, 30)}...`);
|
||||
|
||||
resultDiv.textContent = '🔄 请求中...';
|
||||
resultDiv.style.color = '#ffc107';
|
||||
|
||||
try {
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'accept-language': 'zh-CN,zh;q=0.9',
|
||||
'authorization': `Bearer ${token}`,
|
||||
'currency-code': 'EUR',
|
||||
'device-type': 'pc',
|
||||
'language-id': '1',
|
||||
'origin': 'https://www.qa1.gaia888.com',
|
||||
'referer': 'https://www.qa1.gaia888.com/',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-site',
|
||||
'source': 'us.qa1.gaia888.com',
|
||||
'tenant-id': '2'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('响应状态:', response.status);
|
||||
console.log('响应头:', Object.fromEntries(response.headers.entries()));
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log('✅ API 调用成功');
|
||||
console.log('响应数据:', data);
|
||||
|
||||
resultDiv.textContent = `✅ 成功 (HTTP ${response.status}) | 订单 ${orderId}`;
|
||||
resultDiv.style.color = '#28a745';
|
||||
|
||||
alert(`✅ 订单 API 调用成功!\n\n订单 ID: ${orderId}\n状态码: ${response.status}\n\n详细数据请查看控制台`);
|
||||
} else {
|
||||
const errorText = await response.text();
|
||||
console.error('❌ API 调用失败');
|
||||
console.error('状态码:', response.status);
|
||||
console.error('响应内容:', errorText);
|
||||
|
||||
resultDiv.textContent = `❌ 失败 (HTTP ${response.status})`;
|
||||
resultDiv.style.color = '#dc3545';
|
||||
|
||||
alert(`❌ 订单 API 调用失败\n\n状态码: ${response.status}\n错误: ${errorText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 网络错误:', error);
|
||||
resultDiv.textContent = `❌ 网络错误: ${error.message}`;
|
||||
resultDiv.style.color = '#dc3545';
|
||||
alert(`❌ 网络错误\n\n${error.message}`);
|
||||
}
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function showConversationInfo() {
|
||||
console.log('======================================');
|
||||
console.log('Chatwoot Widget 会话信息');
|
||||
console.log('======================================');
|
||||
|
||||
if (window.$chatwoot) {
|
||||
try {
|
||||
// 尝试获取会话信息
|
||||
const info = window.$chatwoot.getConversationInfo();
|
||||
console.log('✅ 会话信息:', info);
|
||||
document.getElementById('conversationId').textContent =
|
||||
info && info.conversationId ? info.conversationId : '无法获取';
|
||||
} catch (e) {
|
||||
console.log('⚠️ 无法获取会话信息:', e.message);
|
||||
document.getElementById('conversationId').textContent = '无法获取';
|
||||
}
|
||||
} else {
|
||||
console.log('❌ Widget 未初始化');
|
||||
document.getElementById('conversationId').textContent = 'Widget 未初始化';
|
||||
}
|
||||
|
||||
// 显示本地存储
|
||||
const storage = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
storage[key] = localStorage.getItem(key);
|
||||
}
|
||||
}
|
||||
console.log('本地存储 (Chatwoot 相关):', storage);
|
||||
document.getElementById('localStorageData').textContent =
|
||||
Object.keys(storage).length > 0 ? JSON.stringify(storage, null, 2) : '无';
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function checkWidgetStatus() {
|
||||
console.log('======================================');
|
||||
console.log('Widget 状态检查');
|
||||
console.log('======================================');
|
||||
console.log('window.$chatwoot:', window.$chatwoot);
|
||||
console.log('window.chatwootSDK:', window.chatwootSDK);
|
||||
|
||||
if (window.$chatwoot) {
|
||||
console.log('✅ Widget 已加载');
|
||||
console.log('可用方法:', Object.getOwnPropertyNames(window.$chatwoot));
|
||||
document.getElementById('widgetStatus').textContent = '✅ 已加载';
|
||||
document.getElementById('widgetStatus').style.color = '#28a745';
|
||||
} else {
|
||||
console.log('❌ Widget 未加载');
|
||||
document.getElementById('widgetStatus').textContent = '❌ 未加载';
|
||||
document.getElementById('widgetStatus').style.color = '#dc3545';
|
||||
}
|
||||
|
||||
console.log('======================================');
|
||||
}
|
||||
|
||||
function clearLocalStorage() {
|
||||
if (confirm('确定要清除所有本地存储吗?这将重置会话。')) {
|
||||
// 清除 Chatwoot 相关的本地存储
|
||||
const keysToRemove = [];
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
keysToRemove.forEach(key => localStorage.removeItem(key));
|
||||
|
||||
console.log(`✅ 已清除 ${keysToRemove.length} 个本地存储项`);
|
||||
console.log('清除的键:', keysToRemove);
|
||||
|
||||
alert(`✅ 已清除 ${keysToRemove.length} 个本地存储项\n\n页面将重新加载以创建新的会话。`);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时显示本地存储和检查 Token
|
||||
window.addEventListener('load', function() {
|
||||
// 显示本地存储
|
||||
const storage = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key.includes('chatwoot') || key.includes('widget')) {
|
||||
storage[key] = localStorage.getItem(key);
|
||||
}
|
||||
}
|
||||
if (Object.keys(storage).length > 0) {
|
||||
document.getElementById('localStorageData').textContent = JSON.stringify(storage, null, 2);
|
||||
}
|
||||
|
||||
// 自动检查 Token
|
||||
setTimeout(checkToken, 500);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Chatwoot Widget -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="http://localhost:3000";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
// 获取 token 函数
|
||||
function getCookie(name) {
|
||||
const value = `; ${document.cookie}`;
|
||||
const parts = value.split(`; ${name}=`);
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
return null;
|
||||
}
|
||||
|
||||
const token = getCookie('token');
|
||||
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '39PNCMvbMk3NvB7uaDNucc6o',
|
||||
baseUrl: BASE_URL,
|
||||
locale: 'zh_CN',
|
||||
userIdentifier: token || 'web_user_' + Date.now()
|
||||
});
|
||||
|
||||
console.log('✅ Chatwoot Widget 已加载');
|
||||
console.log('Locale: zh_CN');
|
||||
console.log('User Identifier:', token || 'web_user_' + Date.now());
|
||||
|
||||
document.getElementById('widgetStatus').textContent = '✅ 已加载';
|
||||
document.getElementById('widgetStatus').style.color = '#28a745';
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user