Files
nofx/start.sh
tinkle-community 1bbd4b44ac feat(solo): beginner-friendly onboarding — smart setup guide + direct config commands
start.sh:
- Interactive Telegram Bot Token prompt on first run
- Token format validation (must match 12345:ABC... pattern)
- Friendly step-by-step startup instructions after launch

telegram/bot.go:
- /start now shows context-aware setup guide based on actual config state:
  - No AI model → explains how to configure, lists all providers
  - AI model OK but no exchange → guides to configure exchange via chat
  - All configured → full capabilities welcome message
- New: direct setup commands ('配置 deepseek sk-xxx') bypass LLM entirely
  so AI model can be configured even before any model exists (bootstrap fix)
- All messages now in Chinese (匹配用户语言)

telegram/agent/prompt.go:
- Added first-time setup detection section
- Agent told to never ask user to visit web UI — everything via chat
2026-03-08 18:40:51 +08:00

477 lines
16 KiB
Bash
Executable File
Raw 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.

#!/bin/bash
# ═══════════════════════════════════════════════════════════════
# NOFX AI Trading System - Docker Quick Start Script
# Usage: ./start.sh [command]
# ═══════════════════════════════════════════════════════════════
set -e
# ------------------------------------------------------------------------
# Color Definitions
# ------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# ------------------------------------------------------------------------
# Utility Functions: Colored Output
# ------------------------------------------------------------------------
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# ------------------------------------------------------------------------
# Detection: Docker Compose Command (Backward Compatible)
# ------------------------------------------------------------------------
detect_compose_cmd() {
if command -v docker compose &> /dev/null; then
COMPOSE_CMD="docker compose"
elif command -v docker-compose &> /dev/null; then
COMPOSE_CMD="docker-compose"
else
print_error "Docker Compose 未安装!请先安装 Docker Compose"
exit 1
fi
print_info "使用 Docker Compose 命令: $COMPOSE_CMD"
}
# ------------------------------------------------------------------------
# Validation: Docker Installation
# ------------------------------------------------------------------------
check_docker() {
if ! command -v docker &> /dev/null; then
print_error "Docker 未安装!请先安装 Docker: https://docs.docker.com/get-docker/"
exit 1
fi
detect_compose_cmd
print_success "Docker 和 Docker Compose 已安装"
}
# ------------------------------------------------------------------------
# Validation: Environment File (.env)
# ------------------------------------------------------------------------
check_env() {
if [ ! -f ".env" ]; then
print_warning ".env 不存在,从模板复制..."
cp .env.example .env
print_info "已创建 .env 文件"
fi
print_success "环境变量文件存在"
}
# ------------------------------------------------------------------------
# Helper: Check if env var is set and not placeholder
# ------------------------------------------------------------------------
is_env_configured() {
local var_name="$1"
local value=$(grep "^${var_name}=" .env 2>/dev/null | cut -d'=' -f2-)
# 去除引号
value=$(echo "$value" | tr -d '"'"'")
# 检查是否为空或占位符
if [ -z "$value" ]; then
return 1
fi
# 检查是否是示例值
case "$value" in
*your-*|*YOUR_*|*change-this*|*CHANGE_THIS*|*example*|*EXAMPLE*)
return 1
;;
esac
return 0
}
# ------------------------------------------------------------------------
# Helper: Generate and set env var in .env file
# ------------------------------------------------------------------------
set_env_var() {
local var_name="$1"
local var_value="$2"
# 如果变量已存在(即使是占位符),替换它
if grep -q "^${var_name}=" .env 2>/dev/null; then
# macOS 和 Linux 兼容的 sed
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s|^${var_name}=.*|${var_name}=${var_value}|" .env
else
sed -i "s|^${var_name}=.*|${var_name}=${var_value}|" .env
fi
else
# 变量不存在,追加
echo "${var_name}=${var_value}" >> .env
fi
}
# ------------------------------------------------------------------------
# Validation: Encryption Keys in .env
# ------------------------------------------------------------------------
check_encryption() {
print_info "检查加密密钥配置..."
local generated=false
# 检查并生成 JWT_SECRET
if ! is_env_configured "JWT_SECRET"; then
print_warning "JWT_SECRET 未配置,正在生成..."
local jwt_secret=$(openssl rand -base64 32)
set_env_var "JWT_SECRET" "$jwt_secret"
print_success "JWT_SECRET 已生成"
generated=true
fi
# 检查并生成 DATA_ENCRYPTION_KEY
if ! is_env_configured "DATA_ENCRYPTION_KEY"; then
print_warning "DATA_ENCRYPTION_KEY 未配置,正在生成..."
local data_key=$(openssl rand -base64 32)
set_env_var "DATA_ENCRYPTION_KEY" "$data_key"
print_success "DATA_ENCRYPTION_KEY 已生成"
generated=true
fi
# 检查并生成 RSA_PRIVATE_KEY
if ! is_env_configured "RSA_PRIVATE_KEY"; then
print_warning "RSA_PRIVATE_KEY 未配置,正在生成..."
# 生成 RSA 密钥并转换为单行格式(\n 替换为 \\n
local rsa_key=$(openssl genrsa 2048 2>/dev/null | awk '{printf "%s\\n", $0}')
set_env_var "RSA_PRIVATE_KEY" "\"$rsa_key\""
print_success "RSA_PRIVATE_KEY 已生成"
generated=true
fi
if [ "$generated" = true ]; then
echo ""
print_success "所有缺失的密钥已自动生成并保存到 .env"
print_warning "请妥善保管 .env 文件,不要提交到版本控制系统"
echo ""
fi
print_success "加密密钥检查完成"
print_info " • JWT_SECRET: OK"
print_info " • DATA_ENCRYPTION_KEY: OK"
print_info " • RSA_PRIVATE_KEY: OK"
# 修复 .env 文件权限
chmod 600 .env 2>/dev/null || true
}
# ------------------------------------------------------------------------
# Utility: Read Environment Variables
# ------------------------------------------------------------------------
read_env_vars() {
if [ -f ".env" ]; then
NOFX_FRONTEND_PORT=$(grep "^NOFX_FRONTEND_PORT=" .env 2>/dev/null | cut -d'=' -f2 || echo "3000")
NOFX_BACKEND_PORT=$(grep "^NOFX_BACKEND_PORT=" .env 2>/dev/null | cut -d'=' -f2 || echo "8080")
NOFX_FRONTEND_PORT=$(echo "$NOFX_FRONTEND_PORT" | tr -d '"'"'" | tr -d ' ')
NOFX_BACKEND_PORT=$(echo "$NOFX_BACKEND_PORT" | tr -d '"'"'" | tr -d ' ')
NOFX_FRONTEND_PORT=${NOFX_FRONTEND_PORT:-3000}
NOFX_BACKEND_PORT=${NOFX_BACKEND_PORT:-8080}
else
NOFX_FRONTEND_PORT=3000
NOFX_BACKEND_PORT=8080
fi
}
# ------------------------------------------------------------------------
# Validation: Database Directory (data/)
# ------------------------------------------------------------------------
check_database() {
# Ensure data directory exists
if [ ! -d "data" ]; then
print_warning "数据目录不存在,创建 data/ 目录..."
install -m 700 -d data
print_success "已创建 data/ 目录"
else
print_success "数据目录存在"
fi
}
# ------------------------------------------------------------------------
# First-time Setup: Telegram Bot Token
# ------------------------------------------------------------------------
setup_telegram() {
if is_env_configured "TELEGRAM_BOT_TOKEN"; then
local token=$(grep "^TELEGRAM_BOT_TOKEN=" .env | cut -d'=' -f2- | tr -d '"'"'")
print_success "Telegram Bot Token 已配置: ${token:0:10}..."
return
fi
echo ""
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} 🤖 Telegram Bot 配置(必须)${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo " 还没有 Bot Token按以下步骤获取"
echo ""
echo " 1. 打开 Telegram搜索 @BotFather"
echo " 2. 发送 /newbot"
echo " 3. 输入机器人名字(随意,如 MyTradingBot"
echo " 4. 输入用户名(必须以 bot 结尾,如 my_trading_bot"
echo " 5. BotFather 会给你一串 Token格式如"
echo " 1234567890:AABBCCDDEEFFaabbccddeeff..."
echo ""
while true; do
read -p " 请粘贴 Bot Token: " bot_token
bot_token=$(echo "$bot_token" | tr -d ' ')
if [ -z "$bot_token" ]; then
print_warning "Token 不能为空,请重新输入"
continue
fi
if [[ ! "$bot_token" =~ ^[0-9]+:.+ ]]; then
print_warning "Token 格式不对(应为 数字:字母, 如 123456:ABC...)请重试"
continue
fi
break
done
set_env_var "TELEGRAM_BOT_TOKEN" "$bot_token"
print_success "Bot Token 已保存 ✅"
echo ""
}
# ------------------------------------------------------------------------
# Service Management: Start
# ------------------------------------------------------------------------
start() {
echo ""
echo -e "${CYAN}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ 🚀 NOFX 个人 AI 交易机器人 启动向导 ║${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════════╝${NC}"
echo ""
read_env_vars
if [ ! -d "data" ]; then
install -m 700 -d data
fi
# Interactive setup for first-time users
setup_telegram
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
print_info "正在启动服务..."
if [ "$1" == "--build" ]; then
$COMPOSE_CMD up -d --build
else
$COMPOSE_CMD up -d
fi
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ ✅ 启动成功!接下来: ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
echo ""
echo " 1. 打开 Telegram找到你的机器人"
echo " 2. 发送 /start 绑定账号"
echo " 3. 机器人会引导你完成 AI 模型和交易所配置"
echo " 4. 配置完成后,直接发消息让机器人帮你交易"
echo ""
echo -e " Web 管理界面: ${BLUE}http://localhost:${NOFX_FRONTEND_PORT}${NC}(可选)"
echo -e " 查看日志: ${YELLOW}./start.sh logs${NC}"
echo -e " 停止服务: ${YELLOW}./start.sh stop${NC}"
echo ""
}
# ------------------------------------------------------------------------
# Service Management: Stop
# ------------------------------------------------------------------------
stop() {
print_info "正在停止服务..."
$COMPOSE_CMD stop
print_success "服务已停止"
}
# ------------------------------------------------------------------------
# Service Management: Restart
# ------------------------------------------------------------------------
restart() {
print_info "正在重启服务..."
$COMPOSE_CMD restart
print_success "服务已重启"
}
# ------------------------------------------------------------------------
# Monitoring: Logs
# ------------------------------------------------------------------------
logs() {
if [ -z "$2" ]; then
$COMPOSE_CMD logs -f
else
$COMPOSE_CMD logs -f "$2"
fi
}
# ------------------------------------------------------------------------
# Monitoring: Status
# ------------------------------------------------------------------------
status() {
read_env_vars
print_info "服务状态:"
$COMPOSE_CMD ps
echo ""
print_info "健康检查:"
curl -s "http://localhost:${NOFX_BACKEND_PORT}/api/health" | jq '.' || echo "后端未响应"
}
# ------------------------------------------------------------------------
# Maintenance: Clean (Destructive)
# ------------------------------------------------------------------------
clean() {
print_warning "这将删除所有容器和数据!"
read -p "确认删除?(yes/no): " confirm
if [ "$confirm" == "yes" ]; then
print_info "正在清理..."
$COMPOSE_CMD down -v
print_success "清理完成"
else
print_info "已取消"
fi
}
# ------------------------------------------------------------------------
# Maintenance: Update
# ------------------------------------------------------------------------
update() {
print_info "正在更新..."
git pull
$COMPOSE_CMD up -d --build
print_success "更新完成"
}
# ------------------------------------------------------------------------
# Command: Regenerate all keys (force)
# ------------------------------------------------------------------------
regenerate_keys() {
print_warning "这将重新生成所有加密密钥!"
print_warning "如果已有加密数据,重新生成后将无法解密!"
echo ""
read -p "确认重新生成?(yes/no): " confirm
if [ "$confirm" != "yes" ]; then
print_info "已取消"
return
fi
check_env
print_info "正在生成新的密钥..."
# 生成 JWT_SECRET
local jwt_secret=$(openssl rand -base64 32)
set_env_var "JWT_SECRET" "$jwt_secret"
print_success "JWT_SECRET 已生成"
# 生成 DATA_ENCRYPTION_KEY
local data_key=$(openssl rand -base64 32)
set_env_var "DATA_ENCRYPTION_KEY" "$data_key"
print_success "DATA_ENCRYPTION_KEY 已生成"
# 生成 RSA_PRIVATE_KEY
local rsa_key=$(openssl genrsa 2048 2>/dev/null | awk '{printf "%s\\n", $0}')
set_env_var "RSA_PRIVATE_KEY" "\"$rsa_key\""
print_success "RSA_PRIVATE_KEY 已生成"
chmod 600 .env 2>/dev/null || true
echo ""
print_success "所有密钥已重新生成并保存到 .env"
print_warning "请妥善保管 .env 文件"
}
# ------------------------------------------------------------------------
# Help: Usage Information
# ------------------------------------------------------------------------
show_help() {
echo "NOFX AI Trading System - Docker 管理脚本"
echo ""
echo "用法: ./start.sh [command] [options]"
echo ""
echo "命令:"
echo " start [--build] 启动服务(可选:重新构建)"
echo " stop 停止服务"
echo " restart 重启服务"
echo " logs [service] 查看日志(可选:指定服务名 backend/frontend"
echo " status 查看服务状态"
echo " clean 清理所有容器和数据"
echo " update 更新代码并重启"
echo " regenerate-keys 重新生成所有加密密钥(慎用)"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " ./start.sh start --build # 构建并启动"
echo " ./start.sh logs backend # 查看后端日志"
echo " ./start.sh status # 查看状态"
echo ""
echo "首次使用:"
echo " 直接运行 ./start.sh 即可,缺失的密钥会自动生成"
}
# ------------------------------------------------------------------------
# Main: Command Dispatcher
# ------------------------------------------------------------------------
main() {
check_docker
case "${1:-start}" in
start)
check_env
check_encryption
check_database
start "$2"
;;
stop)
stop
;;
restart)
restart
;;
logs)
logs "$@"
;;
status)
status
;;
clean)
clean
;;
update)
update
;;
regenerate-keys)
regenerate_keys
;;
help|--help|-h)
show_help
;;
*)
print_error "未知命令: $1"
show_help
exit 1
;;
esac
}
# Execute Main
main "$@"