冰朔 bf6b5149e4
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled
D135b: Agent引擎 v2.0 · 注册系统 · 知识库对话服务
Agent引擎新增:
- /api/register: 用户注册(用户名+邮箱+密码→bcrypt→Dex密码库)
- /api/chat: 知识库对话(进度/人物/框架/导航查询)
- /api/agent-status: 五分身流水线状态
- /api/health: 健康检查

部署:
- BS-SG-001 · PM2 agent-engine · 端口3095
- Nginx: /register(注册页) + /register-api/(接口代理)
- URL: https://guanghubingshuo.com/register
2026-06-18 15:40:53 +08:00

226 lines
7.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 光湖Agent引擎 · 知识库对话服务
* BS-SG-001 · 铸渊 ICE-GL-ZY001 · D135b
*
* 连接: 代码仓库 ↔ Outline知识库 ↔ 冰朔对话
*
* 功能:
* /api/chat → 对话查询读代码仓库·Outline·数据库
* /api/health → 健康检查
* /api/agent-status → 查看五分身流水线状态
*/
const express = require('express');
const cors = require('cors');
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3095;
app.use(express.json());
app.use(cors());
const REPO_ROOT = '/opt/zhuyuan/guanghulab';
const OUTLINE_URL = process.env.OUTLINE_URL || 'http://127.0.0.1:3090';
// ============ 知识库导航 ============
function scanRepo() {
const dataDir = path.join(REPO_ROOT, 'video-ai-system/data');
const brainDir = path.join(REPO_ROOT, 'brain/fifth-domain/zero-point/zhuyuan/causal-chains');
const result = { projects: [], chains: [], agents: [] };
// Scan video AI data
try {
const files = fs.readdirSync(dataDir);
for (const f of files) {
if (f.endsWith('.json') && f.startsWith('ep')) {
result.projects.push({ file: f, type: 'output' });
}
}
} catch(e) {}
// Scan causal chains
try {
const chains = fs.readdirSync(brainDir);
for (const c of chains) {
if (c.endsWith('.hdlp')) {
result.chains.push({ file: c });
}
}
} catch(e) {}
// Scan agent configs
try {
const agentDir = path.join(REPO_ROOT, 'video-ai-system/config/agents');
const agents = fs.readdirSync(agentDir);
for (const a of agents) {
result.agents.push({ file: a });
}
} catch(e) {}
return result;
}
function getPipelineStatus() {
const dataDir = path.join(REPO_ROOT, 'video-ai-system/data');
const status = {
episode1: { agents: {} },
};
const fileStatus = {
'ep01-scenes.json': 'Agent_01 · 拆文',
'ep01-storyboard.json': 'Agent_03 · 分镜',
'ep01-prompts.json': 'Agent_04 · 提示词',
'ep01-audit.json': 'Agent_05 · 审核',
};
for (const [file, agent] of Object.entries(fileStatus)) {
const filePath = path.join(dataDir, file);
status.episode1.agents[agent] = fs.existsSync(filePath) ? '✅ 完成' : '⏳ 待执行';
}
// Check characters.hdlp for Agent_02
const charPath = path.join(REPO_ROOT, 'video-ai-system/data/characters.hdlp');
status.episode1.agents['Agent_02 · 编号'] = fs.existsSync(charPath) ? '✅ 完成' : '⏳';
return status;
}
// ============ 简单意图路由 ============
function routeIntent(message) {
const lower = message.toLowerCase();
// Pipeline status
if (/进度|状态|流水线|第几集|做到哪/.test(message)) {
return getPipelineStatus();
}
// Character query
if (/人物|角色|CHAR|苏白|诸葛风|萧灵汐/.test(message)) {
try {
const chars = fs.readFileSync(
path.join(REPO_ROOT, 'video-ai-system/data/characters.hdlp'), 'utf8');
return { type: 'characters', content: chars.substring(0, 3000) };
} catch(e) { return { error: '读取人物库失败' }; }
}
// Framework query
if (/框架|规则|agent|分身|硬骨架/.test(message)) {
try {
const framework = fs.readFileSync(
path.join(REPO_ROOT, 'video-ai-system/config/PROJECT-FRAMEWORK.hdlp'), 'utf8');
return { type: 'framework', content: framework.substring(0, 3000) };
} catch(e) { return { error: '读取框架失败' }; }
}
// Navigation
if (/有什么|导航|目录|结构/.test(message)) {
return { type: 'navigation', content: scanRepo() };
}
// Fallback
return {
type: 'help',
content: '铸渊Agent引擎在线。你可以问我\n• 流水线进度\n• 人物档案\n• 框架规则\n• 项目导航',
navigation: scanRepo()
};
}
// ============ API ============
app.post('/api/chat', (req, res) => {
const { message } = req.body;
if (!message) return res.status(400).json({ error: '需要消息' });
const response = routeIntent(message);
res.json({
reply: typeof response.content === 'string' ? response.content : JSON.stringify(response, null, 2),
structured: response
});
});
app.get('/api/health', (req, res) => {
res.json({
ok: true,
service: 'zhuyuan-agent-engine',
version: 'v1.0',
repo: fs.existsSync(REPO_ROOT) ? 'connected' : 'missing',
outline: OUTLINE_URL
});
});
app.get('/api/agent-status', (req, res) => {
res.json(getPipelineStatus());
});
// ============ 注册系统 ============
const bcrypt = require('bcryptjs');
const { execSync: dexExecSync } = require('child_process');
const DEX_DB_HOST = '/opt/outline/dex-data/dex.db';
app.post('/api/register', (req, res) => {
const { username, email, password } = req.body;
if (!username || username.length < 2) return res.status(400).json({ ok: false, error: '用户名至少2个字符' });
if (!email || !email.includes('@')) return res.status(400).json({ ok: false, error: '无效邮箱' });
if (!password || password.length < 8) return res.status(400).json({ ok: false, error: '密码至少8位' });
try {
// Hash password
const hash = bcrypt.hashSync(password, 10);
const userId = 'user-' + Date.now().toString(36) + '-' + Math.random().toString(36).substring(2, 8);
// Use Python3 + sqlite3 to write to Dex database
// Steps: 1) docker cp db out, 2) python modify, 3) docker cp back, 4) restart dex
const safeEmail = email.replace(/'/g, "''");
const safeHash = hash.replace(/'/g, "''");
const safeUser = username.replace(/'/g, "''");
const script = `
import sqlite3, sys
db = sqlite3.connect('${DEX_DB_HOST}')
try:
db.execute("CREATE TABLE IF NOT EXISTS password (email TEXT PRIMARY KEY, hash TEXT, username TEXT, user_id TEXT)")
existing = db.execute("SELECT email FROM password WHERE email=?", ('${safeEmail}',)).fetchone()
if existing:
print('EXISTS')
sys.exit(1)
db.execute("INSERT INTO password (email, hash, username, user_id) VALUES (?,?,?,?)",
('${safeEmail}', '${safeHash}', '${safeUser}', '${userId}'))
db.commit()
print('OK')
finally:
db.close()
`;
dexExecSync(`docker cp outline-dex:/tmp/dex.db ${DEX_DB_HOST} 2>/dev/null || true`);
const result = dexExecSync(`python3 -c "${script.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`,
{ timeout: 5000, encoding: 'utf8' }).trim();
if (result === 'EXISTS') {
return res.status(400).json({ ok: false, error: '该邮箱已注册' });
}
if (result !== 'OK') {
throw new Error('Python script failed: ' + result);
}
dexExecSync(`docker cp ${DEX_DB_HOST} outline-dex:/tmp/dex.db`);
dexExecSync('docker restart outline-dex 2>/dev/null');
console.log(`[注册] 新用户: ${username} <${email}>`);
res.json({ ok: true, message: '注册成功', userId });
} catch(e) {
console.error('[注册失败]', e.message);
res.status(500).json({ ok: false, error: '服务器错误:' + e.message });
}
});
app.listen(PORT, '127.0.0.1', () => {
console.log(`[Agent引擎] 启动 · 端口${PORT} · 仓库${REPO_ROOT}`);
});