#!/bin/bash # build-graph-html.sh — 生成共享 graph-engine 驱动的离线知识图谱 HTML # # 用法: # bash scripts/build-graph-html.sh # # 前置:需要先运行 build-graph-data.sh 生成 wiki/graph-data.json # # 行为: # 1. 读取 packages/graph-engine/dist/engine.iife.js # 2. 内嵌 graph-data.json 与可选 .wiki-graph-layout.json 钉位 # 3. 注入离线启动脚本:创建 graph engine,持久化钉位到 localStorage # 4. 生成单文件 knowledge-graph.html # # 退出码:0 成功;1 依赖/文件缺失/参数错误 set -eu SCRIPT_DIR="${BASH_SOURCE[0]%/*}" [ "$SCRIPT_DIR" = "${BASH_SOURCE[0]}" ] && SCRIPT_DIR="." SCRIPT_DIR="$(cd "$SCRIPT_DIR" && pwd)" # shellcheck disable=SC1091 source "$SCRIPT_DIR/shared-config.sh" print_usage() { cat <<'USAGE' 用法: bash scripts/build-graph-html.sh 示例: bash scripts/build-graph-html.sh /path/to/wiki-root USAGE } die() { echo "ERROR: $1" >&2 exit 1 } ensure_file() { local file="$1" local label="${2:-文件}" [ -f "$file" ] || { echo "ERROR: 找不到${label} $file" >&2 echo " 请先运行 npm run build -w @llm-wiki/graph-engine,或重装 skill。" >&2 exit 1 } } json_for_script() { perl -pe 's||<\\/script>|gi' "$1" } script_for_inline() { perl -pe 's|//# sourceMappingURL=.*$||' "$1" } html_escape_text() { printf '%s' "$1" | perl -pe 's/&/&/g; s//>/g; s/"/"/g; s/'"'"'/'/g' } while [ "$#" -gt 0 ]; do case "$1" in -h|--help) print_usage exit 0 ;; --) shift break ;; -*) die "未知选项: $1" ;; *) break ;; esac done [ "$#" -eq 1 ] || { print_usage >&2 exit 1 } WIKI_ROOT="$1" command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is not installed. Install it via:" >&2 print_install_hint jq exit 1 } SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" DATA="$WIKI_ROOT/wiki/graph-data.json" LAYOUT="$WIKI_ROOT/.wiki-graph-layout.json" ENGINE="$SKILL_DIR/packages/graph-engine/dist/engine.iife.js" MARKED="$SKILL_DIR/deps/marked.min.js" PURIFY="$SKILL_DIR/deps/purify.min.js" OUTPUT="$WIKI_ROOT/wiki/knowledge-graph.html" [ -f "$DATA" ] || { echo "ERROR: 未找到 $DATA" >&2 echo " 请先运行 build-graph-data.sh 生成图谱数据" >&2 exit 1 } ensure_file "$ENGINE" "graph-engine IIFE 产物" ensure_file "$MARKED" "marked vendor" ensure_file "$PURIFY" "purify vendor" WIKI_TITLE=$(jq -r '.meta.wiki_title // "知识库"' "$DATA") NODE_COUNT=$(jq -r '.meta.total_nodes // 0' "$DATA") EDGE_COUNT=$(jq -r '.meta.total_edges // 0' "$DATA") BUILD_DATE=$(jq -r '.meta.build_date // ""' "$DATA") BUILD_DATE_SHORT="${BUILD_DATE:0:10}" [ -n "$BUILD_DATE_SHORT" ] || BUILD_DATE_SHORT="未知" WIKI_TITLE_HTML=$(html_escape_text "$WIKI_TITLE") NODE_COUNT_HTML=$(html_escape_text "$NODE_COUNT") EDGE_COUNT_HTML=$(html_escape_text "$EDGE_COUNT") BUILD_DATE_SHORT_HTML=$(html_escape_text "$BUILD_DATE_SHORT") layout_json='{"version":2,"pins":{},"updatedAt":""}' if [ -f "$LAYOUT" ]; then if layout_json_candidate=$(jq -c '{version:(.version // 1), pins:(.pins // {}), updatedAt:(.updatedAt // "")}' "$LAYOUT" 2>/dev/null); then layout_json="$layout_json_candidate" else echo "WARN: 忽略损坏的钉位文件:$LAYOUT" >&2 fi fi output_dir="$(dirname "$OUTPUT")" mkdir -p "$output_dir" output_tmp="$OUTPUT.partial" output_next="$OUTPUT.next" rm -f "$output_tmp" "$output_next" cat > "$output_tmp" < 知识图谱 · ${WIKI_TITLE_HTML}

${WIKI_TITLE_HTML} 知识舆图

国风知识库·数字山水图

${NODE_COUNT_HTML} 节点 ${EDGE_COUNT_HTML} 关联 ${BUILD_DATE_SHORT_HTML}
|<\/script>|gi' >> "$output_tmp" cat >> "$output_tmp" <<'HTML_ENGINE' HTML_BOOT mv "$output_tmp" "$output_next" mv "$output_next" "$OUTPUT" rm -f \ "$output_dir/d3.min.js" \ "$output_dir/rough.min.js" \ "$output_dir/marked.min.js" \ "$output_dir/purify.min.js" \ "$output_dir/graph-wash.js" \ "$output_dir/graph-wash-helpers.js" \ "$output_dir/LICENSE-d3.txt" \ "$output_dir/LICENSE-roughjs.txt" \ "$output_dir/LICENSE-marked.txt" \ "$output_dir/LICENSE-purify.txt" output_size=$(wc -c < "$OUTPUT" | tr -d ' ') output_kb=$((output_size / 1024)) echo "交互式图谱已生成:" echo " - $OUTPUT (${output_kb} KB)" echo " 节点 $NODE_COUNT · 关联 $EDGE_COUNT" echo "" echo "查看方式:" echo " 双击 $OUTPUT"