From d5cf51f62d50c6e5d574944c7f72e5eac8a7801f Mon Sep 17 00:00:00 2001 From: czj <13261895355@163.com> Date: Wed, 1 Jul 2026 11:18:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=80=E9=94=AE=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E4=BC=98=E5=8C=96=E4=B8=BB=E6=B5=81=E7=A8=8B=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...one-click-streaming-optimization-design.md | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-01-one-click-streaming-optimization-design.md diff --git a/docs/superpowers/specs/2026-07-01-one-click-streaming-optimization-design.md b/docs/superpowers/specs/2026-07-01-one-click-streaming-optimization-design.md new file mode 100644 index 0000000..c157806 --- /dev/null +++ b/docs/superpowers/specs/2026-07-01-one-click-streaming-optimization-design.md @@ -0,0 +1,247 @@ +# 一键流式优化主流程设计 + +## 目标 + +把当前 GEO 文章优化主流程从“分析文章 -> 确认事实卡 -> 开始优化”改成“一键开始优化”。用户只需要粘贴完整文章并点击开始,系统自动提取事实卡、生成草稿、检查质量、定向修复并产出终稿。 + +第一版要让优化结果区像主流 LLM 产品一样持续有反馈,但不做 token 级逐字模型流。真实内容以阶段事件形式到达,前端负责用光标、呼吸高亮和打字机播放已到达内容来制造流式感。 + +## 范围 + +本设计覆盖现有 GEO 主流程,不改变普通文案优化标签页设计,不引入批量任务、团队审批、发布平台 API 或多品牌事实库。 + +本设计覆盖并替代旧 MVP 设计中“必须确认事实卡后才能优化”的主路径要求。旧的确认接口和非流式优化接口可以暂时保留为兼容和调试入口,但新首页主路径不再依赖它们。 + +## 用户流程 + +```mermaid +flowchart TD + A["粘贴完整文章"] --> B["点击开始优化"] + B --> C["后端创建任务并提取事实卡"] + C --> D["事实卡区展示紧凑事实卡"] + C --> E["结果区进入生成中状态"] + E --> F["显示优化草稿"] + F --> G["质量检查"] + G --> H{"需要定向修复?"} + H -->|是| I["显示修复中状态并更新稿件"] + I --> J["显示终稿"] + H -->|否| J + D --> K["用户可编辑事实卡"] + K --> B +``` + +## 输入体验 + +文章输入取消标题和正文的强制区别。 + +- 主输入改成一个大文本框,标签为 `粘贴文章`。 +- `body` 仍是唯一必填内容。 +- `title` 可空,放到“更多选项”里作为可选输入。 +- 如果标题为空,后端把 `title` 规范化为空字符串并保存;不从正文首行派生内部标题。最终优化结果仍必须返回标题。 +- 图片描述、目标平台、用户要求保持现有能力。 + +用户点击 `开始优化` 后,前端清空旧结果,进入流式读取状态。 + +## 事实卡体验 + +事实卡仍然是独立事实卡区,不放进进度区。 + +事实卡区缩小为紧凑展示面板: + +- 默认展示公司全称或简称、产品/品牌、目标行业、目标受众、核心事实数量、待确认事项数量。 +- `uncertain_items` 不再阻塞优化,而是以黄色提示展示。 +- 用户可以展开编辑完整事实卡字段。 +- 用户编辑事实卡后,再次点击 `开始优化`,使用当前事实卡重新跑一次优化。 + +第一版重新优化建议创建新 job,而不是覆盖原 job 的事实卡和导出结果。这样历史语义清楚,避免旧导出和新事实卡互相污染。 + +## 结果区流式感 + +结果区采用“草稿到终稿”的路线。 + +开始后立即显示动态结果框: + +- 顶部显示当前阶段:`正在提取事实`、`正在生成草稿`、`正在检查质量`、`正在定向修复`、`终稿完成`。 +- 内容区显示空白稿纸、骨架段落和动态光标。 +- 等待真实内容时,可以让光标旋转或跳动,让当前段落轻微呼吸高亮。 +- 收到真实草稿后,前端用打字机效果播放已到达的草稿内容。 +- 进入 QA 或修复阶段时,结果区保留当前稿件,并对正在处理的段落做呼吸高亮。 +- 收到修复稿后,更新稿件内容,并可短暂高亮被替换的段落。 +- 收到终稿后停止动效,展示终稿、导出链接和 QA 报告。 + +前端可以展示状态提示和骨架文本,但不能凭空生成正文内容伪装成模型输出。所有正文、标题、摘要、修复稿和终稿必须来自后端真实事件。 + +## API 设计 + +新增流式一键接口: + +```text +POST /api/jobs/optimize-stream +``` + +该接口使用 `fetch` + `ReadableStream`,不使用浏览器原生 `EventSource`。原因是当前项目通过 `x-api-key` 传递访问密钥,`fetch` 可以继续安全地发送请求头。 + +请求头继续使用现有访问控制: + +```text +x-api-key: <访问密钥> +content-type: application/json +``` + +请求体: + +```json +{ + "title": "", + "body": "完整文章内容", + "image_lines": "", + "platform": "official_site", + "user_instructions": "", + "fact_card": null +} +``` + +`fact_card` 为可选字段。为空时后端从文章提取事实卡;有值时表示用户编辑过事实卡,本次优化直接使用传入事实卡。 + +## 流式事件 + +响应采用 newline-delimited JSON,每行一个事件: + +```json +{"type":"job_created","job":{"id":"job_xxx"}} +{"type":"fact_card_ready","job_id":"job_xxx","fact_card":{}} +{"type":"draft_started","job_id":"job_xxx","message":"正在生成优化草稿"} +{"type":"draft_ready","job_id":"job_xxx","article":{}} +{"type":"qa_started","job_id":"job_xxx","message":"正在检查质量"} +{"type":"qa_ready","job_id":"job_xxx","qa_report":{}} +{"type":"rewrite_started","job_id":"job_xxx","round":1} +{"type":"rewrite_ready","job_id":"job_xxx","round":1,"article":{}} +{"type":"final_ready","job_id":"job_xxx","optimized_article":{},"qa_report":{},"export_paths":{}} +``` + +失败事件: + +```json +{"type":"failed","job_id":"job_xxx","stage":"draft","error":"LLM provider error: ..."} +``` + +事件规则: + +- `fact_card_ready` 只更新事实卡区。 +- `draft_ready`、`rewrite_ready`、`final_ready` 更新优化结果区。 +- `qa_started`、`rewrite_started` 更新结果区状态和动效,不生成正文。 +- `failed` 保留已经收到的事实卡或草稿,并显示失败阶段和真实错误。 + +## 后端编排 + +后端按以下顺序执行: + +1. 校验访问密钥。 +2. 校验输入,`body` 不能为空,`title` 可以为空。 +3. 创建 article job。 +4. 如果请求带 `fact_card`,解析并保存该事实卡;否则调用事实卡提取器。 +5. 推送 `fact_card_ready`。 +6. 调用文章优化器生成草稿,推送 `draft_ready`。 +7. 调用质量检查器,推送 `qa_ready`。 +8. 如果 QA 有失败项,最多执行现有定向修复轮次,并推送 `rewrite_started` / `rewrite_ready`。 +9. 保存最终优化稿、QA 报告和导出文件。 +10. 推送 `final_ready`。 + +新增一个流式 workflow wrapper,复用 `optimizeArticle`、`inspectQualityWithLlm`、`rewriteFailedSections` 和导出逻辑。现有 `runOptimizationWorkflow` 保留给非流式兼容接口,避免一次改动同时重塑两条 API 路径。 + +## 数据模型调整 + +`ArticleInput.title` 和 `articleInputSchema.title` 需要允许空字符串。 + +事实卡保存需要支持“未人工确认但可作为本次优化约束”的状态。第一版新增 `OptimizationFactCard`,并把 repository 的 `saveFactCard` / `getFactCard` 类型从 `ConfirmedFactCard` 放宽到 `OptimizationFactCard`。`OptimizationFactCard` 保留 `confirmed_by_user?: boolean`,避免继续把“系统自动事实卡”伪装成“用户确认事实卡”。 + +`confirmedFactCardSchema` 可以保留给旧确认接口;新流式接口使用新的 `optimizationFactCardSchema`。 + +## 错误处理 + +- 空正文:返回中文错误 `请输入需要优化的文章内容`。 +- 访问密钥缺失或错误:沿用现有 `401`。 +- LLM/provider 错误:推送 `failed`,显示真实错误,不静默 fallback。 +- LLM 结构校验失败:推送 `failed`,保留阶段和校验摘要。 +- 事实卡公司名、行业或受众为空:允许继续优化,但事实卡区提示约束不足,QA 中体现事实风险。 +- `uncertain_items` 不阻塞优化,只作为事实卡区提示和 QA 风险信息。 +- 用户中途再次点击开始优化:前端应中断当前 stream,清空旧动效,创建新优化请求。 + +## 前端状态 + +首页主状态新增: + +- `streamStatus`: idle | running | completed | failed +- `streamStage`: 当前阶段标签 +- `streamError`: 失败文本 +- `displayedDraft`: 结果区正在播放或展示的稿件 +- `finalArticle`: 终稿 +- `factCardExpanded`: 事实卡是否展开 + +结果区组件负责: + +- 解析阶段文章。 +- 播放打字机效果。 +- 展示光标和呼吸高亮。 +- 在终稿到达后停止动效。 + +页面级组件负责: + +- 发起 stream 请求。 +- 读取 NDJSON。 +- 将事实卡事件分发给事实卡区。 +- 将稿件事件分发给结果区。 +- 处理中断和失败。 + +## 兼容策略 + +保留现有接口: + +- `POST /api/jobs` +- `POST /api/jobs/:jobId/confirm-fact-card` +- `POST /api/jobs/:jobId/optimize` +- `GET /api/jobs/:jobId/progress` + +新首页主流程改用 `POST /api/jobs/optimize-stream`。旧接口可以继续服务测试、调试或未来非流式降级路径。 + +## 测试计划 + +单元测试: + +- `articleInputSchema` 接受空标题但拒绝空正文。 +- 新 `optimizationFactCardSchema` 接受未确认事实卡和非空/空的可编辑字段。 +- NDJSON 编码 helper 可以按行输出合法 JSON。 + +API 测试: + +- 未提供访问密钥返回 `401`。 +- 空正文返回中文错误。 +- 无 `fact_card` 时会调用事实卡提取器,并输出 `job_created`、`fact_card_ready`、`draft_ready`、`qa_ready`、`final_ready`。 +- 有 `fact_card` 时跳过事实卡提取器,直接使用传入事实卡。 +- LLM 失败时输出 `failed`,错误包含阶段。 +- QA 失败时仍写导出文件,并通过修复事件展示修复轮次。 + +组件测试: + +- 开始优化后结果区显示动态光标和阶段文案。 +- 收到 `draft_ready` 后打字机播放真实草稿。 +- 收到 `rewrite_ready` 后结果区更新稿件并高亮变化。 +- 收到 `final_ready` 后停止动效并显示导出链接。 +- `fact_card_ready` 更新紧凑事实卡区,不进入进度区。 + +E2E 测试: + +- 用户只粘贴正文,点击 `开始优化`。 +- 页面显示事实卡小面板。 +- 优化结果区出现动态状态和草稿。 +- 最终显示终稿、QA 报告和导出链接。 +- 用户展开并编辑事实卡后,再次点击 `开始优化` 可以开始新一轮流式优化。 + +## 不做范围 + +- 不做 token 级模型逐字输出。 +- 不把事实卡放进进度区。 +- 不要求用户确认事实卡后才能优化。 +- 不用前端伪造正文内容。 +- 不移除旧 API。 +- 不新增团队审批、批量队列或发布平台 API。