恢复画布抠图模型默认请求契约
恢复角色、图标和 UI 素材提取自动提交默认 segModel。 后端重新接收并校验 segModel,非法值不回显内部 provider 或模型。 保持普通用户响应、搜索、详情、导出与错误文本的内部信息脱敏。 修正 Owner/Public、External OpenAPI 与站内 BFF 请求边界文档。 补齐前后端请求序列化和安全回归测试。
This commit is contained in:
@@ -19,9 +19,9 @@
|
||||
## 2026-07-30 抠图实际后端作为 generationInputs 顶层内部元数据保存
|
||||
|
||||
- 背景:角色、图标图集和 UI 图集抠图派生资产需要保留最终实际执行的处理后端,供后台诊断 BgFilter、阿里云通用抠图和本地键色的降级结果;把抠图模型写成 `generationInputs.fields` 的“处理模型”会进入图片信息,与用户可见输入快照语义冲突,而覆盖正式资产 `model` 又会丢失源生图模型。
|
||||
- 决策:继续使用现有 `generation_inputs_json` JSON 包络,不修改 SpacetimeDB schema。`fields` / `references` 只保存用户可见生成输入;仿照顶层 `screenColorHex`,抠图派生资产在顶层写入 `mattingProvider` / `mattingModel`。BgFilter 记录本次实际 `seg_model`;阿里云记录 `Aliyun Matting / segment-common-image`;本地键色记录 `Genarrative Local / screen-color-keying`。三条链路的正式资产 `model` 继续继承源生图模型,图片信息不读取顶层内部字段。`screenColorHex`、`mattingProvider`、`mattingModel` 和素材顶层 `provider` 属于内部执行信息:素材 owner、精选提交响应和后台管理接口仍按既有权限读取原始值,匿名 `GET /api/editor/showcase/resources` 必须在 public payload 边界删除三个 `generationInputs` 顶层内部键并省略 `provider`,历史精选快照不做数据迁移。角色动作逐帧可能混用多个 fallback,本次不把单帧结果提升为整组动画模型。
|
||||
- 决策:继续使用现有 `generation_inputs_json` JSON 包络,不修改 SpacetimeDB schema。`fields` / `references` 只保存用户可见生成输入;仿照顶层 `screenColorHex`,抠图派生资产在顶层写入 `mattingProvider` / `mattingModel`。BgFilter 记录本次实际 `seg_model`;阿里云记录 `Aliyun Matting / segment-common-image`;本地键色记录 `Genarrative Local / screen-color-keying`。三条链路的正式资产 `model` 继续继承源生图模型,图片信息不读取顶层内部字段。`screenColorHex`、`mattingProvider`、`mattingModel` 和素材顶层 `provider` 属于内部执行信息:普通用户(包括素材 owner)、精选提交 / 点赞响应与匿名公开读取统一省略,只有后台管理和服务端 raw 审计读取原始值;历史数据不迁移,在 User/Public mapper 边界清理。角色动作逐帧可能混用多个 fallback,本次不把单帧结果提升为整组动画模型。
|
||||
- 影响范围:`server-rs/crates/api-server/src/editor_project.rs` 的抠图结果和角色 / 图标 / UI 派生资产持久化、图片信息兼容测试、后端数据契约与图片画布 MVP 文档;不修改前端生产展示逻辑、请求 DTO、SpacetimeDB 表、迁移或生成绑定。
|
||||
- 验证方式:后端单测覆盖三种实际结果映射、顶层元数据不改写 `fields`,结构断言覆盖三条派生资产持久化链路仍保留源生图模型;public mapper 测试同时证明匿名响应省略 `provider` 和三个内部键、owner 精选快照仍保留原始值;前端测试覆盖顶层字段不在图片信息出现。运行 `cargo test -p api-server editor_project::tests --manifest-path server-rs/Cargo.toml`、图片信息定向前端测试、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`、`npm run typecheck`、`npm run check:encoding` 和 `git diff --check`。
|
||||
- 验证方式:后端单测覆盖三种实际结果映射、顶层元数据不改写 `fields`,结构断言覆盖三条派生资产持久化链路仍保留源生图模型;User/Public mapper 测试同时证明素材 owner、精选提交 / 点赞与匿名响应均省略 `provider` 和三个内部键,Admin raw payload 保留原始值;前端测试覆盖顶层字段不在图片信息或搜索索引出现。运行 `cargo test -p api-server editor_project::tests --manifest-path server-rs/Cargo.toml`、图片信息定向前端测试、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`、`npm run typecheck`、`npm run check:encoding` 和 `git diff --check`。
|
||||
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
---
|
||||
@@ -31,7 +31,7 @@
|
||||
- 背景:2026-07-30 的记录误把素材 owner 与后台审计并列为原始抠图执行信息的读取方。owner 是普通用户,前端不展示字段不能阻止其从项目资源、素材库、精选提交 / 点赞回包、画布布局或任务完成响应的网络 payload 读取 BgFilter、阿里云、本地键色、具体分割模型或背景色。
|
||||
- 决策:本条取代 2026-07-30 决策中“素材 owner、精选提交响应仍可读取原始值”的表述。普通用户(包括素材 owner)和匿名公开读取必须共同过滤素材顶层 `provider`、内部处理 `model`,以及 `generationInputs` 顶层 `screenColorHex`、`mattingProvider`、`mattingModel`;正常用户可见生成 `model` 和其他合法功能性顶层字段(例如 `characterAnimation`)保持不变。User/Owner mapper 先完成该清理,public mapper 在其基础上叠加公开字段规则;后台管理与服务端审计继续使用 raw mapper 和持久化原值。历史数据不迁移,统一在读取边界清理。
|
||||
- 入站与持久化:客户端提交的 `generationInputs` 不得伪造上述内部键,服务端在实际处理完成后才写入可信值。手动去背景的正式素材 `model` 必须继承经服务端验证的正常源生图模型;若来源或祖先链不存在正常模型则为 `null`,不得写入 `BgFilter complex` 等内部处理模型。内部抠图 provider / model 可继续持久化供后台审计,普通用户完成响应和用户可见错误文本均不得暴露它们;手动去背景与角色动作透明化失败在 Owner HTTP / 任务状态边界统一替换为稳定业务文案,原始错误只留在任务记录、tracing 和后台审计。
|
||||
- 影响范围:项目资源、素材库、精选提交 / 点赞、图片 / 图标 / 视频 / 音频 / 角色动画生成完成、Agent 紧凑结果和识别出的画布资源 / 图层快照的 User/Public mapper;手动去背景持久化和完成响应;External Editor API 创建素材 / 资源时的保留键入站清理;相应 API / OpenAPI 契约、前端搜索 / 详情 / ZIP 过滤测试与后台 raw 审计测试。不修改 SpacetimeDB schema、迁移或 bindings。
|
||||
- 影响范围:项目资源、素材库、精选提交 / 点赞、图片 / 图标 / 视频 / 音频 / 角色动画生成完成、Agent 紧凑结果和识别出的画布资源 / 图层快照的 User/Public mapper;手动去背景持久化和完成响应;External Editor API 创建素材 / 资源时的保留键入站清理;相应响应 / OpenAPI 契约、前端搜索 / 详情 / ZIP 过滤测试与后台 raw 审计测试。同源画布 BFF 的角色、图标和 UI 请求继续由前端自动提交默认 `segModel=birefnet`,后端继续校验并在缺失时回落默认值;该请求控制字段不进入 `generationInputs`、普通用户响应、搜索、详情、导出或错误详情。角色动作的 `seg_model` 继续由后端固定。不修改 SpacetimeDB schema、迁移或 bindings。
|
||||
- 验证方式:Owner 和匿名响应覆盖无 `provider`、无内部 `model`、无三个内部 `generationInputs` 键,且正常 `model` 与 `characterAnimation` 仍保留;Admin raw payload 保持完整。覆盖历史 `BgFilter complex`、三类入站伪造键、手动去背景源模型回溯和用户错误文本过滤;运行 api-server 定向测试、前端定向测试、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`、`npm run typecheck`、`npm run check:encoding` 与 `git diff --check`。
|
||||
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -116,7 +116,7 @@ SpacetimeDB procedure:
|
||||
1. 通过 OSS / asset object adapter 持久化媒体文件。
|
||||
2. 写入 `editor_asset`,让生成素材进入账号级素材库。
|
||||
3. 如果请求带 `projectId`,写入 `editor_project_resource`。
|
||||
4. 返回图片读取地址、素材 ID、资源 ID、尺寸、prompt、model、provider 和 taskId。
|
||||
4. 返回图片读取地址、素材 ID、资源 ID、尺寸、prompt、model 和 taskId;普通 External API 响应、项目资源与素材 read model 不返回生成 provider 或内部抠图审计字段。同源画布前端自动提交默认 `segModel` 属于站内 BFF 请求契约,不因此向 External OpenAPI 开放该字段。
|
||||
|
||||
如果请求未带 `projectId`,只生成并写入素材库;调用方可随后创建项目或自行保存画板布局。
|
||||
|
||||
|
||||
@@ -333,6 +333,7 @@ impl EditorAgentTool for GenerateImageTool {
|
||||
style: None,
|
||||
model: Some(args.model),
|
||||
screen_color: None,
|
||||
seg_model: None,
|
||||
aspect_ratio: Some(args.aspect_ratio),
|
||||
image_size: Some(args.image_size),
|
||||
reference_image_srcs: Some(reference_image_srcs),
|
||||
@@ -440,6 +441,7 @@ impl EditorAgentTool for GenerateCharacterTool {
|
||||
style: None,
|
||||
model: Some(args.model),
|
||||
screen_color: Some("auto".to_string()),
|
||||
seg_model: Some("birefnet".to_string()),
|
||||
aspect_ratio: Some(args.aspect_ratio),
|
||||
image_size: Some(args.image_size),
|
||||
reference_image_srcs: Some(reference_image_srcs),
|
||||
@@ -549,6 +551,7 @@ impl EditorAgentTool for GenerateUiDesignTool {
|
||||
style: None,
|
||||
model: Some(args.model),
|
||||
screen_color: None,
|
||||
seg_model: None,
|
||||
aspect_ratio: Some(args.aspect_ratio),
|
||||
image_size: Some(args.image_size),
|
||||
reference_image_srcs: Some(reference_image_srcs),
|
||||
@@ -802,6 +805,7 @@ impl EditorAgentTool for GenerateIconSpritesheetTool {
|
||||
style: None,
|
||||
model: Some(args.model),
|
||||
screen_color: Some("auto".to_string()),
|
||||
seg_model: Some("birefnet".to_string()),
|
||||
aspect_ratio: Some(args.aspect_ratio),
|
||||
image_size: Some(args.image_size),
|
||||
project_id: Some(context.conversation.project_id.clone()),
|
||||
|
||||
@@ -151,7 +151,6 @@ const EDITOR_UI_DESIGN_ASSET_IMAGE_KIND: &str = "editor_ui_design_asset";
|
||||
const EDITOR_LEGACY_GREEN_SCREEN_SOURCE_ASSET_KIND: &str = "editor_green_screen_source";
|
||||
const EDITOR_PROVIDER_SOURCE_SLOT: &str = "provider_source";
|
||||
pub(crate) const EDITOR_BGFILTER_DEFAULT_SEG_MODEL: &str = "birefnet";
|
||||
#[cfg(test)]
|
||||
const EDITOR_BGFILTER_SEG_MODEL_ANIME_SEG: &str = "anime-seg";
|
||||
const EDITOR_BGFILTER_MATTING_PROVIDER: &str = "BgFilter";
|
||||
const EDITOR_ALIYUN_MATTING_PROVIDER: &str = "Aliyun Matting";
|
||||
@@ -270,6 +269,7 @@ pub struct EditorImageGenerationRequest {
|
||||
pub(crate) style: Option<String>,
|
||||
pub(crate) model: Option<String>,
|
||||
pub(crate) screen_color: Option<String>,
|
||||
pub(crate) seg_model: Option<String>,
|
||||
pub(crate) aspect_ratio: Option<String>,
|
||||
pub(crate) image_size: Option<String>,
|
||||
pub(crate) reference_image_srcs: Option<Vec<String>>,
|
||||
@@ -327,6 +327,7 @@ pub struct EditorIconSpritesheetGenerationRequest {
|
||||
pub(crate) style: Option<String>,
|
||||
pub(crate) model: Option<String>,
|
||||
pub(crate) screen_color: Option<String>,
|
||||
pub(crate) seg_model: Option<String>,
|
||||
pub(crate) aspect_ratio: Option<String>,
|
||||
pub(crate) image_size: Option<String>,
|
||||
pub(crate) project_id: Option<String>,
|
||||
@@ -351,6 +352,7 @@ pub struct EditorUiDesignAssetExtractionRequest {
|
||||
pub(crate) source_image_src: String,
|
||||
pub(crate) model: Option<String>,
|
||||
pub(crate) screen_color: Option<String>,
|
||||
pub(crate) seg_model: Option<String>,
|
||||
pub(crate) reference_image_srcs: Option<Vec<String>>,
|
||||
pub(crate) aspect_ratio: String,
|
||||
pub(crate) image_size: String,
|
||||
@@ -1673,7 +1675,13 @@ pub(crate) async fn generate_editor_image_for_owner(
|
||||
// 仍白发一次 gpt-5-mini 决策。这里先固化决策需要、但随后会被 payload 消费掉的输入。
|
||||
let requested_screen_color = payload.screen_color.clone();
|
||||
let reference_count = payload.reference_image_srcs.as_ref().map_or(0, Vec::len);
|
||||
let seg_model = is_character_generation.then_some(EDITOR_BGFILTER_DEFAULT_SEG_MODEL);
|
||||
let seg_model = if is_character_generation {
|
||||
Some(parse_editor_bgfilter_seg_model(
|
||||
payload.seg_model.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let is_ui_design_generation = matches!(normalized_kind, Some("ui-design"));
|
||||
let is_publication_material_generation =
|
||||
matches!(normalized_kind, Some("publication-material"));
|
||||
@@ -4380,6 +4388,22 @@ fn sign_editor_private_object_read_url(
|
||||
.map_err(|error| map_oss_error(error, "aliyun-oss"))
|
||||
}
|
||||
|
||||
fn parse_editor_bgfilter_seg_model(value: Option<&str>) -> Result<&'static str, AppError> {
|
||||
let Some(value) = value.map(str::trim).filter(|value| !value.is_empty()) else {
|
||||
return Ok(EDITOR_BGFILTER_DEFAULT_SEG_MODEL);
|
||||
};
|
||||
match value.to_ascii_lowercase().as_str() {
|
||||
EDITOR_BGFILTER_DEFAULT_SEG_MODEL => Ok(EDITOR_BGFILTER_DEFAULT_SEG_MODEL),
|
||||
EDITOR_BGFILTER_SEG_MODEL_ANIME_SEG => Ok(EDITOR_BGFILTER_SEG_MODEL_ANIME_SEG),
|
||||
_ => Err(
|
||||
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
|
||||
"field": "segModel",
|
||||
"message": "抠图参数无效。",
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
struct PersistEditorSpritesheetSlicesInput {
|
||||
owner_user_id: String,
|
||||
project_id: Option<String>,
|
||||
@@ -4588,7 +4612,7 @@ pub(crate) async fn generate_editor_icon_spritesheet_for_owner(
|
||||
// 仍白发一次 gpt-5-mini 决策。这里先固化决策需要的输入。
|
||||
let requested_screen_color = payload.screen_color.clone();
|
||||
let reference_count = 1 + payload.reference_image_srcs.as_ref().map_or(0, Vec::len);
|
||||
let seg_model = EDITOR_BGFILTER_DEFAULT_SEG_MODEL;
|
||||
let seg_model = parse_editor_bgfilter_seg_model(payload.seg_model.as_deref())?;
|
||||
let mut reference_images =
|
||||
Vec::with_capacity(1 + payload.reference_image_srcs.as_ref().map_or(0, Vec::len));
|
||||
reference_images.push(
|
||||
@@ -5519,7 +5543,7 @@ pub(crate) async fn extract_editor_ui_design_assets_for_owner(
|
||||
"从 UI 设计图提取被红色框选的素材,输出 spritesheet。目标规格 {} {}。",
|
||||
payload.aspect_ratio, payload.image_size
|
||||
);
|
||||
let seg_model = EDITOR_BGFILTER_DEFAULT_SEG_MODEL;
|
||||
let seg_model = parse_editor_bgfilter_seg_model(payload.seg_model.as_deref())?;
|
||||
let reference_image = parse_editor_reference_image(
|
||||
state,
|
||||
caller.owner_user_id.as_str(),
|
||||
@@ -12355,12 +12379,7 @@ mod tests {
|
||||
}))
|
||||
.expect("UI extraction request should deserialize dimensions");
|
||||
assert_eq!(request.screen_color.as_deref(), Some("#E6D8FF"));
|
||||
assert!(
|
||||
serde_json::to_value(&request)
|
||||
.expect("request should serialize")
|
||||
.get("segModel")
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(request.seg_model.as_deref(), Some("anime-seg"));
|
||||
let generation_options = normalize_editor_ui_design_asset_extraction_options(
|
||||
request.model.as_deref(),
|
||||
request.aspect_ratio.as_str(),
|
||||
@@ -12426,12 +12445,7 @@ mod tests {
|
||||
|
||||
assert_eq!(request.prompt, "生成图片");
|
||||
assert_eq!(request.screen_color.as_deref(), Some("#CFEFFF"));
|
||||
assert!(
|
||||
serde_json::to_value(&request)
|
||||
.expect("request should serialize")
|
||||
.get("segModel")
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(request.seg_model.as_deref(), Some("anime-seg"));
|
||||
assert_eq!(request.style, None);
|
||||
}
|
||||
|
||||
@@ -12698,12 +12712,7 @@ mod tests {
|
||||
Some(vec!["/generated-images/editor/style.png".to_string()])
|
||||
);
|
||||
assert_eq!(request.screen_color.as_deref(), Some("#7FB3FF"));
|
||||
assert!(
|
||||
serde_json::to_value(&request)
|
||||
.expect("request should serialize")
|
||||
.get("segModel")
|
||||
.is_none()
|
||||
);
|
||||
assert_eq!(request.seg_model.as_deref(), Some("anime-seg"));
|
||||
assert_eq!(request.asset_label.as_deref(), Some(" 冒险界面图标 "));
|
||||
assert_eq!(request.style, None);
|
||||
|
||||
@@ -12811,6 +12820,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_bgfilter_seg_model_parser_defaults_and_rejects_unknown_without_internal_details() {
|
||||
assert_eq!(
|
||||
parse_editor_bgfilter_seg_model(None).expect("default should parse"),
|
||||
EDITOR_BGFILTER_DEFAULT_SEG_MODEL
|
||||
);
|
||||
assert_eq!(
|
||||
parse_editor_bgfilter_seg_model(Some("Anime-Seg")).expect("anime seg should parse"),
|
||||
EDITOR_BGFILTER_SEG_MODEL_ANIME_SEG
|
||||
);
|
||||
|
||||
let error =
|
||||
parse_editor_bgfilter_seg_model(Some("u2net")).expect_err("unknown model should fail");
|
||||
let body = error.body_text();
|
||||
assert!(body.contains("抠图参数无效"));
|
||||
assert!(!body.to_ascii_lowercase().contains("bgfilter"));
|
||||
assert!(!body.contains(EDITOR_BGFILTER_DEFAULT_SEG_MODEL));
|
||||
assert!(!body.contains(EDITOR_BGFILTER_SEG_MODEL_ANIME_SEG));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn editor_bgfilter_worker_budget_covers_two_attempts_and_parent_reserves() {
|
||||
let config = AppConfig::default();
|
||||
|
||||
@@ -3529,6 +3529,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
sourceImageSrc:
|
||||
'generated-character-drafts/editor/generation-references/marked-ui-design.png',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-ui-extract',
|
||||
|
||||
@@ -100,6 +100,7 @@ export const DEFAULT_ICON_DESCRIPTIONS = [
|
||||
'冻结按钮',
|
||||
];
|
||||
export const DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR = 'auto';
|
||||
export const DEFAULT_EDITOR_BGFILTER_SEG_MODEL = 'birefnet';
|
||||
export const UI_DESIGN_ASSET_EXTRACTION_PROMPT =
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。';
|
||||
export const QUICK_EDIT_SIZE_PRESETS = [
|
||||
|
||||
@@ -343,6 +343,7 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
style: 'pixelArt',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '2K',
|
||||
@@ -716,6 +717,7 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
|
||||
iconDescriptions: ['返回按钮\n\n设置按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
style: 'pixelArt',
|
||||
aspectRatio: '3:2',
|
||||
imageSize: '2K',
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
buildUiDesignGenerationInputs,
|
||||
buildVideoGenerationInputs,
|
||||
CHARACTER_ANIMATION_MODEL,
|
||||
DEFAULT_EDITOR_BGFILTER_SEG_MODEL,
|
||||
DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR,
|
||||
DEFAULT_SOUND_EFFECT_DURATION_SECONDS,
|
||||
DEFAULT_SOUND_EFFECT_MODEL,
|
||||
@@ -342,6 +343,7 @@ export function buildImageGenerationSubmissionPlan({
|
||||
].filter((src): src is string => Boolean(src));
|
||||
const imageModel = normalizeEditorImageModel(dialog.imageModel);
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
return {
|
||||
kind: 'image',
|
||||
normalizedPrompt,
|
||||
@@ -350,6 +352,7 @@ export function buildImageGenerationSubmissionPlan({
|
||||
kind: 'character',
|
||||
model: imageModel,
|
||||
screenColor,
|
||||
segModel,
|
||||
style: dialog.style === 'pixelArt' ? 'pixelArt' : 'none',
|
||||
aspectRatio: dialog.aspectRatio ?? '1:1',
|
||||
imageSize: dialog.imageSize ?? '1K',
|
||||
@@ -616,6 +619,7 @@ export function buildIconSpritesheetGenerationSubmissionPlan(
|
||||
|
||||
const rememberImageModel = normalizeEditorImageModel(dialog.imageModel);
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
return {
|
||||
ok: true,
|
||||
iconDescriptions,
|
||||
@@ -633,6 +637,7 @@ export function buildIconSpritesheetGenerationSubmissionPlan(
|
||||
iconDescriptions,
|
||||
model: rememberImageModel,
|
||||
screenColor,
|
||||
segModel,
|
||||
style: dialog.style === 'pixelArt' ? 'pixelArt' : 'none',
|
||||
aspectRatio: dialog.aspectRatio ?? '1:1',
|
||||
imageSize: dialog.imageSize ?? '1K',
|
||||
|
||||
@@ -2573,6 +2573,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
sourceImageSrc: 'generated/ui-design.png',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -2709,6 +2710,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
'generated-character-drafts/editor/generation-references/reference.png',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
canvasCompletion: expect.objectContaining({
|
||||
@@ -2770,6 +2772,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
expect(extractEditorUiDesignAssetsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
referenceImageSrcs: ['generated/ref-style.png'],
|
||||
generationInputs: expect.objectContaining({
|
||||
references: expect.arrayContaining([
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
buildQuickEditGenerationInputs,
|
||||
buildUiDesignAssetExtractionGenerationInputs,
|
||||
buildVideoGenerationInputs,
|
||||
DEFAULT_EDITOR_BGFILTER_SEG_MODEL,
|
||||
DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR,
|
||||
DEFAULT_IMAGE_MODEL,
|
||||
DEFAULT_VIDEO_MODEL,
|
||||
@@ -1085,6 +1086,7 @@ export function useImageCanvasGenerationSubmissionWorkflow({
|
||||
);
|
||||
}
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
const generationInputs = buildUiDesignAssetExtractionGenerationInputs(
|
||||
sourceLayer,
|
||||
options.references,
|
||||
@@ -1121,6 +1123,7 @@ export function useImageCanvasGenerationSubmissionWorkflow({
|
||||
options.model ?? DEFAULT_IMAGE_MODEL,
|
||||
),
|
||||
screenColor,
|
||||
segModel,
|
||||
...(referenceImageSrcs.length ? { referenceImageSrcs } : {}),
|
||||
projectId,
|
||||
generationInputs,
|
||||
|
||||
@@ -837,6 +837,7 @@ describe('editorProjectClient', () => {
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#FFD6C2',
|
||||
segModel: 'anime-seg',
|
||||
style: 'pixelArt',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '1K',
|
||||
@@ -861,6 +862,7 @@ describe('editorProjectClient', () => {
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#FFD6C2',
|
||||
segModel: 'anime-seg',
|
||||
style: 'pixelArt',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '1K',
|
||||
@@ -1014,6 +1016,7 @@ describe('editorProjectClient', () => {
|
||||
iconDescriptions: ['返回按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#E6D8FF',
|
||||
segModel: 'anime-seg',
|
||||
style: 'none',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
@@ -1035,6 +1038,7 @@ describe('editorProjectClient', () => {
|
||||
iconDescriptions: ['返回按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#E6D8FF',
|
||||
segModel: 'anime-seg',
|
||||
style: 'none',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
@@ -1153,6 +1157,7 @@ describe('editorProjectClient', () => {
|
||||
sourceImageSrc: '/generated-images/editor/ui-design.png',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#7FB3FF',
|
||||
segModel: 'anime-seg',
|
||||
referenceImageSrcs: ['/generated-images/editor/ui-ref.png'],
|
||||
projectId: 'editor-project-1',
|
||||
assetFolderId: 'project',
|
||||
@@ -1175,6 +1180,7 @@ describe('editorProjectClient', () => {
|
||||
sourceImageSrc: '/generated-images/editor/ui-design.png',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#7FB3FF',
|
||||
segModel: 'anime-seg',
|
||||
referenceImageSrcs: ['/generated-images/editor/ui-ref.png'],
|
||||
projectId: 'editor-project-1',
|
||||
generationInputs: {
|
||||
|
||||
@@ -197,6 +197,7 @@ export type EditorImageGenerationInput = {
|
||||
| 'publication-material';
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
style?: EditorImageGenerationStyle;
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
@@ -229,6 +230,7 @@ export type EditorIconSpritesheetGenerationInput = {
|
||||
iconDescriptions: string[];
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
style?: EditorImageGenerationStyle;
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
@@ -250,6 +252,7 @@ export type EditorUiDesignAssetExtractionInput = {
|
||||
sourceImageSrc: string;
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
referenceImageSrcs?: string[];
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
@@ -916,6 +919,7 @@ export async function generateEditorImage(input: EditorImageGenerationInput) {
|
||||
...(input.kind ? { kind: input.kind } : {}),
|
||||
...(input.model ? { model: input.model } : {}),
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.style ? { style: input.style } : {}),
|
||||
...(input.aspectRatio ? { aspectRatio: input.aspectRatio } : {}),
|
||||
...(input.imageSize ? { imageSize: input.imageSize } : {}),
|
||||
@@ -962,6 +966,7 @@ export async function generateEditorIconSpritesheet(
|
||||
iconDescriptions: input.iconDescriptions,
|
||||
model: input.model?.trim() || EDITOR_IMAGE_MODEL_NANOBANANA2,
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.style ? { style: input.style } : {}),
|
||||
...(input.aspectRatio ? { aspectRatio: input.aspectRatio } : {}),
|
||||
...(input.imageSize ? { imageSize: input.imageSize } : {}),
|
||||
@@ -1009,6 +1014,7 @@ export async function extractEditorUiDesignAssets(
|
||||
sourceImageSrc: input.sourceImageSrc,
|
||||
...(input.model ? { model: input.model } : {}),
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.referenceImageSrcs?.length
|
||||
? { referenceImageSrcs: input.referenceImageSrcs }
|
||||
: {}),
|
||||
|
||||
Reference in New Issue
Block a user