7e3adc38b9
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/172 Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me>
23 KiB
23 KiB
画板图标素材生成入口设计
日期:2026-06-15
更新时间:2026-08-10
背景
图片画布编辑器已有普通图片生成、生成规范、生成角色形象和角色动画入口。本次新增 生成图标素材,用于通过一段完整需求生成一张纯色背景 spritesheet;后端去背景正常成功后,再尝试自动拆分为可独立编辑的素材。
入口与画布表现
- 底部 AI 画布工具栏新增
生成图标素材按钮。 - 点击后立即在画布中心创建图标素材占位图,不复用普通“单张空白图片”图标;占位图表现为一叠空白素材图标卡片。
- 图标素材占位图必须按当前模型、比例和 K 档对应的真实 provider 请求像素初始化;切换参数后继续保持占位尺寸与请求尺寸一致,不得用固定
360x360 / 512x512框代替生成目标。 - 图标素材面板锚定在占位图下方,和现有生成输入框同一层级展示。
- 透明背景处理正常成功后删除占位态:透明 spritesheet 作为主图(
assetKind: "icon-spritesheet",generatedLayerId锚点)放入画布,provider 带背景原图作为第二个同类型图层放在透明主图右侧,按 alpha 连通域成功拆出的assetKind: "icon"素材从原图右侧继续铺放;透明背景处理最终失败时,后端完成快照只用 provider 原图替换占位态。 - 选中
assetKind: "icon-spritesheet"图层时,图片浮动工具栏显示拆分图集;手动拆分只追加独立素材,不复制原图集。 - 用户把现有图层手动标记为“图集”时,必须先持久化一条
assetKind: "icon-spritesheet"的项目资源并把返回的resourceId写回图层;项目资源只能在媒体来源和assetKind都相同时复用,不得因同源图片而返回旧类型资源。持久化完成前必须禁用“拆分图集”,持久化失败时回滚到上一个已确认的素材标签和资源引用,并失效该轮未确认的标签撤销记录。后端拆分授权只信任该项目资源的assetKind,图层assetKindOverride仅用于展示,不能把其它资源提升为可拆分图集。 - 图标规范图写入
assetKind: "icon-spec",用于刷新后保留标签和限制点选来源。
面板结构
- 第一模块为
图标规范。- 点击后弹出菜单:
从画布中选择、新建图标规范、上传图片。 从画布中选择进入画布点选状态,只允许选择assetKind: "icon-spec"的图标规范图片;其它图片点击无效。新建图标规范复用生成规范表单,规格类型为图标规范,生成成功后图层标记为icon-spec。上传图片使用现有本地图片上传入口,上传图只绑定到本次面板,不自动放入画布;存在当前项目时创建assetKind: "icon-spec"的项目资源,不存在当前项目时创建同类型账号素材,提交图集生成时只使用持久化返回的resourceId或assetId,不得按通用image类型登记。
- 点击后弹出菜单:
- 第二模块为素材描述文本框。
- UI 复用角色形象生成面板同款单个文本输入框,让用户直接叙述多个素材。
- 默认按换行填入:
返回按钮、设置按钮、下一关按钮、提示按钮、原图按钮、冻结按钮。 - 生成时只去除整段文本首尾空白,不按换行、逗号、顿号、分号、斜杠、竖线或语义枚举解析素材数量;文本框内容作为一段完整用户需求进入 prompt。
面板外观
- 图标素材面板不再使用列表式素材描述框,也不再按描述项横向扩宽;素材描述区改为与角色形象生成面板一致的单个文本输入框。
- 图标规范入口采用 Lovart 式参考卡:左侧预览缩略图,中间显示当前绑定名称,右侧显示绑定状态和三个轻量动作入口,不再只是两行文字平铺。
- 规范卡的
从画布中选择 / 新建图标规范 / 上传图片继续保留独立菜单,但菜单只负责来源切换,不承载说明文案。
生成契约
- 前端提交到
POST /api/editor/icon-spritesheets/generations。 - 图标规范生成在 inline 模式下也必须先建立带稳定请求指纹的 generation operation,并由编辑器生成 durable billing 边界包住共享执行器;不得在
operation=None时调用 provider 后再进入原子结果持久化。 - 图标 spritesheet 的入队与实际执行路径都必须在引用解析、generation input 重建、定价和 provider / OSS 副作用之前预检 owner、项目和最终素材目录,并将返回的 canonical
projectId + assetFolderId回写到后续流程;请求省略目录时按实际写入的 owner 默认目录预检,worker 不得只信任入队时的旧校验结果。 - queued 图标规范生成由共享原子结果持久化使用 worker caller 中的 lease 一并完成任务并清理 lease;共享执行器返回成功后 worker 只能返回
Ok(()),不得再次调用 job completion。 - queued 图标规范生成在本地文本门禁后、参考资源 owner 解析和定价之前执行目标预检,并把 canonical
projectId + assetFolderId写入任务 payload;不存在、越权或目录不匹配必须由提交请求同步失败,不得入队后再变成 worker 失败。 - spritesheet 队列提交对主图标规范只运行 metadata-only resolver,校验 owner、
assetKind="icon-spec"、对象元数据和保存的游戏类型,不读取 OSS object body;worker 执行时复用同一 metadata resolver 重新确认当前事实,并在通过后只下载一次图片正文。 - inline 与持久队列入口共用同一份
iconDescriptionsprompt 合同:请求数组原始长度先满足 OpenAPI1..100,不得通过丢弃空白项绕过maxItems;随后去除空白项仍须至少保留 1 条,单条最多200个 Unicode 字符,以换行拼接后合计最多2000个 Unicode 字符且不超过6144个 UTF-8 字节。请求边界校验成功后生成ValidatedEditorIconSpritesheetPrompt,后续 prompt builder 不接受裸字符串。队列入口必须在引用解析、定价和任务持久化前同步拒绝可预测错误,不能把无效任务留给 worker 延迟失败。 - worker 解析主
referenceId时必须通过spacetime-client的通用窄查询resolve_editor_reference在同一事务快照内完成引用解析和 owner 校验:该字段只接受当前 owner 的项目资源 ID 或素材 ID,并只按两张表的主键查询;不接受objectKey、image_src、URL 或临时 key 作为主规范引用。两张表先按owner_user_id筛选候选,再判断同一 ID 是否在当前 owner 范围内同时命中;其它账号的同名 ID 不得制造歧义或阻断当前账号的合法引用。记录带asset_object_id时必须按该 ID 读取对象并同时核对 bucket、object key 与 owner,只有明确缺少asset_object_id的兼容旧行才允许按对象位置查询。procedure 复用既有EditorProjectResourceSnapshot或EditorAssetSnapshot返回唯一已验证行,不接收图标业务类型参数、不新建图标专属快照,也不得拉取当前用户的完整工程列表或素材库。assetKind="icon-spec"与genre都由图标图集业务代码从返回行校验和提取。入队与 inline 预检只核对引用行和 asset object 元数据,不下载图片正文;最终执行重新解析当前事实并只下载一次实际参考图。解析成功后的objectKey是服务端内部存储事实,不是该请求的输入协议。引用不存在、owner 不匹配、asset object 不存在或数据库调用失败时 procedure 直接失败;业务类型不符或保存的游戏类型无效时 API 失败;合法规范没有已保存游戏类型时允许genre=None。 - 请求字段:
referenceId:图标主规范的正式引用,必填且只允许当前 owner 的项目资源 ID 或素材 ID。本地临时图必须先按assetKind="icon-spec"上传并登记为项目资源或账号素材,再提交返回的resourceId或assetId;禁止提交objectKey、URL、Data URL、Blob URL 或临时 key。iconDescriptions:兼容现有接口的图标需求数组,1..100;当前画布前端固定把完整文本作为唯一数组元素提交。数组长度只表达请求文本,不作为自动拆分数量;单项、聚合字符和 UTF-8 字节上限按上一条 prompt 合同执行。model:支持gemini-3.1-flash-image-preview(UI 显示nanobanana2)和gpt-image-2,默认nanobanana2。aspectRatio:按x:y展示,选项跟随模型。imageSize:按0.5K / 1K / 2K展示,选项跟随模型。style:可选生成风格,同时影响提交给 provider 的提示词和回图后的像素规整;未勾选像素艺术时传"none",勾选时传"pixelArt"。- 计费不属于客户端请求字段:前端不提交
priceMudPoints,后端按归一化后的模型和尺寸从运行时编辑器生成定价配置计算价格。队列模式在入队时冻结该价格,worker 的预扣、退款、响应priceMudPoints和资产generationCostMudPoints都使用同一入队价格;定价配置变更只影响之后入队的任务。
- 模型与尺寸选项:
nanobanana2:比例1:1 / 4:3 / 3:2 / 2:3 / 9:16 / 16:9;大小0.5K / 1K / 2K。后端走/v1beta/models/{model}:generateContent,把图标规范图作为inline_data,并把aspectRatio/imageSize写入generationConfig.imageConfig;0.5K按 VectorEngine 文档传"512"。gpt-image-2:比例1:1 / 4:3 / 3:2 / 2:3 / 9:16 / 16:9;大小1K / 2K。后端走/v1/images/edits,把图标规范图作为 multipartimage。K 档按最长边计算,并转换为 provider 可直接生成的合法像素:1K的1:1 / 4:3 / 3:2 / 2:3 / 9:16 / 16:9分别为1024x1024 / 1024x768 / 1024x688 / 688x1024 / 608x1088 / 1088x608;2K分别为2048x2048 / 2048x1536 / 2048x1376 / 1376x2048 / 1152x2048 / 2048x1152。其中 9:16 的 1K 尺寸按 provider 最小总像素和 16 对齐约束修正。禁止把 2K 竖图回落为 1K 请求,也禁止在回图后放大伪造所选 K 档。
- 用户在角色或图标素材面板中切换过模型后,下一次打开这两类面板继续使用上次模型。
- 不展示抠图背景色或抠图模型选择;前端用户路径固定提交
screenColor=auto和segModel=birefnet。后端在组装 prompt 前把auto自动决策为具体 hex,最多重试 3 次,失败后兜底#CFEFFF,最终 prompt 和 BgFilter 不透传auto。 - Prompt 固定为:
参考图1的图标规范,背景必须是自动决策出的单一纯色抠图背景,且平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光;禁止出现文字。根据以下用户需求生成图标素材并整理成一张 spritesheet;不同图标素材之间必须彼此分离并保留清晰间距,避免描边、底板、投影或装饰元素连接相邻图标:
<完整用户需求>
上述最终 spritesheet prompt、玩法润色 prompt、美术风格润色 prompt 和规范图生图 prompt 都是自然语言文本,必须保留已经过长度与空白校验的用户原文;不得把 R&B、引号或尖括号改写成 XML entity。只有 build_extra_param_prompt 中真正位于 <playSetting> / <artStyle> XML 元素内的数据执行 XML 转义。
像素风格后处理
- 图标素材面板增加紧凑的
像素艺术勾选项。选择保存于现有生成器快照,并可随现有请求和队列 payload 传递;不写入用户可见generationInputs、素材元数据或新建的持久化记录。 style省略、为null、空字符串或"none"时按内部None处理且不告警;"pixelArt"启用像素规整。未知字符串按None继续生成,并通过既有通用warning返回unsupported-image-style;非字符串 JSON 仍返回400。- 2026-08-01 修订:
"pixelArt"不再只是后处理,同时向提交给 provider 的提示词末尾追加独立一行约束。图标链路使用「每个图标素材均为像素风格」,不得使用「画面为像素风格」——图集生成后要按纯色抠像,绿幕底必须保持平整,画面级像素化要求会与同一段提示词里的「纯色背景必须平整无纹理、无渐变」互相拆台;一张图内是多个彼此分离的素材,需要逐个点名,避免模型只把其中一部分做成像素块。注入发生在build_editor_icon_spritesheet_prompt返回之后,该函数签名和输出契约不变。约束句只随工程化提示词写入原图 spritesheet 的editor_project_resourceprompt 列;透明结果的 prompt 列是"去除纯色背景",自动拆分的切片是"自动拆分图集",两者都不含约束句。与普通图片和角色形象不同,本链路响应体的prompt字段返回的也是含约束句的工程化提示词,而不是用户输入——图标请求本身没有prompt字段(收的是iconDescriptions),因此调用方(含外部 API v1)能直接看到绿幕子句、间距要求和本次新增的像素约束。以上 prompt 列写入与响应字段规则都是既有行为,与web/master一致,本次只是让被回传的模板多了一行。不新增 OSS PUT、项目资源、图集画布项或切片画布项。尚未约束各素材共用同一像素块大小(estimate_step_size取全图相邻峰间距的第 30 百分位,块大小不一时步长估计会偏),等实测。 - 图标链路以已持久化的带纯色背景 provider 原图实际尺寸为基准;BgFilter 正常成功后,把 Alpha 蒙版回贴到该同尺寸平底原图,再执行像素规整。网格分析源使用平底 provider 原图,RGBA 采样源使用 Alpha 已回贴的透明图;这两份内部输入仍必须同尺寸。规整结果按一格一输出像素采样后,再按单一整数倍 nearest 放大到最接近规整输入的尺寸,编码为透明 spritesheet,成功后才进入原有连通域自动拆分。
- 首版固定参数为分析色数
16、Alpha 覆盖阈值0.375、像素格尺寸自动检测、固定色板关闭、K-means 最大采样262144。单格颜色按Σ(A × RGB) / ΣA进行 Alpha 加权;覆盖率Σ(A / 255) / N >= 0.375且ΣA > 0时输出硬 Alpha255,否则输出严格[0,0,0,0]。分析色数不限制最终输出色数。 - 像素规整 CPU 工作使用进程级最大并发
2;取得并发许可的排队时间与实际处理时间共享最多30秒预算,同时不得晚于当前请求 deadline,最终以两者中更早者为准。输入图片任一边不得超过10000像素,总像素不得超过8294400;超限、排队超时或处理超时均保留 Alpha 已回贴的透明图并走非致命降级,随后仍可进入原有自动拆分。 - snapper 把整数倍放大后的图编码为最终透明 spritesheet;禁止非整数拉回平底 provider 原图尺寸。图标链路继续不执行角色链路的前置 Lanczos 交付尺寸归一,最终透明图集宽高比等于逻辑图,尺寸接近但不保证等于规整输入。实现应复用 Alpha 回贴阶段读取的平底 provider 原图;必要时最多增加一次读取已有 provider 对象的 OSS GET,不得增加 OSS PUT。
- 开启或关闭像素风格都保持现有 provider 原图、透明图集和实际成功切片的持久化与画布数量不变。开启时透明图集本身就是唯一的整数倍放大 PNG;禁止另存未放大逻辑图、输入尺寸恢复版、像素化前后双份图集、预览或诊断图,也不新增 asset kind、项目资源、画布 item、任务类型或数据库字段。资源、响应和画布结果使用最终 PNG 的实际宽高,不要求与 provider 原图或生成占位尺寸相等。
- 图标图集的 BgFilter
flat调用固定使用cross_check=on。BgFilter 最终失败、Alpha 比例漂移超过5%、provider 原图修复性回读失败、Alpha 回贴失败或透明图完整解码失败时,都统一只保留 provider 原图且不拆分,像素规整不运行;像素规整自身失败但透明图仍通过完整解码和尺寸守卫时,才保留该透明图并继续上传和拆分,通过通用warning非致命提示,不退款。sliceWarning继续只表达可信透明图成功后的自动拆分失败。
去背与保存
- 父流程收到 spritesheet 后先把带解析后纯色背景的源图写入私有 OSS,并在上传完成后释放原图缓冲;随后只持 object key,并仅向同机唯一 loopback
bgfilter-worker发起一次内部 HTTP RPC,请求中的源图只以 object key 传递,并附带 BgFilter 参数、排队预算maxQueueWaitMs、调用预算callBudgetMs和有界审计关联,父流程不签发 BgFilter URL、不直连 provider,也不重试已被 worker 接收的内部 RPC(连接从未建立时按调度方案 §5.1 有界重连)。子 worker 在Qadmission 和Semaphore(N)约束下执行这次逻辑调用;排队只消耗maxQueueWaitMs,取得 provider permit 后才启动callBudgetMs。每次 provider attempt 前重新签发 600 秒 GET URL,multipart 固定传image_url、screen_color=<screenColor>、seg_model=<segModel>、background_mode=flat和cross_check=on,不包含file,并在调用预算内最多执行两次顺序 attempt。前端用户路径固定提交screenColor=auto与默认segModel=birefnet,后端仍识别内部保留的anime-seg,但这些内部参数不对用户可见。成功时,子 worker 通过内部 HTTP 二进制 body 把经过校验的图片字节直接返回父流程,不持久化中间结果;BgFilter 最终失败且父业务预算仍有效时,由父流程进入“阿里云通用抠图(按签名 URL 单独下载)→ 本地键色(再按 object key 独立下载一次原图并在产出后释放)”降级链。 - 透明背景处理正常成功时,父流程把带背景原图和经完整解码 / 尺寸守卫验证的透明 spritesheet 写入 OSS、项目资源和账号素材库,再识别 alpha 连通域并执行附加拆分。BgFilter 最终失败或后续 Alpha / 尺寸恢复、原图回读、透明图完整解码失败、但 provider 原图已经持久化时,任务以
completed + warning收口,只把 provider 原图作为唯一主图放入画布,不创建透明图集,也不继续拆分,iconImageSrcs=[]、sliceWarning=null。该收口不捕获 phase 上报、provider 原图持久化或canvasCompletion写回错误;provider 原图本身解码失败时在首次持久化前失败,不允许用512×512伪造元数据。 - 自动拆分只在透明图集成功后执行,属于 best-effort 附加动作,不参与图集生成的成功判定。连通域识别或切片持久化失败时,接口仍返回并回填整张透明图集,
iconImageSrcs=[],并通过sliceWarning.code/reason暴露非阻断原因;sliceWarning与透明背景最终失败使用的通用warning互斥,因为透明背景失败时不会进入拆分,但可与风格归一化或像素规整产生的通用warning并存。前者只表示透明图集成功但自动拆分失败,sliceWarning.reason原始契约保持不变。前端在 inline、worker 队列完成和刷新恢复三条路径统一显示对应 warning toast,用户可在图集工具栏手动重试。 - 响应通过
iconImageSrcs返回成功切片素材。图标自动拆分、手动拆分图集和 UI 提取复用同一个 bounded CPU helper 和 platform 实现:全部原始连通域(包括随后过滤的噪点)最多4096个,辅助部件通过64px空间网格只检查最大48px邻域候选;有效输出按视觉阅读顺序命名为素材 N。 - 三条拆分路径共同限制单边最多
4096像素、总像素最多2048×2048、最多64个输出;输出限制在排序、裁剪和 PNG 编码前检查。整段图片 CPU 工作在 2 路 semaphore、30 秒本地上限与请求 deadline 共同保护的spawn_blocking中执行,permit 由 blocking 闭包持有。自动拆分超限以稳定sliceWarning非阻断降级且不产生切片 PUT、资源或画布切片;手动拆分超限在首次持久化前返回422。
前端铺放规则
- 透明 spritesheet 主图放在原占位图位置附近;provider 带背景原图放在透明主图右侧。
- 自动拆分素材从 provider 原图右侧开始换行铺放;手动拆分使用相同布局,但保留原图集不变。
- 生成成功后关闭图标素材面板,选中透明 spritesheet 主图,并打开图层面板。
验收
- 点击
生成图标素材后出现一叠空白图标占位和图标素材面板。 图标规范 -> 从画布中选择只能选择图标规范图,点击普通图片或角色规范图不会绑定。- 默认提示文本会完整进入 prompt;用户输入不再被解析为素材数量。例如“各种敌人头像:骷髅 哥布林 强盗 龙 蝙蝠等”只是一段完整需求,不代表必须生成或拆出
6个素材。 - 默认打开图标素材面板时选中
nanobanana2 / 1:1 / 1K;模型切换后,角色和图标素材面板之间沿用上次选择的模型。 - 图标素材生成请求必须带
model、aspectRatio和imageSize;nanobanana2请求体必须包含generationConfig.imageConfig.aspectRatio/imageSize,gpt-image-2请求必须包含文档映射后的size。 - 图标素材面板可选择
style: "none" | "pixelArt";none完整保持原处理路径,且提交给 provider 的提示词与未带该字段时逐字一致,pixelArt在提示词末尾追加「每个图标素材均为像素风格」并在 Alpha 回贴后、自动拆分前执行内存像素规整,直接持久化整数倍放大后的透明图集;该图集宽高比等于逻辑图、尺寸接近规整输入,最终 OSS PUT、项目资源、图集画布项和切片画布项数量不得因此增加。 - 图标素材生成可以上传普通附加参考图;提交时图标主规范图走
referenceId,且只提交当前 owner 的项目资源 ID 或素材 ID。普通附加参考图单独走referenceImageSrcs,继续允许稳定objectKey/ 项目资源 ID / 素材 ID,但禁止 Data URL / Blob URL。两类引用都写入generationInputs.references,不得用普通附加参考图协议放宽主规范边界。 - 透明背景处理和自动拆分都成功后,画布同时出现透明 spritesheet 主图、其右侧的 provider 原图,以及从原图右侧铺开的全部有效连通域图标图层,图标依次命名为
素材 N;透明图集成功但拆分失败时仍出现透明主图与右侧原图,透明背景处理最终失败时只出现 provider 原图。 - 选中透明图集图层时显示
拆分图集;点击后源图集显示扫描蒙层与拆图中状态,工具栏按钮同步切换为旋转图标和拆图中并禁用重复提交。完成后恢复工具栏,不新增第二张图集,只在 provider 原图右侧追加自动识别的独立素材,并同步写入素材库。 - 把同源派生图层从其它标签改为“图集”时,在项目资源返回新
resourceId前“拆分图集”保持禁用;持久化成功后拆分请求必须指向assetKind: "icon-spritesheet"的新资源,失败时标签回滚且不发起拆分请求。 - 生成图标素材的提交体不包含
priceMudPoints;后端必须按归一化后的模型和尺寸计算价格,不信任客户端声明。queue 任务的计费、退款和结果投影使用入队时冻结的同一价格。