Initial commit of integrated agent system

This commit is contained in:
cillin
2026-03-30 17:46:44 +08:00
commit 0fa413380c
337 changed files with 75268 additions and 0 deletions

333
start.sh Executable file
View File

@@ -0,0 +1,333 @@
#!/usr/bin/env bash
# ============================================================
# 大时代 生产环境启动脚本
#
# 用法:
# ./start.sh # 构建前端 + 后台启动全部服务 (默认)
# ./start.sh --no-build # 跳过前端构建
# ./start.sh --no-daemon # 前台运行 (不使用 nohup)
# ./start.sh --gateway-only # 仅启动 Gateway (配合 nginx)
# ./start.sh stop # 停止所有后台服务
# ./start.sh status # 查看服务状态
#
# 环境变量:
# WORKERS=2 # uvicorn worker 数 (默认: 2)
# GATEWAY_HOST=0.0.0.0 # Gateway 绑定地址
# GATEWAY_PORT=8765 # Gateway 端口
# FRONTEND_PORT=80 # 前端服务端口 (默认: 80)
# ============================================================
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${SCRIPT_DIR}"
WORKERS="${WORKERS:-2}"
GATEWAY_HOST="${GATEWAY_HOST:-0.0.0.0}"
GATEWAY_PORT="${GATEWAY_PORT:-8765}"
FRONTEND_PORT="${FRONTEND_PORT:-80}"
PID_DIR="${SCRIPT_DIR}/.pids"
LOG_DIR="${SCRIPT_DIR}/logs"
FRONTEND_DIST="${SCRIPT_DIR}/frontend/dist"
DAEMON=true
BUILD_FRONTEND=true
GATEWAY_ONLY=false
ACTION="start"
for arg in "$@"; do
case "$arg" in
--no-daemon) DAEMON=false ;;
--no-build) BUILD_FRONTEND=false ;;
--gateway-only) GATEWAY_ONLY=true ;;
stop) ACTION="stop" ;;
status) ACTION="status" ;;
*) echo -e "${YELLOW}忽略未知参数: ${arg}${NC}" ;;
esac
done
ensure_dirs() {
mkdir -p "${PID_DIR}" "${LOG_DIR}"
}
save_pid() {
local name="$1" pid="$2"
echo "${pid}" > "${PID_DIR}/${name}.pid"
}
read_pid() {
local name="$1"
local pidfile="${PID_DIR}/${name}.pid"
if [ -f "${pidfile}" ]; then
cat "${pidfile}"
fi
}
is_running() {
local pid="$1"
[ -n "${pid}" ] && kill -0 "${pid}" 2>/dev/null
}
stop_service() {
local name="$1"
local pid
pid="$(read_pid "${name}")"
if is_running "${pid}"; then
echo -e " ${YELLOW}停止${NC} ${name} (PID: ${pid})"
kill "${pid}" 2>/dev/null || true
local count=0
while is_running "${pid}" && [ "${count}" -lt 20 ]; do
sleep 0.5
count=$((count + 1))
done
if is_running "${pid}"; then
echo -e " ${RED}强制终止${NC} ${name}"
kill -9 "${pid}" 2>/dev/null || true
fi
fi
rm -f "${PID_DIR}/${name}.pid"
}
print_status() {
local name="$1" port="$2"
local pid
pid="$(read_pid "${name}")"
if is_running "${pid}"; then
echo -e " ${GREEN}${NC} ${name} (PID: ${pid}, 端口: ${port})"
else
echo -e " ${RED}${NC} ${name} (未运行)"
fi
}
load_env() {
if [ -f .env ]; then
set -a
# shellcheck disable=SC1091
source .env
set +a
else
echo -e "${YELLOW}警告: 未检测到 .env将使用环境变量或默认值${NC}"
fi
}
check_prereqs() {
# Resolve the Python interpreter to use. Prefer the project venv.
if [ -x "${SCRIPT_DIR}/.venv/bin/python" ]; then
PYTHON="${SCRIPT_DIR}/.venv/bin/python"
else
PYTHON="$(command -v python3 2>/dev/null || command -v python 2>/dev/null || true)"
fi
if [ -z "${PYTHON}" ]; then
echo -e "${RED}未找到 python${NC}"
exit 1
fi
echo -e "${GREEN}使用 Python: ${PYTHON}${NC}"
command -v lsof >/dev/null 2>&1 || {
echo -e "${RED}未找到 lsof${NC}"
exit 1
}
}
kill_port() {
local port="$1"
local pids
pids="$(lsof -ti :"${port}" 2>/dev/null || true)"
if [ -n "${pids}" ]; then
echo -e "${YELLOW}端口 ${port} 已被占用,清理 PID:${NC} ${pids}"
echo "${pids}" | xargs kill -9 2>/dev/null || true
sleep 0.5
fi
}
do_stop() {
echo -e "${CYAN}停止所有服务...${NC}"
for svc in frontend agent_service trading_service news_service runtime_service openclaw_service; do
stop_service "${svc}"
done
echo -e "${GREEN}已停止${NC}"
}
do_status() {
echo ""
echo -e "${CYAN}服务状态${NC}"
print_status "agent_service" 8000
print_status "trading_service" 8001
print_status "news_service" 8002
print_status "runtime_service" 8003
print_status "openclaw_service" 8004
print_status "frontend" "${FRONTEND_PORT}"
echo ""
echo -e " ${CYAN}${NC} Gateway 由 runtime_service 管理,通过前端启动任务触发"
echo ""
if [ -d "${FRONTEND_DIST}" ]; then
echo -e " ${GREEN}${NC} 前端已构建: ${FRONTEND_DIST}"
else
echo -e " ${YELLOW}${NC} 前端未构建,运行: cd frontend && npm run build"
fi
echo ""
}
build_frontend() {
if ! ${BUILD_FRONTEND}; then
return
fi
echo ""
echo -e "${CYAN}构建前端...${NC}"
if [ -d "frontend" ] && command -v npm >/dev/null 2>&1; then
if [ -f "frontend/package-lock.json" ]; then
(cd frontend && npm ci && npm run build)
else
(cd frontend && npm install && npm run build)
fi
echo -e "${GREEN}前端构建完成: ${FRONTEND_DIST}${NC}"
else
echo -e "${RED}前端构建失败: 需要 npm 和 frontend 目录${NC}"
exit 1
fi
}
start_single_daemon() {
local name="$1" app_path="$2" port="$3"
echo -e " ${GREEN}${NC} ${name} → :${port} (${WORKERS} workers)"
nohup env SERVICE_NAME="${name}" "${PYTHON}" -m uvicorn "${app_path}" \
--host 0.0.0.0 \
--port "${port}" \
--workers "${WORKERS}" \
--log-level warning \
--no-access-log \
>> "${LOG_DIR}/${name}.log" 2>&1 &
save_pid "${name}" $!
}
start_daemon() {
if ! ${GATEWAY_ONLY}; then
start_single_daemon "agent_service" "backend.apps.agent_service:app" 8000
start_single_daemon "trading_service" "backend.apps.trading_service:app" 8001
start_single_daemon "news_service" "backend.apps.news_service:app" 8002
start_single_daemon "runtime_service" "backend.apps.runtime_service:app" 8003
start_single_daemon "openclaw_service" "backend.apps.openclaw_service:app" 8004
fi
echo -e " ${GREEN}${NC} frontend → http://0.0.0.0:${FRONTEND_PORT}"
nohup env SERVICE_NAME="frontend" "${PYTHON}" -m uvicorn "backend.apps.frontend_service:app" \
--host 0.0.0.0 \
--port "${FRONTEND_PORT}" \
--workers "${WORKERS}" \
--log-level warning \
--no-access-log \
>> "${LOG_DIR}/frontend.log" 2>&1 &
save_pid "frontend" $!
echo ""
echo -e "${GREEN}所有服务已在后台启动${NC}"
echo " 日志目录: ${LOG_DIR}/"
echo " PID 目录: ${PID_DIR}/"
echo ""
echo " 查看状态: ./start.sh status"
echo " 查看日志: tail -f ${LOG_DIR}/gateway.log"
echo " 停止服务: ./start.sh stop"
echo ""
}
PIDS=()
cleanup_foreground() {
echo ""
echo -e "${YELLOW}正在停止所有服务...${NC}"
if [ "${#PIDS[@]}" -gt 0 ]; then
kill "${PIDS[@]}" 2>/dev/null || true
wait "${PIDS[@]}" 2>/dev/null || true
fi
}
start_single_foreground() {
local name="$1" app_path="$2" port="$3"
echo -e " ${GREEN}${NC} ${name} → :${port}"
env SERVICE_NAME="${name}" "${PYTHON}" -m uvicorn "${app_path}" \
--host 0.0.0.0 \
--port "${port}" \
--log-level warning \
--no-access-log &
PIDS+=($!)
}
start_foreground() {
trap cleanup_foreground EXIT INT TERM
if ! ${GATEWAY_ONLY}; then
start_single_foreground "agent_service" "backend.apps.agent_service:app" 8000
start_single_foreground "trading_service" "backend.apps.trading_service:app" 8001
start_single_foreground "news_service" "backend.apps.news_service:app" 8002
start_single_foreground "runtime_service" "backend.apps.runtime_service:app" 8003
start_single_foreground "openclaw_service" "backend.apps.openclaw_service:app" 8004
fi
echo -e " ${GREEN}${NC} frontend → http://0.0.0.0:${FRONTEND_PORT}"
env SERVICE_NAME="frontend" "${PYTHON}" -m uvicorn "backend.apps.frontend_service:app" \
--host 0.0.0.0 \
--port "${FRONTEND_PORT}" \
--log-level warning \
--no-access-log &
PIDS+=($!)
echo ""
echo -e "${GREEN}服务以前台模式运行。按 Ctrl+C 停止。${NC}"
wait
}
do_start() {
ensure_dirs
check_prereqs
load_env
export TRADING_SERVICE_URL="${TRADING_SERVICE_URL:-http://localhost:8001}"
export NEWS_SERVICE_URL="${NEWS_SERVICE_URL:-http://localhost:8002}"
export RUNTIME_SERVICE_URL="${RUNTIME_SERVICE_URL:-http://localhost:8003}"
export OPENCLAW_SERVICE_URL="${OPENCLAW_SERVICE_URL:-http://localhost:8004}"
build_frontend
echo ""
echo -e "${CYAN}停止已有服务...${NC}"
for svc in frontend agent_service trading_service news_service runtime_service openclaw_service; do
stop_service "${svc}"
done
echo ""
echo -e "${CYAN}══════════════════════════════════════════${NC}"
echo -e "${CYAN} 大时代 · 生产环境启动${NC}"
echo -e "${CYAN}══════════════════════════════════════════${NC}"
echo ""
if ${DAEMON}; then
start_daemon
else
start_foreground
fi
}
case "${ACTION}" in
start)
do_start
;;
stop)
do_stop
;;
status)
do_status
;;
*)
echo -e "${RED}未知动作: ${ACTION}${NC}"
exit 1
;;
esac