# InsightReply 实施计划 (Implementation Plan) > 本文档记录了 InsightReply 各模块的具体技术实现方案,是 `DEVELOPMENT_PLAN.md`(做什么)的落地补充(怎么做)。 > 功能完善度的产品策略分析见 → [`PRODUCT_ROADMAP.md`](./PRODUCT_ROADMAP.md) --- ## 一、数据抓取策略 (Data Acquisition Strategy) InsightReply 采用 **"前端主动感知 + 后端规则引擎"** 的双模式来实现数据抓取: ### 1. 插件端交互式抓取 (User-Driven) * **触发场景**:用户在 X (Twitter) 上浏览推文时,想针对某条推文生成评论。 * **实现逻辑**:Content Script 直接从浏览器 DOM 中提取当前选定推文的作者、正文、互动数 (Like/Reply)。 * **优点**:零延迟,无需后端预先抓取该推文,即看即得。 ### 2. 后端雷达监控抓取 (System-Driven / Radar) * **方案选型对比**: | 方案 | 代表 | 优点 | 缺点 | 月费 | |------|------|------|------|------| | 付费 SaaS | Apify / RapidAPI | 即插即用,免维护 | 按次计费 | $30-$100+ | | 自建开源 | **Nitter + Camoufox** | 几乎免费 | 技术门槛高 | 仅服务器费 | * **最终选型**:自建 Nitter 开源方案。 * **Nitter 实例地址**:`https://x.beenglish.eu.org/` --- ## 二、浏览器插件技术实现 (Extension Architecture) ### 1. Content Script 与 UI 注入 * **Content Script (`src/content/index.ts`)**:监听页面 URL 变化,使用 `MutationObserver` 实时检测新加载的推文 DOM 节点。 * **Shadow DOM 注入**:在推文操作栏注入"Insight"入口按钮。点击后展示主面板,面板挂载在 Shadow DOM 内,确保与 Twitter 原生样式完全隔离。 * **Background Service Worker**:作为中转站,处理与后端 Go API 的通信和认证。 ### 2. UI 设计规范 (ui-ux-pro-max) * **暗黑毛玻璃风格**:主色调 `#0A0A0A` ~ `#171717`,浮动面板使用 `backdrop-filter: blur()`。 * **品牌渐变色**:紫蓝渐变 `#8B5CF6` → `#3B82F6`,用于 CTA 按钮和高亮标签。 * **字体**:优先使用 `Inter` / `Geist` / `SF Pro` 等现代无衬线字体。 * **微动画**:所有状态切换配 `ease-in-out` 过渡(`200ms-300ms`)。 ### 3. 技术栈规范 * **Tailwind CSS v4**:所有间距、颜色从 Design Tokens 读取,禁止硬编码内联样式。 * **Vue 3 Composition API**:高频 UI 元素(`Button`, `Card`, `Badge`)封装为基础组件。 * **`cn()` 工具函数**:基于 `clsx` + `tailwind-merge` 统一处理动态 Class 冲突。 * **轻量化打包**:禁止引入完整组件库,采用按需加载。 ### 4. Content Script 性能优化策略 *(新增)* > 在 Twitter 重型 SPA 中,粗暴监听全文档 DOM 变更会产生严重性能问题。 * **收缩监听范围**:将 `MutationObserver` 的 `observe` 目标从 `document.body` 收缩到 `main[role="main"]` 或 Timeline 容器。 * **防抖扫描**:`scanTweets()` 加入 `requestIdleCallback` 或 `debounce(200ms)`,避免高频回调。 * **已处理标记**:通过 `WeakSet` 记录已注入按钮的推文节点,避免重复扫描。 * **多选择器 Fallback**:Twitter 的 `data-testid` 属性随时可能变更,已处理推文选择器应支持多层 Fallback: ```typescript const TWEET_SELECTORS = [ 'article[data-testid="tweet"]', 'article[role="article"]', 'div[data-testid="cellInnerDiv"] article' ]; ``` --- ## 三、高可用后台抓取系统 (Industry Radar - Enterprise Architecture) 考虑到系统的**稳定性、安全性和反风控 (Anti-Ban)**,自建 Nitter 之上的抓取系统设计为一套健壮的企业级爬虫架构。 ### 1. 终极反风控与防封禁策略 (Anti-Ban Mechanisms) | 机制 | 说明 | |------|------| | **请求抖动 (Jitter)** | 每次请求间加入 `1s-5s` 强随机延迟,严禁整点并发 | | **熔断降级 (Circuit Breaker)** | Nitter 连续返回 429/503 时自动暂停 30 分钟 | | **Fallback 节点池** | 主节点熔断时自动切换到备用 Nitter 实例 | | **指纹轮换 (Fingerprint Rotation)** | 同步轮换 UA + `Sec-Ch-Ua` + `Accept-Language` 等全套 Header | | **会话隔离 (Session Isolation)** | 每个采集任务独立 Cookie Jar,避免跨任务身份串联 | ### 2. 高可用采集架构 (Scraper & Queue) * **异步任务队列**:基于 Redis 的 `Asynq`,解耦"触发"与"执行",控制最大并发数。 * **指数退避重试 (Exponential Backoff)**:失败后按 1min → 3min → 10min 递增重试间隔。 * **采集器健壮性**: * `goquery` 解析找不到元素时记录 Warn,返回部分数据,**绝不 Panic**。 * 关键报错时 **Dump HTML 快照**到日志表,方便排查 Nitter DOM 结构变更。 ### 3. 数据计算与存储层 * **批量 Upsert**:使用 `ON CONFLICT DO UPDATE` 策略,降低 IO 压力,防止死锁。 * **热度公式**: ``` heat_score = (Like增量 × 0.4) + (RT增量 × 0.3) + (Reply增量 × 0.3) ``` * **动态智能抓取频率 (Smart Crawling)**: * 🔥 热度飙升的推文 → **高频队列**(每 15 分钟抓一次) * 🧊 24 小时无新动态 → **低频队列**(每 4 小时抓一次) * 极大节省抓取资源,显著降低被封概率。 --- ## 四、后端安全与认证体系 *(新增)* ### 1. JWT 认证方案 所有 `/api/v1` 路由(除 `/auth/*` 外)必须经过 JWT 认证中间件。 * **技术选型**:`go-chi/jwtauth` + HMAC-SHA256 签名。 * **Token 结构**: ```json { "sub": "user-uuid", "tier": "Pro", "exp": 1709164800 } ``` * **刷新策略**:Access Token 有效期 24h,Refresh Token 有效期 30d,存于 `chrome.storage.local`。 ### 2. Rate Limiting(分级限流) | Tier | 评论生成 | 监控关键词 | 监控账号 | |------|---------|-----------|---------| | Free | 10 次/天 | 3 个 | 3 个 | | Pro | 无限 | 20 个 | 20 个 | | Premium | 无限 | 50 个 | 50 个 | * **实现方案**:基于 Redis 的滑动窗口计数器,Key 格式:`ratelimit:{user_id}:{action}:{window}`。 * **中间件挂载**:在 chi Router 中通过 `r.Use(RateLimitMiddleware)` 全局或分路由挂载。 ### 3. CORS 配置 ```go r.Use(cors.Handler(cors.Options{ AllowedOrigins: []string{"chrome-extension://*", "https://x.com", "https://twitter.com"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"Authorization", "Content-Type"}, AllowCredentials: true, MaxAge: 300, })) ``` --- ## 五、LLM 服务韧性设计 *(新增)* ### 1. 调用链路防护 ``` 请求 → Timeout Guard (30s) → Circuit Breaker → Retry (max 2) → OpenAI API ``` * **Timeout**:`context.WithTimeout(ctx, 30*time.Second)` 包裹每次 LLM 调用。 * **Circuit Breaker**:使用 `sony/gobreaker`,连续 5 次失败后半开,每 60s 试探一次恢复。 * **指数退避重试**:仅对 5xx / Timeout 重试,4xx(如 quota exceeded)立即失败。 ### 2. 多模型动态路由与 Fallback 系统重构为 **多 Provider 支持 (OpenAI / Anthropic / DeepSeek / Gemini)**,以应对不同用户的专属模型偏好和单一 Provider 宕机时的容灾。同时支持**代理接口与自定义模型**。 **路由与配置设计**: 1. **环境变量驱动 (ENV)**:管理员可通过配置 `OPENAI_BASE_URL` 改写接口地址(完美兼容 Groq、vLLM、Ollama 等任意 OpenAI 兼容代理)。 2. **可用模型下发**:通过 `OPENAI_AVAILABLE_MODELS="gpt-4o,gpt-4o-mini"` 配置白名单,后端通过 `GET /sys/config/llms` 统一向前端下发。 3. **前端交互 (`default_llm_model`)**:前端展示为**「可输入的下拉列表 (Combobox)」**,用户既可从系统下发的列表中点选,也支持手动输入任意字符串,实现完全自定义。 4. **故障转移 (Fallback)**:当前尝试的 Provider 返回 5xx 时,按兜底顺序切换:`Anthropic → OpenAI → Gemini → DeepSeek`。 **统一适配器抽象**: 建立统一的 `LLMProvider` 接口,抹平各平台 API 结构差异,内部集成对应 SDK: - OpenAI (含兼容代理): `sashabaranov/go-openai` (支持通过 Builder 传入 BaseURL) - Anthropic: 直接构造 REST API 请求 - DeepSeek: 兼容 OpenAI SDK,基于 `DEEPSEEK_BASE_URL` 重连 - Gemini: `google.golang.org/api/generativelanguage/v1beta` ### 3. Token 成本审计 每次 LLM 调用记录 `prompt_tokens + completion_tokens`,写入 `api_usage_logs` 表: ```sql INSERT INTO api_usage_logs (user_id, provider, model, prompt_tokens, completion_tokens, cost_usd) VALUES ($1, $2, $3, $4, $5, $6); ``` --- ## 六、Prompt 工程规范 *(新增)* ### 1. 策略模板结构 每个评论策略维护独立的 Prompt 模板文件,存放于 `server/prompts/` 目录: ``` server/prompts/ ├── system.txt # 全局 System Prompt ├── cognitive_upgrade.txt # 认知升级型 ├── contrarian.txt # 反向观点型 ├── data_supplement.txt # 数据补充型 ├── empathy.txt # 共鸣型 └── founder_exp.txt # 创始人经验型 ``` ### 2. Prompt 结构公式 (必须遵守) ``` [System Prompt] - 角色定义:专业社交媒体表达顾问 - 输出约束:字数、语言、格式 [User Prompt] - 用户身份标签:{identity} - 目标推文:{tweet_content} - 策略指令:{strategy_specific_instruction} - 结构公式:Hook + Position + Insight + Brevity - Few-shot 示例:2-3 条高质量参考 [Constraints] - 不超过 280 字符 (或用户指定长度) - 语言:与原推文一致,或用户指定 - 语气与身份匹配 - 禁止引号包裹 ``` ### 3. 批量生成规范 API 单次返回 5 种策略 × 2 条备选 = **10 条候选评论**: * 方案 A:单次 LLM 调用,Prompt 中要求 JSON 数组输出 * 方案 B:5 组并发调用,每组 n=2 * **推荐方案 A**,减少 API 调用次数 --- ## 七、后端 Go 接口规范 * 采用 RESTful 标准。 * 所有接口返回统一 JSON 结构: ```json { "code": 200, "message": "success", "data": {} } ``` * 错误码体系:`4xxx` 为客户端错误,`5xxx` 为服务端错误。 * 详细接口文档见 → [`docs/API.md`](./API.md) --- ## 八、环境变量与配置管理 *(新增)* 所有运行时配置统一通过环境变量注入,**禁止硬编码**。 | 变量名 | 说明 | 示例 | |-------|------|------| | `DATABASE_URL` | PostgreSQL 连接串 | `postgres://user:pass@host:5432/db` | | `OPENAI_API_KEY` | OpenAI API Key | `sk-...` | | `JWT_SECRET` | JWT 签名密钥 | 随机 32+ 字符串 | | `SERVER_PORT` | 服务端口 | `8080` | | `CORS_ORIGINS` | 允许的跨域来源 | `chrome-extension://*` | | `LOG_LEVEL` | 日志级别 | `info` / `debug` / `warn` | | `LLM_TIMEOUT_SEC` | LLM 调用超时秒数 | `30` | 模板文件 → [`server/.env.example`](../server/.env.example) --- ## 九、验证计划 (Verification Plan) | # | 验证项 | 方法 | |---|--------|------| | 1 | 防封控链路 | 模拟 100 并发请求,验证熔断 + Jitter 能正确拦截 | | 2 | HTML 解析容错 | 模拟账号冻结/推文被删等异常页面,确认不会 Panic | | 3 | Shadow DOM 隔离 | 在 X 深色/浅色模式下验证插件样式不被污染 | | 4 | 端到端生成链路 | 插件点击 → Background → Go API → LLM → 返回结果 | | 5 | JWT 认证 *(新增)* | 无 Token / 过期 Token / 非法 Token 拒绝访问 | | 6 | Rate Limiting *(新增)* | Free 用户超 10 次/天后返回 429 | | 7 | LLM 韧性 *(新增)* | 模拟 OpenAI 超时 / 5xx,验证熔断降级 + 重试 | | 8 | Graceful Shutdown *(新增)* | 发送 SIGTERM,验证在途请求完成后才退出 | | 9 | Onboarding 流程 *(新增)* | 首次打开插件触发引导,设置存入 chrome.storage + 后端 | | 10 | 多条备选评论 *(新增)* | 验证返回 3 条备选,Sidebar 卡片式展示正确 | | 11 | 热度标签 *(新增)* | 在高互动推文旁正确显示 🔥/⚡ 标签 | | 12 | 效果追踪闭环 *(新增)* | 复制评论 → 24h 后回查 → 互动数据写入 DB | --- ## 十、用户 Onboarding 实现方案 *(新增)* ### 1. 流程设计 首次安装/首次打开插件时,检测 `chrome.storage.sync` 中是否存在 `onboarding_completed` 标志。若无,显示 3 步引导: ```typescript // background/index.ts chrome.runtime.onInstalled.addListener(({ reason }) => { if (reason === 'install') { chrome.storage.sync.set({ onboarding_completed: false }); } }); ``` ### 2. 数据存储 | 字段 | 存储位置 | 说明 | |------|---------|------| | `identity_label` | `chrome.storage.sync` + `users` 表 | 身份标签 | | `language_preference` | `chrome.storage.sync` + `users` 表 | 偏好语言 | | `tone_preference` | `chrome.storage.sync` + `user_style_profiles` 表 | 风格倾向 | | `onboarding_completed` | `chrome.storage.sync` | 是否已完成引导 | ### 3. 与生成链路的集成 用户设置完成后,每次生成评论时自动读取 `chrome.storage.sync` 中的偏好,附加到 `GENERATE_REPLY` 消息中: ```typescript // 改造 Sidebar.vue 的 generate() const prefs = await chrome.storage.sync.get(['identity_label', 'language_preference', 'tone_preference']); chrome.runtime.sendMessage({ type: 'GENERATE_REPLY', payload: { tweetContent: props.tweetData.content, strategy: 'all', identity: prefs.identity_label, language: prefs.language_preference, tone: prefs.tone_preference } }); ``` --- ## 十一、前端热度标签实现方案 *(新增)* ### 1. 判断逻辑 ```typescript interface HeatLevel { label: string; emoji: string; className: string; } const getHeatLevel = (likes: number, minutesAgo: number): HeatLevel | null => { if (likes > 1000 && minutesAgo < 120) { return { label: 'Trending', emoji: '🔥', className: 'heat-trending' }; } if (likes > 100 && minutesAgo < 60) { return { label: 'Rising', emoji: '⚡', className: 'heat-rising' }; } return null; }; ``` ### 2. 注入位置 在 `injectInsightButton()` 函数中,紧挨 Insight 按钮旁边注入热度标签: * 🔥 Trending:红色渐变 Badge (`background: linear-gradient(135deg, #ef4444, #f97316)`) * ⚡ Rising:黄色渐变 Badge (`background: linear-gradient(135deg, #f59e0b, #eab308)`) ### 3. 时间计算 从推文 DOM 中的 `