refactor: DevTools → ethend 重命名 + 加入生产环境
- 目录 devtools/ → ethend/ - CLI 脚本 devtools.sh/.bat → ethend.sh/.bat - 环境变量 DEVTOOLS_PORT → ETHEND_PORT - docker-compose.yml 新增 ethend 服务(生产部署) - 同步更新全部文档、注释和配置文件 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* 管理控制台配置
|
||||
* 定义各服务的启动参数、端口、健康检查等
|
||||
*/
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const ROOT = path.resolve(__dirname, '../..');
|
||||
|
||||
const isWin = os.platform() === 'win32';
|
||||
|
||||
// 读取 backend/.env 文件,将值合并到 process.env(不覆盖已有的环境变量)
|
||||
// 这样 ethend 启动各服务时能传递用户配置的凭据
|
||||
function loadEnvFile() {
|
||||
const envPath = path.join(ROOT, 'backend', '.env');
|
||||
try {
|
||||
const content = fs.readFileSync(envPath, 'utf-8');
|
||||
for (const line of content.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const eqIdx = trimmed.indexOf('=');
|
||||
if (eqIdx === -1) continue;
|
||||
const key = trimmed.substring(0, eqIdx).trim();
|
||||
const val = trimmed.substring(eqIdx + 1).trim();
|
||||
if (key && val !== undefined) {
|
||||
process.env[key] = process.env[key] || val;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// .env 文件不存在,使用默认值
|
||||
}
|
||||
}
|
||||
loadEnvFile();
|
||||
|
||||
/** 跨平台 Go 二进制路径 */
|
||||
function findGoBin() {
|
||||
// 优先使用环境变量
|
||||
if (process.env.GOROOT) return path.join(process.env.GOROOT, 'bin', 'go');
|
||||
// Windows 常见路径
|
||||
const candidates = isWin
|
||||
? ['C:\\Program Files\\Go\\bin\\go.exe', 'C:\\Go\\bin\\go.exe', 'go']
|
||||
: ['/usr/local/go/bin/go', '/usr/bin/go', 'go'];
|
||||
for (const p of candidates) {
|
||||
if (p === 'go' || fs.existsSync(p)) return p;
|
||||
}
|
||||
return 'go';
|
||||
}
|
||||
|
||||
const GO_BIN = findGoBin();
|
||||
|
||||
export const ETHEND_PORT = process.env.ETHEND_PORT || 9090;
|
||||
export const LOGS_DIR = path.resolve(__dirname, '../logs');
|
||||
export const GATEWAY_URL = process.env.GATEWAY_URL || 'http://localhost:8080';
|
||||
export const PLUGIN_MANAGER_URL = process.env.PLUGIN_MANAGER_URL || 'http://localhost:8094';
|
||||
export const ADMIN_USERNAME = process.env.ADMIN_USERNAME || 'admin';
|
||||
export const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'cyrene-dev-admin';
|
||||
|
||||
export const SERVICES = {
|
||||
'ai-core': {
|
||||
name: 'AI-Core',
|
||||
cwd: path.join(ROOT, 'backend/ai-core'),
|
||||
command: './main',
|
||||
env: {
|
||||
AI_CORE_PORT: '8081',
|
||||
PERSONA_DIR: './internal/persona',
|
||||
SEARXNG_URL: process.env.SEARXNG_URL || 'http://localhost:8088',
|
||||
IOT_SERVICE_URL: process.env.IOT_SERVICE_URL || process.env.IOT_DEBUG_SERVICE_URL || 'http://localhost:8083',
|
||||
ENABLE_BACKGROUND_THINKING: process.env.ENABLE_BACKGROUND_THINKING || 'true',
|
||||
},
|
||||
healthUrl: 'http://localhost:8081/api/v1/health',
|
||||
port: 8081,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'iot-debug-service': {
|
||||
name: 'IoT Debug',
|
||||
cwd: path.join(ROOT, 'backend/iot-debug-service'),
|
||||
command: './main',
|
||||
env: {
|
||||
IOT_DEBUG_PORT: '8083',
|
||||
},
|
||||
healthUrl: 'http://localhost:8083/api/v1/health',
|
||||
port: 8083,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
gateway: {
|
||||
name: 'Gateway',
|
||||
cwd: path.join(ROOT, 'backend/gateway'),
|
||||
command: './main',
|
||||
env: {
|
||||
GATEWAY_PORT: '8080',
|
||||
JWT_SECRET: process.env.JWT_SECRET || 'dev-secret-key-change-me',
|
||||
AI_CORE_URL: 'http://localhost:8081',
|
||||
MEMORY_SERVICE_URL: process.env.MEMORY_SERVICE_URL || 'http://localhost:8091',
|
||||
ADMIN_USERNAME: process.env.ADMIN_USERNAME || 'admin',
|
||||
ADMIN_PASSWORD: process.env.ADMIN_PASSWORD || 'cyrene-dev-admin',
|
||||
REGISTRATION_ENABLED: process.env.REGISTRATION_ENABLED || 'true',
|
||||
},
|
||||
healthUrl: 'http://localhost:8080/api/v1/health',
|
||||
port: 8080,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'memory-service': {
|
||||
name: '记忆服务',
|
||||
cwd: path.join(ROOT, 'backend/memory-service'),
|
||||
command: './main',
|
||||
env: {
|
||||
PORT: '8091',
|
||||
DB_URL: process.env.DB_URL || 'postgres://cyrene:cyrene_pass@localhost:5432/cyrene_ai?sslmode=disable',
|
||||
},
|
||||
healthUrl: 'http://localhost:8091/api/v1/health',
|
||||
port: 8091,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'voice-service': {
|
||||
name: '语音识别服务',
|
||||
cwd: path.join(ROOT, 'backend/voice-service'),
|
||||
command: './main',
|
||||
env: {
|
||||
PORT: '8093',
|
||||
WHISPER_BINARY: './whisper.cpp/main',
|
||||
WHISPER_MODEL: './whisper.cpp/models/ggml-small.bin',
|
||||
WHISPER_LANGUAGE: 'zh',
|
||||
DASHSCOPE_API_KEY: process.env.DASHSCOPE_API_KEY || '',
|
||||
DASHSCOPE_STT_MODEL: 'gummy-chat-v1',
|
||||
},
|
||||
healthUrl: 'http://localhost:8093/api/v1/health',
|
||||
port: 8093,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'plugin-manager': {
|
||||
name: '插件管理器',
|
||||
cwd: path.join(ROOT, 'backend/plugin-manager'),
|
||||
command: './main',
|
||||
env: {
|
||||
PORT: '8094',
|
||||
IOT_SERVICE_URL: process.env.IOT_SERVICE_URL || process.env.IOT_DEBUG_SERVICE_URL || 'http://localhost:8083',
|
||||
},
|
||||
healthUrl: 'http://localhost:8094/api/v1/health',
|
||||
port: 8094,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'platform-bridge': {
|
||||
name: '多平台桥接',
|
||||
cwd: path.join(ROOT, 'backend/platform-bridge'),
|
||||
command: './main',
|
||||
env: {
|
||||
PORT: '8095',
|
||||
AI_CORE_URL: 'http://localhost:8081',
|
||||
QQ_BOT_PORT: process.env.QQ_BOT_PORT || '8096',
|
||||
TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN || '',
|
||||
TELEGRAM_WEBHOOK_URL: process.env.TELEGRAM_WEBHOOK_URL || '',
|
||||
QQ_ADMIN_UID: process.env.QQ_ADMIN_UID || '',
|
||||
TELEGRAM_ADMIN_UID: process.env.TELEGRAM_ADMIN_UID || '',
|
||||
},
|
||||
healthUrl: 'http://localhost:8095/health',
|
||||
port: 8095,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
frontend: {
|
||||
name: 'Frontend',
|
||||
cwd: path.join(ROOT, 'frontend/web'),
|
||||
command: 'npx',
|
||||
args: ['vite', '--host', '0.0.0.0'],
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
},
|
||||
healthUrl: 'http://localhost:5173',
|
||||
port: 5173,
|
||||
nodeBin: 'node',
|
||||
npmBin: 'npx',
|
||||
// frontend不需要预编译,dev server即可
|
||||
buildCommand: null,
|
||||
},
|
||||
};
|
||||
|
||||
/** 各服务默认的日志文件路径 */
|
||||
export function logFile(serviceId) {
|
||||
return path.join(LOGS_DIR, `${serviceId}.log`);
|
||||
}
|
||||
Reference in New Issue
Block a user