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:
2026-05-30 09:32:36 +08:00
parent 27187997b3
commit 365f5ceb2f
30 changed files with 455 additions and 189 deletions
+3
View File
@@ -45,6 +45,9 @@ ENABLE_BACKGROUND_THINKING=true
# ========== Webhook(可选) ========== # ========== Webhook(可选) ==========
WEBHOOK_API_KEY= WEBHOOK_API_KEY=
# ========== 管理控制台端口 ==========
ETHEND_PORT=9090
# ========== 反向代理端口(避免与已有 nginx 等服务冲突) ========== # ========== 反向代理端口(避免与已有 nginx 等服务冲突) ==========
CADDY_HTTP_PORT=80 CADDY_HTTP_PORT=80
CADDY_HTTPS_PORT=443 CADDY_HTTPS_PORT=443
+4 -4
View File
@@ -59,10 +59,10 @@ docs/*
debug/cache/ debug/cache/
debug/logs/ debug/logs/
# ========== DevTools 运行时 ========== # ========== ethend 运行时 ==========
devtools/node_modules/ ethend/node_modules/
devtools/logs/ ethend/logs/
devtools/package-lock.json ethend/package-lock.json
# ========== 语音服务外部依赖 (C++ 编译产物 / 模型文件) ========== # ========== 语音服务外部依赖 (C++ 编译产物 / 模型文件) ==========
backend/voice-service/whisper.cpp/ backend/voice-service/whisper.cpp/
+32 -32
View File
@@ -1,6 +1,6 @@
# Cyrene 部署指南 # Cyrene 部署指南
三种方式启动开发环境:**DevTools 一键**(推荐)、**手动逐服务**、**Docker Compose**。 三种方式启动开发环境:**ethend 一键**(推荐)、**手动逐服务**、**Docker Compose**。
--- ---
@@ -9,9 +9,9 @@
| 依赖 | 版本 | 用途 | | 依赖 | 版本 | 用途 |
|------|------|------| |------|------|------|
| Go | 1.21+ | 编译后端服务 | | Go | 1.21+ | 编译后端服务 |
| Node.js | 20+ (LTS) | 前端 / DevTools | | Node.js | 20+ (LTS) | 前端 / ethend |
| Docker & Docker Compose | — | 数据库 & 基础设施 | | Docker & Docker Compose | — | 数据库 & 基础设施 |
| Git Bash (Windows) | — | 运行 devtools.sh | | Git Bash (Windows) | — | 运行 ethend.sh |
### Windows 额外要求 ### Windows 额外要求
@@ -23,14 +23,14 @@ Windows 提供两个启动脚本:
| 脚本 | 终端 | 适用场景 | | 脚本 | 终端 | 适用场景 |
|------|------|----------| |------|------|----------|
| `devtools.bat` | CMD / PowerShell | 双击运行,无需 Git Bash | | `ethend.bat` | CMD / PowerShell | 双击运行,无需 Git Bash |
| `devtools.sh` | Git Bash | 完整 CLI 体验(推荐) | | `ethend.sh` | Git Bash | 完整 CLI 体验(推荐) |
两者支持相同的命令集,日常开发推荐使用 Git Bash 运行 `./devtools.sh`;快速启动可直接双击 `devtools.bat` 两者支持相同的命令集,日常开发推荐使用 Git Bash 运行 `./ethend.sh`;快速启动可直接双击 `ethend.bat`
--- ---
## 方式一:DevTools 一键启动(推荐) ## 方式一:ethend 一键启动(推荐)
### 1. 配置环境变量 ### 1. 配置环境变量
@@ -44,13 +44,13 @@ cp backend/.env.example backend/.env
### 2. 启动数据库 ### 2. 启动数据库
```bash ```bash
./devtools.sh db:start ./ethend.sh db:start
``` ```
### 3. 编译并启动全部服务 ### 3. 编译并启动全部服务
```bash ```bash
./devtools.sh start --build ./ethend.sh start --build
``` ```
首次运行会编译全部后端 Go 服务(约 1-2 分钟),之后按依赖顺序启动全部服务,每步等待健康检查通过。 首次运行会编译全部后端 Go 服务(约 1-2 分钟),之后按依赖顺序启动全部服务,每步等待健康检查通过。
@@ -59,10 +59,10 @@ cp backend/.env.example backend/.env
| 地址 | 说明 | | 地址 | 说明 |
|------|------| |------|------|
| `http://localhost:9090` | DevTools 管理面板 | | `http://localhost:9090` | ethend 管理面板 |
| `http://localhost:5173` | 前端聊天界面 | | `http://localhost:5173` | 前端聊天界面 |
详细 CLI 用法见 [docs/api/devtools.md](docs/api/devtools.md)。 详细 CLI 用法见 [docs/api/ethend.md](docs/api/ethend.md)。
--- ---
@@ -111,7 +111,7 @@ cd frontend/web && npm install && npx vite --host 0.0.0.0
docker compose -f docker-compose.dev.yml up -d docker compose -f docker-compose.dev.yml up -d
``` ```
启动服务:postgres, redis, qdrant, minio, searxng, memory-service, voice-service, iot-debug-service, ai-core, gateway, devtools。前端需本地启动。 启动服务:postgres, redis, qdrant, minio, searxng, memory-service, voice-service, iot-debug-service, ai-core, gateway, ethend。前端需本地启动。
### 生产环境 ### 生产环境
@@ -140,16 +140,16 @@ Cyrene/
│ ├── voice-service/ # 语音服务 (DashScope STT + Edge-TTS) │ ├── voice-service/ # 语音服务 (DashScope STT + Edge-TTS)
│ ├── iot-debug-service/ # IoT 调试服务 (8 个模拟智能家居设备) │ ├── iot-debug-service/ # IoT 调试服务 (8 个模拟智能家居设备)
│ └── pkg/ # 共享包 (logger, plugins — 15 个通用插件/工具) │ └── pkg/ # 共享包 (logger, plugins — 15 个通用插件/工具)
├── devtools/ # DevTools 管理面板 (Express + WebSocket) ├── ethend/ # ethend 管理面板 (Express + WebSocket)
├── scripts/ # 辅助脚本 (migrate / tunnel / whisper-setup / pg-backup) ├── scripts/ # 辅助脚本 (migrate / tunnel / whisper-setup / pg-backup)
├── searxng/ # SearXNG 搜索引擎配置 ├── searxng/ # SearXNG 搜索引擎配置
├── backups/ # 数据库备份文件 ├── backups/ # 数据库备份文件
├── test/ # E2E 测试 ├── test/ # E2E 测试
├── docs/ # 文档 ├── docs/ # 文档
├── docker-compose.dev.db.yml # 开发基础设施 ├── docker-compose.dev.db.yml # 开发基础设施
├── docker-compose.dev.yml # 开发环境 (DB + 后端 + DevTools + SearXNG) ├── docker-compose.dev.yml # 开发环境 (DB + 后端 + ethend + SearXNG)
├── docker-compose.yml # 生产环境 (+ Caddy) ├── docker-compose.yml # 生产环境 (+ Caddy)
└── devtools.sh # DevTools CLI └── ethend.sh # ethend CLI
``` ```
--- ---
@@ -165,7 +165,7 @@ Cyrene/
| 8091 | Memory Service | 否 | | 8091 | Memory Service | 否 |
| 8088 | SearXNG | 否 | | 8088 | SearXNG | 否 |
| 8093 | Voice Service | 否 | | 8093 | Voice Service | 否 |
| 9090 | DevTools | 是 | | 9090 | ethend | 是 |
| 5432 | PostgreSQL | 否 | | 5432 | PostgreSQL | 否 |
| 6379 | Redis | 否 | | 6379 | Redis | 否 |
| 6333 | Qdrant HTTP | 否 | | 6333 | Qdrant HTTP | 否 |
@@ -239,10 +239,10 @@ Cyrene/
## 数据库管理 ## 数据库管理
```bash ```bash
# 通过 DevTools CLI # 通过 ethend CLI
./devtools.sh db:start # 启动 ./ethend.sh db:start # 启动
./devtools.sh db:stop # 停止 ./ethend.sh db:stop # 停止
./devtools.sh db:status # 状态检查 ./ethend.sh db:status # 状态检查
# 直接 Docker Compose # 直接 Docker Compose
docker compose -f docker-compose.dev.db.yml up -d docker compose -f docker-compose.dev.db.yml up -d
@@ -280,23 +280,23 @@ docker exec -it cyrene_postgres psql -U cyrene -d cyrene_ai
| 脚本 | 终端 | 说明 | | 脚本 | 终端 | 说明 |
|------|------|------| |------|------|------|
| `devtools.bat` | CMD / PowerShell | 双击即可运行,无需 Git Bash | | `ethend.bat` | CMD / PowerShell | 双击即可运行,无需 Git Bash |
| `devtools.sh` | Git Bash | 完整 CLI(推荐) | | `ethend.sh` | Git Bash | 完整 CLI(推荐) |
```cmd ```cmd
:: CMD 中直接运行 :: CMD 中直接运行
devtools.bat start --build ethend.bat start --build
devtools.bat status ethend.bat status
devtools.bat logs gateway ethend.bat logs gateway
:: Git Bash 中运行 :: Git Bash 中运行
./devtools.sh start --build ./ethend.sh start --build
./devtools.sh status ./ethend.sh status
``` ```
### 编译差异 ### 编译差异
Windows 下 Go 编译产物为 `main.exe` 而非 `main`DevTools 已自动处理此差异,手动编译时需要注意: Windows 下 Go 编译产物为 `main.exe` 而非 `main`ethend 已自动处理此差异,手动编译时需要注意:
```bash ```bash
# Windows (Git Bash / PowerShell) # Windows (Git Bash / PowerShell)
@@ -325,9 +325,9 @@ netstat -ano | findstr ":8080"
# 杀进程 (PowerShell) # 杀进程 (PowerShell)
powershell -Command "Stop-Process -Id <PID> -Force" powershell -Command "Stop-Process -Id <PID> -Force"
# 或者直接用 DevTools CLI(跨平台兼容) # 或者直接用 ethend CLI(跨平台兼容)
./devtools.sh status # 查看各服务端口状态 ./ethend.sh status # 查看各服务端口状态
./devtools.sh stop # 停止 DevTools ./ethend.sh stop # 停止 ethend
``` ```
### Docker Desktop ### Docker Desktop
@@ -361,7 +361,7 @@ export PATH="$PATH:/c/Program Files/nodejs"
| 症状 | 可能原因 | 解决 | | 症状 | 可能原因 | 解决 |
|------|----------|------| |------|----------|------|
| `go: command not found` | Go 未加入 PATH | 重启 Git Bash 或手动 `export PATH` | | `go: command not found` | Go 未加入 PATH | 重启 Git Bash 或手动 `export PATH` |
| `Only one usage of each socket address` | 端口被占用 | `./devtools.sh stop` 或用 PowerShell 杀进程 | | `Only one usage of each socket address` | 端口被占用 | `./ethend.sh stop` 或用 PowerShell 杀进程 |
| `docker: error during connect` | Docker Desktop 未启动 | 启动 Docker Desktop 等待就绪 | | `docker: error during connect` | Docker Desktop 未启动 | 启动 Docker Desktop 等待就绪 |
| `GOWORK` 相关编译错误 | 未设置 GOWORK=off | `export GOWORK=off` 或在命令前加 `GOWORK=off` | | `GOWORK` 相关编译错误 | 未设置 GOWORK=off | `export GOWORK=off` 或在命令前加 `GOWORK=off` |
| `npm install` 卡住 | Windows 下 npm 网络问题 | 设置镜像 `npm config set registry https://registry.npmmirror.com` | | `npm install` 卡住 | Windows 下 npm 网络问题 | 设置镜像 `npm config set registry https://registry.npmmirror.com` |
+7 -7
View File
@@ -19,7 +19,7 @@
| 前端配置文件 | `frontend/web/vite.config.ts`, `frontend/web/tsconfig.json`, `frontend/web/tailwind.config.ts` 等 | 构建和样式配置 | | 前端配置文件 | `frontend/web/vite.config.ts`, `frontend/web/tsconfig.json`, `frontend/web/tailwind.config.ts` 等 | 构建和样式配置 |
| 前端入口 | `frontend/web/index.html` | HTML 入口 | | 前端入口 | `frontend/web/index.html` | HTML 入口 |
| 公共资源 | `frontend/web/public/` | 静态资源(头像、背景图、manifest 等) | | 公共资源 | `frontend/web/public/` | 静态资源(头像、背景图、manifest 等) |
| DevTools | `devtools/` | 管理面板源码 | | ethend | `ethend/` | 管理面板源码 |
| Python 测试脚本 | `debug/cache/*.py` | 调试和端到端测试脚本 | | Python 测试脚本 | `debug/cache/*.py` | 调试和端到端测试脚本 |
| Shell 调试脚本 | `debug/*.sh`, `debug/*.mjs` | Chromium 调试、诊断脚本 | | Shell 调试脚本 | `debug/*.sh`, `debug/*.mjs` | Chromium 调试、诊断脚本 |
| 项目配置 | `.editorconfig`, `.gitignore`, `package.json` 等 | 项目级配置 | | 项目配置 | `.editorconfig`, `.gitignore`, `package.json` 等 | 项目级配置 |
@@ -36,7 +36,7 @@
|------|----------|------| |------|----------|------|
| 编译后的 Go 二进制 | `main`, `backend/*/main`, `backend/*/cmd/*` (不含 `.go`) | 平台相关,需在 Windows 重新编译 | | 编译后的 Go 二进制 | `main`, `backend/*/main`, `backend/*/cmd/*` (不含 `.go`) | 平台相关,需在 Windows 重新编译 |
| Windows 可执行文件 | `*.exe` | 旧的 Windows 编译产物 | | Windows 可执行文件 | `*.exe` | 旧的 Windows 编译产物 |
| Node.js 依赖 | `node_modules/`, `frontend/web/node_modules/`, `frontend/node_modules/`, `devtools/node_modules/` | 体积大,通过 `npm install` 重新安装 | | Node.js 依赖 | `node_modules/`, `frontend/web/node_modules/`, `frontend/node_modules/`, `ethend/node_modules/` | 体积大,通过 `npm install` 重新安装 |
| 前端构建产物 | `frontend/web/dist/` | 通过 `npm run build` 重新构建 | | 前端构建产物 | `frontend/web/dist/` | 通过 `npm run build` 重新构建 |
| 敏感配置文件 | `backend/.env` | 包含 API 密钥和密码 | | 敏感配置文件 | `backend/.env` | 包含 API 密钥和密码 |
| 锁文件 | `package-lock.json`, `frontend/web/package-lock.json`, `frontend/package-lock.json` | 跨平台 npm 依赖树可能不同 | | 锁文件 | `package-lock.json`, `frontend/web/package-lock.json`, `frontend/package-lock.json` | 跨平台 npm 依赖树可能不同 |
@@ -241,10 +241,10 @@ docker-compose -f docker-compose.dev.db.yml up -d
### 6.5 启动顺序 ### 6.5 启动顺序
**推荐使用 DevTools 一键启动**(自动编译 + 按序启动 + 健康检查): **推荐使用 ethend 一键启动**(自动编译 + 按序启动 + 健康检查):
```cmd ```cmd
cd devtools cd ethend
node src\index.js node src\index.js
:: 浏览器打开 http://localhost:9090,点击「一键启动」 :: 浏览器打开 http://localhost:9090,点击「一键启动」
``` ```
@@ -252,10 +252,10 @@ node src\index.js
或使用启动脚本: 或使用启动脚本:
```cmd ```cmd
devtools.bat ethend.bat
``` ```
DevTools 会按以下顺序自动编译并启动所有 6 个服务: ethend 会按以下顺序自动编译并启动所有 6 个服务:
| 顺序 | 服务 | 端口 | 说明 | | 顺序 | 服务 | 端口 | 说明 |
|------|------|------|------| |------|------|------|------|
@@ -266,7 +266,7 @@ DevTools 会按以下顺序自动编译并启动所有 6 个服务:
| 5 | gateway | 8080 | API 网关 / JWT / WebSocket | | 5 | gateway | 8080 | API 网关 / JWT / WebSocket |
| 6 | frontend | 5173 | React 开发服务器 | | 6 | frontend | 5173 | React 开发服务器 |
> 每个步骤会自动等待健康检查通过后再启动下一个服务。如果 Go 二进制未编译,DevTools 会自动先编译再启动。 > 每个步骤会自动等待健康检查通过后再启动下一个服务。如果 Go 二进制未编译,ethend 会自动先编译再启动。
如需手动逐个启动: 如需手动逐个启动:
+14 -14
View File
@@ -89,10 +89,10 @@ docker compose -f docker-compose.dev.db.yml up -d
```bash ```bash
# Linux / macOS (Git Bash) # Linux / macOS (Git Bash)
./devtools.sh start --build ./ethend.sh start --build
# Windows CMD / PowerShell # Windows CMD / PowerShell
devtools.bat start --build ethend.bat start --build
``` ```
按依赖顺序编译并启动全部 8 个服务:memory → plugin-manager → iot-debug → voice → ai-core → platform-bridge → gateway → frontend。 按依赖顺序编译并启动全部 8 个服务:memory → plugin-manager → iot-debug → voice → ai-core → platform-bridge → gateway → frontend。
@@ -102,21 +102,21 @@ devtools.bat start --build
| 地址 | 说明 | | 地址 | 说明 |
|------|------| |------|------|
| `http://localhost:5173` | 前端聊天界面 | | `http://localhost:5173` | 前端聊天界面 |
| `http://localhost:9090` | DevTools 管理面板 | | `http://localhost:9090` | ethend 管理面板 |
使用 `.env` 中配置的 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 登录。 使用 `.env` 中配置的 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 登录。
### 其他 CLI 命令 ### 其他 CLI 命令
```bash ```bash
./devtools.sh status # 查看服务状态 ./ethend.sh status # 查看服务状态
./devtools.sh logs gateway # 查看 Gateway 日志 ./ethend.sh logs gateway # 查看 Gateway 日志
./devtools.sh build ai-core # 单独编译 AI-Core ./ethend.sh build ai-core # 单独编译 AI-Core
./devtools.sh db:status # 检查数据库状态 ./ethend.sh db:status # 检查数据库状态
./devtools.sh help # 完整帮助 ./ethend.sh help # 完整帮助
``` ```
详见 [docs/api/devtools.md](docs/api/devtools.md)。 详见 [docs/api/ethend.md](docs/api/ethend.md)。
--- ---
@@ -135,7 +135,7 @@ Cyrene/
│ ├── plugin-manager/ # 插件管理器 (管理 API,插件逻辑在 pkg/plugins) │ ├── plugin-manager/ # 插件管理器 (管理 API,插件逻辑在 pkg/plugins)
│ ├── platform-bridge/ # 多平台桥接 (QQ / Telegram / Discord / Webhook) │ ├── platform-bridge/ # 多平台桥接 (QQ / Telegram / Discord / Webhook)
│ └── pkg/ # 共享包 (logger, plugins — 15 个通用插件/工具) │ └── pkg/ # 共享包 (logger, plugins — 15 个通用插件/工具)
├── devtools/ # DevTools 管理面板 (Express + WebSocket) ├── ethend/ # ethend 管理面板 (Express + WebSocket)
├── scripts/ # 辅助脚本 (migrate / tunnel / whisper-setup / pg-backup) ├── scripts/ # 辅助脚本 (migrate / tunnel / whisper-setup / pg-backup)
├── backups/ # 数据库备份文件 (.gitignore) ├── backups/ # 数据库备份文件 (.gitignore)
├── test/ # E2E 测试 ├── test/ # E2E 测试
@@ -145,8 +145,8 @@ Cyrene/
├── docker-compose.dev.db.yml # 开发基础设施 (仅 DB) ├── docker-compose.dev.db.yml # 开发基础设施 (仅 DB)
├── docker-compose.dev.yml # 开发环境一键启动 ├── docker-compose.dev.yml # 开发环境一键启动
├── docker-compose.yml # 生产环境 (含 Caddy) ├── docker-compose.yml # 生产环境 (含 Caddy)
├── devtools.sh # DevTools CLI (Git Bash) ├── ethend.sh # ethend CLI (Git Bash)
├── devtools.bat # DevTools CLI (CMD / PowerShell) ├── ethend.bat # ethend CLI (CMD / PowerShell)
└── Caddyfile # 反向代理配置 └── Caddyfile # 反向代理配置
``` ```
@@ -165,7 +165,7 @@ Cyrene/
| 8093 | Voice Service | 否 | | 8093 | Voice Service | 否 |
| 8094 | Plugin Manager | 否 | | 8094 | Plugin Manager | 否 |
| 8095 | Platform Bridge | 否 | | 8095 | Platform Bridge | 否 |
| 9090 | DevTools | 是 | | 9090 | ethend | 是 |
| 5432 | PostgreSQL | 否 | | 5432 | PostgreSQL | 否 |
| 6379 | Redis | 否 | | 6379 | Redis | 否 |
| 6333 | Qdrant HTTP | 否 | | 6333 | Qdrant HTTP | 否 |
@@ -200,7 +200,7 @@ Cyrene/
|------|------| |------|------|
| [Deploy.md](Deploy.md) | 部署指南(含 Windows 说明) | | [Deploy.md](Deploy.md) | 部署指南(含 Windows 说明) |
| [docs/api/gateway-api.md](docs/api/gateway-api.md) | 客户端 API 文档 | | [docs/api/gateway-api.md](docs/api/gateway-api.md) | 客户端 API 文档 |
| [docs/api/devtools.md](docs/api/devtools.md) | DevTools CLI + Web 控制台文档 | | [docs/api/ethend.md](docs/api/ethend.md) | ethend CLI + Web 控制台文档 |
| [docs/api/backend-services/](docs/api/backend-services/) | 后端服务 API 文档 | | [docs/api/backend-services/](docs/api/backend-services/) | 后端服务 API 文档 |
| [docs/dev_must_read.md](docs/dev_must_read.md) | 开发者必读 | | [docs/dev_must_read.md](docs/dev_must_read.md) | 开发者必读 |
| [docs/pg-backup-migration.md](docs/pg-backup-migration.md) | PG 备份与迁移指南 | | [docs/pg-backup-migration.md](docs/pg-backup-migration.md) | PG 备份与迁移指南 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -176,7 +176,7 @@ func (h *Hub) cleanupIdleSessions() {
} }
} }
// GetAllActiveSessions 返回所有会话状态(包括 idle),供 DevTools 监看使用 // GetAllActiveSessions 返回所有会话状态(包括 idle),供 ethend 监看使用
func (h *Hub) GetAllActiveSessions() []*SessionState { func (h *Hub) GetAllActiveSessions() []*SessionState {
h.mu.RLock() h.mu.RLock()
defer h.mu.RUnlock() defer h.mu.RUnlock()
+224
View File
@@ -0,0 +1,224 @@
package main
import (
"flag"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
func main() {
mode := flag.String("mode", "offline", "测试模式: offline (非实时) 或 realtime (实时)")
file := flag.String("file", "", "音频文件路径 (WAV/MP3/OGG/FLAC)")
server := flag.String("server", "http://localhost:8093", "Voice-Service 地址")
lang := flag.String("lang", "zh", "语言代码")
flag.Parse()
if *file == "" {
fmt.Println("用法: test_asr -mode=offline -file=audio.wav [-server=http://localhost:8093]")
os.Exit(1)
}
switch *mode {
case "offline":
testOffline(*server, *file, *lang)
case "realtime":
testRealtime(*server, *file, *lang)
default:
fmt.Printf("未知模式: %s (支持: offline, realtime)\n", *mode)
os.Exit(1)
}
}
// testOffline 测试非实时语音识别 (HTTP multipart 上传)。
func testOffline(server, filePath, lang string) {
fmt.Printf("=== 非实时 ASR 测试 ===\n")
fmt.Printf("服务器: %s\n", server)
fmt.Printf("文件: %s\n", filePath)
fmt.Printf("语言: %s\n\n", lang)
// 读取音频文件
audioData, err := os.ReadFile(filePath)
if err != nil {
fmt.Printf("读取文件失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("音频大小: %d bytes\n", len(audioData))
// 创建 multipart 请求
req, err := http.NewRequest("POST", server+"/api/v1/transcribe", nil)
if err != nil {
fmt.Printf("创建请求失败: %v\n", err)
os.Exit(1)
}
// 使用 multipart form
body, contentType, err := createMultipartBody(audioData, filePath, lang)
if err != nil {
fmt.Printf("创建 multipart body 失败: %v\n", err)
os.Exit(1)
}
req.Body = body
req.Header.Set("Content-Type", contentType)
start := time.Now()
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Printf("请求失败: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
elapsed := time.Since(start)
respBody, _ := io.ReadAll(resp.Body)
fmt.Printf("状态码: %d\n", resp.StatusCode)
fmt.Printf("耗时: %v\n", elapsed)
fmt.Printf("响应:\n%s\n", string(respBody))
if resp.StatusCode == 200 {
fmt.Println("\n✅ 非实时语音识别成功!")
} else {
fmt.Println("\n❌ 非实时语音识别失败")
}
}
// testRealtime 测试实时语音识别 (WebSocket 流式)。
func testRealtime(server, filePath, lang string) {
fmt.Printf("=== 实时 ASR 测试 ===\n")
fmt.Printf("服务器: %s\n", server)
fmt.Printf("文件: %s\n", filePath)
fmt.Printf("语言: %s\n\n", lang)
// 读取音频文件
audioData, err := os.ReadFile(filePath)
if err != nil {
fmt.Printf("读取文件失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("音频大小: %d bytes\n", len(audioData))
// 推断格式
format := inferFormat(filePath)
// 连接 WebSocket
wsURL := fmt.Sprintf("ws://%s/api/v1/stt/stream?format=%s&language=%s",
server[7:], format, lang) // 去掉 http:// 前缀
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
if err != nil {
fmt.Printf("WebSocket 连接失败: %v\n", err)
os.Exit(1)
}
defer conn.Close()
fmt.Printf("WebSocket 已连接: %s\n", wsURL)
// 设置 interrupt 处理
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
// goroutine: 读取识别结果
done := make(chan struct{})
go func() {
defer close(done)
for {
_, msg, err := conn.ReadMessage()
if err != nil {
fmt.Printf("读取结果错误: %v\n", err)
return
}
fmt.Printf("◀ 结果: %s\n", string(msg))
}
}()
// 模拟实时流式发送音频(每 100ms 发送 3200 bytes
chunkSize := 3200
totalSent := 0
start := time.Now()
var elapsed time.Duration
cancelled := false
for i := 0; i < len(audioData); i += chunkSize {
end := i + chunkSize
if end > len(audioData) {
end = len(audioData)
}
select {
case <-interrupt:
fmt.Println("\n用户中断")
cancelled = true
default:
}
if cancelled {
break
}
if err := conn.WriteMessage(websocket.BinaryMessage, audioData[i:end]); err != nil {
fmt.Printf("发送音频失败: %v\n", err)
break
}
totalSent += end - i
fmt.Printf("▶ 发送 %d/%d bytes (%.1f%%)\n", totalSent, len(audioData),
float64(totalSent)/float64(len(audioData))*100)
time.Sleep(100 * time.Millisecond)
}
elapsed = time.Since(start)
// 发送停止消息
conn.WriteMessage(websocket.TextMessage, []byte(`{"action":"stop"}`))
// 等待最后的结果
time.Sleep(2 * time.Second)
fmt.Printf("\n总耗时: %v, 总发送: %d bytes\n", elapsed, totalSent)
fmt.Println("✅ 实时语音识别测试完成")
}
func inferFormat(filename string) string {
ext := ""
for i := len(filename) - 1; i >= 0; i-- {
if filename[i] == '.' {
ext = filename[i+1:]
break
}
}
switch ext {
case "wav", "wave":
return "wav"
case "mp3", "mpeg":
return "mp3"
case "ogg", "opus":
return "ogg"
case "flac":
return "flac"
case "m4a", "mp4", "aac":
return "m4a"
default:
return "pcm"
}
}
func createMultipartBody(audioData []byte, filename, lang string) (io.ReadCloser, string, error) {
boundary := "cyrene-asr-test-boundary"
header := fmt.Sprintf("--%s\r\nContent-Disposition: form-data; name=\"audio\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n",
boundary, filename)
footer := fmt.Sprintf("\r\n--%s\r\nContent-Disposition: form-data; name=\"language\"\r\n\r\n%s\r\n--%s--\r\n",
boundary, lang, boundary)
pr, pw := io.Pipe()
go func() {
pw.Write([]byte(header))
pw.Write(audioData)
pw.Write([]byte(footer))
pw.Close()
}()
return pr, "multipart/form-data; boundary=" + boundary, nil
}
+1 -1
View File
@@ -668,7 +668,7 @@ print("\n" + "=" * 70)
print("Part I: 服务日志摘要") print("Part I: 服务日志摘要")
print("=" * 70) print("=" * 70)
LOG_DIR = "/home/aska/Code/Cyrene/devtools/logs" LOG_DIR = "/home/aska/Code/Cyrene/ethend/logs"
log_files = { log_files = {
"ai-core": f"{LOG_DIR}/ai-core.log", "ai-core": f"{LOG_DIR}/ai-core.log",
"gateway": f"{LOG_DIR}/gateway.log", "gateway": f"{LOG_DIR}/gateway.log",
+1 -1
View File
@@ -4,7 +4,7 @@ import json, time, base64, os
from websocket import create_connection from websocket import create_connection
PAGE_URL = "http://localhost:5199/" PAGE_URL = "http://localhost:5199/"
CDP_WS = "ws://127.0.0.1:9225/devtools/browser/b2fca0da-35d6-4180-8413-eddf53753c6a" CDP_WS = "ws://127.0.0.1:9225/ethend/browser/b2fca0da-35d6-4180-8413-eddf53753c6a"
def send_cmd(ws, method, params=None, msg_id=1): def send_cmd(ws, method, params=None, msg_id=1):
payload = json.dumps({"id": msg_id, "method": method, "params": params or {}}) payload = json.dumps({"id": msg_id, "method": method, "params": params or {}})
+6 -6
View File
@@ -74,19 +74,19 @@ services:
- "8088:8080" - "8088:8080"
restart: unless-stopped restart: unless-stopped
# ========== 开发调试工具 ========== # ==========管理控制台 ==========
devtools: ethend:
container_name: cyrene_devtools container_name: cyrene_ethend
build: build:
context: ./devtools context: ./ethend
dockerfile: Dockerfile dockerfile: Dockerfile
environment: environment:
DEVTOOLS_PORT: "9090" ETHEND_PORT: "9090"
GATEWAY_URL: http://gateway:8080 GATEWAY_URL: http://gateway:8080
AI_CORE_URL: http://ai-core:8081 AI_CORE_URL: http://ai-core:8081
MEMORY_SERVICE_URL: http://memory-service:8091 MEMORY_SERVICE_URL: http://memory-service:8091
VOICE_SERVICE_URL: http://voice-service:8093 VOICE_SERVICE_URL: http://voice-service:8093
PLATFORM_BRIDGE_URL: http://platform-bridge:8095 IOT_DEBUG_SERVICE_URL: http://iot-debug-service:8083
ADMIN_USERNAME: admin ADMIN_USERNAME: admin
ADMIN_PASSWORD: cyrene-dev-admin ADMIN_PASSWORD: cyrene-dev-admin
ports: ports:
+21
View File
@@ -143,6 +143,27 @@ services:
IOT_DEBUG_PORT: "8083" IOT_DEBUG_PORT: "8083"
restart: unless-stopped restart: unless-stopped
# ========== 管理控制台 ==========
ethend:
container_name: cyrene_ethend
build:
context: ./ethend
dockerfile: Dockerfile
environment:
ETHEND_PORT: "${ETHEND_PORT:-9090}"
GATEWAY_URL: http://gateway:8080
AI_CORE_URL: http://ai-core:8081
MEMORY_SERVICE_URL: http://memory-service:8091
VOICE_SERVICE_URL: http://voice-service:8093
IOT_DEBUG_SERVICE_URL: http://iot-debug-service:8083
ADMIN_USERNAME: ${ADMIN_USERNAME:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
ports:
- "${ETHEND_PORT:-9090}:9090"
depends_on:
- gateway
restart: unless-stopped
# ========== 基础设施 ========== # ========== 基础设施 ==========
postgres: postgres:
container_name: cyrene_postgres container_name: cyrene_postgres
+17 -17
View File
@@ -1,12 +1,12 @@
# Cyrene DevTools 文档 # Cyrene ethend 文档
DevTools 是 Cyrene 项目的开发管理控制台,提供 Web UI + CLI 两种使用方式。默认端口 **9090** ethend 是 Cyrene 项目的开发管理控制台,提供 Web UI + CLI 两种使用方式。默认端口 **9090**
--- ---
## 目录 ## 目录
1. [CLI 命令 (devtools.sh)](#1-cli-命令) 1. [CLI 命令 (ethend.sh)](#1-cli-命令)
2. [Web 控制台面板](#2-web-控制台面板) 2. [Web 控制台面板](#2-web-控制台面板)
3. [REST API](#3-rest-api) 3. [REST API](#3-rest-api)
@@ -14,16 +14,16 @@ DevTools 是 Cyrene 项目的开发管理控制台,提供 Web UI + CLI 两种
## 1. CLI 命令 ## 1. CLI 命令
`./devtools.sh [命令] [选项]` `./ethend.sh [命令] [选项]`
### 基本命令 ### 基本命令
| 命令 | 说明 | | 命令 | 说明 |
|------|------| |------|------|
| `start` | 启动 DevTools 控制台 | | `start` | 启动 ethend 控制台 |
| `start --build` | 编译全部后端服务后启动 | | `start --build` | 编译全部后端服务后启动 |
| `start --fresh` | 强制重启全部后端服务后启动 | | `start --fresh` | 强制重启全部后端服务后启动 |
| `stop` | 停止 DevTools 控制台 | | `stop` | 停止 ethend 控制台 |
| `status` | 查看所有服务状态(运行/停止、PID、uptime) | | `status` | 查看所有服务状态(运行/停止、PID、uptime) |
| `logs <服务ID> [行数]` | 查看服务日志 | | `logs <服务ID> [行数]` | 查看服务日志 |
| `build [服务ID]` | 编译服务(不指定则编译全部) | | `build [服务ID]` | 编译服务(不指定则编译全部) |
@@ -36,7 +36,7 @@ DevTools 是 Cyrene 项目的开发管理控制台,提供 Web UI + CLI 两种
| 选项 | 说明 | | 选项 | 说明 |
|------|------| |------|------|
| `--port, -p <端口>` | 指定 DevTools 端口 (默认: 9090) | | `--port, -p <端口>` | 指定 ethend 端口 (默认: 9090) |
| `--fresh` | 启动前强制重启全部后端服务 | | `--fresh` | 启动前强制重启全部后端服务 |
| `--build` | 启动前编译全部服务 | | `--build` | 启动前编译全部服务 |
@@ -47,12 +47,12 @@ DevTools 是 Cyrene 项目的开发管理控制台,提供 Web UI + CLI 两种
### 示例 ### 示例
```bash ```bash
./devtools.sh # 快速启动 ./ethend.sh # 快速启动
./devtools.sh start --build # 编译后启动 ./ethend.sh start --build # 编译后启动
./devtools.sh start --fresh # 全新重启 ./ethend.sh start --fresh # 全新重启
./devtools.sh logs gateway 20 # 查看 Gateway 最近 20 行日志 ./ethend.sh logs gateway 20 # 查看 Gateway 最近 20 行日志
./devtools.sh build ai-core # 仅编译 AI-Core ./ethend.sh build ai-core # 仅编译 AI-Core
./devtools.sh db:status # 检查数据库状态 ./ethend.sh db:status # 检查数据库状态
``` ```
--- ---
@@ -139,13 +139,13 @@ STT 转录日志(内存环形缓冲,最多 200 条),支持上传音频
## 3. REST API ## 3. REST API
DevTools 自身暴露的 REST API,供脚本和外部工具使用。 ethend 自身暴露的 REST API,供脚本和外部工具使用。
### 健康检查 ### 健康检查
``` ```
GET /api/health GET /api/health
→ { "status": "ok", "service": "cyrene-devtools", "uptime": 3600, "wsClients": 2 } → { "status": "ok", "service": "cyrene-ethend", "uptime": 3600, "wsClients": 2 }
``` ```
### 服务管理 ### 服务管理
@@ -191,7 +191,7 @@ GET /api/dashboard
所有代理路由自动获取 Gateway JWT Token(通过 admin 凭据登录并缓存)。 所有代理路由自动获取 Gateway JWT Token(通过 admin 凭据登录并缓存)。
| DevTools 路径 | 目标服务 | 实际路径 | | ethend 路径 | 目标服务 | 实际路径 |
|---------------|----------|----------| |---------------|----------|----------|
| `/api/memory/*` | Gateway | `/api/v1/memory/*` | | `/api/memory/*` | Gateway | `/api/v1/memory/*` |
| `/api/sessions*` | Gateway | `/api/v1/admin/sessions*` | | `/api/sessions*` | Gateway | `/api/v1/admin/sessions*` |
@@ -201,7 +201,7 @@ GET /api/dashboard
| `/api/tool-calls*` | AI-Core | `/api/v1/tools/calls*` | | `/api/tool-calls*` | AI-Core | `/api/v1/tools/calls*` |
| `/api/voice/status` | Voice-Service | `/api/v1/status` | | `/api/voice/status` | Voice-Service | `/api/v1/status` |
| `/api/voice/transcribe` | Voice-Service | `/api/v1/transcribe` | | `/api/voice/transcribe` | Voice-Service | `/api/v1/transcribe` |
| `/api/voice/logs` | DevTools 内部 | 内存环形缓冲区 | | `/api/voice/logs` | ethend 内部 | 内存环形缓冲区 |
| `/api/v1/thinking*` | Memory-Service | `/api/v1/thinking*` | | `/api/v1/thinking*` | Memory-Service | `/api/v1/thinking*` |
| `/api/memory-timeline` | Memory-Service | 合并 Memories + Thinking | | `/api/memory-timeline` | Memory-Service | 合并 Memories + Thinking |
| `/api/chat-platforms/*` | Platform-Bridge | `/api/v1/*` | | `/api/chat-platforms/*` | Platform-Bridge | `/api/v1/*` |
+8 -8
View File
@@ -25,7 +25,7 @@
- [自定义 Hooks](#44-自定义-hooks) - [自定义 Hooks](#44-自定义-hooks)
- [API 模块](#45-api-模块) - [API 模块](#45-api-模块)
- [WebSocket 消息流](#46-websocket-消息流) - [WebSocket 消息流](#46-websocket-消息流)
5. [DevTools (9090) — 调试工具](#五devtools-9090--调试工具) 5. [ethend (9090) — 调试工具](#五ethend-9090--调试工具)
6. [对话管线详解](#六对话管线详解) 6. [对话管线详解](#六对话管线详解)
7. [数据库设计](#七数据库设计) 7. [数据库设计](#七数据库设计)
8. [安全性](#八安全性) 8. [安全性](#八安全性)
@@ -588,9 +588,9 @@ App
--- ---
## 五、DevTools (:9090) — 调试工具 ## 五、ethend (:9090) — 调试工具
**目录**`devtools/` **目录**`ethend/`
**类型**Node.js Express 应用 **类型**Node.js Express 应用
### 5.1 服务管理 ### 5.1 服务管理
@@ -616,14 +616,14 @@ App
### 5.3 关键配置 ### 5.3 关键配置
**构建命令**[config.js](devtools/src/config.js)): **构建命令**[config.js](ethend/src/config.js)):
```javascript ```javascript
buildCommand: 'go', buildCommand: 'go',
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'], buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
goBin: GO_BIN goBin: GO_BIN
``` ```
所有 Go 服务统一编译为 `main.exe`Windows),DevTools 通过 `./main` 启动。**自定义二进制名称不会被 DevTools 识别。** 所有 Go 服务统一编译为 `main.exe`Windows),ethend 通过 `./main` 启动。**自定义二进制名称不会被 ethend 识别。**
--- ---
@@ -767,7 +767,7 @@ postgres://cyrene:cyrene_pass@localhost:5432/cyrene_ai?sslmode=disable
| Memory | 8091 | net/http + pgvector | | Memory | 8091 | net/http + pgvector |
| Voice | 8093 | net/http + whisper.cpp | | Voice | 8093 | net/http + whisper.cpp |
| Frontend (dev) | 5173 | Vite | | Frontend (dev) | 5173 | Vite |
| DevTools | 9090 | Express | | ethend | 9090 | Express |
### 常用命令 ### 常用命令
@@ -777,7 +777,7 @@ cd backend/ai-core && GOWORK=off go build -o main.exe ./cmd/main.go
cd backend/gateway && GOWORK=off go build -o main.exe ./cmd/main.go cd backend/gateway && GOWORK=off go build -o main.exe ./cmd/main.go
# ... 其他服务同理 # ... 其他服务同理
# 或通过 DevTools API # 或通过 ethend API
curl -X POST http://localhost:9090/api/services/ai-core/build curl -X POST http://localhost:9090/api/services/ai-core/build
curl -X POST http://localhost:9090/api/services/gateway/build curl -X POST http://localhost:9090/api/services/gateway/build
@@ -845,7 +845,7 @@ Phase 6 新增,位于 `backend/models.json``.gitignore` 已排除)。格
} }
``` ```
**配置管理 API**Gateway adminDevTools 代理提供 UI): **配置管理 API**Gateway adminethend 代理提供 UI):
| Method | Path | Description | | Method | Path | Description |
|--------|------|-------------| |--------|------|-------------|
+1
View File
@@ -26,6 +26,7 @@ docker compose logs -f
| memory-service | 8091 (内部) | 记忆检索 | | memory-service | 8091 (内部) | 记忆检索 |
| voice-service | 8093 (内部) | 语音识别 | | voice-service | 8093 (内部) | 语音识别 |
| iot-debug-service | 8083 (内部) | IoT 调试 | | iot-debug-service | 8083 (内部) | IoT 调试 |
| ethend | 9090 (外部) | 管理控制台 |
| postgres | 5432 (内部) | 数据库 (pgvector/pg16) | | postgres | 5432 (内部) | 数据库 (pgvector/pg16) |
| redis | 6379 (内部) | 缓存 | | redis | 6379 (内部) | 缓存 |
| qdrant | 6333 (内部) | 向量数据库 | | qdrant | 6333 (内部) | 向量数据库 |
+1 -1
View File
@@ -85,7 +85,7 @@ HOST_EXEC_MAX_TIMEOUT=300
## 验证 ## 验证
DevTools 或 API 测试: ethend 或 API 测试:
```bash ```bash
# 通过 API 发送消息,让昔涟使用 os_exec # 通过 API 发送消息,让昔涟使用 os_exec
+28 -28
View File
@@ -1,15 +1,15 @@
@echo off @echo off
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
:: ======================================== :: ========================================
:: Cyrene DevTools CLI (Windows CMD) :: Cyrene ethend CLI (Windows CMD)
:: Usage: devtools.bat [command] [options] :: Usage: ethend.bat [command] [options]
:: ======================================== :: ========================================
set "SCRIPT_DIR=%~dp0" set "SCRIPT_DIR=%~dp0"
set "DEVTOOLS_DIR=%SCRIPT_DIR%devtools" set "ETHEND_DIR=%SCRIPT_DIR%ethend"
set "ROOT=%SCRIPT_DIR%" set "ROOT=%SCRIPT_DIR%"
if "%DEVTOOLS_PORT%"=="" (set PORT=9090) else (set PORT=%DEVTOOLS_PORT%) if "%ETHEND_PORT%"=="" (set PORT=9090) else (set PORT=%ETHEND_PORT%)
set "LOG_DIR=%DEVTOOLS_DIR%\logs" set "LOG_DIR=%ETHEND_DIR%\logs"
set "LOG_FILE=%LOG_DIR%\sh.log" set "LOG_FILE=%LOG_DIR%\sh.log"
set "DB_COMPOSE_FILE=%ROOT%docker-compose.dev.db.yml" set "DB_COMPOSE_FILE=%ROOT%docker-compose.dev.db.yml"
@@ -34,15 +34,15 @@ goto :help
:: ========================================== :: ==========================================
:help :help
echo Cyrene DevTools - Development Management Tool echo Cyrene ethend - Development Management Tool
echo. echo.
echo Usage: devtools.bat [command] [options] echo Usage: ethend.bat [command] [options]
echo. echo.
echo Commands: echo Commands:
echo start Start DevTools console (default) echo start Start ethend console (default)
echo start --build Build all services before start echo start --build Build all services before start
echo start --fresh Force restart all services before start echo start --fresh Force restart all services before start
echo stop Stop DevTools console echo stop Stop ethend console
echo status Show all service status echo status Show all service status
echo logs [service] View service logs (default: last 20 lines) echo logs [service] View service logs (default: last 20 lines)
echo build [service] Build service(s) (omit to build all) echo build [service] Build service(s) (omit to build all)
@@ -56,12 +56,12 @@ echo --build Build all backend services before start
echo --fresh Force restart all services before start echo --fresh Force restart all services before start
echo. echo.
echo Examples: echo Examples:
echo devtools.bat Quick start echo ethend.bat Quick start
echo devtools.bat start --build Build and start echo ethend.bat start --build Build and start
echo devtools.bat start --fresh Fresh restart echo ethend.bat start --fresh Fresh restart
echo devtools.bat logs gateway View Gateway log echo ethend.bat logs gateway View Gateway log
echo devtools.bat build ai-core Build AI-Core only echo ethend.bat build ai-core Build AI-Core only
echo devtools.bat db:status Check database echo ethend.bat db:status Check database
echo. echo.
echo Web console: http://localhost:%PORT% echo Web console: http://localhost:%PORT%
exit /b 0 exit /b 0
@@ -85,7 +85,7 @@ exit /b 1
:start :start
echo. echo.
echo ========================================== echo ==========================================
echo Cyrene DevTools echo Cyrene ethend
echo ========================================== echo ==========================================
call :check_node call :check_node
for /f "tokens=*" %%i in ('!NODE_CMD! --version') do echo Node.js: %%i for /f "tokens=*" %%i in ('!NODE_CMD! --version') do echo Node.js: %%i
@@ -117,7 +117,7 @@ if %DO_FRESH%==1 (
curl -s -o nul "http://localhost:%PORT%/api/health" 2>nul curl -s -o nul "http://localhost:%PORT%/api/health" 2>nul
if %ERRORLEVEL%==0 ( if %ERRORLEVEL%==0 (
echo. echo.
echo [OK] DevTools already running: http://localhost:%PORT% echo [OK] ethend already running: http://localhost:%PORT%
echo API: http://localhost:%PORT%/api/health echo API: http://localhost:%PORT%/api/health
exit /b 0 exit /b 0
) )
@@ -129,7 +129,7 @@ for /f "tokens=5" %%a in ('netstat -ano ^| findstr /R ":%PORT% " ^| findstr "LIS
timeout /t 1 /nobreak >nul timeout /t 1 /nobreak >nul
) )
cd /d "%DEVTOOLS_DIR%" cd /d "%ETHEND_DIR%"
:: Install dependencies :: Install dependencies
if not exist "node_modules\" ( if not exist "node_modules\" (
@@ -141,16 +141,16 @@ if not exist "node_modules\" (
if not exist "%LOG_DIR%" mkdir "%LOG_DIR%" if not exist "%LOG_DIR%" mkdir "%LOG_DIR%"
echo. echo.
echo [INFO] Starting DevTools on port %PORT% echo [INFO] Starting ethend on port %PORT%
echo Web UI: http://localhost:%PORT% echo Web UI: http://localhost:%PORT%
echo API: http://localhost:%PORT%/api/health echo API: http://localhost:%PORT%/api/health
echo WebSocket: ws://localhost:%PORT%/ws echo WebSocket: ws://localhost:%PORT%/ws
echo. echo.
start "Cyrene-DevTools" /B !NODE_CMD! src\index.js 1>>"%LOG_FILE%" 2>&1 start "Cyrene-ethend" /B !NODE_CMD! src\index.js 1>>"%LOG_FILE%" 2>&1
:: Health check (up to 30s) :: Health check (up to 30s)
echo [INFO] Waiting for DevTools to be ready... echo [INFO] Waiting for ethend to be ready...
set MAX_WAIT=30 set MAX_WAIT=30
set WAITED=0 set WAITED=0
:health_loop :health_loop
@@ -159,7 +159,7 @@ powershell -Command "try { (Invoke-WebRequest 'http://localhost:%PORT%/api/healt
if %ERRORLEVEL%==0 ( if %ERRORLEVEL%==0 (
echo. echo.
echo ========================================== echo ==========================================
echo DevTools is ready! echo ethend is ready!
echo Console: http://localhost:%PORT% echo Console: http://localhost:%PORT%
echo Log: %LOG_FILE% echo Log: %LOG_FILE%
echo ========================================== echo ==========================================
@@ -179,22 +179,22 @@ exit /b 0
:: ========================================== :: ==========================================
:stop :stop
for /f "tokens=5" %%a in ('netstat -ano ^| findstr /R ":%PORT% " ^| findstr "LISTENING"') do ( for /f "tokens=5" %%a in ('netstat -ano ^| findstr /R ":%PORT% " ^| findstr "LISTENING"') do (
echo [INFO] Stopping DevTools (PID: %%a)... echo [INFO] Stopping ethend (PID: %%a)...
taskkill /PID %%a /F >nul 2>&1 taskkill /PID %%a /F >nul 2>&1
echo [OK] DevTools stopped echo [OK] ethend stopped
exit /b 0 exit /b 0
) )
echo [INFO] DevTools is not running echo [INFO] ethend is not running
exit /b 0 exit /b 0
:: ========================================== :: ==========================================
:status :status
curl -s -o nul "http://localhost:%PORT%/api/health" 2>nul curl -s -o nul "http://localhost:%PORT%/api/health" 2>nul
if %ERRORLEVEL% neq 0 ( if %ERRORLEVEL% neq 0 (
echo [ERROR] DevTools is offline echo [ERROR] ethend is offline
exit /b 1 exit /b 1
) )
echo [OK] DevTools online echo [OK] ethend online
echo. echo.
echo Service Status: echo Service Status:
curl -s "http://localhost:%PORT%/api/services" 2>nul | !NODE_CMD! -e "const d=require('fs').readFileSync(0,'utf-8');const s=JSON.parse(d);for(const[k,v]of Object.entries(s)){const icon=v.status==='running'?'+':' ';const pid=v.pid?' (PID:'+v.pid+')':'';const upt=v.uptime?' uptime:'+Math.round(v.uptime/1000)+'s':'';console.log(' ['+icon+'] '+v.name.padEnd(18)+v.status+pid+upt);}" 2>nul curl -s "http://localhost:%PORT%/api/services" 2>nul | !NODE_CMD! -e "const d=require('fs').readFileSync(0,'utf-8');const s=JSON.parse(d);for(const[k,v]of Object.entries(s)){const icon=v.status==='running'?'+':' ';const pid=v.pid?' (PID:'+v.pid+')':'';const upt=v.uptime?' uptime:'+Math.round(v.uptime/1000)+'s':'';console.log(' ['+icon+'] '+v.name.padEnd(18)+v.status+pid+upt);}" 2>nul
@@ -208,7 +208,7 @@ exit /b 0
set SVC_ID=%2 set SVC_ID=%2
set LINES=%3 set LINES=%3
if "%SVC_ID%"=="" ( if "%SVC_ID%"=="" (
echo Usage: devtools.bat logs ^<service-id^> [lines] echo Usage: ethend.bat logs ^<service-id^> [lines]
echo Available: gateway, ai-core, memory-service, tool-engine, voice-service, iot-debug-service, plugin-manager, platform-bridge, frontend echo Available: gateway, ai-core, memory-service, tool-engine, voice-service, iot-debug-service, plugin-manager, platform-bridge, frontend
exit /b 1 exit /b 1
) )
+37 -37
View File
@@ -1,15 +1,15 @@
#!/bin/bash #!/bin/bash
# ======================================== # ========================================
# Cyrene DevTools 启动脚本 # Cyrene ethend 启动脚本
# 管理开发环境: 数据库 / 服务编译 / DevTools 控制台 # 管理开发环境: 数据库 / 服务编译 / ethend 控制台
# ======================================== # ========================================
set -e set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DEVTOOLS_DIR="$SCRIPT_DIR/devtools" ETHEND_DIR="$SCRIPT_DIR/ethend"
ROOT="$SCRIPT_DIR" ROOT="$SCRIPT_DIR"
PORT="${DEVTOOLS_PORT:-9090}" PORT="${ETHEND_PORT:-9090}"
LOG_DIR="$DEVTOOLS_DIR/logs" LOG_DIR="$ETHEND_DIR/logs"
LOG_FILE="$LOG_DIR/sh.log" LOG_FILE="$LOG_DIR/sh.log"
# 颜色 # 颜色
@@ -28,16 +28,16 @@ esac
# ========== 帮助 ========== # ========== 帮助 ==========
show_help() { show_help() {
echo -e "${CYAN}Cyrene DevTools${NC} — 开发环境管理工具" echo -e "${CYAN}Cyrene ethend${NC} — 开发环境管理工具"
echo "" echo ""
echo -e "${BOLD}用法:${NC} ./devtools.sh [命令] [选项]" echo -e "${BOLD}用法:${NC} ./ethend.sh [命令] [选项]"
echo "" echo ""
echo -e "${BOLD}命令:${NC}" echo -e "${BOLD}命令:${NC}"
echo " (无参数) 启动 DevTools 控制台 (默认)" echo " (无参数) 启动 ethend 控制台 (默认)"
echo " start 启动 DevTools 控制台" echo " start 启动 ethend 控制台"
echo " start --fresh 强制重启全部后端服务后启动" echo " start --fresh 强制重启全部后端服务后启动"
echo " start --build 编译全部服务后启动" echo " start --build 编译全部服务后启动"
echo " stop 停止 DevTools 控制台" echo " stop 停止 ethend 控制台"
echo " status 查看所有服务状态" echo " status 查看所有服务状态"
echo " logs [服务ID] 查看服务日志 (默认显示最近 20 行)" echo " logs [服务ID] 查看服务日志 (默认显示最近 20 行)"
echo " build [服务ID] 编译服务 (不指定则编译全部)" echo " build [服务ID] 编译服务 (不指定则编译全部)"
@@ -47,17 +47,17 @@ show_help() {
echo " help 显示此帮助" echo " help 显示此帮助"
echo "" echo ""
echo -e "${BOLD}选项:${NC}" echo -e "${BOLD}选项:${NC}"
echo " --port, -p <端口> 指定 DevTools 端口 (默认: 9090)" echo " --port, -p <端口> 指定 ethend 端口 (默认: 9090)"
echo " --fresh 启动前强制重启全部后端服务" echo " --fresh 启动前强制重启全部后端服务"
echo " --build 启动前编译全部服务" echo " --build 启动前编译全部服务"
echo "" echo ""
echo -e "${BOLD}示例:${NC}" echo -e "${BOLD}示例:${NC}"
echo " ./devtools.sh # 快速启动" echo " ./ethend.sh # 快速启动"
echo " ./devtools.sh start --build # 编译后启动" echo " ./ethend.sh start --build # 编译后启动"
echo " ./devtools.sh start --fresh # 全新重启" echo " ./ethend.sh start --fresh # 全新重启"
echo " ./devtools.sh logs gateway # 查看 Gateway 日志" echo " ./ethend.sh logs gateway # 查看 Gateway 日志"
echo " ./devtools.sh build ai-core # 仅编译 AI-Core" echo " ./ethend.sh build ai-core # 仅编译 AI-Core"
echo " ./devtools.sh db:status # 检查数据库" echo " ./ethend.sh db:status # 检查数据库"
echo "" echo ""
echo -e "${BOLD}Web 控制台:${NC} http://localhost:$PORT" echo -e "${BOLD}Web 控制台:${NC} http://localhost:$PORT"
} }
@@ -248,8 +248,8 @@ show_logs() {
tail -n "$lines" "$log_path" tail -n "$lines" "$log_path"
} }
# ========== 启动 DevTools ========== # ========== 启动 ethend ==========
start_devtools() { start_ethend() {
local do_build=false local do_build=false
local do_fresh=false local do_fresh=false
@@ -265,7 +265,7 @@ start_devtools() {
echo "" echo ""
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} Cyrene DevTools${NC}" echo -e "${CYAN} Cyrene ethend${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
# 依赖检查 # 依赖检查
@@ -291,9 +291,9 @@ start_devtools() {
# 检查并释放端口 # 检查并释放端口
if port_in_use "$PORT"; then if port_in_use "$PORT"; then
# 检查是否是已有 DevTools 实例 # 检查是否是已有 ethend 实例
if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then
echo -e "${GREEN}DevTools 已在运行: http://localhost:$PORT${NC}" echo -e "${GREEN}ethend 已在运行: http://localhost:$PORT${NC}"
echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}" echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}"
return 0 return 0
fi fi
@@ -301,8 +301,8 @@ start_devtools() {
kill_port "$PORT" kill_port "$PORT"
fi fi
# 切换到 devtools 目录 # 切换到 ethend 目录
cd "$DEVTOOLS_DIR" cd "$ETHEND_DIR"
# 安装依赖 # 安装依赖
if [ ! -d "node_modules" ] || [ ! -f "node_modules/.package-lock.json" ]; then if [ ! -d "node_modules" ] || [ ! -f "node_modules/.package-lock.json" ]; then
@@ -314,14 +314,14 @@ start_devtools() {
mkdir -p "$LOG_DIR" mkdir -p "$LOG_DIR"
echo "" echo ""
echo -e "${GREEN}启动 DevTools 服务器 (端口: $PORT)...${NC}" echo -e "${GREEN}启动 ethend 服务器 (端口: $PORT)...${NC}"
echo -e "${CYAN} Web 控制台: http://localhost:$PORT${NC}" echo -e "${CYAN} Web 控制台: http://localhost:$PORT${NC}"
echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}" echo -e "${CYAN} API: http://localhost:$PORT/api/health${NC}"
echo -e "${CYAN} WebSocket: ws://localhost:$PORT/ws${NC}" echo -e "${CYAN} WebSocket: ws://localhost:$PORT/ws${NC}"
echo "" echo ""
echo -e "${YELLOW}正在后台启动...${NC}" echo -e "${YELLOW}正在后台启动...${NC}"
# 后台启动 DevTools # 后台启动 ethend
nohup node src/index.js > "$LOG_FILE" 2>&1 & nohup node src/index.js > "$LOG_FILE" 2>&1 &
local pid=$! local pid=$!
cd "$ROOT" cd "$ROOT"
@@ -331,7 +331,7 @@ start_devtools() {
if health_check "http://localhost:$PORT/api/health" 30; then if health_check "http://localhost:$PORT/api/health" 30; then
echo "" echo ""
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN} DevTools 已启动!${NC}" echo -e "${GREEN} ethend 已启动!${NC}"
echo -e "${GREEN} PID: ${pid}${NC}" echo -e "${GREEN} PID: ${pid}${NC}"
echo -e "${GREEN} 控制台: http://localhost:$PORT${NC}" echo -e "${GREEN} 控制台: http://localhost:$PORT${NC}"
echo -e "${GREEN} 日志: ${LOG_FILE}${NC}" echo -e "${GREEN} 日志: ${LOG_FILE}${NC}"
@@ -356,25 +356,25 @@ start_devtools() {
fi fi
} }
# ========== 停止 DevTools ========== # ========== 停止 ethend ==========
stop_devtools() { stop_ethend() {
if port_in_use "$PORT"; then if port_in_use "$PORT"; then
echo -e "${CYAN}停止 DevTools...${NC}" echo -e "${CYAN}停止 ethend...${NC}"
if $IS_WIN; then if $IS_WIN; then
kill_port "$PORT" kill_port "$PORT"
else else
fuser -k "$PORT/tcp" 2>/dev/null || true fuser -k "$PORT/tcp" 2>/dev/null || true
fi fi
echo -e "${GREEN}DevTools 已停止${NC}" echo -e "${GREEN}ethend 已停止${NC}"
else else
echo -e "${YELLOW}DevTools 未在运行${NC}" echo -e "${YELLOW}ethend 未在运行${NC}"
fi fi
} }
# ========== 查看状态 ========== # ========== 查看状态 ==========
show_status() { show_status() {
if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then if curl -s -o /dev/null "http://localhost:$PORT/api/health" 2>/dev/null; then
echo -e "${GREEN}DevTools 在线${NC}" echo -e "${GREEN}ethend 在线${NC}"
# 获取服务状态 # 获取服务状态
local status_json=$(curl -s "http://localhost:$PORT/api/services" 2>/dev/null) local status_json=$(curl -s "http://localhost:$PORT/api/services" 2>/dev/null)
@@ -401,7 +401,7 @@ show_status() {
echo "" echo ""
db_status db_status
else else
echo -e "${RED}DevTools 离线${NC}" echo -e "${RED}ethend 离线${NC}"
fi fi
} }
@@ -414,17 +414,17 @@ case "$CMD" in
show_help show_help
;; ;;
start|"") start|"")
start_devtools "$@" start_ethend "$@"
;; ;;
stop) stop)
stop_devtools stop_ethend
;; ;;
status) status)
show_status show_status
;; ;;
logs) logs)
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo -e "${YELLOW}用法: ./devtools.sh logs <服务ID>${NC}" echo -e "${YELLOW}用法: ./ethend.sh logs <服务ID>${NC}"
echo "可用服务: gateway, ai-core, memory-service, tool-engine, voice-service, iot-debug-service, plugin-manager, platform-bridge, frontend" echo "可用服务: gateway, ai-core, memory-service, tool-engine, voice-service, iot-debug-service, plugin-manager, platform-bridge, frontend"
exit 1 exit 1
fi fi
+2 -2
View File
@@ -8,8 +8,8 @@ RUN npm ci --omit=dev
COPY src/ ./src/ COPY src/ ./src/
COPY public/ ./public/ COPY public/ ./public/
ENV DEVTOOLS_PORT=9090 ENV ETHEND_PORT=9090
ENV NODE_ENV=development ENV NODE_ENV=production
EXPOSE 9090 EXPOSE 9090
@@ -1,7 +1,7 @@
{ {
"name": "cyrene-devtools", "name": "cyrene-ethend",
"version": "1.0.0", "version": "1.0.0",
"description": "Cyrene AI 开发调试工具 - 服务管理、日志监控、性能分析", "description": "Cyrene AI 高级管理控制台 - 服务管理、日志监控、性能分析",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cyrene DevTools</title> <title>Cyrene ethend</title>
<style> <style>
/* ========== CSS Variables (深色主题) ========== */ /* ========== CSS Variables (深色主题) ========== */
:root { :root {
@@ -747,7 +747,7 @@ input[type="range"] { accent-color: var(--accent); padding: 0; }
<!-- ========== 侧边栏 ========== --> <!-- ========== 侧边栏 ========== -->
<aside id="sidebar"> <aside id="sidebar">
<div class="sidebar-header"> <div class="sidebar-header">
<span class="sidebar-title">🛠️ DevTools</span> <span class="sidebar-title">ethend</span>
<button id="toggle-sidebar" title="折叠侧边栏"></button> <button id="toggle-sidebar" title="折叠侧边栏"></button>
</div> </div>
<nav class="sidebar-nav"> <nav class="sidebar-nav">
@@ -1319,7 +1319,7 @@ async function renderDashboard() {
'</div>' + '</div>' +
'<div class="stat-card orange">' + '<div class="stat-card orange">' +
'<div class="stat-value" id="stat-heap">' + (data.system?.heapUsedMB ?? '—') + ' MB</div>' + '<div class="stat-value" id="stat-heap">' + (data.system?.heapUsedMB ?? '—') + ' MB</div>' +
'<div class="stat-label">DevTools 内存</div>' + '<div class="stat-label">ethend 内存</div>' +
'</div>' + '</div>' +
'</div>' + '</div>' +
@@ -1331,7 +1331,7 @@ async function renderDashboard() {
'<button class="btn btn-sm btn-accent" onclick="svcAction(\'start-all\')">▶ 一键启动</button>' + '<button class="btn btn-sm btn-accent" onclick="svcAction(\'start-all\')">▶ 一键启动</button>' +
'<button class="btn btn-sm" onclick="svcAction(\'start-all-fresh\')">🔄 强制重启全部</button>' + '<button class="btn btn-sm" onclick="svcAction(\'start-all-fresh\')">🔄 强制重启全部</button>' +
'<button class="btn btn-sm btn-red" onclick="svcAction(\'stop-all\')">⏹ 全部停止</button>' + '<button class="btn btn-sm btn-red" onclick="svcAction(\'stop-all\')">⏹ 全部停止</button>' +
'<button class="btn btn-sm" onclick="restartDevTools()" style="margin-left:8px;border-color:var(--accent);color:var(--accent)" title="重启 DevTools 自身以应用更新">🔁 重启 DevTools</button>' + '<button class="btn btn-sm" onclick="restartEthend()" style="margin-left:8px;border-color:var(--accent);color:var(--accent)" title="重启 ethend 自身以应用更新">🔁 重启 ethend</button>' +
'</div>' + '</div>' +
'</div>' + '</div>' +
'<div class="cards-grid cards-4" id="dashboard-svc-cards"></div>' + '<div class="cards-grid cards-4" id="dashboard-svc-cards"></div>' +
@@ -2624,11 +2624,11 @@ async function clearSvcLogs() {
renderServiceLog(); renderServiceLog();
} }
// ---- DevTools 自重启 ---- // ---- ethend 自重启 ----
async function restartDevTools() { async function restartEthend() {
if (!confirm('确定要重启 DevTools 吗?\n\n页面将在几秒后自动刷新。')) return; if (!confirm('确定要重启 ethend 吗?\n\n页面将在几秒后自动刷新。')) return;
try { try {
await api('/api/devtools/restart', { method: 'POST' }); await api('/api/ethend/restart', { method: 'POST' });
} catch (e) { } catch (e) {
// 请求可能在收到响应前就中断(因为服务已退出),这是正常的 // 请求可能在收到响应前就中断(因为服务已退出),这是正常的
} }
@@ -1,5 +1,5 @@
/** /**
* 调试工具配置 * 管理控制台配置
* 定义各服务的启动参数端口健康检查等 * 定义各服务的启动参数端口健康检查等
*/ */
@@ -15,7 +15,7 @@ const ROOT = path.resolve(__dirname, '../..');
const isWin = os.platform() === 'win32'; const isWin = os.platform() === 'win32';
// 读取 backend/.env 文件,将值合并到 process.env(不覆盖已有的环境变量) // 读取 backend/.env 文件,将值合并到 process.env(不覆盖已有的环境变量)
// 这样 DevTools 启动各服务时能传递用户配置的凭据 // 这样 ethend 启动各服务时能传递用户配置的凭据
function loadEnvFile() { function loadEnvFile() {
const envPath = path.join(ROOT, 'backend', '.env'); const envPath = path.join(ROOT, 'backend', '.env');
try { try {
@@ -53,7 +53,7 @@ function findGoBin() {
const GO_BIN = findGoBin(); const GO_BIN = findGoBin();
export const DEVTOOLS_PORT = process.env.DEVTOOLS_PORT || 9090; export const ETHEND_PORT = process.env.ETHEND_PORT || 9090;
export const LOGS_DIR = path.resolve(__dirname, '../logs'); export const LOGS_DIR = path.resolve(__dirname, '../logs');
export const GATEWAY_URL = process.env.GATEWAY_URL || 'http://localhost:8080'; 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 PLUGIN_MANAGER_URL = process.env.PLUGIN_MANAGER_URL || 'http://localhost:8094';
+16 -16
View File
@@ -1,5 +1,5 @@
/** /**
* Cyrene DevTools - 主入口 * Cyrene ethend - 主入口
* *
* 提供: * 提供:
* - REST API: 服务管理状态查询性能分析健康检查代理 * - REST API: 服务管理状态查询性能分析健康检查代理
@@ -17,7 +17,7 @@ import { execSync, spawn } from 'child_process';
import { processManager } from './process-manager.js'; import { processManager } from './process-manager.js';
import { performanceMonitor } from './performance.js'; import { performanceMonitor } from './performance.js';
import { SERVICES, DEVTOOLS_PORT, LOGS_DIR, logFile, GATEWAY_URL, PLUGIN_MANAGER_URL, ADMIN_USERNAME, ADMIN_PASSWORD } from './config.js'; import { SERVICES, ETHEND_PORT, LOGS_DIR, logFile, GATEWAY_URL, PLUGIN_MANAGER_URL, ADMIN_USERNAME, ADMIN_PASSWORD } from './config.js';
const AI_CORE_URL = process.env.AI_CORE_URL || 'http://localhost:8081'; const AI_CORE_URL = process.env.AI_CORE_URL || 'http://localhost:8081';
const MEMORY_SERVICE_URL = process.env.MEMORY_SERVICE_URL || 'http://localhost:8091'; const MEMORY_SERVICE_URL = process.env.MEMORY_SERVICE_URL || 'http://localhost:8091';
@@ -209,15 +209,15 @@ async function proxyToAICore(path, opts = {}) {
app.get('/api/health', (_req, res) => { app.get('/api/health', (_req, res) => {
res.json({ res.json({
status: 'ok', status: 'ok',
service: 'cyrene-devtools', service: 'cyrene-ethend',
uptime: process.uptime(), uptime: process.uptime(),
wsClients: wsClients.size, wsClients: wsClients.size,
}); });
}); });
// ---- DevTools 自重启 ---- // ---- ethend 自重启 ----
app.post('/api/devtools/restart', (_req, res) => { app.post('/api/ethend/restart', (_req, res) => {
res.json({ success: true, message: 'DevTools 正在重启...' }); res.json({ success: true, message: 'ethend 正在重启...' });
// 延迟 500ms 确保响应已发送,然后 spawn 新进程并退出 // 延迟 500ms 确保响应已发送,然后 spawn 新进程并退出
setTimeout(() => { setTimeout(() => {
@@ -918,7 +918,7 @@ const sttLogEntries = [];
const MAX_STT_LOGS = 200; const MAX_STT_LOGS = 200;
/** /**
* 记录 STT 请求日志devtools 自身维护因为 voice-service 无持久化日志 * 记录 STT 请求日志ethend 自身维护因为 voice-service 无持久化日志
*/ */
function recordSTTLog(entry) { function recordSTTLog(entry) {
sttLogEntries.unshift(entry); sttLogEntries.unshift(entry);
@@ -969,7 +969,7 @@ app.post('/api/voice/transcribe', async (req, res) => {
try { try {
// 构建 multipart/form-data 请求转发到 Voice-Service // 构建 multipart/form-data 请求转发到 Voice-Service
const boundary = '----DevToolsFormBoundary' + Math.random().toString(36).slice(2); const boundary = '----ethendFormBoundary' + Math.random().toString(36).slice(2);
const crlf = '\r\n'; const crlf = '\r\n';
const headerParts = [ const headerParts = [
'--' + boundary + crlf, '--' + boundary + crlf,
@@ -1026,7 +1026,7 @@ app.post('/api/voice/transcribe', async (req, res) => {
recordSTTLog(logEntry); recordSTTLog(logEntry);
return res.status(voiceResp.status).json({ return res.status(voiceResp.status).json({
...voiceBody, ...voiceBody,
devtools_log_id: logEntry.id, ethend_log_id: logEntry.id,
}); });
} }
@@ -1045,7 +1045,7 @@ app.post('/api/voice/transcribe', async (req, res) => {
recordSTTLog(logEntry); recordSTTLog(logEntry);
return res.json({ return res.json({
...voiceBody, ...voiceBody,
devtools_log_id: logEntry.id, ethend_log_id: logEntry.id,
}); });
} catch (err) { } catch (err) {
const elapsedMs = Date.now() - startTime; const elapsedMs = Date.now() - startTime;
@@ -1070,7 +1070,7 @@ app.post('/api/voice/transcribe', async (req, res) => {
hint: isConnRefused hint: isConnRefused
? 'Voice-Service 服务未启动,请先在「服务管理」面板中启动 Voice-Service' ? 'Voice-Service 服务未启动,请先在「服务管理」面板中启动 Voice-Service'
: 'Voice-Service 服务无响应,请检查网络连接和服务状态', : 'Voice-Service 服务无响应,请检查网络连接和服务状态',
devtools_log_id: logEntry.id, ethend_log_id: logEntry.id,
}); });
} }
}); });
@@ -1725,11 +1725,11 @@ performanceMonitor.start();
// 确保日志目录存在 // 确保日志目录存在
fs.mkdirSync(LOGS_DIR, { recursive: true }); fs.mkdirSync(LOGS_DIR, { recursive: true });
server.listen(DEVTOOLS_PORT, () => { server.listen(ETHEND_PORT, () => {
console.log(`🛠️ Cyrene DevTools 已启动: http://localhost:${DEVTOOLS_PORT}`); console.log(`🛠️ Cyrene ethend 已启动: http://localhost:${ETHEND_PORT}`);
console.log(` API: http://localhost:${DEVTOOLS_PORT}/api/health`); console.log(` API: http://localhost:${ETHEND_PORT}/api/health`);
console.log(` WebSocket: ws://localhost:${DEVTOOLS_PORT}/ws`); console.log(` WebSocket: ws://localhost:${ETHEND_PORT}/ws`);
console.log(` Web控制台: http://localhost:${DEVTOOLS_PORT}`); console.log(` Web控制台: http://localhost:${ETHEND_PORT}`);
console.log(''); console.log('');
console.log(' 可用服务:'); console.log(' 可用服务:');
for (const [id, svc] of Object.entries(SERVICES)) { for (const [id, svc] of Object.entries(SERVICES)) {
+17
View File
@@ -0,0 +1,17 @@
// 页面路由 Store — 管理当前显示的页面
import { create } from 'zustand';
export type PageId = 'chat' | 'admin-models' | 'admin-dashboard' | 'profile';
interface PageState {
currentPage: PageId;
setPage: (page: PageId) => void;
goToChat: () => void;
}
export const usePageStore = create<PageState>((set) => ({
currentPage: 'chat',
setPage: (page) => set({ currentPage: page }),
goToChat: () => set({ currentPage: 'chat' }),
}));
+1 -1
View File
@@ -55,7 +55,7 @@ tar -czf "${OUTPUT_DIR}/${ARCHIVE_NAME}" \
--exclude='frontend/web/node_modules' \ --exclude='frontend/web/node_modules' \
--exclude='frontend/web/dist' \ --exclude='frontend/web/dist' \
--exclude='frontend/node_modules' \ --exclude='frontend/node_modules' \
--exclude='devtools/node_modules' \ --exclude='ethend/node_modules' \
--exclude='frontend/packages/*/node_modules' \ --exclude='frontend/packages/*/node_modules' \
--exclude='.env' \ --exclude='.env' \
--exclude='backend/.env' \ --exclude='backend/.env' \