diff --git a/docs/source-analysis.html b/docs/source-analysis.html
index 48aaabb..ed40e5e 100644
--- a/docs/source-analysis.html
+++ b/docs/source-analysis.html
@@ -610,7 +610,8 @@
web/app/page.tsx | 旧 React 单对话框生成台源码仍保留,便于以后回滚或抽能力;当前生产根域名已经由 web/canvas-app/ 画布产物覆盖,不再把这个 React 首页作为默认首屏。该页面里的模式也已收敛为文生图、文生视频、图生视频;图生视频只显示“上传图片”,不把“首帧/首尾帧”作为用户入口。旧 TK 复刻工作台组件仍保留在 web/components/ad-recreation-board.tsx,但不再作为默认首页渲染。 |
web/canvas-app/ | SKG 内部画布应用:从 chatfire-AI/huobao-canvas 交互逻辑改造而来。当前策略是“保留成熟画布能力,替换品牌/路由/API”:Vue Flow 节点画布、项目列表、推荐词、AI 润色、自动执行、工作流模板、首帧/尾帧/参考图节点、图片/视频/LLM 配置节点、模型配置和批量下载都保留;可见品牌收敛为 SKG logo,不展示上游注册链接或外部品牌。生产路径固定为根域名 /,内部路由用 /p/:id?;项目列表和画布 JSON 优先同步到服务端 Postgres,浏览器本地存储只是缓存/导入来源;来源说明保存在 THIRD_PARTY_NOTICES.md,不展示给终端用户。 |
web/canvas-app/src/stores/projects.js | 画布项目 Pinia store:启动时先读本地 localStorage["ai-canvas-projects"] 作为缓存,再调用 GET /canvas-projects 拉服务端项目;如果发现本地旧项目,会调用 POST /canvas-projects/import 导入到当前登录用户。新建、重命名、画布节点变更、复制和删除会同步到 /canvas-projects,本地缓存只用于快速打开和网络异常兜底。 |
- web/canvas-app/src/views/Canvas.vue | 画布主交互:恢复上游底部 prompt composer、AI 润色、自动执行、推荐词、节点菜单、工作流面板、API/模型设置入口和批量下载入口。自动执行会调用 useWorkflowOrchestrator 分析提示词,创建文生图、图转视频、故事板、多角度分镜或绘本节点组;手动模式只创建文本节点,用户自行连接节点。底部推荐词为短词池,4 个一组单行展示,刷新按钮只轮换下一组,不改变输入面板高度。 |
+ web/canvas-app/src/views/Canvas.vue | 画布主交互:恢复上游底部 prompt composer、AI 润色、自动执行、推荐词、节点菜单、工作流面板、API/模型设置入口和批量下载入口。自动执行会调用 useWorkflowOrchestrator 分析提示词,创建文生图、图转视频、故事板、多角度分镜或绘本节点组;手动模式只创建文本节点,用户自行连接节点。底部推荐词来自共享短词池,4 个一组单行展示,刷新按钮在 30 组内轮换,不改变输入面板高度。 |
+ web/canvas-app/src/config/suggestions.js | 首页和画布共用的推荐词配置:维护 QUICK_SUGGESTION_GROUPS,当前为 30 组 / 120 个短词,每组 4 个,控制刷新按钮的轮换范围;词条保持短小,避免推荐栏换行或顶起 composer。 |
web/canvas-app/src/config/models.js | 画布媒体模型和规格的前端白名单:图片只内置 auto、gpt-image-2、gemini-3-pro-image-preview,尺寸只内置 auto、1024x1536、1024x1024、1536x1024;视频只内置 seedance / Seedance 2.0 Fast,画幅和时长对齐后端 /health 能力边界。useModelConfig.js 和 Pinia 模型 store 会忽略浏览器本地自定义图片/视频模型,防止旧缓存把不可用模型带回生成下拉。 |
web/canvas-app/src/hooks/useApi.js | 画布到本项目后端的适配层:不再读取浏览器 API Key,而是使用当前登录会话 Cookie 调用 /api。文生图 / 图生图先创建轻量 creative job,再调用 /frames/0/generate;文生视频 / 图生视频调用 /storyboard/video 并轮询 /jobs/{id},完成后把图片或 mp4 URL 写回画布节点。useChat 已从 SKG 广告文案接口切到 /prompt/polish:AI 润色显式使用 image/video prompt 模式,LLM 节点使用通用 chat 模式,避免自动注入用户没有提到的 SKG 或营销语境;后端会判断原提示词是否有人物意图,无人物时禁止新增人物,有人物时才声明虚构 AI 角色。 |
web/scripts/sync-canvas-root.mjs | 构建桥接脚本:在 next build 静态导出完成后,把 Vite 画布产物 web/canvas-app/dist 覆盖到 web/out 根目录,使 https://marketing.skg.com 登录后直接进入画布;旧 web/scripts/sync-canvas-dist.mjs 保留但不再由生产构建调用。 |
@@ -1243,6 +1244,18 @@ ProductRefStateItem {
变更记录
这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。
+
+
+ 2026-05-26 · 推荐词扩展为 30 组共享短词池
+ Canvas
+ UX
+
+
+
问题:推荐词刷新已经可用,但词池只有少数组,用户连续点击时会很快回到同一批,感觉“刷来刷去就这两组”。
+
改动:新增 web/canvas-app/src/config/suggestions.js,把首页 Home.vue 和画布 Canvas.vue 的推荐词统一改为 QUICK_SUGGESTION_GROUPS,当前 30 组 / 120 个短词,每次仍显示 4 个并按组轮换。
+
影响:用户可以连续刷新更多主题、场景、产品、镜头和风格灵感;推荐栏仍保持单行短词展示,不会顶起输入框。
+
+
2026-05-26 · 推荐词刷新改为短词轮换
diff --git a/web/canvas-app/src/config/suggestions.js b/web/canvas-app/src/config/suggestions.js
new file mode 100644
index 0000000..e1dfe29
--- /dev/null
+++ b/web/canvas-app/src/config/suggestions.js
@@ -0,0 +1,32 @@
+export const QUICK_SUGGESTION_GROUPS = [
+ ['魔法森林', '三只小猫', '多角度分镜', '夏日田野'],
+ ['雨夜街摊', '产品特写', '水花慢镜', '极简桌面'],
+ ['无人物街景', '夜市霓虹', '电商白底', '咖啡窗边'],
+ ['插画封面', '厨房晨光', '3D 产品', '海边慢步'],
+ ['樱花小路', '玻璃花房', '露营夜灯', '复古厨房'],
+ ['雪山清晨', '海边黄昏', '森林木屋', '城市天台'],
+ ['未来展厅', '透明材质', '金属微光', '柔和阴影'],
+ ['香水静物', '珠宝近景', '护肤瓶身', '白底套图'],
+ ['手作陶杯', '咖啡拉花', '甜品橱窗', '面包出炉'],
+ ['雨后街角', '地铁站台', '便利店夜', '书店暖光'],
+ ['儿童绘本', '水彩动物', '云朵小岛', '童话城堡'],
+ ['动漫少女', '机甲少年', '赛博街区', '霓虹背光'],
+ ['古风庭院', '宋式茶席', '竹林小径', '月下湖面'],
+ ['户外露营', '徒步山路', '公路日落', '湖边野餐'],
+ ['宠物写真', '猫咪午睡', '小狗奔跑', '兔子花园'],
+ ['办公桌面', '键盘特写', '创意白板', '会议晨光'],
+ ['运动瞬间', '瑜伽清晨', '跑步剪影', '泳池水花'],
+ ['科技发布', '产品旋转', '参数分镜', '开箱镜头'],
+ ['家居客厅', '卧室暖灯', '窗边绿植', '阳台微风'],
+ ['餐桌俯拍', '火锅热气', '寿司吧台', '水果切面'],
+ ['微距花瓣', '水滴叶片', '蝴蝶停留', '晨露草地'],
+ ['沙漠公路', '银河帐篷', '极光雪原', '热气球'],
+ ['电影海报', '悬疑走廊', '逆光人物', '红蓝光影'],
+ ['产品拆解', '材质对比', '功能三镜', '使用场景'],
+ ['小镇集市', '老街门牌', '木质招牌', '雨伞人群'],
+ ['空镜转场', '慢推镜头', '俯拍街区', '环绕拍摄'],
+ ['品牌主图', '社媒封面', '直播背景', '短片开场'],
+ ['草莓蛋糕', '柠檬汽水', '冰块特写', '夏日餐桌'],
+ ['山谷溪流', '雾气森林', '日出云海', '秋叶小路'],
+ ['无脸模特', '侧脸剪影', '背影行走', '虚拟角色']
+]
diff --git a/web/canvas-app/src/views/Canvas.vue b/web/canvas-app/src/views/Canvas.vue
index 783495b..f6cb02d 100644
--- a/web/canvas-app/src/views/Canvas.vue
+++ b/web/canvas-app/src/views/Canvas.vue
@@ -291,6 +291,7 @@ import ApiSettings from '../components/ApiSettings.vue'
import DownloadModal from '../components/DownloadModal.vue'
import WorkflowPanel from '../components/WorkflowPanel.vue'
import AppHeader from '../components/AppHeader.vue'
+import { QUICK_SUGGESTION_GROUPS } from '../config/suggestions'
// API Config state | API 配置状态
const modelStore = useModelStore()
@@ -444,17 +445,10 @@ const inputPlaceholder = '你可以试着说"帮我生成一个二次元的卡
// Quick suggestions | 快捷建议
const suggestionPage = ref(0)
-const suggestionGroups = [
- ['魔法森林', '三只小猫', '多角度分镜', '夏日田野'],
- ['雨夜街摊', '产品特写', '水花慢镜', '极简桌面'],
- ['无人物街景', '夜市霓虹', '电商白底', '咖啡窗边'],
- ['插画封面', '厨房晨光', '3D 产品', '海边慢步']
-]
-
-const suggestions = computed(() => suggestionGroups[suggestionPage.value % suggestionGroups.length])
+const suggestions = computed(() => QUICK_SUGGESTION_GROUPS[suggestionPage.value % QUICK_SUGGESTION_GROUPS.length])
const refreshSuggestions = () => {
- suggestionPage.value = (suggestionPage.value + 1) % suggestionGroups.length
+ suggestionPage.value = (suggestionPage.value + 1) % QUICK_SUGGESTION_GROUPS.length
}
// Add new node | 添加新节点
diff --git a/web/canvas-app/src/views/Home.vue b/web/canvas-app/src/views/Home.vue
index c38ee2a..92efbdb 100644
--- a/web/canvas-app/src/views/Home.vue
+++ b/web/canvas-app/src/views/Home.vue
@@ -232,6 +232,7 @@ import {
import { useModelStore } from '../stores/pinia'
import ApiSettings from '../components/ApiSettings.vue'
import AppHeader from '../components/AppHeader.vue'
+import { QUICK_SUGGESTION_GROUPS } from '../config/suggestions'
const router = useRouter()
const dialog = useDialog()
@@ -285,17 +286,10 @@ const renameTargetId = ref(null)
// Suggestions tags | 建议标签
const suggestionPage = ref(0)
-const suggestionGroups = [
- ['魔法森林', '三只小猫', '多角度分镜', '夏日田野'],
- ['雨夜街摊', '产品特写', '水花慢镜', '极简桌面'],
- ['无人物街景', '夜市霓虹', '电商白底', '咖啡窗边'],
- ['插画封面', '厨房晨光', '3D 产品', '海边慢步']
-]
-
-const suggestions = computed(() => suggestionGroups[suggestionPage.value % suggestionGroups.length])
+const suggestions = computed(() => QUICK_SUGGESTION_GROUPS[suggestionPage.value % QUICK_SUGGESTION_GROUPS.length])
const refreshSuggestions = () => {
- suggestionPage.value = (suggestionPage.value + 1) % suggestionGroups.length
+ suggestionPage.value = (suggestionPage.value + 1) % QUICK_SUGGESTION_GROUPS.length
}
// Format date | 格式化日期