Files
InsightReply/docs/IMPLEMENTATION_PLAN.md
zs 8cf6cb944b
Some checks failed
Extension Build & Release / build (push) Failing after 1m5s
Backend Deploy (Go + Docker) / deploy (push) Failing after 1m40s
Web Console Deploy (Vue 3 + Vite) / deploy (push) Has been cancelled
feat: 部署初版测试
2026-03-02 21:25:21 +08:00

555 lines
21 KiB
Markdown
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.
# 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<HTMLElement>` 记录已注入按钮的推文节点,避免重复扫描。
* **多选择器 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 有效期 24hRefresh 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 数组输出
* 方案 B5 组并发调用,每组 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 中的 `<time datetime="...">` 元素提取发帖时间,计算与当前时间的差值:
```typescript
const timeEl = tweetElement.querySelector('time');
const postedAt = new Date(timeEl?.getAttribute('datetime') || '');
const minutesAgo = (Date.now() - postedAt.getTime()) / 60000;
```
---
## 十二、数据飞轮 — 效果追踪与风格学习 *(新增)*
### 1. 效果追踪数据流
```
用户复制评论
│ copyToClipboard() → 同时记录 hash(reply_text) 到 chrome.storage.local
chrome.storage.local:
tracked_replies: [{
hash: "a1b2c3",
text: "Most people miss...",
strategy: "contrarian",
copied_at: 1709164800,
tweet_url: "https://x.com/.../status/..."
}]
Content Script 延迟触发 (当用户访问自己 Profile 页时)
│ 条件: URL 匹配 x.com/{current_user}
扫描用户近期 Tweets/Replies
│ 对比 tracked_replies 中的 text hash
匹配成功 → 提取当前 Likes / Replies 数
chrome.runtime.sendMessage → Background → POST /api/v1/replies/{id}/performance
写入 reply_performance 表
```
### 2. 风格学习 Prompt 注入
当 `user_style_profiles` 表有足够数据(≥ 10 条追踪记录)后,生成评论时自动注入风格画像:
```
[附加上下文 - 个人风格画像]
基于你过去 30 天的高互动评论分析:
- 最有效策略: {top_strategies} (平均互动率 {avg_rate}%)
- 风格特征: {style_description}
- 高频高互动关键词: {keywords}
- 偏好评论长度: {avg_length} 字符
请参考以上风格特征生成评论。
```
### 3. 风格特征提取 (后端定时任务)
每周对每个用户的 `reply_performance` 数据运行一次 LLM 分析:
```
System: 你是社交媒体互动分析专家。
User: 以下是该用户最近 30 天互动率最高的 10 条评论:
{replies_list}
请总结其写作风格特征, 包括:
1. 最常用的句式结构
2. 高频关键词或短语
3. 语气倾向 (专业/幽默/犀利)
4. 平均有效长度
输出为 JSON 格式。
```
---
## 十三、用户可配置系统设计 *(新增)*
> **设计原则**:系统不硬编码任何特定产品/领域/策略。所有与用户场景相关的能力均通过用户自定义设置实现,确保对任意行业、任意产品类型的可扩展性。
### 1. 架构思想:零硬编码 (Zero Hardcoding)
```
传统做法 (❌):
Prompt 里写死 "你是一个 AI 创始人,正在推广 SwiftBiu..."
可扩展做法 (✅):
Prompt 运行时从 user_product_profiles 表 + user_custom_strategies 表
动态拼装上下文,适用于任何用户、任何产品
```
### 2. 产品档案 (Product Profile) 注入机制
当用户配置了产品档案后,生成评论时自动注入以下上下文块:
```
[产品上下文 — 自动注入,仅当用户已配置产品档案时]
你正在帮助一位 {identity} 撰写社交评论。
该用户正在推广的产品: {product_name} — {tagline}
产品所属领域: {domain}
核心功能: {key_features}
目标用户群: {target_users}
{custom_context}
注意:
- 不要直接提及产品名称或链接 (除非用户使用了"创始人实战型"策略)
- 评论应从 {domain} 领域专家的角度出发,让读者产生"这个人很懂行"的印象
- 引发好奇心 → 点击 Profile → 发现产品,而非硬推
```
### 3. 自定义策略运行时
用户自定义的策略模板支持以下**模板变量**,运行时自动替换:
| 变量 | 来源 | 说明 |
|------|------|------|
| `{tweet_content}` | 当次请求 | 目标推文原文 |
| `{identity}` | 用户设置 | 身份标签 |
| `{product_name}` | 产品档案 | 产品名称 |
| `{domain}` | 产品档案 | 所属领域 |
| `{key_features}` | 产品档案 | 核心功能 |
| `{competitors}` | 产品档案 | 竞品列表 |
| `{language}` | 用户设置 | 输出语言 |
| `{max_length}` | 当次请求 | 最大字符数 |
| `{custom_context}` | 产品档案 | 自定义上下文 |
**后端处理流程**
```go
// service/ai_service.go
func (s *AIService) buildPrompt(req GenerateRequest, profile *ProductProfile, strategies []Strategy) string {
// 1. 加载 System Prompt
// 2. 如果有产品档案 → 注入产品上下文块
// 3. 合并内置策略 + 用户自定义策略
// 4. 替换所有模板变量
// 5. 如果有风格画像 (user_style_profiles) → 注入风格上下文
// 6. 返回最终 Prompt
}
```
### 4. 前端推文相关性评分
Content Script 基于产品档案中的 `relevance_keywords` 对当前浏览的推文做实时相关性判断:
```typescript
// content/relevance.ts
const scoreRelevance = (tweetText: string, keywords: string[]): number => {
const text = tweetText.toLowerCase();
let score = 0;
for (const kw of keywords) {
if (text.includes(kw.toLowerCase())) score++;
}
return score;
};
// 注入标签
const relevance = scoreRelevance(tweetData.content, userProfile.relevance_keywords);
if (relevance >= 2) {
// 注入 🎯 "High Relevance" 标签
}
```
**关键词来源**`chrome.storage.sync` 缓存用户的 `relevance_keywords`(来自产品档案 API定期同步。
### 5. 前端策略合并展示
Sidebar 策略选择器同时展示系统内置策略和用户自定义策略:
```typescript
// Sidebar.vue
const allStrategies = computed(() => [
...builtinStrategies, // 系统内置 5 种
...userCustomStrategies.value // 用户自定义 N 种 (从 API 拉取)
]);
```
自定义策略用不同背景色或 `⚙️ Custom` 标签区分,方便用户识别。
### 6. Prompt 组装顺序
```
┌─────────────────────────────────────────────┐
│ System Prompt (角色定义 + 输出约束) │
├─────────────────────────────────────────────┤
│ [可选] 产品上下文 (如果用户配置了产品档案) │
├─────────────────────────────────────────────┤
│ [可选] 个人风格画像 (如果有 ≥10 条追踪数据) │
├─────────────────────────────────────────────┤
│ User Prompt: │
│ - 身份标签 │
│ - 目标推文 │
│ - 策略指令 (内置 or 用户模板,变量已替换) │
│ - 结构公式: Hook + Position + Insight │
│ - Few-shot 示例 (系统默认 or 用户自定义) │
├─────────────────────────────────────────────┤
│ Constraints (字数/语言/格式) │
└─────────────────────────────────────────────┘
```