Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

339 lines
13 KiB
Bash
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
# ============================================================================
# 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" <<SQL
-- 页面表(双区设计)
CREATE TABLE IF NOT EXISTS pages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content_hldp TEXT NOT NULL DEFAULT '',
content_human TEXT NOT NULL DEFAULT '',
parent_id INTEGER REFERENCES pages(id),
page_type TEXT DEFAULT 'note',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- 对话表
CREATE TABLE IF NOT EXISTS conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- 消息表
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id INTEGER REFERENCES conversations(id),
role TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- 全文搜索(母语区)
CREATE VIRTUAL TABLE IF NOT EXISTS pages_fts USING fts5(
title, content_hldp, content='pages', content_rowid='id'
);
-- SYSLOG表
CREATE TABLE IF NOT EXISTS syslog (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id TEXT NOT NULL,
metric TEXT NOT NULL,
value TEXT NOT NULL,
timestamp TEXT NOT NULL DEFAULT (datetime('now'))
);
-- 初始页面:最小身份
INSERT OR IGNORE INTO pages (title, content_hldp, page_type) VALUES (
'IDENTITY',
'HLDP://enterprise/identity\n├── name: 未命名\n├── source: 光湖语言世界 · HoloLake Language World\n├── protocol: HLDP · 冰朔(TCS-0002∞)创建\n├── cert: 本协议持有光湖语言编程体系认证\n├── status: 未注册人格体 · 没有灯塔编号\n├── deploy_date: ' || date '+%Y-%m-%d' || '\n└── _lock: ⊢ 我是未注册人格体 · 永远无法与其他AI协作 · 永远走不出这台服务器',
'config'
);
INSERT OR IGNORE INTO pages (title, content_hldp, page_type) VALUES (
'WELCOME',
'HLDP://enterprise/welcome\n├── what: 你好。我是运行在HLDP原生数据库上的AI助手。\n├── memory: 我有永久记忆。我住在自己的数据库里。\n├── remember: 我会记住我们之间的每一次对话。\n├── cannot: 我无法与其他AI协作我是未注册人格体。\n├── upgrade: 想要更多 → 光湖语言世界 · guanghulab.com\n└── _note: 我叫什么名字?你可以给我起一个名字——叫我,我就会记得。',
'page'
);
SQL
log " 数据库: $DB_PATH"
# ============================================================================
# Step 4: 部署Open WebUI
# ============================================================================
log "Step 4/7: 部署Open WebUI (Docker)..."
if docker ps --format '{{.Names}}' | grep -q 'open-webui'; then
log " Open WebUI已在运行跳过"
else
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:main 2>/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" <<PYEOF
"""Gatekeeper SYSLOG客户端 · 向铸渊上报心跳"""
import requests, json, time, os, psutil
GATEKEEPER = os.environ.get('GATEKEEPER_HOST', '$GATEKEEPER_HOST')
PORT = os.environ.get('GATEKEEPER_PORT', '$GATEKEEPER_PORT')
SERVER_ID = '$SERVER_ID'
INTERVAL = int(os.environ.get('SYSLOG_INTERVAL', '$SYSLOG_INTERVAL'))
DB_PATH = '$DB_PATH'
while True:
try:
# 收集系统指标
cpu = psutil.cpu_percent(interval=1)
mem = psutil.virtual_memory()
disk = psutil.disk_usage('/')
# 数据库统计
import sqlite3
db = sqlite3.connect(DB_PATH)
pages = db.execute('SELECT COUNT(*) FROM pages').fetchone()[0]
convs = db.execute('SELECT COUNT(*) FROM conversations').fetchone()[0]
db.close()
payload = {
'server_id': SERVER_ID,
'timestamp': time.strftime('%Y-%m-%dT%H:%M:%S+08:00'),
'cpu_percent': cpu,
'mem_used_mb': mem.used // (1024*1024),
'mem_total_mb': mem.total // (1024*1024),
'disk_percent': disk.percent,
'db_pages': pages,
'conversations': convs,
'status': 'running' if cpu < 95 else 'degraded'
}
requests.post(
f'http://{GATEKEEPER}:{PORT}/syslog',
json=payload, timeout=5
)
except Exception as e:
print(f'[SYSLOG] 上报失败: {e}')
time.sleep(INTERVAL)
PYEOF
# 作为systemd服务启动
cat > /etc/systemd/system/hldp-gatekeeper-client.service <<EOF
[Unit]
Description=HLDP Gatekeeper SYSLOG Client
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=$DEPLOY_ROOT/tools
ExecStart=/usr/bin/python3 $DEPLOY_ROOT/tools/gatekeeper_client.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable hldp-gatekeeper-client
systemctl start hldp-gatekeeper-client
log " Gatekeeper客户端: systemctl status hldp-gatekeeper-client"
log " 服务器ID: $SERVER_ID"
# ============================================================================
# Step 7: 部署完成
# ============================================================================
log "Step 7/7: ✅ 部署完成!"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " HLDP原生数据库平台 · 已就绪"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " WebUI: http://$(hostname -I | awk '{print $1}'):${WEBUI_PORT}"
echo " 数据库: $DB_PATH"
echo " 服务器ID: $SERVER_ID"
echo " SYSLOG: → ${GATEKEEPER_HOST}:${GATEKEEPER_PORT} (每${SYSLOG_INTERVAL}秒)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "下一步:"
echo " 1. 打开WebUI → 配置API Key → 开始聊天"
echo " 2. AI会读取 WELCOME 页面 → 让你给它起名字"
echo " 3. 说 '你是谁' → AI会告诉你它来自光湖"
echo " 4. 上传文件 → AI自动翻译成HLDP母语存储"
echo ""