| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- #!/usr/bin/env bash
- # ============================================================
- # LambdAgent PaaS 一键安装启动脚本
- # 用法:
- # chmod +x setup.sh
- # ./setup.sh # 安装并启动(自动识别 发行包/源码 两种模式)
- # ./setup.sh --build # 构建普通 wheel 包到 dist/(含 .py 源码)
- # ./setup.sh --build-secure # 用 Nuitka 编译成 .so wheel 到 dist-secure/(防逆向,仍需 Python)
- # ./setup.sh --build-binary # 用 Nuitka 打成单文件二进制 dist-binary/(防逆向 + 免装 Python)
- # ./setup.sh --package # 打出「不含源码」的发行包 release/(优先用编译版)
- # ./setup.sh --docker # 使用 Docker 启动
- # ./setup.sh --help # 查看帮助
- #
- # 安装模式(install_deps 自动判定):
- # 发行模式 dist/*.whl 存在 → 从预编译 wheel 安装(终端用户拿到的包用这种)
- # 开发模式 无 wheel 但有源码目录 → editable 安装(开发者本机)
- # ============================================================
- set -e
- # ── 颜色输出 ──────────────────────────────────────────────
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- BLUE='\033[0;34m'
- NC='\033[0m' # No Color
- info() { echo -e "${BLUE}[INFO]${NC} $1"; }
- ok() { echo -e "${GREEN}[OK]${NC} $1"; }
- warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
- fail() { echo -e "${RED}[FAIL]${NC} $1"; exit 1; }
- # ── 项目根目录 ────────────────────────────────────────────
- PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
- cd "$PROJECT_DIR"
- # ── 帮助信息 ──────────────────────────────────────────────
- show_help() {
- echo ""
- echo "LambdAgent PaaS 一键安装启动脚本"
- echo ""
- echo "用法:"
- echo " ./setup.sh 安装依赖并启动服务(自动识别发行/源码模式)"
- echo " ./setup.sh --build 构建普通 wheel 包 → dist/*.whl(仍含 .py 源码)"
- echo " ./setup.sh --build-secure Nuitka 编译成 .so wheel → dist-secure/(防逆向,仍需 Python)"
- echo " ./setup.sh --build-binary Nuitka 打成单文件二进制 → dist-binary/(防逆向 + 免装 Python)"
- echo " ./setup.sh --package 打出不含源码的发行包 → release/(有编译版则优先用)"
- echo " ./setup.sh --docker 使用 Docker Compose 启动"
- echo " ./setup.sh --install 仅安装依赖,不启动服务"
- echo " ./setup.sh --launch 安装并一键启动 Agent 对话"
- echo " ./setup.sh --help 显示此帮助信息"
- echo ""
- echo "发布给终端用户的流程(开发者执行):"
- echo " ./setup.sh --build # 在源码树里先构建 wheel"
- echo " ./setup.sh --package # 组装 release/,里面只有 wheel + 启动脚本,无源码"
- echo " 然后把 release/ 压缩发给用户;用户解压后跑 ./setup.sh 即可"
- echo ""
- echo "环境要求:"
- echo " Python 方式: Python 3.10+"
- echo " Docker 方式: Docker + Docker Compose"
- echo ""
- }
- # ── 检查 Python ───────────────────────────────────────────
- check_python() {
- if command -v python3 &>/dev/null; then
- PYTHON=python3
- elif command -v python &>/dev/null; then
- PYTHON=python
- else
- fail "未找到 Python。请安装 Python 3.10+\n macOS: brew install python@3.12\n Ubuntu: sudo apt install python3 python3-venv python3-pip"
- fi
- # 检查版本
- PY_VERSION=$($PYTHON -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
- PY_MAJOR=$($PYTHON -c 'import sys; print(sys.version_info.major)')
- PY_MINOR=$($PYTHON -c 'import sys; print(sys.version_info.minor)')
- if [ "$PY_MAJOR" -lt 3 ] || { [ "$PY_MAJOR" -eq 3 ] && [ "$PY_MINOR" -lt 10 ]; }; then
- fail "Python 版本过低: $PY_VERSION(需要 3.10+)"
- fi
- ok "Python $PY_VERSION"
- }
- # ── 检查 Docker ───────────────────────────────────────────
- check_docker() {
- if ! command -v docker &>/dev/null; then
- fail "未找到 Docker。请先安装 Docker Desktop\n https://www.docker.com/products/docker-desktop/"
- fi
- if ! docker info &>/dev/null 2>&1; then
- fail "Docker 未运行。请启动 Docker Desktop"
- fi
- if ! command -v docker-compose &>/dev/null && ! docker compose version &>/dev/null 2>&1; then
- fail "未找到 Docker Compose"
- fi
- ok "Docker $(docker --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')"
- }
- # ── 配置 .env 文件 ────────────────────────────────────────
- setup_env() {
- if [ ! -f .env ]; then
- if [ -f .env.example ]; then
- cp .env.example .env
- warn ".env 文件已从 .env.example 创建"
- echo ""
- echo " ┌─────────────────────────────────────────────┐"
- echo " │ 请编辑 .env 文件,填入你的 LLM API Key: │"
- echo " │ │"
- echo " │ 至少填写以下其中一个: │"
- echo " │ DASHSCOPE_API_KEY=sk-xxx │"
- echo " │ OPENAI_API_KEY=sk-xxx │"
- echo " │ ANTHROPIC_API_KEY=sk-xxx │"
- echo " │ DEEPSEEK_API_KEY=sk-xxx │"
- echo " │ │"
- echo " │ 编辑命令: nano .env 或 vim .env │"
- echo " └─────────────────────────────────────────────┘"
- echo ""
- read -p "是否现在编辑 .env 文件?(y/N) " -r
- if [[ $REPLY =~ ^[Yy]$ ]]; then
- if command -v nano &>/dev/null; then
- nano .env
- elif command -v vim &>/dev/null; then
- vim .env
- else
- info "请手动编辑 .env 文件后重新运行此脚本"
- exit 0
- fi
- fi
- fi
- else
- ok ".env 文件已存在"
- fi
- }
- # ── 构建发行 wheel 包 ─────────────────────────────────────
- # 把 lambdagent / agentpaas 两个子包构建成 .whl 放进 dist/。
- # wheel 是「打包后的安装件」——发给用户的不再是整个源码树(含 .git、
- # 测试、商业计划书等),而是这两个 whl。注意:普通 wheel 内部仍是 .py
- # 源文件,它解决的是「别再把整个仓库 editable 送人」,不是代码混淆;
- # 真要防逆向需要 Nuitka 编译,见 docs/DESKTOP_MANUAL_zh.md「源码保护」一节。
- build_wheels() {
- check_python
- if [ ! -d lambdagent ] || [ ! -d agentpaas ]; then
- fail "未找到源码目录(lambdagent/ agentpaas/)。--build 只能在源码树里执行。"
- fi
- # 构建 wheel 走 PEP 517 构建隔离,不依赖 .venv —— 直接用 $PYTHON 即可。
- info "构建 wheel 包 → dist/ ..."
- mkdir -p dist
- rm -f dist/lambdagent-*.whl dist/agentpaas-*.whl
- $PYTHON -m pip wheel --no-deps ./lambdagent -w dist/ --quiet
- $PYTHON -m pip wheel --no-deps ./agentpaas -w dist/ --quiet
- echo ""
- ok "wheel 构建完成:"
- ls -1 dist/lambdagent-*.whl dist/agentpaas-*.whl 2>/dev/null | sed 's/^/ /'
- echo ""
- echo " 下一步: ./setup.sh --package 组装不含源码的发行包"
- echo ""
- }
- # ── 组装「不含源码」的发行包 ──────────────────────────────
- # 产出 release/:只含 wheel + 启动脚本 + 前端静态产物 + 配置样例 + 文档,
- # 不含 lambdagent/src、agentpaas/src、tests、.git、商业计划书等。
- # 把 release/ 压缩后发给终端用户即可。
- package_release() {
- # 优先用编译版(dist-secure/,.so wheel,防逆向);没有则退回普通 dist/
- local WHEEL_SRC=dist
- if ls dist-secure/lambdagent-*.whl >/dev/null 2>&1 && ls dist-secure/agentpaas-*.whl >/dev/null 2>&1; then
- WHEEL_SRC=dist-secure
- info "检测到编译版 wheel,发行包将使用 dist-secure/(.so,防逆向)。"
- elif ! ls dist/lambdagent-*.whl >/dev/null 2>&1 || ! ls dist/agentpaas-*.whl >/dev/null 2>&1; then
- warn "未找到 wheel,先执行普通构建(如需防逆向请改用 ./setup.sh --build-secure)..."
- build_wheels
- fi
- # 从 agentpaas/pyproject.toml 取版本号(兼容无源码时回退到 wheel 文件名)
- local VER
- if [ -f agentpaas/pyproject.toml ]; then
- VER=$(grep -m1 '^version' agentpaas/pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
- else
- VER=$(ls dist/agentpaas-*.whl 2>/dev/null | sed -E 's/.*agentpaas-([0-9][^-]*)-.*/\1/' | head -1)
- fi
- [ -z "$VER" ] && VER="dev"
- info "组装发行包 → release/ ..."
- rm -rf release
- mkdir -p release/dist
- cp "$WHEEL_SRC"/lambdagent-*.whl "$WHEEL_SRC"/agentpaas-*.whl release/dist/
- cp setup.sh release/
- chmod +x release/setup.sh
- # 前端静态产物(已编译,无源码)
- [ -d webui-dist ] && cp -R webui-dist release/
- # 用户需要的配置样例 / 编排文件 / 文档(均非核心源码)
- [ -f .env.example ] && cp .env.example release/
- [ -f docker-compose.yml ] && cp docker-compose.yml release/
- [ -f Dockerfile ] && cp Dockerfile release/ 2>/dev/null || true
- [ -d agentexample ] && cp -R agentexample release/
- mkdir -p release/docs
- [ -f docs/DESKTOP_MANUAL_zh.md ] && cp docs/DESKTOP_MANUAL_zh.md release/docs/
- [ -f QUICK_START.md ] && cp QUICK_START.md release/
- [ -f README.md ] && cp README.md release/
- [ -f LICENSE ] && cp LICENSE release/
- # 清掉 macOS 垃圾文件
- find release -name '.DS_Store' -delete 2>/dev/null || true
- echo ""
- ok "发行包已生成: release/"
- echo " 内容(不含任何 src 源码 / .git / 内部文档):"
- (cd release && find . -maxdepth 2 -type f | sed 's/^/ /' | head -30)
- echo ""
- echo " 压缩发布: zip -r lambdagent-paas-${VER}.zip release/"
- echo " 用户使用: 解压 → cd release → ./setup.sh"
- echo ""
- }
- # ── 创建虚拟环境并安装依赖 ────────────────────────────────
- # 自动判定两种模式:
- # 发行模式: 同目录 dist/*.whl 存在 → 从预编译 wheel 安装(终端用户)
- # 开发模式: 无 wheel 但有源码目录 → editable 安装(开发者本机)
- install_deps() {
- info "创建 Python 虚拟环境..."
- if [ ! -d .venv ]; then
- $PYTHON -m venv .venv
- ok "虚拟环境已创建: .venv/"
- else
- ok "虚拟环境已存在: .venv/"
- fi
- # 激活虚拟环境
- source .venv/bin/activate
- pip install --quiet --upgrade pip >/dev/null 2>&1
- if ls dist/lambdagent-*.whl >/dev/null 2>&1 && ls dist/agentpaas-*.whl >/dev/null 2>&1; then
- # ── 发行模式: 从 wheel 安装 ──
- info "检测到预编译 wheel,按【发行模式】安装..."
- # 先装 lambdagent(agentpaas 依赖它),再装 agentpaas;
- # 第三方依赖(fastapi 等)由 pip 从 PyPI 拉取。
- pip install --quiet --upgrade dist/lambdagent-*.whl
- ok "lambdagent 已从 wheel 安装"
- pip install --quiet --upgrade dist/agentpaas-*.whl
- ok "agentpaas 已从 wheel 安装"
- elif [ -d lambdagent ] && [ -d agentpaas ]; then
- # ── 开发模式: editable 源码安装 ──
- info "未检测到 wheel,按【开发模式】editable 安装源码..."
- # 修复历史 bug: 原为 `pip install -e ".[all]"`(root 无 pyproject,
- # 实际安装失败),lambdagent 真实路径是 ./lambdagent。
- pip install -e "./lambdagent[all]" --quiet 2>&1 | tail -1
- ok "lambdagent 已安装(editable)"
- pip install -e "./agentpaas[dev]" --quiet 2>&1 | tail -1
- ok "agentpaas 已安装(editable)"
- else
- fail "既无 dist/*.whl 也无源码目录(lambdagent/ agentpaas/),无法安装。"
- fi
- echo ""
- ok "所有依赖安装完成!"
- echo ""
- echo " 激活虚拟环境: source .venv/bin/activate"
- echo ""
- }
- # ── Python 方式启动 ───────────────────────────────────────
- start_python() {
- source .venv/bin/activate
- # 加载 .env
- if [ -f .env ]; then
- set -a
- source .env
- set +a
- fi
- info "启动 AgentPaaS 服务(开发模式)..."
- echo ""
- echo " ┌─────────────────────────────────────────────┐"
- echo " │ 服务地址: http://localhost:${AGENTPAAS_PORT:-8000} │"
- echo " │ API 文档: http://localhost:${AGENTPAAS_PORT:-8000}/docs │"
- echo " │ 按 Ctrl+C 停止服务 │"
- echo " └─────────────────────────────────────────────┘"
- echo ""
- python -m agentpaas serve --dev
- }
- # ── Docker 方式启动 ───────────────────────────────────────
- start_docker() {
- check_docker
- setup_env
- info "使用 Docker Compose 启动..."
- # 使用根目录的 docker-compose
- if docker compose version &>/dev/null 2>&1; then
- COMPOSE_CMD="docker compose"
- else
- COMPOSE_CMD="docker-compose"
- fi
- $COMPOSE_CMD -f docker-compose.yml up --build
- }
- # ── 一键启动 Agent 对话 ───────────────────────────────────
- launch_agent() {
- source .venv/bin/activate
- # 加载 .env
- if [ -f .env ]; then
- set -a
- source .env
- set +a
- fi
- CONFIG_FILE="${1:-agent-config.yml}"
- if [ ! -f "$CONFIG_FILE" ]; then
- fail "Agent 配置文件不存在: $CONFIG_FILE\n 请创建配置文件或指定路径: ./setup.sh --launch your-config.yml"
- fi
- info "一键启动 Agent: $CONFIG_FILE"
- python -m agentpaas launch "$CONFIG_FILE"
- }
- # ── 主流程 ────────────────────────────────────────────────
- main() {
- echo ""
- echo "================================================"
- echo " LambdAgent PaaS 一键安装启动"
- echo "================================================"
- echo ""
- case "${1:-}" in
- --help|-h)
- show_help
- exit 0
- ;;
- --build)
- build_wheels
- ;;
- --build-secure)
- check_python
- bash scripts/build_secure.sh "$PYTHON"
- ;;
- --build-binary)
- check_python
- bash scripts/build_binary.sh "$PYTHON"
- ;;
- --package)
- package_release
- ;;
- --docker)
- start_docker
- ;;
- --install)
- check_python
- setup_env
- install_deps
- echo "安装完成! 启动服务请运行:"
- echo " source .venv/bin/activate"
- echo " python -m agentpaas serve --dev"
- ;;
- --launch)
- check_python
- setup_env
- install_deps
- launch_agent "${2:-}"
- ;;
- *)
- check_python
- setup_env
- install_deps
- start_python
- ;;
- esac
- }
- main "$@"
|