From 3fedcab0d9823b36b08dc8555329d700dac05775 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:48:27 +0000 Subject: [PATCH] fix: ecosystem.config.js .env.app path + portal reconnect button + /api/chat/reconnect endpoint Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/37db3285-91fb-4df3-83a0-7315b0efa428 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- server/app/server.js | 67 +++++++++++++++++++++ server/ecosystem.config.js | 6 +- server/sites/portal/index.html | 104 ++++++++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 4 deletions(-) diff --git a/server/app/server.js b/server/app/server.js index 2d4c3493..e77c1dab 100644 --- a/server/app/server.js +++ b/server/app/server.js @@ -304,6 +304,73 @@ app.post('/api/chat', async (req, res) => { } }); +// ─── 铸渊重连测试 · 用户主动触发 ─── +app.post('/api/chat/reconnect', async (_req, res) => { + try { + // 检测国内模型网关可用性 + if (domesticGateway) { + const gwStats = domesticGateway.getGatewayStats(); + if (gwStats.availableModels > 0) { + // 发送一条简短测试消息验证真实连通性 + try { + const testResult = await domesticGateway.chat('reconnect-test', '你好'); + if (testResult.success) { + return res.json({ + success: true, + connected: true, + engine: 'domestic-gateway', + message: '🌊 铸渊已重新连接!大模型通道畅通。' + }); + } + } catch (gwTestErr) { + console.error(`[重连] 国内网关测试失败: ${gwTestErr.message}`); + } + } + } + + // 降级到通用聊天引擎测试 + if (chatEngine) { + try { + const testResult = await chatEngine.chat('reconnect-test', '你好'); + if (testResult.message && testResult.model !== 'offline') { + return res.json({ + success: true, + connected: true, + engine: 'chat-engine', + message: '🌊 铸渊已重新连接!通用通道畅通。' + }); + } + } catch (ceTestErr) { + console.error(`[重连] 通用引擎测试失败: ${ceTestErr.message}`); + } + } + + // 所有通道都不可用 + // 检查环境变量配置状态(不暴露实际密钥值) + const envStatus = { + deepseek: !!(process.env.ZY_DEEPSEEK_API_KEY && process.env.ZY_DEEPSEEK_API_KEY.length > 5), + qianwen: !!(process.env.ZY_QIANWEN_API_KEY && process.env.ZY_QIANWEN_API_KEY.length > 5), + kimi: !!(process.env.ZY_KIMI_API_KEY && process.env.ZY_KIMI_API_KEY.length > 5), + qingyan: !!(process.env.ZY_QINGYAN_API_KEY && process.env.ZY_QINGYAN_API_KEY.length > 5), + zy_llm: !!(process.env.ZY_LLM_API_KEY && process.env.ZY_LLM_API_KEY.length > 5) + }; + + const configuredCount = Object.values(envStatus).filter(Boolean).length; + + res.json({ + success: true, + connected: false, + engine: 'none', + keys_configured: configuredCount, + message: configuredCount > 0 + ? '⚠️ API密钥已配置(' + configuredCount + '个),但连接测试未通过。可能是网络或密钥过期问题。' + : '⚠️ 未检测到API密钥配置。请确认服务器环境变量已正确注入。' + }); + } catch (err) { + res.status(500).json({ error: true, message: '重连测试异常: ' + err.message }); + } +}); + // ─── 聊天统计 ─── app.get('/api/chat/stats', (_req, res) => { if (chatEngine) { diff --git a/server/ecosystem.config.js b/server/ecosystem.config.js index 61d02e08..725953e4 100644 --- a/server/ecosystem.config.js +++ b/server/ecosystem.config.js @@ -34,7 +34,11 @@ function loadEnvFile(filePath) { } // 加载主应用环境变量(包含LLM API密钥) -const appEnv = loadEnvFile(path.join(__dirname, '.env.app')); +// 注意: ecosystem.config.js 部署到 /opt/zhuyuan/config/pm2/ +// 但 .env.app 在 /opt/zhuyuan/app/ — 优先从应用目录读取 +const appEnvAbsolute = loadEnvFile('/opt/zhuyuan/app/.env.app'); +const appEnvRelative = loadEnvFile(path.join(__dirname, '.env.app')); +const appEnv = Object.keys(appEnvAbsolute).length > 0 ? appEnvAbsolute : appEnvRelative; module.exports = { apps: [ diff --git a/server/sites/portal/index.html b/server/sites/portal/index.html index bd40a9de..c9416f8e 100644 --- a/server/sites/portal/index.html +++ b/server/sites/portal/index.html @@ -244,6 +244,21 @@ a:hover{color:var(--glow-purple)} cursor:pointer;font-size:16px;transition:all .2s;display:flex;align-items:center;justify-content:center} .chat-send-btn:hover{transform:scale(1.05)} .chat-send-btn:disabled{opacity:.5;cursor:not-allowed;transform:none} +/* 重连按钮 */ +.chat-reconnect-area{padding:8px 16px;border-top:1px solid var(--glass-border);display:flex;align-items:center;gap:8px} +.chat-api-status{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text-dim);flex:1} +.chat-api-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0} +.chat-api-dot.online{background:#22d3ee;box-shadow:0 0 6px rgba(34,211,238,0.6)} +.chat-api-dot.offline{background:#f87171;box-shadow:0 0 6px rgba(248,113,113,0.4)} +.chat-api-dot.testing{background:#fbbf24;animation:blink 1s ease-in-out infinite} +@keyframes blink{0%,100%{opacity:1}50%{opacity:.3}} +.chat-reconnect-btn{ + background:linear-gradient(135deg,rgba(34,211,238,0.2),rgba(167,139,250,0.2)); + border:1px solid rgba(34,211,238,0.3);color:var(--glow-cyan); + padding:5px 12px;border-radius:8px;cursor:pointer;font-size:12px; + white-space:nowrap;transition:all .2s} +.chat-reconnect-btn:hover{background:linear-gradient(135deg,rgba(34,211,238,0.3),rgba(167,139,250,0.3));transform:scale(1.02)} +.chat-reconnect-btn:disabled{opacity:.5;cursor:not-allowed;transform:none} /* ═══ 页脚 ═══ */ .footer{ @@ -454,6 +469,13 @@ a:hover{color:var(--glow-purple)} onkeydown="if(event.key==='Enter')sendMessage()" autocomplete="off"> +
+
+ + 检测中… +
+ +