From 01dcd83987af7fe4ffbe0c81c2d36f6b41f08270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A9=B9=E6=96=87=E6=B6=9B?= <53+mp_1787300862_s8r25x@noreply.git.brainwork.club> Date: Wed, 16 Sep 2026 13:37:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8B=86=E8=A7=A3=E5=8D=95=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20Demo=20=E4=B8=BA=20Vite=20+=20React=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 保留根目录 index.html 作为 v1 单文件原型(不参与构建) - app/ 下新建 Vite + React 工程(vite.config root 指向 app/,两版互不干扰) - 状态收敛到 useAppStore(表单/消息/串行确认/一键发品 + 4 条异步编排流) - 生成卡片重构为结构化数据驱动渲染,按钮为真实 React 事件 - 6 大表单模块卡片化;Agent 意图解析与偏好学习抽为独立 lib - 功能与视觉与 v1 完全一致,浏览器端全流程回归通过 --- .gitignore | 3 + README.md | 72 +- app/index.html | 12 + app/src/App.jsx | 22 + app/src/components/AssistantPanel.jsx | 97 ++ app/src/components/FormArea.jsx | 35 + app/src/components/GenCardView.jsx | 63 + app/src/components/MessageItem.jsx | 20 + app/src/components/OneClickModal.jsx | 118 ++ app/src/components/TaskCardView.jsx | 33 + app/src/components/Toast.jsx | 21 + app/src/components/TopBar.jsx | 16 + app/src/components/cards/Card.jsx | 16 + app/src/components/cards/DetailCard.jsx | 37 + app/src/components/cards/ImageCard.jsx | 34 + app/src/components/cards/IntroCard.jsx | 26 + app/src/components/cards/ItineraryCard.jsx | 40 + app/src/components/cards/PriceCard.jsx | 56 + app/src/components/cards/TitleCard.jsx | 65 + app/src/data/genData.js | 245 +++ app/src/lib/agent.js | 60 + app/src/lib/oc.js | 36 + app/src/main.jsx | 10 + app/src/store/context.js | 10 + app/src/store/useAppStore.js | 541 +++++++ app/src/styles/global.css | 463 ++++++ package-lock.json | 1698 ++++++++++++++++++++ package.json | 20 + vite.config.js | 22 + 29 files changed, 3872 insertions(+), 19 deletions(-) create mode 100644 app/index.html create mode 100644 app/src/App.jsx create mode 100644 app/src/components/AssistantPanel.jsx create mode 100644 app/src/components/FormArea.jsx create mode 100644 app/src/components/GenCardView.jsx create mode 100644 app/src/components/MessageItem.jsx create mode 100644 app/src/components/OneClickModal.jsx create mode 100644 app/src/components/TaskCardView.jsx create mode 100644 app/src/components/Toast.jsx create mode 100644 app/src/components/TopBar.jsx create mode 100644 app/src/components/cards/Card.jsx create mode 100644 app/src/components/cards/DetailCard.jsx create mode 100644 app/src/components/cards/ImageCard.jsx create mode 100644 app/src/components/cards/IntroCard.jsx create mode 100644 app/src/components/cards/ItineraryCard.jsx create mode 100644 app/src/components/cards/PriceCard.jsx create mode 100644 app/src/components/cards/TitleCard.jsx create mode 100644 app/src/data/genData.js create mode 100644 app/src/lib/agent.js create mode 100644 app/src/lib/oc.js create mode 100644 app/src/main.jsx create mode 100644 app/src/store/context.js create mode 100644 app/src/store/useAppStore.js create mode 100644 app/src/styles/global.css create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 vite.config.js diff --git a/.gitignore b/.gitignore index dc0e2f1..3ebccfa 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,8 @@ # 本地服务 node_modules/ +# 构建产物 +dist/ + # 本地推送脚本(含本地环境信息,不入库) push-to-gitea.sh diff --git a/README.md b/README.md index 4caac41..37f70a1 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,63 @@ 飞猪商家商品发布平台右侧嵌入的 AI 助手交互式演示。模拟完整的商品发布页(六大模块表单)+ 右侧 AI 助手面板,主打「一键发品」与「越用越好用」的偏好学习机制。 -## 快速开始 +仓库包含两个版本,展示同一个 Demo 从「单文件原型」到「前端工程化」的演进: -无需构建,直接用浏览器打开: +| 版本 | 入口 | 说明 | +|---|---|---| +| v1 单文件原型 | `index.html` | HTML + CSS + JS 零依赖,浏览器直接打开 | +| v2 工程化版 | `app/`(Vite + React) | 组件化拆分、状态收敛、可扩展接入真实 LLM | + +两个版本的功能与视觉完全一致。 + +## 快速开始(Vite + React 版) ```bash -open index.html +npm install +npm run dev # 开发:http://localhost:5173 +npm run build # 构建产物输出到 dist/ +npm run preview # 本地预览构建产物 ``` -或启动本地静态服务: +单文件版无需构建:直接 `open index.html`。 + +## 工程结构 -```bash -npx serve . ``` +├── index.html # v1 单文件 Demo(保留作对照,不参与 Vite 构建) +├── vite.config.js # Vite 配置(root 指向 app/,与根目录 index.html 互不干扰) +├── app/ +│ ├── index.html # Vite 入口 +│ └── src/ +│ ├── main.jsx # 应用挂载 +│ ├── App.jsx # 布局组合 + Store 注入 +│ ├── styles/global.css # 全局样式(自 v1 完整迁移,类名不变) +│ ├── data/ +│ │ └── genData.js # 8 个工具的结构化生成器(文案/卡片/回填数据) +│ ├── lib/ +│ │ ├── agent.js # Agent 意图解析:parseBrief / parseMultiTools / 意图正则 +│ │ └── oc.js # 偏好学习:localStorage 持久化 + 成长等级 +│ ├── store/ +│ │ ├── useAppStore.js # 状态中枢:表单/消息/串行确认/一键发品 + 异步编排流 +│ │ └── context.js # Store Context +│ └── components/ +│ ├── TopBar.jsx # 顶部导航 +│ ├── FormArea.jsx # 左侧表单(6 大模块) +│ ├── cards/ # 6 个表单模块卡片(Title/Intro/Detail/Image/Itinerary/Price) +│ ├── AssistantPanel.jsx # 右侧 AI 助手面板 +│ ├── MessageItem.jsx / GenCardView.jsx / TaskCardView.jsx # 消息流三种消息 +│ ├── OneClickModal.jsx # 一键发品弹窗(配置→进度→完成 状态机) +│ └── Toast.jsx +├── Prompt提示词设计文档.md # 各工具背后的 Prompt 设计规范(可直接落地真实 LLM) +└── AI领教营/ # 项目方法论笔记(AI 价值/边界/验证框架) +``` + +### 架构要点 + +- **数据驱动渲染**:v1 中拼接 HTML 字符串的生成卡片,v2 重构为结构化数据(`head / lines / foot / tips`),按钮全部是真实 React 事件 +- **异步编排与 UI 解耦**:`quickAction / agentRun / multiToolRun / startOC` 四条编排流集中在 store,通过 ref 读取最新状态避免闭包过期 +- **human-in-the-loop 串行确认**:每个工具生成后 Promise 挂起,等待自动倒计时(5s)或手动确认,支持运行中随时切换模式 +- **偏好学习持久化**:`ocStore` 写入 localStorage,跨会话预填配置与成长等级 ## 功能概览 @@ -46,14 +90,6 @@ npx serve . - 即时记忆:每次发品沉淀偏好(localStorage),下次自动预填配置 - 成长等级:Lv.1 通用模板(0-2 次)→ Lv.2 风格匹配(3-9 次)→ Lv.3 爆款复刻(10+ 次) -## 目录结构 - -``` -├── index.html # 单文件 Demo(HTML + CSS + JS,零依赖) -├── Prompt提示词设计文档.md # 各工具背后的 Prompt 设计规范(可直接落地真实 LLM) -└── AI领教营/ # 项目方法论笔记(AI 价值/边界/验证框架) -``` - ## 设计规范 - **品牌主色**:`#FF7A1A`(飞猪橙黄),渐变 `#FFA200 → #FF6600` @@ -61,11 +97,9 @@ npx serve . ## 落地指引 -Demo 中的生成逻辑为前端模拟数据(`genData`)。接入真实 LLM 时: +Demo 中的生成逻辑为前端模拟数据(`app/src/data/genData.js`)。接入真实 LLM 时: -1. 将助手面板抽成 Vue/React 独立组件 -2. 按设计文档定义 API 契约(表单上下文 + 生成类型 → 流式返回) +1. 将 `lib/agent.js` 的意图解析替换为 LLM function calling +2. 按 `Prompt提示词设计文档.md` 定义 API 契约(表单上下文 + 生成类型 → 流式返回) 3. Agent 编排对应后端 Agent Loop:意图分类 → 参数抽取 → function calling → 结果回填 → 偏好沉淀 4. 偏好沉淀对应商家画像服务,喂给 LLM 的个性化 prompt - -详见 `Prompt提示词设计文档.md`。 diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..4763952 --- /dev/null +++ b/app/index.html @@ -0,0 +1,12 @@ + + + + + + 商品发布 - 旅智工作台 + + +
+ + + diff --git a/app/src/App.jsx b/app/src/App.jsx new file mode 100644 index 0000000..15a36b4 --- /dev/null +++ b/app/src/App.jsx @@ -0,0 +1,22 @@ +import { useAppStore } from './store/useAppStore' +import { StoreContext } from './store/context' +import TopBar from './components/TopBar' +import FormArea from './components/FormArea' +import AssistantPanel from './components/AssistantPanel' +import OneClickModal from './components/OneClickModal' +import Toast from './components/Toast' + +export default function App() { + const store = useAppStore() + return ( + + +
+ + +
+ + +
+ ) +} diff --git a/app/src/components/AssistantPanel.jsx b/app/src/components/AssistantPanel.jsx new file mode 100644 index 0000000..f6c9292 --- /dev/null +++ b/app/src/components/AssistantPanel.jsx @@ -0,0 +1,97 @@ +import { useEffect, useRef, useState } from 'react' +import { useStore } from '../store/context' +import MessageItem from './MessageItem' + +/** 右侧:AI 助手面板(快捷生成 / 消息流 / 对话输入) */ +export default function AssistantPanel() { + const { + messages, panelCollapsed, setPanelCollapsed, + quickAction, openOC, sendMessage + } = useStore() + const [input, setInput] = useState('') + const msgListRef = useRef(null) + + /* 新消息时自动滚动到底部 */ + useEffect(() => { + requestAnimationFrame(() => { + const el = msgListRef.current + if (el) el.scrollTop = el.scrollHeight + }) + }, [messages]) + + const quickItems = [ + { type: 'title', icon: 'q1', em: '📝', label: '商品标题' }, + { type: 'intro', icon: 'q2', em: '💎', label: '详细介绍' }, + { type: 'detail', icon: 'q7', em: '📄', label: '商品详情' }, + { type: 'image', icon: 'q5', em: '🖼️', label: '配图建议' }, + { type: 'itinerary', icon: 'q3', em: '🗺️', label: '行程规划' }, + { type: 'price', icon: 'q4', em: '💰', label: '价格库存' }, + { type: 'seo', icon: 'q6', em: '🔍', label: 'SEO 词' }, + { type: 'check', icon: 'q6', em: '🛡️', label: '合规检查' } + ] + + const send = () => { + const text = input.trim() + if (!text) return + setInput('') + sendMessage(text) + } + + return ( +
+ +
+
🤖
+
+
旅智小助 商品发布专精
+
在线 · 已读取当前页面表单内容
+
+
+ +
+
+ +
+
⚡ 快捷生成(对应左侧 6 大模块)
+ +
+ {quickItems.map(q => ( + + ))} +
+
+ +
+ {messages.map(m => )} +
+ +
+
+