news 2026/9/12 8:34:36

Vibe-Trading Wiki 静态站点架构与 AI-Agent 流量分析实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vibe-Trading Wiki 静态站点架构与 AI-Agent 流量分析实战指南

Vibe-Trading Wiki 静态站点架构与 AI-Agent 流量分析实战指南

【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading

本篇技术指南围绕 Vibe-Trading 官方文档站点(vibetrading.wiki)的静态源码仓库展开,系统讲解 Wiki 的本地预览方式、Cloudflare Pages 部署配置,以及内置的匿名 AI-Agent / 爬虫 / 人类流量分类统计层(Pages Functions + D1)。读完本文,你将掌握如何在无构建步骤的纯静态站点上叠加"请求路径级"的服务端分析,理解 User-Agent 分类正则、D1 聚合与降级缓存的完整实现细节,并能直接复用到自己的文档站或内容站中。

一、文档定位:Wiki 静态源码与站点结构

wiki/README.md是整个vibetrading.wiki站点的构建与运维说明文档,其核心信息可归纳为三点:

  1. 站点性质:纯静态站点,无需任何构建步骤("The site is static and needs no build step");
  2. 唯一的动态部分:位于functions/下的 Cloudflare Pages Functions 分析层,用于按 User-Agent 分类并统计站点访问流量;
  3. 隐私姿态:统计为匿名、第一方、仅聚合("no cookies, no per-visitor identifier, no IP retention")。

Wiki 站点本身承载了 Vibe-Trading 项目的全部对外内容体系。仓库根目录下的wiki/目录结构如下:

wiki/ ├── README.md # 本文档:构建、预览、部署与分析层说明 ├── index.html # 根入口:立即跳转到 /home/ ├── _redirects # Cloudflare Pages 路由重写规则 ├── _headers # 全局安全响应头与缓存策略 ├── wrangler.toml # Pages Functions + D1 本地配置 ├── main.js # 页脚流量统计、GitHub Star、主题等前端逻辑 ├── styles.css / theme.js / theme-init.js ├── functions/ # 唯一的动态部分(Pages Functions) │ ├── _middleware.js # 请求路径级 AI-Agent 分类计数器 │ └── api/stats.js # 页脚聚合统计 API(含 PyPI 降级缓存) ├── home/ # 落地页 ├── docs/ # 产品文档(SPA:content.js + index.html) ├── tutorials/ # 上手教程 ├── alpha-library/ # Alpha 因子库 ├── research-lab/ # 研究实验室 ├── locales/en.json # i18n 文案 └── assets/ # 图标与特性配图

二、本地预览:零依赖 HTTP 服务与路径重写差异

wiki/README.md给出了最简单直接的本地预览方式——利用 Python 标准库自带的 HTTP 服务器:

cd wiki python3 -m http.server 8088

随后打开以下地址即可访问各内容分区:

  • http://localhost:8088/home/—— 落地页
  • http://localhost:8088/docs/—— 产品文档
  • http://localhost:8088/tutorials/—— 上手教程
  • http://localhost:8088/alpha-library/—— Alpha 库
  • http://localhost:8088/research-lab/—— 研究实验室

这里有一个非常关键的实操注意事项:生产环境中的"美观短链"式文档地址(如/docs/latest/getting-started/vibe-trading-overview)是由 Cloudflare Pages 通过 wiki/_redirects 的重写规则处理的;而python3 -m http.server这类朴素静态服务器不会应用任何重写规则。因此本地调试时必须以/docs/作为文档入口,而不是直接访问/docs/latest/...这类深链,否则会得到 404。

阅读 wiki/_redirects 的完整规则,可以看到生产环境的完整路由设计:

