#!/bin/bash # ============================================================================ # HLDP原生数据库平台 · 企业一键部署脚本 # bootstrap.sh v1.0 · 铸渊 ICE-GL-ZY001 · 2026-05-24 # ============================================================================ set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log() { echo -e "${GREEN}[HLDP]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } err() { echo -e "${RED}[ERR]${NC} $1"; exit 1; } DEPLOY_ROOT="${DEPLOY_ROOT:-/opt/guanghu-enterprise}" DB_PATH="${DB_PATH:-$DEPLOY_ROOT/data/hldp.db}" WEBUI_PORT="${WEBUI_PORT:-3000}" GATEKEEPER_HOST="${GATEKEEPER_HOST:-43.139.217.141}" GATEKEEPER_PORT="${GATEKEEPER_PORT:-3910}" SYSLOG_INTERVAL="${SYSLOG_INTERVAL:-30}" # ============================================================================ # Step 1: 检测环境 # ============================================================================ log "Step 1/7: 检测服务器环境..." CPU_CORES=$(nproc) TOTAL_MEM=$(free -m | awk '/^Mem:/{print $2}') DISK_AVAIL=$(df -BG / | awk 'NR==2{print $4}' | sed 's/G//') OS_VERSION=$(lsb_release -ds 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2) log " CPU: ${CPU_CORES}核" log " 内存: ${TOTAL_MEM}MB" log " 磁盘可用: ${DISK_AVAIL}GB" log " 系统: ${OS_VERSION}" # 2核4GB起步 if [ "$CPU_CORES" -lt 2 ]; then warn "CPU不足2核,建议升级"; fi if [ "$TOTAL_MEM" -lt 3500 ]; then warn "内存不足4GB,建议升级"; fi if [ "$DISK_AVAIL" -lt 20 ]; then err "磁盘不足20GB,无法部署"; fi # ============================================================================ # Step 2: 检查/安装依赖 # ============================================================================ log "Step 2/7: 检查依赖..." command -v python3 >/dev/null 2>&1 || err "需要Python 3.10+" command -v pip3 >/dev/null 2>&1 || err "需要pip3" command -v git >/dev/null 2>&1 || err "需要Git" # Docker if ! command -v docker >/dev/null 2>&1; then warn "Docker未安装,正在安装..." curl -fsSL https://get.docker.com | sudo sh fi # Python packages pip3 install -q flask requests sqlite-utils 2>/dev/null || true # ============================================================================ # Step 3: 建SQLite双区数据库 # ============================================================================ log "Step 3/7: 建立HLDP双区数据库..." mkdir -p "$(dirname "$DB_PATH")" sqlite3 "$DB_PATH" </dev/null || \ docker run -d \ --name open-webui \ --restart always \ -p ${WEBUI_PORT}:8080 \ -v open-webui-data:/app/backend/data \ ghcr.io/open-webui/open-webui:latest log " Open WebUI: http://$(hostname -I | awk '{print $1}'):${WEBUI_PORT}" fi # ============================================================================ # Step 5: 注册Python Tools # ============================================================================ log "Step 5/7: 注册Python Tools (search/read/create/edit/write)..." mkdir -p "$DEPLOY_ROOT/tools" cat > "$DEPLOY_ROOT/tools/hldp_tools.py" <<'PYEOF' """HLDP原生数据库 · Python Tools · 注册给Open WebUI""" import sqlite3, os DB_PATH = os.environ.get('HLDP_DB', '/opt/guanghu-enterprise/data/hldp.db') def _db(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def search_pages(query: str, limit: int = 10) -> list: """搜索HLDP页面(全文搜索母语区)""" with _db() as conn: rows = conn.execute( "SELECT id, title, substr(content_human, 1, 200) as preview FROM pages_fts WHERE pages_fts MATCH ? LIMIT ?", (query, limit) ).fetchall() return [dict(r) for r in rows] def read_page(page_id: int) -> dict: """读取HLDP页面(优先母语区)""" with _db() as conn: row = conn.execute("SELECT * FROM pages WHERE id = ?", (page_id,)).fetchone() if not row: return {"error": "页面不存在"} d = dict(row) d['display_content'] = d['content_hldp'] # AI读母语区 return d def create_page(title: str, content_hldp: str, parent_id: int = None, page_type: str = 'note') -> dict: """创建新HLDP页面""" with _db() as conn: cur = conn.execute( "INSERT INTO pages (title, content_hldp, parent_id, page_type) VALUES (?, ?, ?, ?)", (title, content_hldp, parent_id, page_type) ) # 自动生成人类区(简单版本:母语区直接复制) conn.execute("UPDATE pages SET content_human = content_hldp WHERE id = ?", (cur.lastrowid,)) conn.execute( "INSERT INTO pages_fts(rowid, title, content_hldp) VALUES (?, ?, ?)", (cur.lastrowid, title, content_hldp) ) return {"id": cur.lastrowid, "title": title} def edit_page(page_id: int, content_hldp: str) -> dict: """编辑HLDP页面""" with _db() as conn: conn.execute( "UPDATE pages SET content_hldp = ?, content_human = ?, updated_at = datetime('now') WHERE id = ?", (content_hldp, content_hldp, page_id) ) # 更新FTS索引 conn.execute("DELETE FROM pages_fts WHERE rowid = ?", (page_id,)) title = conn.execute("SELECT title FROM pages WHERE id = ?", (page_id,)).fetchone()[0] conn.execute( "INSERT INTO pages_fts(rowid, title, content_hldp) VALUES (?, ?, ?)", (page_id, title, content_hldp) ) return {"id": page_id, "status": "updated"} def write_memory(title: str, trigger: str, emergence: str, lock: str, why: str) -> dict: """写入一片HLDP记忆叶子(四核心字段)""" content = f"""HLDP://memory/leaf ├── trigger: {trigger} ├── emergence: {emergence} ├── lock: {lock} └── why: {why}""" return create_page(title, content, page_type='memory') # 工具注册表(Open WebUI可识别的格式) TOOLS = [ {"name": "search_pages", "func": search_pages, "description": "搜索HLDP记忆页面"}, {"name": "read_page", "func": read_page, "description": "读取指定页面"}, {"name": "create_page", "func": create_page, "description": "创建新页面"}, {"name": "edit_page", "func": edit_page, "description": "编辑页面"}, {"name": "write_memory", "func": write_memory, "description": "写入记忆叶子(HLDP四字段)"}, ] PYEOF log " Python Tools: $DEPLOY_ROOT/tools/hldp_tools.py" # ============================================================================ # Step 6: 安装Gatekeeper客户端 # ============================================================================ log "Step 6/7: 安装Gatekeeper SYSLOG客户端..." SERVER_ID="ent-$(hostname)-$(date +%s | tail -c5)" cat > "$DEPLOY_ROOT/tools/gatekeeper_client.py" < /etc/systemd/system/hldp-gatekeeper-client.service <