同步前端图片模型测试到 GPT Image 2.5 重命名
- 6 个 image-editor 测试文件的旧 gpt-image-2 断言改为 gpt-image-2.5 / GPT Image 2.5,覆盖图集导出、元数据弹窗、UI 素材提取模型菜单与生成/快速编辑 dialog 参数快照 - 工作流测试夹具与提取模型按钮改用 IMAGE_MODEL_GPT_IMAGE_2_5 常量,legacy 夹具保留并断言提交边界归一为当前业务模型 - decision-log 2026-09-21 条目补 platform-image 与前端全量测试验证结论
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
- 边界:nanobanana 生成与编辑共用一个 concrete model,参考图不改变档位;不引入跨模型 fallback;历史持久化值与审计字符串不改写。
|
||||
- 同批修复:`raw_image_edit` 发送前复用共享 `ensure_provider_matches_model` 白名单校验;`platform-image` 兜底 task id 前缀改为跟随实际 provider(`tiantoken-edit` / `tiantoken-nanobanana` 不再带 `vector-engine` 前缀);`resolve_image_provider` 增加 `gpt-image-2 → Tiantoken` 断言把历史值意图钉死;删除 `openai_image_generation.rs` 中仅测试使用的 `create_openai_image_edit` / `create_openai_image_edit_with_references`(测试改用 `..._and_model` 变体,保留空参考图本地校验覆盖);`normalize_editor_generation_options` 的具体 provider key 改用常量;External v1 OpenAPI 的 `model` 描述改为与实现一致(`kind=ui-design` / `publication-material` 固定 `gpt-image-2.5`,UI 素材提取未传默认 nanobanana)。
|
||||
- 影响范围:`api-server`(`editor_generation_config`、`editor_project`、`editor_project_icon`、`character_visual_assets`、`editor_agent/tool`、`openai_image_generation`)、`platform-image`(`raw_image_edit`、`runtime/executor`、集成测试)、ADR、里程碑文档、External v1 OpenAPI 描述、`.codex/skills/gpt-image-2-apimart` 脚本与 SKILL.md(改用 `TIANTOKEN_*` 凭据 + concrete model)。
|
||||
- 验证:`cargo test -p api-server editor_generation_config`、`cargo test -p api-server editor_agent::tool`、`cargo test -p api-server`(1123 passed / 1 failed,失败项为 mock LLM 连接超时,单测隔离重跑通过)。
|
||||
- 验证:`cargo test -p api-server editor_generation_config`、`cargo test -p api-server editor_agent::tool`、`cargo test -p api-server`(1123 passed / 1 failed,失败项为 mock LLM 连接超时,单测隔离重跑通过);`cargo test -p platform-image`(22 + 64 + 14 passed);`npx vitest run` 全量 382 files / 4619 passed(6 个测试文件的旧 `gpt-image-2` 断言与 mock 请求体读取竞态同步修正);`npm run typecheck`、`npm run check:encoding`、`git diff --check` 通过。
|
||||
- 关联文档:[`docs/adr/【ADR】GPT Image 2.5模型路由与历史值兼容-2026-09-18.md`](../../adr/【ADR】GPT%20Image%202.5模型路由与历史值兼容-2026-09-18.md)、[`docs/project-memory/plans/【里程碑】GPT Image 2.5 provider边界重构-2026-09-18.md`](../plans/【里程碑】GPT%20Image%202.5%20provider边界重构-2026-09-18.md)。
|
||||
|
||||
## 2026-09-21 图片 provider 白名单收紧,并整体删除 gpt-image-2-c
|
||||
|
||||
@@ -1527,7 +1527,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
expect(generateEditorImageMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
kind: 'spec',
|
||||
model: 'gpt-image-2',
|
||||
model: 'gpt-image-2.5',
|
||||
size: '2048x1152',
|
||||
aspectRatio: '16:9',
|
||||
imageSize: '2K',
|
||||
@@ -1872,7 +1872,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
await waitFor(() => {
|
||||
expect(generateEditorIconSpritesheetMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
model: 'gpt-image-2',
|
||||
model: 'gpt-image-2.5',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '2K',
|
||||
}),
|
||||
@@ -2315,7 +2315,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
expect(generateEditorImageMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
kind: 'spec',
|
||||
model: 'gpt-image-2',
|
||||
model: 'gpt-image-2.5',
|
||||
size: '2048x1152',
|
||||
aspectRatio: '16:9',
|
||||
imageSize: '2K',
|
||||
@@ -3894,7 +3894,7 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
expect(within(metadataDialog).getByText('生成提示词')).toBeTruthy();
|
||||
expect(within(metadataDialog).getByText('一张可修改的生成图')).toBeTruthy();
|
||||
expect(within(metadataDialog).getByText('Model')).toBeTruthy();
|
||||
expect(within(metadataDialog).getByText('gpt-image-2')).toBeTruthy();
|
||||
expect(within(metadataDialog).getByText('GPT Image 2.5')).toBeTruthy();
|
||||
expect(within(metadataDialog).queryByText('Size')).toBeNull();
|
||||
expect(within(metadataDialog).getByText('Resolution')).toBeTruthy();
|
||||
expect(within(metadataDialog).getByText('1024 x 1024 px')).toBeTruthy();
|
||||
|
||||
@@ -1274,7 +1274,7 @@ describe('ImageCanvasEditorView', () => {
|
||||
fields: [{ title: '生成提示词', value: '明亮主视觉' }],
|
||||
references: [],
|
||||
},
|
||||
model: 'gpt-image-2',
|
||||
model: 'GPT Image 2.5',
|
||||
task: '1',
|
||||
object: 'asset-object-visible',
|
||||
resolution: '1024 x 1024 px',
|
||||
|
||||
@@ -187,7 +187,7 @@ describe('ImageCanvasExportModel', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
model: 'gpt-image-2',
|
||||
model: 'GPT Image 2.5',
|
||||
task: '1',
|
||||
object: 'generated/layer.png',
|
||||
resolution: '1024 x 1024 px',
|
||||
@@ -268,7 +268,7 @@ describe('ImageCanvasExportModel', () => {
|
||||
],
|
||||
references: [],
|
||||
});
|
||||
expect(metadata.visible.model).toBe('gpt-image-2');
|
||||
expect(metadata.visible.model).toBe('GPT Image 2.5');
|
||||
});
|
||||
|
||||
it('builds a Spine JSON attachment timeline from image sequence frames', () => {
|
||||
|
||||
@@ -81,7 +81,7 @@ describe('ImageCanvasMetadataModalView', () => {
|
||||
within(dialog).getByText('项目资源 · resource-reference'),
|
||||
).toBeTruthy();
|
||||
expect(within(dialog).getByText('Model')).toBeTruthy();
|
||||
expect(within(dialog).getByText('gpt-image-2')).toBeTruthy();
|
||||
expect(within(dialog).getByText('GPT Image 2.5')).toBeTruthy();
|
||||
expect(within(dialog).getByText('1024 x 768 px')).toBeTruthy();
|
||||
expect(within(dialog).queryByText('Provider')).toBeNull();
|
||||
expect(within(dialog).queryByText(/VectorEngine/u)).toBeNull();
|
||||
@@ -129,7 +129,7 @@ describe('ImageCanvasMetadataModalView', () => {
|
||||
expect(within(dialog).getByText('角色抠图')).toBeTruthy();
|
||||
expect(within(dialog).queryByText('处理模型')).toBeNull();
|
||||
expect(within(dialog).getByText('Model')).toBeTruthy();
|
||||
expect(within(dialog).getByText('gpt-image-2')).toBeTruthy();
|
||||
expect(within(dialog).getByText('GPT Image 2.5')).toBeTruthy();
|
||||
expect(within(dialog).queryByText('birefnet')).toBeNull();
|
||||
expect(within(dialog).queryByText('Aliyun Matting')).toBeNull();
|
||||
expect(within(dialog).queryByText('segment-common-image')).toBeNull();
|
||||
|
||||
@@ -6,7 +6,7 @@ import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { CanvasLayer } from './ImageCanvasEditorTypes';
|
||||
import {
|
||||
IMAGE_MODEL_GPT_IMAGE_2,
|
||||
IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
IMAGE_MODEL_NANOBANANA2,
|
||||
} from './ImageCanvasGenerationModel';
|
||||
import type { UiAssetExtractionState } from './ImageCanvasUiAssetExtractionModel';
|
||||
@@ -229,11 +229,11 @@ describe('ImageCanvasUiAssetExtractionOverlayView', () => {
|
||||
fireEvent.click(
|
||||
within(screen.getByRole('menu', { name: '提取素材模型选项' })).getByRole(
|
||||
'button',
|
||||
{ name: 'gpt-image-2' },
|
||||
{ name: 'GPT Image 2.5' },
|
||||
),
|
||||
);
|
||||
|
||||
expect(onModelChange).toHaveBeenCalledWith(IMAGE_MODEL_GPT_IMAGE_2);
|
||||
expect(onModelChange).toHaveBeenCalledWith(IMAGE_MODEL_GPT_IMAGE_2_5);
|
||||
});
|
||||
|
||||
it('disables extraction submission while reference uploads are pending', () => {
|
||||
@@ -298,12 +298,12 @@ describe('ImageCanvasUiAssetExtractionOverlayView', () => {
|
||||
fireEvent.click(
|
||||
within(screen.getByRole('menu', { name: '提取素材模型选项' })).getByRole(
|
||||
'button',
|
||||
{ name: 'gpt-image-2' },
|
||||
{ name: 'GPT Image 2.5' },
|
||||
),
|
||||
);
|
||||
|
||||
expect(alertMock).toHaveBeenCalledWith(
|
||||
'当前已有 5 张参考图,gpt-image-2 最多允许 4 张,请先删除多余参考图后再切换',
|
||||
'当前已有 5 张参考图,GPT Image 2.5 最多允许 4 张,请先删除多余参考图后再切换',
|
||||
);
|
||||
expect(onModelChange).not.toHaveBeenCalled();
|
||||
expect(screen.getByRole('menu', { name: '提取素材模型选项' })).toBeTruthy();
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING,
|
||||
DEFAULT_IMAGE_MODEL,
|
||||
IMAGE_MODEL_GPT_IMAGE_2,
|
||||
IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
} from './ImageCanvasGenerationModel';
|
||||
import {
|
||||
readPerfectPixelOperations,
|
||||
@@ -622,7 +623,7 @@ function GenerationWorkflowHarness({
|
||||
status: 'idle',
|
||||
composerOpen: true,
|
||||
sourceLayerId: 'layer-source',
|
||||
imageModel: 'gpt-image-2',
|
||||
imageModel: IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '2K',
|
||||
})
|
||||
@@ -780,7 +781,7 @@ function GenerationWorkflowHarness({
|
||||
status: 'idle',
|
||||
composerOpen: true,
|
||||
generatedLayerId: 'layer-source',
|
||||
imageModel: 'gpt-image-2',
|
||||
imageModel: IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '2K',
|
||||
})
|
||||
@@ -797,7 +798,7 @@ function GenerationWorkflowHarness({
|
||||
status: 'generating',
|
||||
composerOpen: false,
|
||||
sourceLayerId: 'layer-source',
|
||||
imageModel: 'gpt-image-2',
|
||||
imageModel: IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '1K',
|
||||
})
|
||||
@@ -1241,7 +1242,7 @@ function GenerationWorkflowHarness({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
workflow.changeUiAssetExtractionModel(IMAGE_MODEL_GPT_IMAGE_2)
|
||||
workflow.changeUiAssetExtractionModel(IMAGE_MODEL_GPT_IMAGE_2_5)
|
||||
}
|
||||
>
|
||||
选择GPT提取模型
|
||||
@@ -1504,7 +1505,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
'游戏名:星海远征\n游戏分类:冒险\n一句话描述游戏:驾驶飞船探索星云',
|
||||
);
|
||||
expect(screen.getByTestId('dialog-image-options').textContent).toBe(
|
||||
'publication:gpt-image-2:9:16:1K',
|
||||
'publication:gpt-image-2.5:9:16:1K',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1522,7 +1523,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
'layer-source:idle:-',
|
||||
);
|
||||
expect(screen.getByTestId('quick-edit-image-options').textContent).toBe(
|
||||
'quick-edit:gpt-image-2:2:3:2K',
|
||||
'quick-edit:gpt-image-2.5:2:3:2K',
|
||||
);
|
||||
expect(screen.getByTestId('quick-edit-selection').textContent).toBe(
|
||||
'layer-source:none:0',
|
||||
@@ -1722,7 +1723,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
expect(generateEditorImageMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
prompt: '旧版森林场景',
|
||||
model: IMAGE_MODEL_GPT_IMAGE_2,
|
||||
model: IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
generationInputs: expect.objectContaining({
|
||||
version: 2,
|
||||
action: 'image.generate',
|
||||
@@ -1788,7 +1789,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
expect.objectContaining({
|
||||
prompt: '红发骑士',
|
||||
kind: 'character',
|
||||
model: IMAGE_MODEL_GPT_IMAGE_2,
|
||||
model: IMAGE_MODEL_GPT_IMAGE_2_5,
|
||||
referenceImageSrcs: ['resource-character-spec'],
|
||||
generationInputs: expect.objectContaining({
|
||||
version: 2,
|
||||
@@ -1880,7 +1881,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
|
||||
expect(screen.getByTestId('dialog').textContent).toBe('-');
|
||||
expect(screen.getByTestId('quick-edit-image-options').textContent).toBe(
|
||||
'quick-edit:gpt-image-2:2:3:2K',
|
||||
'quick-edit:gpt-image-2.5:2:3:2K',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1906,7 +1907,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
'generate:idle:open:-:placeholder',
|
||||
);
|
||||
expect(screen.getByTestId('dialog-image-options').textContent).toBe(
|
||||
'generate:gpt-image-2:2:3:2K',
|
||||
'generate:gpt-image-2.5:2:3:2K',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1925,7 +1926,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
'generate:idle:open:-:placeholder',
|
||||
);
|
||||
expect(screen.getByTestId('dialog-image-options').textContent).toBe(
|
||||
'generate:gpt-image-2:2:3:2K',
|
||||
'generate:gpt-image-2.5:2:3:2K',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -5131,7 +5132,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
fireEvent.click(screen.getByRole('button', { name: '框选UI素材' }));
|
||||
|
||||
expect(screen.getByTestId('ui-extraction').textContent).toBe(
|
||||
'layer-source:ellipse:1:idle:gpt-image-2',
|
||||
'layer-source:ellipse:1:idle:gpt-image-2.5',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user