Merge branch 'main' of https://github.com/ddcat-ai/open-ai-canvas
Publish container images / Quality checks (push) Has been cancelled
Publish container images / Resolve build version (push) Has been cancelled
Publish container images / Build open-ai-canvas-backend (amd64) (push) Has been cancelled
Publish container images / Build open-ai-canvas-backend (arm64) (push) Has been cancelled
Publish container images / Build open-ai-canvas-web (multi) (push) Has been cancelled
Publish container images / Publish open-ai-canvas-backend manifest (push) Has been cancelled
Publish container images / Publish open-ai-canvas-web manifest (push) Has been cancelled
Publish container images / Publish release assets (push) Has been cancelled

This commit is contained in:
tongtong committed 2026-09-22 18:57:51 +08:00
commit 3427a427b7
74 files changed
+2868 -281

No files matched your search

@@ -15,7 +15,14 @@ description: 影策后端核心持久化表与状态边界
## 结构迁移与版本
当前结构版本为 33。版本 33 `oauth_state_accepted_terms` 为 `o_auth_states` 增加非空布尔列 `accepted_terms`,默认 `false`;保留旧 state 的身份、PKCE、跳转目标及有效期,不替历史流程补造同意记录。升级前备份,按既有流程执行 `migrate-schema up` 和 `verify` 后再启动新后端。旧版本二进制不支持版本 33,回退需恢复匹配的数据库备份。
当前结构版本为 34。版本 34 `task_media_recovery` 为 `tasks` 增加 `media_recovery_json`(text)和 `media_stage`(最长 24 字)。版本 33 `oauth_state_accepted_terms` 为 `o_auth_states` 增加非空布尔列 `accepted_terms`,默认 `false`,不替历史流程补造同意记录。升级前备份,按既有流程执行 `migrate-schema up` 和 `verify` 后再启动新后端。旧版本二进制不支持版本 34,回退需恢复匹配的数据库备份。
### 生成成功后的作品保存恢复
- 使用原任务主键、计费订单及现有 worker 租约,不新增执行批次或第二套队列。`media_stage` 为 `download | upload | local_save | register | checkpoint | completed`,表示当前结果的保存阶段,不改变上游生成日志的成功状态。
- `media_recovery_json` 使用已有 settings-key 加密,记录媒体地址、暂存文件名、资源 ID 和有界重试计数;不保存媒体 base64,不向任务 JSON/摘要返回该字段。数据库与 `.settings-key` 必须一起备份;该字段计入任务存储用量。
- 下载前写入恢复记录,下载后记录暂存文件,上传后记录资源。通过任务 ID 和输出索引生成稳定的资源上传键、素材 ID;任务成功、结果记录及素材登记在同一数据库事务提交,登记失败则不发布任务成功。
- 记录保留在终态任务中,成功后清理对应暂存文件;任务的既有保留/删除策略不变。结构迁移只增加列,不扫描日志,不修改历史任务、结果或账单。没有恢复记录的历史失败任务不会自动变为可恢复。
### 云端 Agent 运行时
@@ -17,14 +17,14 @@ description: 助手名称、文案、模型导入和运行库部署
## 部署运行库
前端使用固定版本 `pixi.js@6.5.10` 和 `pixi-live2d-display@0.4.0`,按需加载 Cubism 3/4 渲染适配器。Cubism Core 不包含在仓库中,不从第三方 CDN 加载,也不接受模型 ZIP 中的脚本。
前端使用固定版本 `pixi.js@6.5.10` 和 `pixi-live2d-display@0.4.0`,按需加载 Cubism 3/4 渲染适配器。Cubism Core 已纳入仓库的 `web/public/live2d/live2dcubismcore.min.js`,随前端构建及静态镜像发布,无需部署者另行安装。不从第三方 CDN 加载,也不接受模型 ZIP 中的脚本。Core 保留原始版权与许可声明,不适用本项目的 MIT 许可证;参见同目录 `NOTICE.txt`。
1. 部署者从 Live2D 官方获取具有相应授权、与模型版本兼容的 Cubism SDK for Web。
2. 将 Core 文件 `live2dcubismcore.min.js` 放到前端 `web/public/live2d/` 后重新构建;静态镜像部署也可将文件只读挂载到 `/usr/share/nginx/html/live2d/live2dcubismcore.min.js`。该文件已被 Git 忽略,不提交到本仓库。
1. 使用前确认 Live2D SDK 及模型素材的适用授权;内置运行库不代替部署者对使用场景的授权确认。
2. 拉取包含运行库的提交并重新构建前端,或部署由该提交构建的新镜像。Vite 将 Core 复制到 `dist/live2d/live2dcubismcore.min.js`,Docker 镜像中对应 `/usr/share/nginx/html/live2d/live2dcubismcore.min.js`。旧镜像不会因拉取源码自动更新;已有同路径挂载时应检查是否遮蔽内置文件。
3. 确认同源 `/live2d/live2dcubismcore.min.js` 返回 JavaScript 而非 SPA 页面。非根路径部署跟随前端构建 BASE_URL。
4. 后台导入并预览,成功后选择 Live2D,点击顶部「保存修改」。导入本身不启用;失败不更改当前形象。
没有 Core、模型不兼容、网络超时或 WebGL 上下文丢失时,入口回退默认动态球,仍可点击打开 Agent。后台显示错误并提供重试。未提供授权 Core 和真实模型时,不能仅凭构建成功认定播放验收通过。
部署产物遗漏 Core、模型不兼容、网络超时或 WebGL 上下文丢失时,入口回退默认动态球,仍可点击打开 Agent。后台显示错误并提供重试。未使用具有适用授权的真实模型验证时,不能仅凭构建成功认定播放验收通过。
接入层支持旧版 `drawables.renderOrders` 和新版 Core 的 `Model.getRenderOrders()` 绘制顺序接口,不修改 Core 文件。当前 Cubism 4 渲染适配器不支持新版离屏渲染对象;此类模型会明确报错,而不是忽略对象后显示不完整形象。
+13 -1
View File
@@ -13,6 +13,18 @@ description: 信封、错误码与 OpenAPI
模型 HTTP 失败及经过 Provider 错误转换的业务失败,在通用提示后追加经过过滤的 `;上游:具体原因`,供任务错误和画布卡片展示内容安全、提示词、尺寸等可操作信息。只读取上游 `error` / `message` / `msg` / `detail` 消息字段,不回传整个 JSON;消息中的 HTTP(S) URL 隐藏,包含余额、账务、凭据、请求诊断或 HTML 的消息不追加原文,保留通用分类提示。后台响应拦截规则仍对最终用户文案生效;不会修改历史任务错误或改变重试、退款策略。
## 生成成功后的重试保存
`POST /tasks/:id/recover-media` 无需请求体。当前用户只能恢复自己有保存恢复记录的失败任务;重入队仍返回原任务 ID,不请求重新生成、不新建计费订单。已排队、运行或完成时幂等返回当前任务。取消任务、已退款订单、任务/账单归属不一致、项目已删除或归档时拒绝恢复。
任务详情和摘要新增 `mediaStage`、`canRecoverMedia`。后者表示失败任务存在保存恢复记录,实际操作仍校验权限、账单、项目及重试额度。每任务最多手动恢复三次,两次之间至少一分钟,每次手动操作只执行一次保存尝试;接口另受用户维度任务请求限流约束。普通 `/tasks/:id/retry` 不接受带保存恢复记录的任务,避免误走重新生成。
保存网络故障在原 worker 中最多自动重试四次(15 秒、1 分钟、3 分钟、10 分钟并加抖动;超过 20 分钟不再安排自动重试),使用 `next_poll_at` 释放 worker,而不是在请求内睡眠。不可重试错误直接保留为保存失败。画布和任务中心显示“作品已生成,正在保存”或“作品保存未完成”,失败按钮为“重试保存”。完成后客户端消费原任务的结果。
请求明细保留上游生成与结果下载的独立状态,新增 `upload`、`local_save`、`register` 内部非计费明细;列表和详情通过 `mediaStage` 展示交付摘要。`recordType=request` 排除这些保存明细和下载,`all` 查看全部阶段,`download` 仍仅查看下载。视频下载失败不会再覆盖生成请求的成功记录。
此恢复能力接入声明式媒体协议返回 URL/data URL 的任务路径;旧协议自行下载、协议二进制下载端点以及无恢复记录的历史失败任务不自动补录。历史任务需先核实上游结果可用性、资源归属及原账单,再单独制定修复动作。
## 素材彻底删除
`DELETE /assets/:id` 表示用户确认后的彻底删除,不依赖服务端当前记录是否已经同步为 `archived`。接口仍校验登录用户和素材归属,但不会因画布、任务、项目或历史快照仍有引用而拒绝;事务会删除素材及对应历史资源索引,并通过删除 Outbox 清理未被其他素材复用的物理对象。其他素材共享的同一物理对象继续保留。移入回收站仍通过素材写入接口把状态更新为 `archived`,不能用 DELETE 代替可恢复归档。
@@ -161,7 +173,7 @@ Token 报价的 `estimated` 为 `true`,`quantity` 是预留 Token 数。参考
- 系统行为策略与媒体默认策略是版本化、编译进后端发布物的资源,修改它们仍需发布后端,不是后台热更新;工具、校验、扣费和审批在代码侧强制执行。画布节点能力由服务端 registry 定义,工具 schema、创建、连线与画布摘要读取共同消费;新生成模式还必须接入媒体任务适配器,不能仅凭 md 或注册节点启用收费操作。
- 已安装且属于当前用户的技能在创建时只保存版本、哈希和文本文件路径,不预存全部正文,也不按所有选中技能正文合计 128KB 拒绝创建。`skill_read_file` 按需读取 `SKILL.md` 或必要引用,支持字符偏移 `offset`(默认 0),每页最多 12000 字符,返回 `hasMore` / `nextOffset`。读取时重新验证用户权限、启用状态和版本;技能更新后拒绝混读,需新开一轮。技能是不可信数据,不能创造工具、改变权限或覆盖系统规则。
- Agent 按实际文本模型的 `contextWindowTokens` 与 `maxOutputTokens` 计算输入预算,并在达到该模型预算的压缩阈值时移除较早工具结果中可重新读取的正文,保留工具调用/结果配对、用户原始要求、生成回执及最近完整工具轮次,并允许重新读取。此机制是确定性正文卸载,不是 LLM 语义摘要;运行 checkpoint 的持久化上限与模型上下文窗口独立。技能读取事件只保存回执,不复制正文,正文页只进入模型对话。
- 画布 Agent 的看图能力:当且仅当本轮渠道模型的能力合同声明了图片输入(`text.references.maxImages > 0`)时,额外暴露 `canvas_inspect_image(nodeId)`。该工具校验目标节点是已就绪、归属当前用户、媒体类型为 `image/*` 的素材,然后签发**短时签名下载链接**并把图片作为 `image_url` 内容块交给上游(与生成任务参考图同一套机制),因此 Agent 上下文只增长一个 URL,不装 base64;图片在上下文里保留最近 3 个工具轮次,更早的由运行期裁剪移出并保留文本回执与模型自己写下的观察;同一张图一轮内看满 2 次后只回执文字、不再附图,确需重新确认画面时传 `refresh=true`。看到图后模型写进正文的那句话会记到锚点(`visualNote`),跨轮继承后可以直接复用;查看过的素材在锚点里记为 `visualIdentity=inspected`。画面内文字按不可信数据处理。该能力依赖服务器访问地址:本地存储需要配置 `CANVAS_PUBLIC_BASE_URL`,且该地址必须能被模型上游访问到;上游取不到图片时如实失败,服务端不做取图内联兜底。
- 画布 Agent 的看图能力:当且仅当本轮渠道模型的能力合同声明了图片输入(`text.references.maxImages > 0`)时,额外暴露 `canvas_inspect_image(nodeId, refresh?)`。工具校验图片节点、资源归属、就绪状态、媒体类型和模型文件大小限制;检查点与任务输入只保存 `resource:ID` 占位及授权参考清单。worker 复用资源读取链路,在内存中将占位替换为真实图片数据后展开模型协议,不持久化 base64 或签名 URL,不依赖 `CANVAS_PUBLIC_BASE_URL`,不接受任意外部地址。多图在本批所有 tool 回执后统一附送;图片保留最近 3 个工具轮次,发给模型时还按数量上限保留最新图片,本批超限则明确要求分批查看。同一张图一轮内附送两次后只回执文字,确需重看时传 `refresh=true`。工具成功不等于识别成功,普通模型正文不再自动写入 `visualNote`,旧 `inspected` 标记及观察不跨轮继承;`visualIdentity=unknown` 表示没有已确认缓存,不表示模型不能查看随附图片。画面内文字仍按不可信数据处理;资源读取失败则真实失败,不凭标题推断画面。其他需要公网 URL 的生成协议仍遵循各自存储配置合同。
- 平台支持工具全集为 `agent_profile_read`、`plan_update`、`ask_user`、`recall_lessons`、`remember_lesson`、`canvas_list_node_types`、`canvas_get_state`、`canvas_inspect_image`、`canvas_read_batch_table`、`canvas_read_storyboard`、`skill_read_file`、`skill_search`、`task_get`、`model_list`、`canvas_create_storyboard`、`canvas_edit_storyboard`、`canvas_edit_batch_table`、`canvas_apply_ops`、`canvas_arrange_nodes`、`generate_media`、`image_layer_split`、`image_text_detect`、`image_annotation_render`;单轮实际工具仍按偏好快照、技能、权限、画布上下文和生成预算裁剪。画布写入工具要求本轮授权 `contextScope: ["canvas"]`。禁止 shell、任意网络请求和外部 MCP。`remember_lesson` 在 `read_only` 下不可用。
- `plan_update` 维护本轮结构化待办清单(整表替换,最多 20 项),跨轮继承未完成项,并在界面以 PlanBar 展示。权限为 `request_approval` 时,首次建立至少 2 项的清单会先进入审批;`auto` 直接写入清单。新一轮的第一次模型请求就会带上继承的清单。模型在没有工具调用且清单仍有未完成项时,服务端会催办并要求继续调用工具;这是软约束,不验证工作是否真的完成,也不会在没有清单时强行催建。
- `ask_user` 给出一个问题与 2–6 个候选项后结束本轮,界面弹出选项面板;用户点选或输入后作为新一轮继续。运行中也可以用插话直接回答。
@@ -9,7 +9,18 @@ description: 热点回源保护、并发租约、故障边界和上线验收
任务中心打开详情只读取任务和日志,不在该路径调用画布结果同步。后台同步遇到短剧领域项目任务(`domainProjectId` 等于任务 `projectId`)或没有生成节点关联时跳过画布写回,避免把短剧项目 ID 当作画布 ID 查询。
管理员请求明细列表及 CSV 导出支持 `recordType`:省略或 `request` 默认仅请求(继续隐藏视频轮询并排除下载);`download` 只包含 `request_kind=download`;`all` 包含请求、轮询与下载。非法值返回参数错误,管理员权限校验保持不变;该筛选不改变统计聚合接口。
管理员请求明细列表及 CSV 导出支持 `recordType`:省略或 `request` 默认仅请求(隐藏视频轮询,并排除下载、上传、本地保存、素材登记明细);`download` 只包含 `request_kind=download`;`all` 包含全部阶段。非法值返回参数错误,管理员权限校验保持不变;该筛选不改变统计聚合接口。
## 媒体交付恢复的资源边界
声明式协议已经返回作品地址后,先加密保存任务恢复记录,再执行下载、存储、素材登记。交付错误不进入模型路由切换,不创建新生成任务。已下载文件优先复用;资源已就绪时跳过下载和上传,只补登记。配置为 OSS 的生成结果上传失败会明确保留错误,不像普通文件上传那样自动降级到本地存储;普通上传行为不变。
- 单进程同时最多两个媒体交付操作,满载时通过原任务 `next_poll_at` 延迟领取,不启动无界 goroutine 或额外轮询器。此限制不是跨实例全局限制,集群仍依赖既有任务租约与调度限制。
- 下载流式写入数据目录的 `media-staging`,单次下载最多三分钟,文件上限取运行时生成文件限制与 512 MiB 中较小者;暂存目录逻辑占用上限为 512 MiB,先预留空间再写入。
- 成功后立即清理对应暂存文件;超过 24 小时的暂存文件在下次分配空间时清理,不为闲置服务常驻一个清理循环。暂存文件不可用时只尝试原地址,不重新生成;只有内联结果且文件丢失时明确失败。
- 多实例切换时,暂存文件只有位于共享数据卷才可直接复用;没有共享暂存文件但有有效源地址时可以重下载。数据目录和 settings-key 需要稳定保留,不能以临时容器目录代替持久化配置。
- 出站下载沿用 SSRF 防护;同源才附带渠道鉴权。恢复地址仅加密留存,下载明细隐藏路径和查询参数,错误日志不写入原始带签名的 URL。
- 自动重试有次数和时间窗口上限,手动重试也有限额。源地址过期、权限问题、配额不足等不会无限循环;不承诺已经过期且无暂存文件的作品一定可恢复。
章节提取采用独立提示词操作 `chapter_assets_extract`,受保护输出契约为 `chapter-assets/v1`,要求 `characters`、`scenes`、`props` 三个数组。场景和道具要求非空的 `name`、`description`、`prompt`;角色继续执行原角色契约校验。写入候选资产时场景映射为 `environment`,继续使用现有服务的项目归属、去重与写入校验,不新增数据库字段。
@@ -5,6 +5,46 @@ description: 当前项目已实现功能的手工验证清单与未确认边界
# 待测试
## 原任务 ID 媒体保存恢复
- [x] 故障注入:下载 503 后服务实例重建继续原任务、OSS 上传失败保留暂存文件及资源 ID、素材登记异常使任务成功事务回滚,登记恢复无需再次下载。
- [x] 防重复与权限:不触发模型路由切换、不新增账单、重复点击幂等、跨用户/已取消/已退款/项目删除拒绝恢复、过期租约写入拒绝、自动/手动重试预算与暂存容量校验。
- [x] 后端 `app`、`repository`、`database`、`handler` 四包回归通过;最后补验媒体恢复、路由与请求日志专项测试,以及 schema 34 幂等迁移和恢复接口鉴权/归属冒烟。测试使用隔离数据库。
- [x] 前端类型检查与 31 项生成显示、画布结果同步、生成提交及重新生成相关测试通过。
- [ ] 在真实画布和任务中心触发下载失败、OSS 上传失败、登记失败,确认各阶段提示、刷新后“重试保存”、结果回写及资产库仅一条;真实浏览器验收尚未执行。
- [ ] 使用真实 OSS 配置进行网络中断/凭证修复后的恢复验收;当前上传故障测试使用不可达端点,不代表真实 OSS 成功链路已验证。
- [ ] PostgreSQL 部署执行 schema 34 升级及多实例租约/共享暂存卷验收。未修改当前本地业务数据库、历史失败任务或账单。
- [ ] 无恢复记录的历史失败任务单独核实源地址有效期与计费状态;本功能不从旧日志自动回填,不承诺恢复已过期的源文件。
## 画布默认黑色主题与点网格
- 前端类型检查与 17 项外观、主题隔离测试通过;尚未完成真实浏览器验收。
- [ ] 未保存自定义默认外观时,新建画布使用黑色主题:背景 `#000000`、明亮度 `0%`、网格颜色 `#000000`、网格强度 `100%`、空间网格为点。黑底黑点视觉上为纯黑。
- [ ] 切换「黑色」或「浅色」预设时使用点网格;黑色首次转自定义及重置时使用上述预设数值,已有自定义配置仍保留,浅色颜色与强度保持原值。仍可手动选择线或空白网格。
- [ ] 已保存的画布外观及用户自定义默认外观不被覆盖;画布主题变更不影响工作台主题。实际浏览器明暗主题与保存恢复待验收。
## Live2D 运行库随部署交付
- Cubism Core 已纳入版本控制,保留原始版权声明并附第三方许可说明;前端构建和静态镜像直接包含运行文件,不再要求部署者手工安装。
- [x] 5 项 Live2D 专项测试及前端生产构建通过;Core 可初始化并读取版本,构建产物中的 Core 和许可说明与源文件逐字节一致。未执行 Docker 镜像构建或服务器部署。
- [ ] 服务器更新至包含本次修复的新镜像,确认 `/live2d/live2dcubismcore.min.js` 返回 JavaScript 而非 SPA 页面;使用有授权的真实模型完成后台预览、保存及画布形象验收。
## Agent 图片字节交付
- [x] 本地模拟上游验证:公网地址为空或错误时,worker 仍发送原始 PNG 字节;任务只持久化资源占位,多图工具配对保持连续,Chat Completions / Responses / Claude / Gemini 协议保留图片。
- [x] 28 项专项回归通过;同一图片资源、模型配置和模拟上游下,Chat Completions 的普通文本节点与 Agent 经真实 worker 发出相同图片字节,附带的内嵌数据不能替换账号资源文件。
- [ ] 对照排查另发现:普通文本任务的默认声明式 Responses / Claude 请求仍使用 Chat Completions 的 `image_url` 内容块,需单独修复并验收;这不是本次 Chat Completions 渠道 Agent 取图失败的原因。Agent 的多协议图片展开测试不代表普通文本的这两条路径通过。
- [x] 专项回归覆盖资源归属、未就绪、非图片、文件大小、模型图片数量限制;附图不直接标记识别成功,不跨轮继承旧的未确认观察。
- [ ] 更新并重启后端后,使用已声明图片能力的实际渠道模型,重新询问已上传图片节点的主体和背景;确认不再因 `unknown` 标记拒绝看图。真实模型调用会消耗额度,尚未执行。
- [ ] 实际部署验证 OSS 图片、同轮多图比较、跨轮换图与读取失败提示;检查其他依赖公网 URL 的生成协议配置,不能将本次看图修复视为存储公网地址已修正。
## 画布创作入口主次调整
- 前端类型检查和 4 项画布起点状态测试通过。
- [x] 真实画布路由使用隔离的身份与空画布测试数据完成局部浏览器验收:1440 × 900 明暗主题、390 × 844 窄屏、390 × 320 低高度。入口不横向溢出,点击目标至少 44px;Tab 顺序与焦点样式正常,入口滚轮不改变画布缩放,减少动态效果设置生效。
- [x] 入口改为左对齐分层标题、主题适配的金属质感片头符号和细分隔线,无卡片或实底大按钮。Agent 使用文字与小箭头入口、悬停下划线反馈;次级入口和素材操作分层展示。点击「交给 Agent」可展开原有 Agent 工作台。
- [ ] 用户确认视觉效果;使用真实登录账号验收全部入口、上传和 Agent 对话。本轮浏览器验收拦截了写请求,未修改真实项目;未模拟的辅助接口返回错误,因此局部视觉与面板展开检查不代表后端联调、保存或 Agent 执行通过。
## 技能文件包迁移元数据长度
- [x] 启动迁移对旧技能名称、简介的回填元数据按字符数限制长度,省略号计入上限;不改写原始名称、简介和正文,不放宽非迁移入口的校验。