无限画布无限画布

待测试

当前版本已实现但仍需人工验证的变更项

待测试

  • 声音开关覆盖全部线上视频渠道 — 前端 VideoSettingsPanel 的 Seedance / Kling / Wan / 通用面板均已提供声音相关开关(Seedance videoGenerateAudio、Kling / 通用 videoSound、Wan videoAudio);HappyHorse 因 new-api 文档白名单不含 audio,已移除声音开关与请求体中的音频字段。后端 Provider 已将对应字段映射到上游请求体(Seedance metadata.generate_audio、Kling metadata.sound、Wan metadata.audio、通用 OpenAI 兼容路径 sound)。需要验证:各线上渠道模型提交视频生成请求时,声音开关状态正确传递到上游;切换模型后声音默认值符合模型能力配置。

  • 生图工作台任务详情增加轮询/刷新状态与 API 调用日志查看 — 前端 /image 页面 TaskDetailPanel 已对齐视频创作台:显示任务编号、已耗时、上游状态;增加「取消任务」「刷新状态」「删除」「API 调用日志」按钮;日志面板支持展开请求/响应、复制单条、复制全部、放大查看。后端 ImageTaskService 在提交、轮询、失败时已将日志写入 task.extra.logs。需要验证:生成中任务详情页自动刷新且已耗时时钟准确;失败任务可查看错误与日志;点击「刷新状态」调用 POST /api/v1/image-tasks/:id/sync 更新状态;日志面板在远程渠道下能展示请求/响应。

  • 修复:生图工作台新建任务后点击「刷新状态」提示「无效ID」 — 根因是 POST /api/v1/image-tasks 返回 data: { task: ImageTask } 嵌套结构,而前端 createImageTask/submitTaskImageTask 直接使用,导致新建任务在本地状态中的 idundefined,右侧详情面板调用 POST /api/v1/image-tasks/${id}/sync 时后端解析失败。已把后端创建响应改为直接返回任务对象(与视频创建 /api/v1/video-tasks 一致),并更新 handler/image_task_test.go。需要验证:新建生图任务后,右侧详情面板立即显示正确的任务编号;点击「刷新状态」能正常同步状态,不再提示「无效ID」。

  • #105 修复:Kling-V3 视频生成缺失必填参数 shot_type — 后端 service/videoprovider/kling.gobuildKlingPayload 现在始终为 Kling 模型写入 metadata.shot_type,未设置时默认 "intelligence";不再依赖 multi_shot=true 才发送。service/videoprovider/videoprovider_test.goTestKlingPayloadWithoutMetadata 已补充对默认 shot_type 的断言。需要验证:Kling-V3 在关闭「多镜头模式」时也能成功创建任务;Kling-V3-omni 行为不受影响;其它视频模型提交请求体不变。

  • 测试:生图/视频相关模块测试覆盖率提升到 ≥90% — 后端 service/imageprovider(92.7%)、service/videoprovider(96.4%)、service/internal/common(100%);前端 image-model-capabilities.ts/video-model-capabilities.ts(100% lines)、services/api/image.ts(99.43% lines)、services/api/video.ts(97.28% lines)。需要验证:新增测试用例与既有业务行为一致,CI 或本地运行目标模块测试无失败。

  • 重构:生图/视频工作台模型协议与任务状态机分离 — 后端新增 service/imageprovider/(GptImageProvider / GeminiImageProvider / OpenAILikeProvider)与 service/videoprovider/(SeedanceProvider / OpenAIVideoProvider),ImageTaskService/VideoTaskService 只负责任务生命周期、积分与状态机,模型参数构造、提交、轮询、解析下沉到 Provider 与 Executor;前端新增 image-model-capabilities.ts/video-model-capabilities.tsservices/api/image.tsservices/api/video.tsVideoSettingsPanel/video 页面已切换到能力层,移除 isGptImageModel/isGeminiImageModel/isSeedanceVideoConfig 等硬编码判断。需要验证:gpt-image-2 / Gemini / dall-e-3 生图、Seedance / Kling / HappyHorse / Wan 视频在远程渠道下参数、路由、参考素材限制与此前一致,新增模型只需新增一个 Provider 文件和一个 Capability 配置即可扩展。

  • 对齐:图片生成请求参数按 ai-api_21526f.yaml 逐模型校准 — 后端 service/image_task.gobuildGenerationsRequest 已按模型拆分:gpt-image-2 固定发送 size1024x1024 / 1024x1536 / 1536x1024)和 qualitylow / medium / high),并把 n 限制为 2;Gemini 图片模型发送 aspect_ratio1:1 / 4:3 / 3:4 / 16:9 / 9:16 / 3:2 / 2:3 / 21:9)和 resolution1K / 2K / 4K),同样限制 n 为 2;其他模型保持原有 quality / size 逻辑。前端 services/api/image.tsrequestGeneration / requestEdit 已同步按模型构造请求体。需要验证 gpt-image-2Gemini 图片模型在 /image 工作台和画布生图节点中请求体与上游文档一致,且不会因为 n 超过 2 而 400。

  • #100 多用户绑定同一模型渠道(方案 A)ModelChannel 增加 idUser 增加 model_channel_id;保存私有配置时为渠道自动生成唯一 ID;SelectModelChannel(modelName, userID) 优先使用用户绑定的渠道,绑定渠道不可用或不支持当前模型时回退全局加权随机;视频任务创建/轮询、AI 代理已登录请求均传入 userID;管理后台用户编辑页新增「绑定模型渠道」下拉框,可设置或清空。需要验证渠道 ID 持久化、用户绑定与回退行为。

  • 对齐:视频生成请求参数按 ai-api.yaml 逐模型校准 — Seedance 原生路径移除不支持的 watermark / scene / seed / negative_promptratio 缺省改为 adaptiveduration 按 2.0(4~15,默认 5)和 1.5 Pro(5/10/12)分别归一化,generate_audio / return_last_frame / draft 按模型支持情况发送;Kling shot_type 选项改为 intelligence / customize,其中 Kling-V3 始终必填、Kling-V3-omni 仅在开启 multi_shot 时必填;Wan 将 prompt_extend / watermark / audio / template 放入 metadata 并默认 prompt_extend=true;HappyHorse 保持 watermark 默认 true;切换视频模型时前端会自动重置为模型推荐默认值。需要验证各模型提交请求体与上游文档一致。

  • 对齐:OpenAI 兼容 /v1/videos 端点按 ai-api.yaml 逐模型校准OpenAIVideoProvider 已按 new-api 文档为 Seedance / Kling / HappyHorse 构造请求体:Seedance 发送 metadata.generate_audioreturn_last_frame(2.0)、draft(1.5 Pro 480p)、scene(参考场景)与参考图 images;Kling 发送 size=mode、文生视频时发送 aspect_ratiometadata.sound/multi_shot/shot_typeshot_type 固定 intelligence);HappyHorse 发送 metadata.watermark/seed/scene,不含 audio;Wan 系列在 OpenAI 兼容端点不支持并返回明确错误。需要验证通过 OpenAI 协议渠道(NewAPI 等)提交这些模型时请求体与上游文档一致。

  • 修复:视频生成完成后浏览器播放报 401 Unauthorized — OpenAI 兼容渠道(如 HappyHorse)的任务完成后,上游返回的是可直接访问的视频 URL(如京东云 OSS),pollOpenAI 现在会优先从响应 output / url 字段解析该地址并写入 ResultURL;如果上游没有返回公开 URL,则继续 fallback 到 /content 下载并走本地代理。前端 <video> 直接使用该公开 URL,不再因缺失 Authorization 头而 401。需要验证 HappyHorse 视频生成完成后可正常播放与下载。

  • 重构:视频工作台参数面板(Issue #99)VideoSettingsPanel 已按模型拆分为 Seedance / Kling / HappyHorse / Wan / 通用五套面板,新增 scenenegative_promptseedreturn_last_framedraftmodeaspect_ratiosoundmulti_shotprompt_extendaudiotemplate 等参数;这些字段会写入 task.extra 并由后端按模型映射到对应上游请求体。需要验证各模型下参数回填、提交请求体字段正确。

  • 修复:HappyHorse 模型被错误识别为文本模型 — 后端 service/settings.go 与前端的 use-config-store.tsisVideoModelName 判断均已增加 happyhorse 关键字;拉取模型列表时,HappyHorse-1.0 应被正确归类到视频模型。

  • 优化:扩展模型类型识别规则以支持 JoyBuilder 模型列表 — 后端新增 isAudioModelName 并统一前后端 isVideoModelName / isImageModelName / isAudioModelName 关键字:视频增加 klinghailuovidu;图片增加 vlvisionglm-4.6vcaption;音频增加 t-a-t-b-t-c-。需要验证 upstream/joybuilder_llm_list.csv 中的 65 个模型在管理后台拉取模型列表后,视频(ViduQ2 / Kling / Hailuo)、音频(T-A/T-B/T-C)、图片(VL / Vision / GLM-4.6V / joycaption)和文本模型能被正确分类。

  • 画布生成配置节点的“生成配置/组装提示词”改为在节点下方打开独立输入浮层;浮层支持输入 @ 从已连接图片、文本、视频、音频中选择引用,引用会以图片缩略图或文本标记展示,图片引用可放大预览;生成时再按当前引用解析为实际素材编号,不再提供或读取输入排序。

  • 图片节点悬浮工具栏新增“局部编辑”入口,打开后可在图片上用画笔/擦除工具绘制遮罩区域、填写局部修改要求,并通过图片编辑接口携带同尺寸 PNG mask 生成新图片节点;结果节点会放在原图右侧并自动连线,原图保持不变。

  • 图片节点悬浮工具栏新增“反推提示词”入口;点击后会在原图右侧创建包含反推预设提示词的文本节点,并继续创建一个已切到“文本”模式的生成配置节点,图片节点和文本节点都会自动连到该配置节点,配置节点会预填包含原图和文本节点引用的组装提示词并自动打开,用户可自行点击配置节点开始生成。

  • 图片节点悬浮工具栏新增“复制提示词”、“放大”和“超分”入口,并在末尾增加 ... 更多按钮;点击“复制提示词”会复制生成该图片的提示词,图片没有提示词时会提示暂无可复制内容;点击 ... 后打开 Ant Design 风格的“自定义工具栏”弹窗,可在图片节点占位上预览悬浮工具栏,信息、删除、存素材、下载、编辑和图片工具都在同一个快捷工具列表中勾选配置,并可切换是否显示按钮文字,保存后写入本地配置;... 配置入口固定显示,预览工具栏下方提供常驻横向滚动控制条。“放大”可在弹窗中选择 1K/2K/4K 目标像素和高清插值、双线性、最近邻算法,按原图比例生成新图片节点,已达到的目标像素会禁用并提示无需放大,最高不超过 4K;“超分”当前只打开暂未实现弹窗。

  • Canvas 资源节点会按当前生成上下文显示 图片1视频1音频1文本1 角标;文本节点内容框和节点底部 prompt 面板输入 @ 时应弹出已连接资源选择器,点击缩略图或文字可插入纯文本编号,并以蓝色 token 视觉高亮。

  • 文本节点连接到生成配置节点时,@ 候选和实际生成输入应读取该生成配置节点的上游参考资源;生成配置输入统计区域应可拖动整个配置节点,预览按钮和设置控件仍保持可点击。

  • 配置弹窗改为“配置与用户偏好”并放大为可滚动弹窗;模型列表由后台渠道配置决定,前台仅保留用户偏好(默认模型、图片/视频/音频参数等),新建画布生图和配置节点会读取“画布默认生图张数”,需要验证远程渠道模型列表能正确显示。

  • 画布音频节点底部生成面板改为音频提示词、音频模型下拉和 OpenAI Speech 参数设置,支持 voiceresponse_formatspeedinstructions 并通过 /audio/speech 生成音频节点;需要验证云端渠道的生成、重试、下载和刷新恢复。

  • 画布左上角菜单和右上角状态栏新增“文档”入口,会使用 NEXT_PUBLIC_DOC_URL 配置的地址并在新标签打开文档站;需要验证登录和未登录状态下顶部入口都可见。

  • 文档站搜索改为中英文混合 tokenizer,中文正文、标题和短语会按中文词、单字、二元和三元片段建立索引;需要验证 /api/search 和搜索弹窗能命中文档中的中文关键词。

  • 文档站改为 Next.js standalone server 输出,新增 docs/Dockerfiledocs/docker-compose.ymldocs/docker-compose.local.yml 独立运行入口;需要验证文档页、搜索接口和 LLM 文本接口在文档站容器中可访问。

  • 画布连线支持右键打开删除菜单;拖拽连线到目标卡片内部、连接点附近或卡片边缘外扩范围内会自动吸附并连接,拖到已有但不可连接的节点附近不会再误弹创建节点菜单。

  • 生图工作台和画布生图会把参考图按当前顺序显示为 图片1图片2 等编号,并在图生图请求的实际提示词中注入编号说明;需要验证 /image 参考图排序、画布配置节点输入顺序和画布助手参考图编号一致。

  • GPT Image 生图请求会在前端把 9:1616:9 等比例转换成合法 WIDTHxHEIGHT 尺寸,并在非法尺寸时直接显示中文错误,避免上游返回 invalid_value Invalid size

  • Docker 部署时,DATABASE_DSN=data/infinite-canvas.db 会在存在 /app/data 挂载目录时自动归一到 /app/data/infinite-canvas.db,需要验证后台模型配置不会再因为工作目录变为 /app/web 而读到空库。

  • Seedance 参考视频被火山判定包含真人或隐私信息时,前端错误摘要会提示改用不含真人的视频、官方允许的模型产物或已授权的 asset:// 素材;参考素材上传目录改为跟随 SQLite 数据目录,并补充公开素材的 HEAD 访问。

  • Seedance 参考素材失败原因排查:后端会把火山上游错误摘要返回给前端;/video 和画布视频生成会按 图片1/视频1/音频1 自动编号参考素材,并在实际请求提示词中注入编号说明;参考视频会在请求前校验大小、时长、宽高、宽高比和像素总量。

  • 画布项目导出改为下载 .zip 压缩包,包内包含 projects.json 和当前画布引用到的本地图片、视频文件,避免只导出 JSON 时丢失媒体内容。

  • 画布库支持多选后一键导出多个画布项目,导出的压缩包可一次恢复多个项目。

  • 画布项目导入改为读取新版 .zip 压缩包,会先按 projects.json 中的文件映射恢复图片、视频到本地存储,再插入画布项目,导入成功后仍停留在画布库。

  • 修复删除画布图片节点或清空画布后撤销时,节点信息恢复但本地图片数据已被清理导致图片丢失的问题。

  • “我的素材”类型筛选区右侧新增文本样式的导出素材和导入素材入口,可将全部素材导出为包含 assets.json 与图片、视频文件的压缩包,并从压缩包恢复素材。

  • 未登录状态下,画布右上角不再显示用户头像菜单、用户名称、算力点余额和退出登录入口,改为显示登录入口;快捷键入口仍可直接打开。

  • 生图工作台的图片参数区复用画布里的紧凑版图像设置面板,尺寸、质量、生成张数的交互保持一致;工作台仍保留独立的模型选择。

  • 生图工作台新增生成记录配置持久化:每次生成会保存提示词、参考图、模型、质量、尺寸和张数,结果图写入本地图片存储后记录只保存 storageKey;点击历史记录会回填本次生成配置并预览结果。

  • 生图工作台生成记录会过滤空缩略图地址,避免历史记录卡片渲染 src="" 图片。

  • 图像设置面板新增默认开启的“16倍数对齐”尺寸 toggle;开启时手动输入宽高并失焦、回车或点击浮层外关闭后,会把非 16 倍数的宽高向上补齐。

  • 视频设置抽成画布和视频创作台共用的紧凑面板,清晰度、尺寸、秒数按固定网格选择并支持手动输入;尺寸选择 auto 时请求不传 size

  • 修复画布和生图工作台选择图片尺寸后,请求图片生成/编辑接口未携带 size 参数的问题;auto 不传,其余比例或像素尺寸会随请求发送。

  • 修复生图工作台和画布生图请求中 quality 参数可能传入上游不支持值导致 400 的问题;请求前会归一化质量枚举,auto 或异常值不再发送给上游。

  • 管理后台新增/编辑渠道时,渠道可用模型支持通过弹窗按“新获取、已有”分组选择,并可在弹窗内手动增加模型或拉取模型列表后再写回表单。

  • 管理后台编辑渠道时,API Key 留空不再触发必填校验,表示沿用已保存的密钥;新增渠道仍要求填写 API Key。

  • 管理后台公开配置里的系统可用模型候选项改为由已启用渠道中选择的模型合并去重生成,最终开放哪些模型仍由公开配置里手动勾选。

  • 视频生成请求参数对齐 grok-imagine-video 接口:使用 resolution_namepreset=normalinput_reference[],支持清晰度、尺寸、秒数快捷选择和手动输入,并支持最多 7 张参考图。

  • 画布视频设置浮层改为挂载到页面根层级并使用自建浮层交互,避免被节点悬浮工具栏遮挡或点击面板内容时关闭。

  • 画布生成配置节点的生图参数改为复用图像设置浮层,支持在同一个入口里调整质量、尺寸和生成张数。

  • 视频清晰度输入框改为只输入数字,提交请求时再拼接 p 单位。

  • 视频生成前端会识别后端 { code, msg } 错误响应,创建失败不再继续轮询 undefined

  • 新增 /video 视频创作台页面,参考生图工作台布局,支持提示词、参考图、视频参数、生成结果、保存素材、下载和本地生成记录;清晰度和秒数均支持常用值选择与手动输入,生成记录只保存媒体 storageKey 并可回填本次提示词、参考图和参数。

  • 视频创作台生成前会把模型、尺寸、秒数、清晰度归一化为视频接口支持的参数,并展示后端返回的错误信息,避免页面侧残留的生图参数影响视频请求。

  • 火山方舟 Agent Plan / Seedance 2.0 视频生成需要在真实账号下验证:/contents/generations/tasks 创建任务、轮询状态、content.video_url 回填画布,以及 401/403/429/超时错误提示。

  • 管理后台保存私有渠道后,需要验证所有已启用渠道里的模型会自动出现在公开 availableModels,并且 defaultVideoModeldefaultImageModeldefaultTextModel 在为空或失效时会自动修复,前台不再显示旧的 grok 默认值。

  • /video 和画布视频设置已按 Seedance 2.0 增加分辨率、比例、4-15 秒/智能时长、生成声音和水印参数;需要在真实浏览器里验证参数回填、生成记录和画布节点配置都能保持一致。

  • /video 支持最多 9 张参考图、3 个参考视频、3 个参考音频;需要验证格式、大小、音频时长提示和生成请求中的 reference_imagereference_videoreference_audio 组装。

  • 画布新增音频节点,支持上传、拖入、播放、移动、缩放、删除,并可作为上游参考音频参与 Seedance 视频生成;需要验证刷新后本地音频 URL 能恢复。

  • Seedance 返回远程视频 URL 但浏览器无法下载为 Blob 时,需要验证视频节点刷新后仍保留远程 URL,并确认上游 URL 有效期限制。

云端部署风险修复(#100 后续加固)

  • 修复:视频任务提交和轮询可能使用不同渠道 — 创建任务时把实际使用的 channel.id 写入 task.extra.channelIdresolveChannelForTask 轮询时优先按 channelId 找回原渠道,原渠道失效/被删除/不支持模型时才回退到 SelectModelChannel(task.Model, task.UserID)。需要验证多渠道路径下,任务创建、重启后兜底轮询、用户绑定变更后仍能查询到原任务状态。
  • 修复:AI 代理 GET 请求忽略登录用户绑定渠道/api/v1/videos/:id/api/v1/videos/:id/content 已改为从 context 读取当前登录用户,并将 user.id 传入 SelectModelChannel,与 POST 代理行为一致。需要验证:绑定渠道的用户在通过画布/视频台查询视频状态时,始终使用其绑定渠道。
  • 修复:历史渠道无持久 ID 导致用户绑定失效 — 启动时新增 EnsureChannelIDs() 迁移:若数据库中已有渠道的 id 为空,自动调用 normalizePrivateSetting 分配唯一 ID 并写回 settings 表。需要验证:升级代码后未手动保存设置,旧渠道也能获得持久 ID,且已绑定的 user.model_channel_id 能正确匹配。
  • 修复:管理后台 settings 页按数组下标合并 API KeymergeChannelApiKeys 已改为按 channel.id 映射回填 apiKey,避免渠道顺序变化时密钥错配。需要验证:保存渠道(新增/删除/调整顺序)后,已保存的 API Key 仍对应正确渠道。
  • 移除:视频参考素材本地上传功能 — 视频生成(Seedance 及 OpenAI 兼容接口)不再支持把本地文件上传到服务端再暴露公网 URL;参考图/视频/音频必须是公网可访问 URL(http/https)或素材库素材(asset://)。前端 services/api/video.ts 已删除 uploadReferenceMedia 及相关本地文件读取逻辑;后端 handler/media_reference.goUploadReferenceMedia 直接返回错误提示;config.PublicBaseURLPUBLIC_BASE_URL 环境变量及相关部署配置已移除。需要验证:选择本地图片/视频/音频作为参考素材时,前端给出明确错误提示;公网 URL 和 asset:// 仍可正常作为参考素材。
  • 部署配置:移除 PUBLIC_BASE_URL 并保留 SQLite 风险提示render.yamldocker-compose.yml 不再声明 PUBLIC_BASE_URLrender.yaml 仍保留 Render 免费实例 SQLite 会丢数据的注释。需要验证:部署配置与文档一致,未配置 PUBLIC_BASE_URL 不再影响视频生成。

Issue #103 视频创作台新增「新建任务」按钮

  • 左侧任务面板新增「新建任务」按钮web/src/app/(user)/video/page.tsxTaskListPanel 顶部工具栏在「刷新」按钮左侧新增一个 Primary 按钮,点击后弹出 Ant Design Modal.confirm 确认弹窗,确认后清空当前编辑区的提示词和参考素材(图片/视频/音频),并取消当前任务高亮(currentTaskId 设为 undefined)。模型、尺寸、时长等参数设置保持不变,历史任务列表 tasks 不会被删除,正在生成的任务也不受影响。需要验证:按钮出现在桌面端和 Drawer 移动端任务列表中;确认后右侧详情区回到空状态,可立即输入新提示词并点击「开始生成」。
  • 修复:右侧生成结果视频不随任务切换而更新TaskDetailPanel<video> 元素未在视频 URL 变化时重新加载,导致切换任务后仍播放上一个任务的生成结果。已为 <video> 增加 key={video.url},URL 变化时会重新挂载并加载新视频。需要验证:在多个已完成的视频任务之间切换,右侧视频立即更新为当前选中任务的结果。

Issue #102 视频任务状态同步与轮询健壮性

  • 新增强制同步接口 — 后端新增 POST /api/v1/video-tasks/:id/syncVideoTaskService.Sync 会校验任务归属、选择原渠道并调用一次 queryUpstreamStatus 回写状态;只要任务已提交到上游(upstream_id 不为空),无论当前状态是生成中、失败、成功还是已取消,都会再去上游查询一次。Sync 内部用 recover 兜底,异常只记录日志不会崩溃。前端 services/api/video-tasks.ts 新增 syncVideoTaskuseVideoTasks 新增 syncTask,视频详情面板「刷新状态」按钮改为调用 syncTask(task.id) 并更新本地任务状态。需要验证:生成中/失败/已取消任务点击刷新后都会同步上游最新状态;尚未提交上游的任务(upstream_id 为空)只返回当前状态。
  • 轮询逻辑重构service/video_task.gopollSeedance / pollOpenAI 已抽取为 querySeedanceStatus / queryOpenAIStatus,由统一的 queryUpstreamStatus 调用;pollTask 改为在 singleflight.Group 中执行,保证同一任务 ID 同时只有一个 goroutine 在轮询。需要验证:多次触发同一任务的轮询(如创建后立刻兜底同步)不会并发请求上游。
  • panic recover 与 stale 兜底submitAndPollpollTask 均增加 defer recover, panic 时把任务标记为失败;StartVideoTaskScheduler 每次 tick 先执行 MarkStaleTasksFailed,将超过 15 分钟仍处于 Processing 且未更新的任务标记失败,再执行 SyncProcessingTasks。需要验证:任务轮询 panic 后状态变为失败并返还算力;长时间无响应的任务 15 分钟后被自动标记失败。
  • 修复:Seedance 子任务错误(如版权)未展示 — 后端 querySeedanceStatusreadVideoUpstreamError 现在会解析 Seedance 响应中 error.messagecontent.subtasks 里的 exactDesc,将可读错误描述写入 task.error_msg;前端 TaskDetailPanel 新增 formatVideoTaskError 解析 JSON 数组错误并展示 exactDesc。需要验证:Seedance 视频因版权等原因失败时,右侧详情区显示“视频内容可能存在版权问题,无法生成。”而不是“未知错误”或原始 JSON。

Issue #106 彻底移除 local 模式

  • 移除前端 local 直连配置web/src/stores/use-config-store.ts 已删除 channelMode / baseUrl / apiKey 字段与相关归一化逻辑;app-config-modal.tsx 移除渠道模式 Segmented、Base URL / API Key 输入框、拉取模型列表按钮和本地模型可选项区;client-root-init.tsx 删除 ?baseUrl=&apiKey= URL 参数注入;model-picker.tsx 移除 local 分支。需要验证:前台配置弹窗只显示模型与参数,不再出现 Base URL / API Key / 本地直连选项;浏览器 localStorage 中不再保存 apiKey
  • API 层统一走后端 /api/v1 代理services/api/image.tsservices/api/video.tsservices/api/audio.ts 已删除 local / remote 双分支,统一使用 /api/v1 + JWT;Seedance 判定从 baseUrl 改为按模型能力 getVideoModelCapability(model).provider === "seedance"。需要验证:图片、视频、音频生成请求均发往 /api/v1/*,未登录时生成按钮给出登录提示;选择 Seedance 模型时参数面板和请求体按 Seedance 路径处理,选择其他模型时走 OpenAI 兼容路径。
  • 后端移除 local 分支并清理任务 Extramodel/setting.go 删除 AllowCustomChannelservice/settings.go 删除相关归一化逻辑;service/image_task.go / service/video_task.goCreate*TaskRequest 删除 ChannelMode / BaseURL / APIKey,任务 extra 不再写入这些字段,仅保留 channelId。需要验证:旧任务 extra 中不再包含 apiKey;历史 local 任务点击「刷新状态」时提示「该任务使用的本地渠道已下线」。
  • 管理后台移除「允许自定义渠道」开关admin/settings/page.tsx 已删除 allowCustomChannel 表单项;web/src/services/api/admin.tsAdminPublicModelChannelSettings 类型已移除该字段。需要验证:后台公开设置页不再显示该开关,保存设置后前台配置弹窗不再出现本地直连入口。
  • 测试同步更新services/api/image.test.tsvideo.test.tsimage-tasks.test.tsuse-image-tasks.test.tspage.test.tsx、能力层测试以及后端 handler/image_task_test.goservice/image_task_test.go 已删除/改写 local 相关用例。需要验证:目标模块测试单独运行无失败。

Phase 1 + Phase 2(素材管理后端)待测试

  • 管理后台「系统设置 → 私有配置」可正确保存和读取上游素材管理 Base URL,保存后素材接口即时生效。
  • 管理后台「用户管理」可为已有用户配置上游 API Key,保存后该用户调用素材接口会携带对应 Key。
  • 管理后台编辑用户时,清空「上游 API Key」输入框并保存,数据库中该字段应被清空为空字符串(而非保留旧值)。
  • 素材组创建接口 /api/v1/asset-groups 在合法参数下能成功创建并返回素材组信息(含上游 upstream_id)。
  • 素材创建接口 /api/v1/assets 在指定合法素材组和类型(Image/Video/Audio)时能成功创建(含上游 upstream_id)。
  • 无权访问其他用户的素材组时,接口返回明确错误信息(无权访问该素材组素材组不存在)。
  • 分页参数 pageSize 超过 500 时会被截断为 500,不会一次性拉取超大数据集。
  • 删除素材组接口 /api/v1/asset-groups/:id 会级联删除组内素材,并返回上游删除成功/失败数量统计。
  • 素材组详情、更新、删除,素材详情、更新、删除等 6 个带路径 ID 的接口,在 Gin 路由下能正确解析 ID,不再返回"无效ID"。
  • 当上游素材已不存在(404)时,级联删除应忽略该错误并继续清理本地数据;上游返回 500 时记录错误但不中断,仍继续清理本地数据并删除素材组,返回统计信息告知用户上游删除结果。
  • 素材创建时若上游成功但本地保存失败(如唯一约束冲突),应触发上游补偿删除,避免产生孤儿数据。
  • 素材详情、更新、删除操作应使用上游返回的 upstream_id 调用上游接口,而非本地自增 id
  • 未配置上游服务地址或 API Key 时,接口返回明确错误(未配置上游服务地址 / 未配置上游 API Key)。

Phase 3(素材库前端)待测试

  • /assets 页面出现"本地素材"和"云端素材组"两个 Tab,默认显示本地素材,Tab 切换流畅。
  • 本地素材 Tab 功能与改造前完全一致(搜索、筛选、分页、增删改、导入导出)。
  • 云端素材组 Tab 左侧显示素材组列表,选中项高亮;无素材组时显示 Empty 状态。
  • "新建素材组"弹窗可正确创建素材组,名称 64 字符、描述 300 字符限制生效,创建成功后列表自动刷新
  • 素材组列表每项右侧有删除图标,点击弹出确认弹窗,提示"素材组内的所有素材将被一并删除,此操作不可撤销"。
  • 确认删除后调用后端接口,成功后列表自动刷新;若删除的是当前选中组,右侧素材网格自动清空或切换到其他组。
  • 选中素材组后右侧显示素材卡片网格,卡片显示预览图(vendorUrl 可用时)或类型图标,以及名称、类型标签、状态标签。
  • "上传素材"弹窗可正确提交素材 URL、类型和名称,提交后卡片状态显示"处理中"。
  • 上传成功后自动轮询状态:每 3 秒刷新,状态变为"可用"或"失败"后停止,2 分钟后无论状态如何都停止轮询。
  • 点击素材卡片打开详情 Drawer,显示本地 ID、字节 assetId、原始 URL、所属组;可点击"复制 assetId"写入剪贴板;可删除素材并刷新列表。
  • 未配置上游 API Key 的用户在云端素材组 Tab 看到"未配置云端素材 API Key"提示。
  • 已配置 API Key 但未配置上游服务地址的用户在云端素材组 Tab 看到"未配置上游服务地址"提示(此前只会静默显示空列表)。
  • 已登录用户调用素材组/素材接口时正确携带 token,不再报"未登录或权限不足"。
  • 登录/获取用户信息时,AuthUser 响应包含 hasUpstreamApiKey 布尔字段;前端 useUserStore 能正确读取该字段。
  • 未配置上游 API Key 的用户进入云端素材组 Tab 时,前端直接通过 hasUpstreamApiKey 前置判断显示提示,不再先发起 API 请求再回退。
  • 素材上传表单验证失败时(如 URL 为空),页面不再抛出 unhandled rejection,验证提示正常显示。
  • 素材管理相关组件(新建素材组、上传素材、素材详情 Drawer)使用 App.useApp() 动态 message 实例,浏览器控制台不再出现 [antd: message] Static function can not consume context like dynamic theme Warning。
  • (#47) 素材详情 Drawer 在深色主题下信息区域可读:预览区、类型/状态标签、信息区域(本地ID、字节ID、URL、所属组)和错误信息均使用 Tailwind dark: 变体适配,无硬编码浅色背景导致的不可读问题。
  • (#53) 素材上传等待体验优化:上游 HTTP 超时 30s → 15s;后端超时错误文案改为"上游处理中,素材可能已创建,请稍后刷新查看状态";前端 loading 提示显示"预计 10-30 秒";超时场景下自动关闭 Modal 并刷新列表,其他错误保持 error 提示。
  • (#54) 素材上传表单增加 URL 格式校验:必须以 http/https 开头、长度 ≤2048、不支持 base64 内联数据;非法 URL 在点击上传前即被表单拦截,不会发送到后端。
  • (#59) 素材上传增加 URL 扩展名与素材类型匹配校验:图片 URL 只能选 Image 类型、视频 URL 只能选 Video 类型、音频 URL 只能选 Audio 类型;无扩展名的 URL(如某些 CDN 链接)允许通过;前后端均做校验,单文件上传和批量上传均生效。
  • (#60) 素材生命周期严格区分:素材列表(素材管理界面)只显示 Active(状态 = 1)的素材;Pending/Processing/Failed/UploadFailed 状态的素材不再出现在素材列表中。AssetID 在创建本地记录时为空字符串,等上游创建成功后填入上游返回的真实 assetId;避免临时 UUID 暴露给用户。
  • (#61) 任务管理器从后端 DB 恢复:打开任务管理器时自动调用 /api/v1/assets/tasks 获取当前用户所有非 Active 素材,刷新页面后任务不会消失。
  • (#62) 批量上传 Step 1 必须先选择素材组才能上传 Excel 并进入 Step 2,未选择分组时给出提示。
  • (#55) 上游返回 HTTP 429 限流时给出明确提示:后端识别 429 并返回"今日素材库调用次数已达上限(10000次),请明日再试";其他上游错误(400/404/500)保持不变。
  • (#56) 素材选择器支持 Video/Audio 类型:移除 Image 硬编码过滤,有 vendorUrl 的 Active 素材(图片/视频/音频)均可展示;预览区根据类型显示不同图标;Empty 提示改为"该组暂无可用素材"。
  • (#57) 素材上传流程重构:后端 Create 改为"先保存本地 Pending 记录 + 异步 goroutine 调上游",用户提交后 1 秒内即可看到"待上传"卡片;异步上传成功变为"处理中",失败变为"上传失败"并显示具体错误;UploadFailed 卡片支持"重试上传";Delete 改为上游删除失败不阻止本地删除;新增 POST /api/v1/assets/:id/retry 重试接口。
  • (#58) 素材详情 Drawer 状态显示完整:处理全部 5 种状态(Active/Failed/UploadFailed/Pending/Processing),UploadFailed 和 Pending 不再错误显示为"处理中";复制 assetId 按钮增加空值保护(disabled + 点击提示);UploadFailed 状态下 Drawer 内显示"重试上传"按钮。
  • (#50) 视频创作台参数设置 Drawer 废弃 height 属性替换为 style={{ height: "82vh" }},消除 [antd: Drawer] height is deprecated Console Warning。
  • (#51) EnsureDefaultAdmin() 在已有空密码 admin 时自动用 ADMIN_PASSWORD 补全密码;无 admin 时仍创建新账户;密码非空时保持原行为不做修改。

Phase 4(视频生成素材选择器)待测试

  • 视频生成页面参考图区域出现"从素材库选择"按钮,点击打开素材选择 Modal。
  • 未配置上游 API Key 的用户打开素材选择 Modal 时,看到"未配置云端素材 API Key"友好提示,而不是空下拉框。
  • Modal 标题为"从素材库选择",下拉选择素材组后展示组内 Active 状态素材。
  • 素材选择器仅展示 Image 类型素材,Video/Audio 类型不应出现在选择列表中。
  • 点击素材卡片后关闭 Modal,该素材出现在参考图列表中。
  • 参考图列表中的云端素材显示预览图(vendorUrl 可用时)或类型图标,点击 × 可移除。
  • 生成视频请求时,云端素材以 asset://assetId 格式传入 Seedance / 火山接口。
  • 非 Seedance 模型下,若选中素材缺少 vendorUrl,前端应在生成前给出明确报错,不发送请求。
  • OpenAI 视频接口下,vendorUrl 可用的云端素材可正常作为参考图上传。
  • 素材选择 Modal 中,vendorUrl 为空的素材卡片不会出现在列表中,避免选中后生成时报"当前模型不支持素材库引用(缺少预览 URL)"。

#95 素材管理 UI 修复与功能补齐

  • 卡片/列表复选框 + 批量操作:卡片视图 hover/选中时显示 checkbox,列表视图新增 checkbox 列和全选;选中后顶部出现批量操作工具栏,支持批量删除和批量移动到分组。
  • 文件大小显示:卡片视图(类型标签旁)、列表视图(大小列)、素材详情 Modal(独立信息行)三处均通过异步 HEAD 请求获取 Content-Length 并缓存显示。
  • 任务管理器增强:任务表格新增缩略图(类型图标)、速度、耗时列;UploadTask store 扩展 startedAt/completedAt/speed/openPanel 字段;processing 状态支持「同步」按钮,done 状态支持「查看」按钮(新标签打开 URL)。
  • 批量上传步骤3:上传完成后显示「打开任务管理器」按钮,点击直接展开底部任务抽屉。
  • 单文件上传提示文案:上传表单底部新增素材规格说明(图片/视频/音频的大小、格式、URL 要求)。
  • 分组拖拽排序:管理分组 Drawer 实现 HTML5 DnD,拖拽时显示蓝色指示线,排序结果保存到 localStorage,分组 pills 按保存顺序渲染。
  • 移动到分组:后端 UpdateTobAssetTobAssetService.Update 扩展支持 groupId 更新;前端批量操作工具栏提供分组 Select 下拉,实现批量移动。
  • 分组标签直接编辑:分组 pill 支持双击进入内联编辑,失焦或回车保存,调用 updateAssetGroup
  • 深色模式切换按钮:素材管理页面顶部工具栏新增主题切换按钮,使用 useThemeStore 并同步更新 document.documentElement

视频生成相关修复(#71~#76)

  • #71 NewAPI 转发豆包视频 404 — resolveAIProxyPathBuildModelChannelURL 已区分 Ark 直连与 NewAPI 路径前缀。
  • #72 Seedance 2.0 参考生视频场景推断 — 参考视频/音频通过 content[].role=reference_video/reference_audio 自动走参考生视频场景;≥3 张纯图片参考当前依赖 content 角色与上游推断,需要验证是否被正确识别为参考生视频。
  • #73 新增本地视频生成配置指南(椋鸟文档风格)— 见 docs/content/docs/canvas/video-generation-guide.mdx
  • #74 Video 预览被容器截断 — 已改为 object-fit: contain(已于先前提交修复)。
  • #75 buildApiUrl 空值/协议校验 — 已在 use-config-store.ts 中补充格式检查。
  • #76 视频生成配置缺少素材管理 API 域名检测 — assertVideoConfig 已增加 starlingdroid.com 域名校验。

管理后台用户管理修复

  • 修复:管理员编辑用户时修改密码不生效 — 根因是 service.SaveUser 返回前会清空 Password 字段,而 AdminSaveUser 在更新 upstreamApiKey 时二次调用了 repository.SaveUser,把空密码覆盖回数据库。修复后第二次保存前会先重新读取数据库中的密码 hash 恢复。需要验证:编辑用户时输入新密码并保存,该用户能用新密码正常登录;同时 upstreamApiKey 的更新仍正常工作。

视频工作台参考素材支持添加在线 http(s) 链接

  • 参考图 / 参考视频 / 参考音频均可通过 URL 添加web/src/app/(user)/video/page.tsx 的参考图、参考视频、参考音频面板均新增「链接」按钮,点击后弹出输入框,支持填写 http://https:// 开头的公网资源地址。系统会根据 URL 后缀推断 MIME 类型(图片 png/jpg/webp/gif,视频 mp4/mov,音频 mp3/wav),无后缀时按各类别默认类型处理。需要验证:三类参考素材都能正常添加、预览/播放、参与生成请求;无效 URL 或非 http(s) 协议会给出中文错误提示;数量超过上限时给出提示并不重复添加。

Issue #104 生图工作台后端代理与任务持久化

  • 后端新增 image_generation_tasks 表与 /api/v1/image-tasks 接口POST 创建任务、GET 列表/详情、POST /:id/cancel 取消、POST /:id/sync 手动同步、POST /:id/results 前端回写结果引用、DELETE /:id 删除。需要验证:登录用户只能访问自己的任务;失败任务返还算力点。
  • 后端不保存图片文件或 base64 — 向上游请求 response_format: "url",完成后把公网 URL 写入 result_urls;前端可将图片下载到浏览器 image-storage 后回写 storageKey,用于 URL 过期后仍能本地预览。需要验证:数据库中 result_urls 不会出现 data:image/...;base64,...
  • 异步提交与轮询POST /api/v1/image-tasks 立即返回 status=Pending;后端 goroutine 提交上游并轮询;同步返回的模型(如 dall-e-3)直接完成,异步模型(如 gpt-image-2Gemini-3.1-Flash-Image-Preview)自动轮询 GET /v1/images/generations/{task_id}。需要验证:任务状态最终变为 Completed/Failed;失败时返还算力。
  • 调度器兜底StartImageTaskScheduler 每 60 秒执行 MarkStaleTasksFailed(10 分钟超时)和 SyncProcessingTasks,避免服务重启后漏掉 Processing 任务。需要验证:重启服务后仍在生成中的任务会继续同步。
  • 左侧「生成任务」面板 — 改造 web/src/app/(user)/image/page.tsx,移除 localforage 日志存储,改为从后端拉取任务列表并每 5 秒轮询刷新。需要验证:新建任务后出现在列表顶部;Processing 任务自动刷新状态。
  • 任务回填与结果展示 — 点击左侧任务,右侧回填提示词、参考图、模型、尺寸、质量、张数,并展示结果图片。需要验证:已完成任务的结果图可正常显示;失败任务展示 error_msg
  • 图生图参考图 — 后端 /images/edits 支持 data:image/...;base64,...http(s)://... 两种参考图;asset:// 暂不支持,会返回明确中文错误。需要验证:从本地上传的参考图能正常参与图生图。
  • 前端并发 — 支持连续提交多个图片任务,每个任务独立轮询。需要验证:多个任务同时 Processing 时,列表状态都能正确更新。
  • 单元/接口测试 — 后端新增 model/image_task_test.gorepository/image_task_test.goservice/image_task_test.gohandler/image_task_test.go;前端新增 web/src/services/api/image-tasks.test.tsweb/src/app/(user)/image/use-image-tasks.test.tsweb/src/app/(user)/image/page.test.tsx。需要验证:go test ./model ./repository ./handlergo test ./service -run TestImageTask 通过;bun run test 全部通过。
  • 修复:任务列表 key 重复、嵌套 button 与轮询时重置当前选中useImageTasks 对拉取到的任务按 id 去重,避免快速新建+刷新时出现重复 key;TaskCard 外层由 <button> 改为带 role="button"<div>,避免内部删除按钮导致非法嵌套;轮询刷新不再把 currentTaskId 重置为第一条。需要验证:控制台不再报 key 重复与 "button cannot contain nested button";生成中任务自动刷新时,右侧仍保持当前选中任务。
  • 修复:结果图 URL 数组被序列化为字符串导致 urls.map is not a functionmodel.ImageTask 新增 MarshalJSON,把 DB 中以 JSON 文本保存的 result_urls 在 API 响应里输出为 JSON 数组;前端 useResolvedResultUrls 也增加兼容性转换,能同时处理数组、JSON 字符串或单条 URL 字符串。需要验证:已完成任务的 resultUrls 在前端为数组,结果图正常显示。

On this page