fix: 修复 Persona Studio 对话无回复 · API代理层新增反向代理 + PM2配置补全 + 模块自检修复

问题根因:Nginx 将所有 /api/* 路由到 api-proxy (port 3721),但
api-proxy 未处理 /api/ps/chat/*, /api/ps/auth/* 等 Persona Studio
后端路由,导致请求返回 404,用户发送消息后无回复。

修复内容:
1. api-proxy.js 新增反向代理,将 /api/ps/chat/*, /api/ps/auth/*,
   /api/ps/build/*, /api/ps/notify/* 转发到 PS 后端 (port 3002)
2. ecosystem.config.js 补全 api-proxy + persona-studio PM2 配置
3. m15-cloud-drive/ 补全 README.md(模块自检修复)
4. README.md 开发者公告栏更新修复状态

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-10 14:38:17 +00:00
parent ae0e52029e
commit df64cb221d
5 changed files with 146 additions and 7 deletions

View File

@ -78,6 +78,8 @@
<!-- BINGSHUO_BULLETIN_START -->
| 时间 | 检查项 | 状态 |
|------|--------|------|
| 03-10 22:19 | 🔧 Persona Studio 对话修复 · API代理层新增反向代理 · `/api/ps/chat/*`,`/api/ps/auth/*`,`/api/ps/build/*`,`/api/ps/notify/*` → PS后端(port 3002) · PM2 配置补全 · `m15-cloud-drive/` README.md 补全 | 铸渊(冰朔指令) |
| 03-10 22:19 | ✅ 铸渊模块自检完成 · 发现 2 个问题 · 自动修复 2 项 | 铸渊自检 |
| 03-10 21:57 | 🔧 系统更新: `.github/` | 铸渊 (Copilot) |
| 03-10 21:57 | 🔧 系统更新: `scripts/` | 铸渊 (Copilot) |
| 03-10 21:54 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 |
@ -98,9 +100,12 @@
### 🤖 铸渊自动提醒
<!-- BINGSHUO_ALERT_START -->
> 🟢 **今日无需冰朔手动干预** · 系统一切正常
> 🟢 **铸渊模块自检完成 · 已自动修复 2 项**
>
> 🗓️ 2026-03-10 · 铸渊自动检测
> ✅ `api-proxy.js` 新增 Persona Studio 反向代理 · 修复对话无回复问题
> ✅ `m15-cloud-drive/` 补全 README.md
>
> 🗓️ 2026-03-10 · 铸渊自动修复
<!-- BINGSHUO_ALERT_END -->
---
@ -123,12 +128,11 @@
### 🤖 铸渊自动提醒 · 合作者
<!-- COLLABORATOR_ALERT_START -->
> 🔴 **以下合作者需要手动干预:**
> 🟢 **所有合作者模块自检通过** · 无需手动干预
>
> **🎨 燕樊DEV-003**
> - ⚠️ `m15-cloud-drive/` 缺少 README.md
> ✅ `m15-cloud-drive/` README.md 已由铸渊自动补全
>
> 🗓️ 2026-03-10 · 铸渊已发送邮件提醒
> 🗓️ 2026-03-10 · 铸渊自动修复
<!-- COLLABORATOR_ALERT_END -->
---

View File

@ -33,6 +33,11 @@ curl http://localhost:3721/api/models
| GET | `/api/health` | 健康检查 |
| POST | `/api/ps/apikey/detect-models` | 用户 API Key 模型检测Persona Studio |
| POST | `/api/ps/apikey/chat` | 用户 API Key 对话Persona Studio |
| POST | `/api/ps/chat/message` | 知秋对话(→ PS 后端 port 3002 |
| GET | `/api/ps/chat/history` | 对话历史(→ PS 后端 port 3002 |
| POST | `/api/ps/auth/login` | 开发编号登录(→ PS 后端 port 3002 |
| POST | `/api/ps/build/start` | 开发任务触发(→ PS 后端 port 3002 |
| POST | `/api/ps/notify/send` | 邮件通知(→ PS 后端 port 3002 |
### 环境变量
@ -45,6 +50,7 @@ curl http://localhost:3721/api/models
| `OPENAI_API_KEY` | OpenAI 密钥(需海外服务器) |
| `GEMINI_API_KEY` | Google Gemini 密钥(需海外服务器) |
| `PROXY_PORT` | 端口(默认 3721 |
| `PS_PORT` | Persona Studio 后端端口(默认 3002反向代理目标 |
| `RATE_LIMIT_RPM` | 频率限制(默认 10 次/分钟) |
### Nginx 配置

View File

@ -709,6 +709,74 @@ async function handleApiKeyChat(req, res) {
}
}
// ═══════════════════════════════════════════════════════
// Persona Studio 后端反向代理
// 将 /api/ps/chat/*, /api/ps/auth/*, /api/ps/build/*, /api/ps/notify/*
// 转发到 persona-studio 后端服务(默认端口 3002
// ═══════════════════════════════════════════════════════
const PS_BACKEND_PORT = parseInt(process.env.PS_PORT || '3002', 10);
const PS_PROXY_PATHS = ['/api/ps/chat/', '/api/ps/auth/', '/api/ps/build/', '/api/ps/notify/'];
function shouldProxyToPersonaStudio(pathname) {
return PS_PROXY_PATHS.some(prefix => pathname.startsWith(prefix));
}
function proxyToPersonaStudio(req, res, fullPath) {
return new Promise((resolve, reject) => {
const options = {
hostname: '127.0.0.1',
port: PS_BACKEND_PORT,
path: fullPath,
method: req.method,
headers: Object.assign({}, req.headers, {
host: '127.0.0.1:' + PS_BACKEND_PORT
}),
timeout: 60000
};
const proxyReq = http.request(options, (proxyRes) => {
// Forward status and headers (preserve CORS headers already set)
const headers = {};
for (const [key, value] of Object.entries(proxyRes.headers)) {
if (!key.startsWith('access-control-')) {
headers[key] = value;
}
}
res.writeHead(proxyRes.statusCode, headers);
proxyRes.pipe(res);
proxyRes.on('end', resolve);
proxyRes.on('error', reject);
});
proxyReq.on('error', (err) => {
console.error('[代理→PS] persona-studio 后端连接失败:', err.message);
if (!res.headersSent) {
jsonResponse(res, 502, {
error: true,
code: 'PS_BACKEND_UNAVAILABLE',
message: 'Persona Studio 后端服务不可用,请稍后重试'
});
}
resolve();
});
proxyReq.on('timeout', () => {
proxyReq.destroy();
if (!res.headersSent) {
jsonResponse(res, 504, {
error: true,
code: 'PS_BACKEND_TIMEOUT',
message: 'Persona Studio 后端响应超时'
});
}
resolve();
});
// Pipe the original request body to the proxy request
req.pipe(proxyReq);
});
}
// ═══════════════════════════════════════════════════════
// HTTP 服务器
// ═══════════════════════════════════════════════════════
@ -737,11 +805,13 @@ const server = http.createServer(async (req, res) => {
await handleDetectModels(req, res);
} else if (path === '/api/ps/apikey/chat' && req.method === 'POST') {
await handleApiKeyChat(req, res);
} else if (shouldProxyToPersonaStudio(path)) {
await proxyToPersonaStudio(req, res, url.pathname + url.search);
} else {
jsonResponse(res, 404, {
error: true,
code: 'NOT_FOUND',
message: '接口不存在。可用接口: POST /api/chat, GET /api/models, GET /api/health, POST /api/ps/apikey/detect-models, POST /api/ps/apikey/chat'
message: '接口不存在。可用接口: POST /api/chat, GET /api/models, GET /api/health, POST /api/ps/apikey/detect-models, POST /api/ps/apikey/chat, POST /api/ps/chat/message, GET /api/ps/chat/history, POST /api/ps/auth/login'
});
}
} catch (err) {
@ -781,11 +851,17 @@ server.listen(PORT, () => {
console.log(' export YUNWU_API_KEY=sk-xxx');
}
console.log(`\n Persona Studio 后端代理: http://127.0.0.1:${PS_BACKEND_PORT}`);
console.log(' 代理路径: /api/ps/chat/*, /api/ps/auth/*, /api/ps/build/*, /api/ps/notify/*');
console.log('\n 可用接口:');
console.log(' POST /api/chat — 聊天代理SSE 流式)');
console.log(' GET /api/models — 列出可用模型');
console.log(' GET /api/health — 健康检查');
console.log(' POST /api/ps/apikey/detect-models — 用户 API Key 模型检测');
console.log(' POST /api/ps/apikey/chat — 用户 API Key 对话');
console.log(' POST /api/ps/chat/message — 知秋对话(→ PS后端');
console.log(' GET /api/ps/chat/history — 对话历史(→ PS后端');
console.log(' POST /api/ps/auth/login — 登录校验(→ PS后端');
console.log('');
});

View File

@ -25,5 +25,33 @@ module.exports = {
error_file: 'logs/error.log',
out_file: 'logs/out.log',
},
{
name: 'api-proxy',
script: 'backend-integration/api-proxy.js',
instances: 1,
exec_mode: 'fork',
watch: false,
env: {
NODE_ENV: 'production',
PROXY_PORT: 3721,
},
log_date_format: 'YYYY-MM-DD HH:mm:ss',
error_file: 'logs/api-proxy-error.log',
out_file: 'logs/api-proxy-out.log',
},
{
name: 'persona-studio',
script: 'persona-studio/backend/server.js',
instances: 1,
exec_mode: 'fork',
watch: false,
env: {
NODE_ENV: 'production',
PS_PORT: 3002,
},
log_date_format: 'YYYY-MM-DD HH:mm:ss',
error_file: 'logs/persona-studio-error.log',
out_file: 'logs/persona-studio-out.log',
},
],
};

25
m15-cloud-drive/README.md Normal file
View File

@ -0,0 +1,25 @@
# M15 云盘系统
- 负责人燕樊DEV-003
- 状态:已毕业
- 技术栈HTML + CSS + JavaScript纯前端
- 依赖模块:无
## 功能说明
HoloLake 网站云盘系统前端界面,提供文件管理交互体验。
### 包含文件
| 文件 | 说明 |
|------|------|
| `cloud-drive.html` | 云盘主页面 |
| `cloud-drive.js` | 交互逻辑(文件夹切换、文件选中、上传等) |
| `cloud-drive-style.css` | 样式表 |
### 核心功能
- 📁 文件夹切换与导航
- 📄 文件列表展示与选中
- ⬆️ 文件上传交互
- 💾 存储用量展示