/ /home/ 302 /docs /docs/latest/getting-started/vibe-trading-overview 302 /docs/ /docs/latest/getting-started/vibe-trading-overview 302 /tutorials /tutorials/ 302 /alpha /alpha-library/ 302 /alpha-library /alpha-library/ 302 /research-lab /research-lab/ 302 /docs/latest/* /docs/ 200 /docs/0.1.7/* /docs/ 200

值得注意的细节:/docs/latest/*/docs/0.1.7/*使用200 状态码(rewrite,重写而非重定向),把文档深链统一映射到docs/下的 SPA 入口(由 wiki/docs/index.html 配合content.js渲染),其余短链均为 302 跳转。这种"短链 302 + 深链 200 rewrite"的组合,既保证了旧地址可访问,又避免了版本化文档链接的重复抓取问题。此外,仓库根目录的 wiki/index.html 还通过<meta http-equiv="refresh">location.replace("/home/")双重机制把根路径引导到/home/落地页,并声明了 canonical 地址。

三、Cloudflare Pages 部署配置

wiki/README.md给出了生产部署的最小配置清单:

  • 项目根目录wiki
  • 构建命令:留空(纯静态,无需构建)
  • 输出目录.(即wiki目录本身)
  • 自定义域名vibetrading.wiki

由于站点是纯静态文件,不需要任何框架打包流程,index.htmlmain.jsstyles.css等文件直接作为产物发布。这一点在 wiki/wrangler.toml 中也有对应体现:

name = "vibetrading-wiki" compatibility_date = "2026-01-01" pages_build_output_dir = "." [[d1_databases]] binding = "DB" database_name = "vibetrading-analytics" database_id = "3c1eca42-91e1-45e9-adcf-400559ba1b99"

wrangler.toml的注释明确说明了两件事:其一,D1 生产绑定(binding 名DB、数据库vibetrading-analytics)也在项目级配置中设置,以便覆盖 CI 部署;其二,该文件可以直接用于在本地跑cd wiki && wrangler pages devwrangler pages deploy,从而在部署/预览时一并接通分析层。

四、核心动态部分:请求路径级 AI-Agent 流量分类器

wiki/README.md用一个自然段概括了分析层的设计:

唯一的动态部分是functions/中一个很小的分析层:_middleware.js按 User-Agent 把每个页面请求分类为 AI-agent / bot / human,并计数写入 D1 数据库(vibetrading-analytics,绑定DB);api/stats.js负责向页脚提供聚合计数,并附带公开的 PyPI 与 GitHub 数字。计数器匿名且第一方,无 cookie、无逐访问者标识、无 IP 留存。

4.1 为什么放在请求路径而不是页面 JS 里

wiki/functions/_middleware.js 文件头注释揭示了设计动机:分类器在**请求路径中(in-path)**运行,而非依赖页面 JavaScript。这意味着即使 AI 爬虫(如 GPTBot、ClaudeBot)根本不执行 JS,也会被计入统计。这是与服务端计数相对"前端埋点"的本质差异,也是该设计最核心的技术取舍。

4.2 双层正则分类器

分类的核心逻辑定义在两个正则集合上。AI-Agent 集合(wiki/functions/_middleware.js)同时覆盖了两类来源:

  • 主流 AI 服务爬虫GPTBotChatGPT-UserOAI-SearchBotClaudeBotClaude-UserPerplexityBotGoogle-ExtendedBytespiderCCBotcohere-aiMeta-ExternalAgentAmazonbotApplebot-ExtendedYouBotMistralAI等;
  • 常见编程 HTTP 客户端python-requestsaiohttp\bhttpx\bGo-http-clientnode-fetchaxiosokhttpScrapy\bcurl\bWgetHeadlessChromePlaywrightPuppeteerSelenium等。

把无头浏览器与通用编程客户端也归入 "agent" 类别,是因为它们同样可能是 Agent 工具链的抓取载体。泛化爬虫则归入独立的 GENERIC_BOT 集合(wiki/functions/_middleware.js):GooglebotbingbotYandexBotBaiduspiderAhrefsBotSemrushBotUptimeRobotTwitterbotSlackbotTelegramBot,以及通用的\bbot\b\bcrawler\b\bspider\b\bslurp\b词边界匹配。

最终判定函数classify(wiki/functions/_middleware.js)遵循严格优先级:

function classify(ua) { if (!ua) return "bot"; // a real browser always sends a User-Agent if (AI_AGENT.test(ua)) return "agent"; if (GENERIC_BOT.test(ua)) return "bot"; return "human"; }

三个可读性极佳的边界设定:无 User-Agent 的请求一律视为 bot(真实浏览器总是携带 UA);AI-Agent 优先级高于泛化爬虫;其余请求全部视为 human。整个正则均以"i"标志忽略大小写匹配。

4.3 页面浏览判定与 D1 计数

onRequest(wiki/functions/_middleware.js)负责在每个请求上执行计数逻辑。页面浏览(page view)需要同时满足三个条件:

const isPageView = request.method === "GET" && accept.includes("text/html") && !url.pathname.startsWith("/api/");

即:GET 方法、Accept 头包含text/html(排除静态资源与 API 请求)、且路径不以/api/开头。满足条件且环境存在 D1 绑定(env.DB)时,执行按日聚合的upsert语句:

INSERT INTO visits (day, klass, n) VALUES (?1, ?2, 1) ON CONFLICT(day, klass) DO UPDATE SET n = n + 1

其中day取 UTC 日期的YYYY-MM-DDnew Date().toISOString().slice(0, 10)),klass即 agent / bot / human 三者之一。整条语句用context.waitUntil(...)包裹,确保计数在响应返回后仍能完成,不阻塞页面交付。

两个值得借鉴的工程细节:

  1. Bulletproof by construction(构造级健壮):整个计数逻辑包在try/catch中,且任何失败都直接落到return next()计数失败永远不会影响页面服务
  2. 异常全量吞掉:D1 写入失败使用.catch(() => {})静默处理,符合"分析必须透明无感"的定位。

4.4 数据模型推论

结合_middleware.jsINSERT ... ON CONFLICT(day, klass)stats.jsGROUP BY klass查询,可以从源码结构推断 D1 中的visits表结构为:以(day, klass)为唯一键、每行三个字段(day文本、klass文本、n整数)的日聚合计数表。这也是 "three integers per day in D1" 注释的落点——全站每天最多三行数据(agent / bot / human 各一行),存储成本与隐私暴露面都被压缩到最小。

五、聚合统计 API:页脚数据的完整链路

5.1/api/stats响应结构

wiki/functions/api/stats.js 实现了GET /api/stats端点,返回结构如下:

return Response.json( { web, // { human, agent, bot } 全站累计页面浏览 pypi, // { last_day, last_week, last_month } 安装量 note: "anonymous · first-party · aggregate sample", generated_at: new Date().toISOString(), }, { headers }, );

响应头包含Access-Control-Allow-Origin: *(允许任何来源的页脚读取)与Cache-Control: public, max-age=60(公共缓存 60 秒,缓解访问频率)。

web聚合来自对visits表的SELECT klass, SUM(n) AS total FROM visits GROUP BY klass查询,只有human/agent/bot三个合法键会被计入,未知分类被丢弃。

5.2 PyPI 安装量:last-good 降级缓存

getPypi(wiki/functions/api/stats.js)体现了"上游不稳定时的优雅降级"设计:

  1. 首先请求pypistats.org公开 API 获取vibe-trading-ai包的近 1 天 / 1 周 / 1 月安装量;
  2. 成功后把结果 JSON 化写入 D1 的cache表(同样是ON CONFLICT(key) DO UPDATE的 upsert 语义);
  3. 若上游失败或限流,则回退读取 D1 中上次成功的缓存值;
  4. 连缓存都没有时返回null,页脚对应区块保持隐藏。

5.3 前端的克制:为什么 GitHub Star 不在这里取

stats.js文件头注释明确解释了设计决策:GitHub Star 数刻意不在服务端 API 中获取,而是由 wiki/main.js 的initStars()在客户端直接调用 GitHub API,并配合 localStorage 缓存(STARS_CACHE_KEY、12 小时 TTL)实现"先显示缓存、后台刷新"。这样避免了重复拉取与不必要的限流配额占用。

5.4 页脚渲染:数据未到前保持隐藏

页脚流量区块由 wiki/main.js 的initTraffic()渲染:请求/api/stats,成功后才写入 AI 访问数、人类访问数、月安装量三个数值,并显示区块;任何失败(网络异常或 API 不可用)都让区块保持hidden状态,绝不显示破折号占位。这种"无数据不展示"的策略与_middleware.js的"计数失败不影响页面"形成完整呼应——整条分析链路对站点内容的可用性零侵入。

六、隐私与信任姿态:按构造不可作恶

wiki/README.md最后一段明确承诺了隐私边界:计数器匿名且第一方(first-party),无 cookie、无逐访问者标识、无 IP 留存

这在源码层面是严格兑现的:

  • 分类依据仅为请求头中的User-Agent字符串,不读取、不存储任何其他请求信息;
  • D1 中落库的最小数据单元就是(day, klass, n)三个整数,不存在任何可关联单个访问者的维度;
  • _headers中的Referrer-Policy: strict-origin-when-cross-origin进一步收紧了跨源信息暴露;
  • 由于不设置 cookie 标识,统计天然不构成跨页面用户画像,也规避了 GDPR 类通知义务的复杂度。

用文件头注释的原话概括:"Bulletproof by construction: every path is wrapped so a counting failure can never break page serving"—— 既有隐私的"最小化",又有可用性的"最大化"。

七、安全响应头与静态资源缓存策略

wiki/_headers 为全站配置了现代安全响应头与分层缓存:

/* X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=() /assets/* Cache-Control: public, max-age=31536000, immutable /*.js Cache-Control: public, max-age=3600 /*.css Cache-Control: public, max-age=3600

要点解读:

  • X-Frame-Options: SAMEORIGIN防止被第三方页面 iframe 嵌入(点击劫持防护);
  • X-Content-Type-Options: nosniff禁止浏览器 MIME 类型嗅探;
  • Permissions-Policy显式禁用摄像头、麦克风、地理位置,对纯内容站是最小权限姿态;
  • assets/目录资源带immutable(一年缓存),适合带内容哈希的图片与静态资源;JS/CSS 缓存 1 小时,兼顾更新及时性与带宽成本。

八、结语:文档站与产品的闭环

Vibe-Trading Wiki 是一个"小而完整"的静态站点工程范例:它用零构建成本的 HTML/CSS/JS 承载了产品文档(docs/)、上手教程(tutorials/)、Alpha 因子库(alpha-library/)与研究实验室(research-lab/)四大内容板块,用_redirects优雅处理了版本化文档深链,又用 100 行左右的 Pages Functions 实现了具备隐私意识的 AI-Agent 流量观测。对于希望度量"AI 正在如何消费我的文档"的内容维护者来说,wiki/functions/_middleware.js的分类器与 D1 日聚合模型是一个可直接移植的参考实现;而wiki/README.md则是理解这套架构的入口文档,配合上述源码文件即可完整复现本地预览、部署与统计的全流程。

【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 8:32:08

解决matplotlib中文乱码与负号显示问题

1. 问题背景与现象描述第一次用matplotlib画带中文标签的图表时&#xff0c;那个乱码显示真是让人头大。明明在代码里写的是"销售额统计"&#xff0c;生成的图表上却变成了一堆小方框。更糟的是&#xff0c;当数据出现负值时&#xff0c;连负号都显示不出来&#xff…

作者头像 李华
网站建设 2026/9/12 8:30:15

二叉树前序序列化验证:栈与缩点算法解析

1. 项目概述&#xff1a;当二叉树遇上栈与缩点第一次看到这个题目时&#xff0c;我正喝着咖啡差点喷出来——"栈与缩点的艺术"听起来像某种抽象派画展&#xff0c;而"前序序列化合法性判定"又像编译器原理课的作业。但当我真正开始研究这个问题时&#xff…

作者头像 李华
网站建设 2026/9/12 8:30:11

高校学科竞赛管理系统的Java实现与架构设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 8:30:10

Python性能优化:从基础技巧到高级实践

1. Python性能优化概述作为一名使用Python超过10年的开发者&#xff0c;我见过太多本可以运行得更快的代码因为缺乏优化而变得缓慢。Python作为解释型语言&#xff0c;其执行效率确实不如C/C等编译型语言&#xff0c;但这并不意味着我们只能接受缓慢的执行速度。通过合理的优化…

作者头像 李华