本地优先的动态博客系统:后端在本地运行,通过本地 Nginx + pb-mapper 对外暴露 HTTPS API;文章与图片统一写入 LanceDB,由前端直接请求云端映射端点访问。
除了内容系统本身,StaticFlow 当前还内置了一套对外 LLM Access 能力:Codex 的 OpenAI-compatible 网关、Kiro 的 Anthropic-compatible 网关、provider 级上游代理解析、可配额度的 gateway key,以及统一的 usage 账本。实现细节见 docs/llm-access-and-kiro-gateway-implementation.md。
"Don't build agents, build skills instead." — Anthropic Expert Talk
本项目不开发独立 AI Agent。
策略:
- 智能能力:交给 Claude Code/Codex + skills
- 工程工具:CLI 只做 LanceDB 读写
static-flow/
├── frontend/ # Yew WASM 前端
├── backend/ # Axum 后端(LanceDB 查询层)
├── shared/ # 共享类型
├── cli/ # LanceDB CLI 工具
└── content/ # 示例 Markdown 与图片
static-flow 对应网站:https://acking-you.github.io/
本项目将运行时数据放在两个 Hugging Face 数据集仓库和一个本地音乐库中管理:
-
当前本地数据根目录:
/mnt/wsl/data4tb/static-flow-data -
Content DB(内容主库 + 请求表 + 交互镜像 + LLM gateway)
- HF 数据集仓库:
LB7666/my_lancedb_data - 远端地址:
git@hf.co:datasets/LB7666/my_lancedb_data - 本地数据目录:
/mnt/wsl/data4tb/static-flow-data/lancedb - 表:
articles,images,taxonomies,article_views,api_behavior_events,article_requests,article_request_ai_runs,article_request_ai_run_chunks,interactive_pages,interactive_page_locales,interactive_assets,llm_gateway_keys,llm_gateway_usage_events,llm_gateway_runtime_config,llm_gateway_proxy_configs,llm_gateway_proxy_bindings,llm_gateway_token_requests,llm_gateway_account_contribution_requests,llm_gateway_sponsor_requests
- HF 数据集仓库:
-
Comments DB(评论审核与 AI 运行记录)
- HF 数据集仓库:
LB7666/static-flow-comments - 远端地址:
git@hf.co:datasets/LB7666/static-flow-comments - 本地数据目录:
/mnt/wsl/data4tb/static-flow-data/lancedb-comments - 表:
comment_tasks,comment_published,comment_audit_logs,comment_ai_runs,comment_ai_run_chunks
- HF 数据集仓库:
-
Music DB(本地优先音乐库)
- 本地数据目录:
/mnt/wsl/data4tb/static-flow-data/lancedb-music - 表:
songs,music_plays,music_comments,music_wishes,music_wish_ai_runs,music_wish_ai_run_chunks
- 本地数据目录:
推荐流程:
- 先通过
sf-cli写入/更新数据(保证 schema 与索引一致)。 - 再用 Git 对数据快照做版本提交。
- 最后 push 到 Hugging Face 数据集远端。
快速配置(SSH + Git Xet):
# 1) 准备 SSH key,并把公钥添加到 https://huggingface.co/settings/keys
ls ~/.ssh/id_ed25519.pub || ssh-keygen -t ed25519 -C "LB7666@hf"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
mkdir -p ~/.ssh
ssh-keyscan -H hf.co >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
ssh -T git@hf.co
# 2) 将本地数据目录绑定到 HF 数据集远端
cd /mnt/wsl/data4tb/static-flow-data/lancedb
git init -b main
git remote remove origin 2>/dev/null || true
git remote add origin git@hf.co:datasets/LB7666/my_lancedb_data
git fetch origin main
git checkout -B main origin/main
# 3) 安装并启用 Git Xet
bash <(curl -fsSL https://raw.githubusercontent.com/huggingface/xet-core/main/git_xet/install.sh)
export PATH="$HOME/.local/bin:$PATH"
git xet install
git xet track "*.lance"
git xet track "*.txn"
git xet track "*.manifest"
# 4) 日常同步
git add -A
git commit -m "data: sync $(date '+%F %T')" || echo "no changes"
git push origin main说明:执行 git xet track 后,.gitattributes 中仍出现 filter=lfs 属于正常现象,
这是 Hugging Face 的 Xet 兼容传输实现方式。
后端同时提供 API 和前端静态文件,通过 pb-mapper + Caddy 对外暴露 HTTPS。
浏览器 -> https://ackingliu.top
-> Caddy (TLS) -> pb-mapper tunnel -> 本地 backend (127.0.0.1:39080)
├── /api/* → API handler
├── /posts/:id → SEO 注入页
├── /sitemap.xml → 动态 sitemap
└── /* → 前端静态文件 (SPA fallback)
启动方式:
# 1. 构建前端(API_BASE=/api,同源请求)
bash scripts/build_frontend_selfhosted.sh
# 2. 启动后端(自动 serve 前端静态文件)
bash scripts/start_backend_selfhosted.sh --daemon
# 日志查看
tail -f /tmp/staticflow-backend.log
# 前端代码改动后需要重新构建 + 重启后端(后端启动时缓存 index.html)
bash scripts/build_frontend_selfhosted.sh
bash scripts/start_backend_selfhosted.sh --daemon前端由 trunk dev server 提供,支持热重载;trunk 自动代理 /api 到后端。
# 1. 启动后端
bash scripts/start_backend_selfhosted.sh
# 2. 启动前端(trunk serve,自动代理 /api -> localhost:39080)
bash scripts/start_frontend_with_api.sh --open后端: http://127.0.0.1:39080 | 前端: http://127.0.0.1:38080
前端部署到 GitHub Pages,API 通过 pb-mapper 隧道访问本地后端。
CI 自动构建,STATICFLOW_API_BASE 由 GitHub repo variables 配置。
浏览器 -> https://acking-you.github.io (GitHub Pages 静态文件)
-> fetch(STATICFLOW_API_BASE/api/...) -> pb-mapper -> 本地 backend
参考配置:
- 自托管 Caddy:云端
/etc/caddy/Caddyfile - GitHub Pages CI:
.github/workflows/deploy.yml - 旧版 Nginx 配置:
deployment-examples/
自托管模式下,StaticFlow 现在不只是内容站点,也会对外暴露两条公开接入面:
/llm-access:Codex 接入页,底层走 OpenAI-compatible 的/api/llm-gateway/v1/kiro-access:Kiro 接入页,底层走 Anthropic-compatible 的/api/kiro-gateway
当前实现的共性:
- 两条接入线都由 StaticFlow backend 代理,不直接暴露上游真实账号
- 上游代理解析统一走共享的 provider 级代理注册表
- key、runtime config、proxy config、proxy binding、usage event 都统一落在 LLM gateway 存储里
- 详细运行时实现、代理优先级、账号路由、缓存刷新和排障路径见 docs/llm-access-and-kiro-gateway-implementation.md
如果你只关心 Codex 接入,公开页会额外给出:
- 已带
/v1的 OpenAI-compatible Base URL - 可公开分发的 API key
- 现成的 Codex provider 配置片段
auth.json备用写法和curl/ Python 示例
推荐的 Codex provider 配置如下:
model_provider = "staticflow"
[model_providers.staticflow]
name = "OpenAI"
base_url = "https://your-host/api/llm-gateway/v1"
wire_api = "responses"
requires_openai_auth = true
supports_websockets = false这个配置的目的,是让 Codex 保持在远端 /responses 和 /responses/compact 路径上工作,避免退回本地兼容路径。
# 前置依赖
rustup target add wasm32-unknown-unknown
cargo install trunk
# 编译二进制
make bin-all
# 初始化 LanceDB
cd cli
../target/release/sf-cli init --db-path ../data/lancedb
# --- 自托管模式(推荐) ---
cd ..
bash scripts/build_frontend_selfhosted.sh
bash scripts/start_backend_selfhosted.sh --daemon
# --- 本地开发模式 ---
cd ..
bash scripts/start_backend_selfhosted.sh # 前台启动后端
bash scripts/start_frontend_with_api.sh --open # 另一个终端,trunk 热重载cd cli
# 编译 CLI 二进制
make bin-cli
# 一键跑完整 CLI 回归测试(docs + images + CRUD + API)
cd ..
./scripts/test_cli_e2e.sh
# 或:BUILD_PROFILE=release ./scripts/test_cli_e2e.sh
cd cli
# 初始化 LanceDB 表结构
../target/release/sf-cli init --db-path ../data/lancedb
# 手动重跑所有应建索引(适合批量导入后)
# - articles.content(全文索引)
# - articles.vector_en / articles.vector_zh(向量索引)
# - images.vector(向量索引)
# - taxonomies 表用于分类/标签元数据(无向量索引)
# - article_views 为 backend 运行时统计表(CLI 无需管理其索引)
../target/release/sf-cli ensure-indexes --db-path ../data/lancedb
# write-article / write-images / sync-notes 默认会自动执行 index-only optimize
# 用于把新写入数据纳入索引覆盖;批量流水线可通过 --no-auto-optimize 关闭
# 写入单篇文章
../target/release/sf-cli write-article \
--db-path ../data/lancedb \
--file ../content/post-001.md \
--date "2026-02-12" \
--summary "文章摘要" \
--tags "rust,wasm" \
--category "Tech" \
--category-description "Engineering notes about Rust + WASM" \
--content-en-file ../tmp/content_en.md \
--summary-zh-file ../tmp/detailed_summary_zh.md \
--summary-en-file ../tmp/detailed_summary_en.md
# 也可写在 markdown frontmatter 中
# category_description: "Rust 与 WASM 的工程实践"
# date: "2026-02-12"
# content_en: |
# detailed_summary:
# zh: |
# en: |
# 若两者同时提供,以 CLI --date 为准。
# `--summary-zh-file` 与 `--summary-en-file` 必须成对提供。
# 批量写入图片
../target/release/sf-cli write-images \
--db-path ../data/lancedb \
--dir ../content/images \
--recursive \
--generate-thumbnail
# 缩略图实现细节
# - 仅在 --generate-thumbnail 时生成,尺寸由 --thumbnail-size 控制(默认 256)
# - 缩略图统一存为 PNG 二进制到 images.thumbnail
# - 读取 /api/images/:id-or-filename?thumb=true 时,thumbnail 为空会自动回退原图 data
# 同步本地笔记目录(markdown + 图片)
# - 自动把 markdown 中引用的本地图片写入 images 表
# - 自动把 markdown 图片链接改写为 images/<sha256_id>
# - 自动 upsert 文章到 articles 表
# - 自动 upsert 分类/标签元数据到 taxonomies 表
../target/release/sf-cli sync-notes \
--db-path ../data/lancedb \
--dir ../content \
--recursive \
--generate-thumbnail
# 查询验证
../target/release/sf-cli query --db-path ../data/lancedb --table articles --limit 10
../target/release/sf-cli query --db-path ../data/lancedb --table articles --limit 1 --format vertical
# 数据库风格管理(增删改查 + 索引)
../target/release/sf-cli db --db-path ../data/lancedb list-tables
../target/release/sf-cli db --db-path ../data/lancedb describe-table articles
../target/release/sf-cli db --db-path ../data/lancedb query-rows articles --where "category='Tech'" --columns id,title,date --limit 5
../target/release/sf-cli db --db-path ../data/lancedb query-rows articles --limit 1 --format vertical
../target/release/sf-cli db --db-path ../data/lancedb count-rows articles --where "vector_en IS NOT NULL"
../target/release/sf-cli db --db-path ../data/lancedb update-rows articles --set "category='Notes'" --where "id='post-001'"
../target/release/sf-cli db --db-path ../data/lancedb delete-rows articles --where "id='draft-001'"
../target/release/sf-cli db --db-path ../data/lancedb list-indexes articles --with-stats
../target/release/sf-cli db --db-path ../data/lancedb ensure-indexes
../target/release/sf-cli db --db-path ../data/lancedb optimize articles
../target/release/sf-cli db --db-path ../data/lancedb optimize images
# 一键立即清理孤儿文件(仅 prune,不做全量重写)
../target/release/sf-cli db --db-path ../data/lancedb cleanup-orphans --table images
# 对全部清理目标表统一清理孤儿文件(含 article_views;若不存在会自动跳过)
../target/release/sf-cli db --db-path ../data/lancedb cleanup-orphans
# 核心表结构(sf-cli 管理)
# - articles:文章内容/元数据 + 向量
# - images:图片二进制 + 向量
# - taxonomies:分类/标签元数据(`kind`、`key`、`name`、`description`)
# 运行时统计表(backend 管理)
# - article_views:浏览事件与日/小时分桶(首次调用 `/api/articles/:id/view` 自动创建)
# 与 backend 同款 API 调试命令
../target/release/sf-cli api --db-path ../data/lancedb list-articles --category "Tech"
../target/release/sf-cli api --db-path ../data/lancedb get-article frontend-architecture
../target/release/sf-cli api --db-path ../data/lancedb search --q "staticflow"
../target/release/sf-cli api --db-path ../data/lancedb semantic-search --q "前端 架构"
../target/release/sf-cli api --db-path ../data/lancedb related-articles frontend-architecture
../target/release/sf-cli api --db-path ../data/lancedb list-tags
../target/release/sf-cli api --db-path ../data/lancedb list-categories
../target/release/sf-cli api --db-path ../data/lancedb list-images
../target/release/sf-cli api --db-path ../data/lancedb search-images --id <image_id>
../target/release/sf-cli api --db-path ../data/lancedb get-image <image_id_or_filename> --thumb --out ./tmp-thumb.bin| 端点 | 说明 |
|---|---|
GET /api/articles |
文章列表(支持 tag/category 过滤) |
GET /api/articles/:id |
文章详情 |
POST /api/articles/:id/view |
记录文章浏览(默认同一文章+客户端 60 秒去重) |
GET /api/articles/:id/view-trend |
文章浏览趋势(按天/按小时,按 Asia/Shanghai 分桶) |
GET /api/articles/:id/related |
相关文章(向量相似) |
GET /api/search?q= |
全文搜索 |
GET /api/semantic-search?q= |
语义搜索(向量,含跨语言回退与语义片段高亮) |
GET /api/images |
图片列表 |
GET /api/images/:id-or-filename |
从 LanceDB 读取图片二进制(支持 ?thumb=true,无缩略图则回退原图) |
GET /api/image-search?id= |
以图搜图 |
GET /api/tags |
标签列表 |
GET /api/categories |
分类列表 |
可观测性:每个 backend 响应都会返回
x-request-id与x-trace-id,并且 backend/shared 的请求内日志会带同一组 ID,便于串联排障。
查询路径可观测:日志会输出
query/path/fastest_path/is_fastest/reason/rows/elapsed_ms,可直接判断是否命中索引或发生回退。
语义高亮模式:
/api/semantic-search默认走快速高亮;追加&enhanced_highlight=true可启用高精度片段重排(更慢)。
浏览统计:建议在文章详情页加载时调用
/api/articles/:id/view;后端默认按“文章 + 客户端指纹”做 60 秒去重(可通过本地 admin 接口/admin/view-analytics-config调整),并按Asia/Shanghai维护日/小时趋势分桶。
检索说明:若你更新了代码但仍看到“英文语义检索无结果”,请重新编译二进制(
cargo build --release -p sf-cli -p static-flow-backend),旧二进制不会包含向量列回退逻辑。
后端(由 scripts/start_backend_selfhosted.sh 自动设置):
DB_ROOT(默认/mnt/wsl/data4tb/static-flow-data,自动解析 content/comments/music 三个 DB)PORT(默认39080)HOST(默认127.0.0.1)SITE_BASE_URL(默认https://ackingliu.top,用于 SEO 注入)FRONTEND_DIST_DIR(默认../frontend/dist,自托管模式的静态文件目录)RUST_ENV(development或production)ALLOWED_ORIGINS(生产可选,逗号分隔 CORS 白名单)
前端构建时:
STATICFLOW_API_BASE- 自托管模式:
/api(由build_frontend_selfhosted.sh设置) - GitHub Pages:绝对 URL(由 CI workflow 的 repo variables 设置)
- 本地开发:
http://127.0.0.1:39080/api(由start_frontend_with_api.sh设置)
- 自托管模式:
# Workspace
cargo build --workspace
cargo test --workspace
cargo fmt --all
cargo clippy --workspace -- -D warnings
# Frontend(自托管构建)
bash scripts/build_frontend_selfhosted.sh
# Frontend(trunk 热重载开发)
bash scripts/start_frontend_with_api.sh --open
# Backend
make bin-backend
bash scripts/start_backend_selfhosted.sh # 前台
bash scripts/start_backend_selfhosted.sh --daemon # 后台(日志: /tmp/staticflow-backend.log)MIT