|
|
@@ -0,0 +1,117 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+# ============================================================
|
|
|
+# build_binary.sh — 用 Nuitka 把整个 agentpaas 打成单个原生可执行文件
|
|
|
+# (standalone + onefile)。用户拿到后【无需安装 Python】,直接 ./agentpaas serve。
|
|
|
+#
|
|
|
+# 与 --build-secure(.so wheel)的区别:
|
|
|
+# --build-secure : 仍是 wheel,用户要有匹配的 Python;保护的是源码
|
|
|
+# --build-binary : 单文件二进制,内嵌 Python + 依赖 + 前端 + 内置包;保护源码 + 免装环境
|
|
|
+#
|
|
|
+# 产物:dist-binary/agentpaas(绑定「平台 + 架构」,如 macOS arm64)。
|
|
|
+#
|
|
|
+# 用法: scripts/build_binary.sh [PYTHON]
|
|
|
+# PYTHON 默认 python3,须为原生架构、3.10+、带头文件(macOS 推荐 Homebrew python3.11)。
|
|
|
+# 环境:
|
|
|
+# PROVIDERS 要打进二进制的 LLM SDK,空格分隔,默认 "anthropic openai"
|
|
|
+# (dashscope 走 openai 兼容/HTTP、ollama 走 HTTP,均无需 SDK)
|
|
|
+# ONEFILE 1=单文件(默认,体验最好但打包耗资源);0=standalone 目录
|
|
|
+# (产出一个文件夹,更省内存、更稳,适合 CI/资源受限机器)
|
|
|
+#
|
|
|
+# 前置: C 编译器(macOS: xcode-select --install)
|
|
|
+# ============================================================
|
|
|
+set -e
|
|
|
+
|
|
|
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
+PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
+cd "$PROJECT_DIR"
|
|
|
+
|
|
|
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
|
|
+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; }
|
|
|
+
|
|
|
+PYTHON="${1:-python3}"
|
|
|
+PROVIDERS="${PROVIDERS:-anthropic openai}"
|
|
|
+ONEFILE="${ONEFILE:-1}"
|
|
|
+command -v "$PYTHON" >/dev/null 2>&1 || fail "未找到 Python: $PYTHON"
|
|
|
+
|
|
|
+# ── 架构/版本/头文件检查(与 build_secure 一致)──────────────
|
|
|
+read -r PYARCH HAVE_H <<EOF
|
|
|
+$("$PYTHON" - <<'PY'
|
|
|
+import platform, sysconfig, os
|
|
|
+inc = sysconfig.get_path('include')
|
|
|
+print(f"{platform.machine()} {int(os.path.exists(os.path.join(inc,'Python.h')))}")
|
|
|
+PY
|
|
|
+)
|
|
|
+EOF
|
|
|
+HOSTARCH="$(uname -m)"
|
|
|
+[ "$PYARCH" = "$HOSTARCH" ] || fail "Python 架构($PYARCH) ≠ 主机($HOSTARCH)。请用原生 $HOSTARCH 的 Python(如 Homebrew python3.11),不要用 Rosetta 下的 x86_64 Python。"
|
|
|
+[ "$HAVE_H" = "1" ] || fail "缺 Python.h 头文件。请装带头文件的 Python(如 Homebrew)。"
|
|
|
+
|
|
|
+# ── 构建专用 venv:装 nuitka + 应用 + provider SDK ─────────
|
|
|
+BUILD_VENV="$PROJECT_DIR/.nuitka-venv"
|
|
|
+[ -x "$BUILD_VENV/bin/python" ] || "$PYTHON" -m venv "$BUILD_VENV"
|
|
|
+BPY="$BUILD_VENV/bin/python"
|
|
|
+info "准备构建环境(装 nuitka + 应用 + provider)..."
|
|
|
+"$BPY" -m pip install -q --upgrade pip nuitka >/dev/null
|
|
|
+# onefile 是 standalone:依赖必须真实安装进构建环境,Nuitka 才能跟进打包
|
|
|
+"$BPY" -m pip install -q ./lambdagent ./agentpaas $PROVIDERS
|
|
|
+
|
|
|
+# 仅对真正装上的 provider 生成 --include-module
|
|
|
+PROVIDER_FLAGS=()
|
|
|
+for p in $PROVIDERS; do
|
|
|
+ if "$BPY" -c "import $p" >/dev/null 2>&1; then
|
|
|
+ PROVIDER_FLAGS+=("--include-module=$p")
|
|
|
+ ok "provider 已纳入: $p"
|
|
|
+ else
|
|
|
+ warn "provider 未装上,跳过: $p"
|
|
|
+ fi
|
|
|
+done
|
|
|
+
|
|
|
+# ── Nuitka standalone + onefile ───────────────────────────
|
|
|
+OUT="$PROJECT_DIR/build_binary_out"
|
|
|
+rm -rf "$OUT"; mkdir -p "$OUT"
|
|
|
+ENTRY="agentpaas/src/agentpaas/__main__.py"
|
|
|
+
|
|
|
+MODE_FLAGS=(--standalone)
|
|
|
+[ "$ONEFILE" = "1" ] && MODE_FLAGS+=(--onefile)
|
|
|
+info "Nuitka 打包二进制(mode: $([ "$ONEFILE" = 1 ] && echo onefile单文件 || echo standalone目录),首次可能 10+ 分钟)..."
|
|
|
+"$BPY" -m nuitka \
|
|
|
+ "${MODE_FLAGS[@]}" \
|
|
|
+ --output-filename=agentpaas \
|
|
|
+ --output-dir="$OUT" \
|
|
|
+ --include-package=uvicorn \
|
|
|
+ --include-module=uvloop --include-module=httptools \
|
|
|
+ --include-module=websockets --include-module=h11 \
|
|
|
+ --include-package=agentpaas --include-package=lambdagent \
|
|
|
+ "${PROVIDER_FLAGS[@]}" \
|
|
|
+ --include-data-dir=webui-dist=webui-dist \
|
|
|
+ --include-data-dir=agentexample/agentpacks=agentexample/agentpacks \
|
|
|
+ --python-flag=no_docstrings \
|
|
|
+ --assume-yes-for-downloads \
|
|
|
+ "$ENTRY"
|
|
|
+
|
|
|
+PLATSUFFIX="$(uname -s | tr 'A-Z' 'a-z')-$HOSTARCH"
|
|
|
+mkdir -p dist-binary
|
|
|
+if [ "$ONEFILE" = "1" ]; then
|
|
|
+ BIN="$OUT/agentpaas"
|
|
|
+ [ -x "$BIN" ] || fail "未生成二进制"
|
|
|
+ cp "$BIN" "dist-binary/agentpaas-$PLATSUFFIX"
|
|
|
+ cp "$BIN" "dist-binary/agentpaas"
|
|
|
+ echo ""
|
|
|
+ ok "单文件二进制已生成 → dist-binary/agentpaas ($(du -h "$BIN" | cut -f1))"
|
|
|
+ echo " 用户用法(无需 Python): ./agentpaas serve --port 8000"
|
|
|
+else
|
|
|
+ # standalone:产出一个目录,整目录即发行件
|
|
|
+ DISTDIR="$OUT/__main__.dist"
|
|
|
+ [ -x "$DISTDIR/agentpaas" ] || fail "未生成 standalone 目录二进制"
|
|
|
+ rm -rf "dist-binary/agentpaas-$PLATSUFFIX.app"
|
|
|
+ cp -R "$DISTDIR" "dist-binary/agentpaas-$PLATSUFFIX.app"
|
|
|
+ echo ""
|
|
|
+ ok "standalone 目录已生成 → dist-binary/agentpaas-$PLATSUFFIX.app/ ($(du -sh "$DISTDIR" | cut -f1))"
|
|
|
+ echo " 用户用法(无需 Python): ./agentpaas-$PLATSUFFIX.app/agentpaas serve --port 8000"
|
|
|
+fi
|
|
|
+echo ""
|
|
|
+warn "提醒: 二进制绑定 $PLATSUFFIX —— 换平台/架构需在对应机器重新构建。"
|
|
|
+warn " 未打包: chromadb 向量库、PDF 外部工具(pandoc/xelatex)——用到这些功能仍需系统侧依赖。"
|