feat: cache canvas media locally

This commit is contained in:
2026-05-28 15:43:54 +08:00
parent 4bcca76098
commit 854947a239
6 changed files with 232 additions and 7 deletions

View File

@@ -626,6 +626,7 @@
<p><strong>2026-05-27 上传参考图持久化:</strong>画布图片节点上传本地文件时先写入后端 creative job再把 <code>/api/jobs/...</code> 资产 URL 保存到节点和服务端画布项目;不再把浏览器 <code>data:</code> base64 当作图片地址保存。项目自动保存增加内容签名去重和 2 秒防抖,减少连续点击或节点测量触发的重复 <code>PUT /canvas-projects</code></p>
<p><strong>2026-05-27 图片模型配置化:</strong>图片生成不再把主模型写死为 <code>gpt-image-2</code>。后端通过 <code>IMAGE_MODEL</code><code>IMAGE_FALLBACK_MODELS</code><code>IMAGE_EXTRA_MODELS</code><code>IMAGE_MODEL_CONFIGS_JSON</code> 和 Ark 专用 <code>ARK_IMAGE_BASE_URL</code>/<code>ARK_IMAGE_API_KEY</code>/<code>ARK_SEEDREAM_IMAGE_MODEL</code> 注册模型;默认仍保持 GPT Image 2 + Gemini 兜底,新增可选 <code>doubao-seedream-4-5-251128</code>Seedream 走 <code>/images/generations</code> + <code>reference_images</code> 并使用 2K/4K 尺寸。</p>
<p><strong>2026-05-26 生图配置恢复版:</strong>按用户要求撤回后续“低/中/高画质、自定义尺寸、Gemini 官方 1K/2K/4K 尺寸、取消自动模型”的实验改动,恢复最初简单配置:图片模型为 <code>auto</code><code>gpt-image-2</code><code>gemini-3-pro-image-preview</code>,尺寸只保留 <code>auto</code><code>1024x1536</code><code>1024x1024</code><code>1536x1024</code>,画质回到单一标准项;<code>auto</code> 仍按后端既有策略优先 GPT Image 2必要时由熔断/兜底走 Gemini。</p>
<p><strong>2026-05-28 画布媒体本地缓存:</strong>图片节点和视频节点显示 <code>/api/jobs/...</code> 生成资产时,会先查当前浏览器的 Cache Storage命中后使用本机 <code>blob:</code> 地址展示,未命中则先用服务器 URL 展示并在后台写入本地缓存。后端对登录保护下的 job 图片、视频和音频返回 <code>Cache-Control: private, max-age=2592000, immutable</code>,让每台电脑自己的浏览器磁盘缓存参与加速,避免刷新画布时反复从 VPS 下载同一素材。</p>
</div>
<p>当前默认业务管线是“个人隔离任务 → 根域名进入个人画布 → 画布项目同步到服务端 Postgres → 用提示词、推荐词、AI 润色、公共工作流或我的工作流创建节点 → 画布自动执行或手动连接图片/视频/文本节点 → 生成结果沉淀在当前个人画布 → 可把当前节点结构保存为我的工作流 → 需要时进入详情页继续编辑”。画布不再被削成三模式入口;首帧、尾帧、参考图、图生视频、多角度分镜、故事板和绘本等上游概念按节点能力保留。底层生成仍由 <code>web/canvas-app/src/hooks/useApi.js</code> 适配到本项目 <code>/creative/jobs/image</code><code>/jobs/{id}/frames/{idx}/generate</code><code>/jobs/{id}/frames/{idx}/storyboard/video</code>AI 润色和通用 LLM 文本生成走 <code>/prompt/polish</code> 并保持中性专业:不主动套入 SKG不主动补产品、平台、广告语境或人物只扩写用户明确写出的主体、动作、场景、镜头、光线和质量细节视频提交若带参考图会在最终提示词中条件声明“参考图里若有人物应按 AI 生成的虚拟角色处理”,避免把 AI 人像素材误当成真实肖像。生成资产按当前登录用户写入个人 job。图片模型由后端运行时配置决定默认 <code>auto</code> 仍优先当前 <code>IMAGE_MODEL</code> 并按 <code>IMAGE_FALLBACK_MODELS</code> 兜底;前端同时提供 GPT/Gemini 旧尺寸和 Seedream 2K/4K 尺寸。视频画幅只显示 <code>720x1280</code><code>1280x720</code><code>1024x1024</code><code>960x1280</code>;视频时长只显示 <code>5/8/10/12/15</code> 秒。多人互不影响依赖后端 <code>owner_id</code>、画布项目 owner、我的工作流 owner 和飞书 / 备用登录会话隔离。旧 React 单对话框首页、信息流复刻链路仍保留在源码里作为回滚/高级能力,但不作为生产默认入口。</p>
<div class="pipeline">
@@ -657,6 +658,7 @@
<tr><td><code>web/canvas-app/src/views/Canvas.vue</code></td><td>画布主交互:恢复上游底部 prompt composer、<code>AI 润色</code><code>自动执行</code>、推荐词、节点菜单、工作流面板、API/模型设置入口和批量下载入口。自动执行会调用 <code>useWorkflowOrchestrator</code> 分析提示词,创建文生图、图转视频、故事板、多角度分镜或绘本节点组;手动模式只创建文本节点,用户自行连接节点。工作流面板支持公共模板和我的工作流:公共模板走本地 <code>createNodes()</code>,我的工作流从云端 <code>workflow_data</code> 插回当前画布,并重新生成节点 ID、按视口中心重排、按映射重连边。Vue Flow 开启可见节点渲染,大画布不再把所有节点同时挂载到 DOM节点数超过 120 时隐藏 MiniMap减少点击后的同步重绘压力。底部推荐词来自共享短词池4 个一组单行展示,刷新按钮在 30 组内轮换,不改变输入面板高度。</td></tr>
<tr><td><code>web/canvas-app/src/config/suggestions.js</code></td><td>首页和画布共用的推荐词配置:维护 <code>QUICK_SUGGESTION_GROUPS</code>,当前为 30 组 / 120 个短词,每组 4 个,控制刷新按钮的轮换范围;词条保持短小,避免推荐栏换行或顶起 composer。</td></tr>
<tr><td><code>web/canvas-app/src/config/models.js</code></td><td>画布媒体模型和规格的前端白名单:图片只内置 <code>auto</code><code>gpt-image-2</code><code>gemini-3-pro-image-preview</code>,尺寸只内置 <code>auto</code><code>1024x1536</code><code>1024x1024</code><code>1536x1024</code>;视频只内置 <code>seedance</code> / <code>Seedance 2.0 Fast</code>,画幅和时长对齐后端 <code>/health</code> 能力边界。<code>useModelConfig.js</code> 和 Pinia 模型 store 会忽略浏览器本地自定义图片/视频模型,防止旧缓存把不可用模型带回生成下拉。</td></tr>
<tr><td><code>web/canvas-app/src/hooks/useCachedMediaUrl.js</code></td><td>画布媒体本地缓存 Hook只缓存同源、登录保护下的 <code>/api/jobs/...</code><code>/api/agent-runs/...</code> 图片 / 视频 / 音频。图片节点和视频节点先用原始 URL 保证首屏可见,再后台写入浏览器 Cache Storage下次打开同一素材时返回本机 <code>blob:</code> URL减少反复从 VPS 下载。</td></tr>
<tr><td><code>web/canvas-app/src/hooks/useApi.js</code></td><td>画布到本项目后端的适配层:不再读取浏览器 API Key而是使用当前登录会话 Cookie 调用 <code>/api</code>。文生图 / 图生图先创建轻量 creative job再调用 <code>/frames/0/generate</code>;本地上传到图片节点的参考图也会先通过 <code>/creative/jobs/image</code> 写成后端资产,再把 <code>/api/jobs/...</code> URL 保存到节点,避免刷新后丢失。文生视频 / 图生视频调用 <code>/storyboard/video</code> 并轮询 <code>/jobs/{id}</code>,完成后把图片或 mp4 URL 写回画布节点。<code>useChat</code> 已从 SKG 广告文案接口切到 <code>/prompt/polish</code>AI 润色显式使用 image/video prompt 模式LLM 节点使用通用 chat 模式,避免自动注入用户没有提到的 SKG、产品、平台或营销语境后端会清理旧润色模板尾巴、判断人物/无人/物体/场景意图,并在输出后检查“有人却禁止人物、无人却新增人物、未写 SKG 却出现 SKG”等冲突。图生视频实际提交到后端后后端会对参考图追加 AI 虚拟角色条件说明,不要求前端判断图片里是否有人脸。</td></tr>
<tr><td><code>web/scripts/sync-canvas-root.mjs</code></td><td>构建桥接脚本:在 <code>next build</code> 静态导出完成后,把 Vite 画布产物 <code>web/canvas-app/dist</code> 覆盖到 <code>web/out</code> 根目录,使 <code>https://marketing.skg.com</code> 登录后直接进入画布;旧 <code>web/scripts/sync-canvas-dist.mjs</code> 保留但不再由生产构建调用。</td></tr>
<tr><td><code>web/app/detail/page.tsx</code></td><td>任务详情页:静态导出路由 <code>/detail/?job=&lt;id&gt;</code>,通过 query 读取 job id调用 <code>getJob</code> 恢复同一任务。页面展示参考图、全部生成图、视频候选、营销图文方案和历史提示词,可继续调用 <code>generateImage</code><code>generateStoryboardVideo</code><code>generateCreativeCopy</code>,并支持删除图片/视频。该页继续依赖后端 owner 过滤,用户不能通过切换 URL 读取别人的任务。</td></tr>