diff --git a/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx b/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx index 83e7bcb00..b2b48f37f 100644 --- a/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx +++ b/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx @@ -3,7 +3,10 @@ import { type Dispatch, type SetStateAction } from 'react'; import { UnifiedModal } from '../common/UnifiedModal'; import { ImageCanvasBasicGenerationComposerView } from './ImageCanvasBasicGenerationComposerView'; import type { GenerateDialogState } from './ImageCanvasEditorTypes'; -import { calculateEditorImageGenerationPrice } from './ImageCanvasGenerationModel'; +import { + calculateEditorImageGenerationPrice, + IMAGE_MODEL_GPT_IMAGE_2_5, +} from './ImageCanvasGenerationModel'; type ImageCanvasEditGenerationModalViewProps = { dialog: GenerateDialogState | null; @@ -17,7 +20,7 @@ export function ImageCanvasEditGenerationModalView({ onSubmit, }: ImageCanvasEditGenerationModalViewProps) { const isOpen = dialog?.mode === 'edit' && dialog.status !== 'generating'; - const dialogImageModel = dialog?.imageModel ?? 'gpt-image-2'; + const dialogImageModel = dialog?.imageModel ?? IMAGE_MODEL_GPT_IMAGE_2_5; const dialogImageSize = dialog?.imageSize ?? '1K'; const editPrice = calculateEditorImageGenerationPrice({ kind: 'quick-edit', diff --git a/src/components/image-editor/ImageCanvasGenerationDialogModel.ts b/src/components/image-editor/ImageCanvasGenerationDialogModel.ts index 6c6a5fb0f..ef6b72ad9 100644 --- a/src/components/image-editor/ImageCanvasGenerationDialogModel.ts +++ b/src/components/image-editor/ImageCanvasGenerationDialogModel.ts @@ -43,7 +43,7 @@ import { EDITOR_IMAGE_DIMENSION_OPTIONS, EDITOR_IMAGE_MODEL_OPTIONS, formatGenerationInputValue, - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, inferEditorImageAspectRatio, inferEditorImageSizeLabel, isNormalizedCanvasGenerationInputs, @@ -426,7 +426,7 @@ export function createPublicationGenerationDialogDraft({ publicationWorkflowId: workflowId, publicationGameInfo: { ...DEFAULT_PUBLICATION_GAME_INFO }, publicationReferences: [], - imageModel: IMAGE_MODEL_GPT_IMAGE_2, + imageModel: IMAGE_MODEL_GPT_IMAGE_2_5, aspectRatio: workflow.aspectRatio, imageSize: workflow.imageSize, placeholder: { @@ -1149,7 +1149,7 @@ function createNormalizedGenerationDialogDraft({ imageModel: getNormalizedString( sourceLayer, 'model', - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, ), }), prompt, @@ -1757,7 +1757,7 @@ export function createSameSourceGenerationDialogDraft({ ...createUiDesignGenerationDialogDraft({ canvasSize, viewport, - imageModel: sourceDialog?.imageModel ?? IMAGE_MODEL_GPT_IMAGE_2, + imageModel: sourceDialog?.imageModel ?? IMAGE_MODEL_GPT_IMAGE_2_5, }), prompt, sourceLayerId: sourceLayer.id, @@ -2000,7 +2000,7 @@ export function createQuickEditGenerationDialogDraft({ assetLabel, status = 'idle', references = [], - model = IMAGE_MODEL_GPT_IMAGE_2, + model = IMAGE_MODEL_GPT_IMAGE_2_5, aspectRatio, imageSize, frame, diff --git a/src/components/image-editor/ImageCanvasGenerationModel.ts b/src/components/image-editor/ImageCanvasGenerationModel.ts index d263af996..8b6fa5273 100644 --- a/src/components/image-editor/ImageCanvasGenerationModel.ts +++ b/src/components/image-editor/ImageCanvasGenerationModel.ts @@ -44,6 +44,7 @@ import { // 中文注释:与 api-server/src/editor_generation_config.rs 保持同名模型定价语义,前端仅作为展示兜底。 export const IMAGE_MODEL_GPT_IMAGE_2 = 'gpt-image-2'; +export const IMAGE_MODEL_GPT_IMAGE_2_C = 'gpt-image-2-c'; export const IMAGE_MODEL_GPT_IMAGE_2_5 = 'gpt-image-2.5'; export const IMAGE_MODEL_NANOBANANA2 = 'gemini-3.1-flash-image-preview'; export const DEFAULT_IMAGE_MODEL = IMAGE_MODEL_NANOBANANA2; @@ -638,9 +639,23 @@ export function normalizeEditorImageModel(model: string | null | undefined) { if (IMAGE_MODEL_NANOBANANA_ALIASES.has(normalizedModel)) { return IMAGE_MODEL_NANOBANANA2; } + if ( + normalizedModel === IMAGE_MODEL_GPT_IMAGE_2 || + normalizedModel === IMAGE_MODEL_GPT_IMAGE_2_C + ) { + return IMAGE_MODEL_GPT_IMAGE_2_5; + } return normalizedModel; } +export function isLegacyEditorImageModel(model: string | null | undefined) { + const normalizedModel = model?.trim(); + return ( + normalizedModel === IMAGE_MODEL_GPT_IMAGE_2 || + normalizedModel === IMAGE_MODEL_GPT_IMAGE_2_C + ); +} + export function getEditorImageModelDisplayName( model: string | null | undefined, ) { @@ -1398,6 +1413,7 @@ export function decodeCanvasGenerationInputs( defaultAspectRatio: string; fixedAspectRatios?: readonly string[]; }) => { + const rawModel = fields.find((field) => field.id === 'model')?.value; const imageModels = EDITOR_IMAGE_MODEL_OPTIONS.map( (option) => option.value, ); @@ -1408,6 +1424,9 @@ export function decodeCanvasGenerationInputs( defaultModel, normalizeEditorImageModel, ); + if (typeof rawModel === 'string' && isLegacyEditorImageModel(rawModel)) { + addFallbackWarning(['model']); + } const dimensions = EDITOR_IMAGE_DIMENSION_OPTIONS[ model as keyof typeof EDITOR_IMAGE_DIMENSION_OPTIONS diff --git a/src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts b/src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts index 6c14a925d..7da42ab9a 100644 --- a/src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts +++ b/src/components/image-editor/ImageCanvasGenerationSubmissionModel.ts @@ -51,7 +51,7 @@ import { DEFAULT_VIDEO_WEB_SEARCH_ENABLED, EDITOR_IMAGE_DIMENSION_OPTIONS, EDITOR_IMAGE_MODEL_OPTIONS, - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, inferEditorImageAspectRatio, inferEditorImageSizeLabel, isQuickEditSupportedLayer, @@ -584,17 +584,17 @@ export function buildImageGenerationSubmissionPlan({ const basePrompt = dialog.prompt.trim() || '快速编辑图片'; const normalizedQuickEditPrompt = basePrompt; const requestedImageModel = normalizeEditorImageModel( - dialog.imageModel ?? IMAGE_MODEL_GPT_IMAGE_2, + dialog.imageModel ?? IMAGE_MODEL_GPT_IMAGE_2_5, ); const imageModel = EDITOR_IMAGE_MODEL_OPTIONS.some( (option) => option.value === requestedImageModel, ) ? requestedImageModel - : IMAGE_MODEL_GPT_IMAGE_2; + : IMAGE_MODEL_GPT_IMAGE_2_5; const dimensionOptions = EDITOR_IMAGE_DIMENSION_OPTIONS[ imageModel as keyof typeof EDITOR_IMAGE_DIMENSION_OPTIONS - ] ?? EDITOR_IMAGE_DIMENSION_OPTIONS[IMAGE_MODEL_GPT_IMAGE_2]; + ] ?? EDITOR_IMAGE_DIMENSION_OPTIONS[IMAGE_MODEL_GPT_IMAGE_2_5]; const supportedAspectRatios = dimensionOptions.aspectRatios as readonly string[]; const supportedImageSizes = @@ -852,7 +852,7 @@ export function buildImageGenerationSubmissionPlan({ } if (dialog.mode === 'ui-design') { - const imageModel = IMAGE_MODEL_GPT_IMAGE_2; + const imageModel = IMAGE_MODEL_GPT_IMAGE_2_5; const referenceImageSrcs = [ dialog.uiDesignSpecReference ? resolveImageReferenceSubmissionSource(dialog.uiDesignSpecReference) @@ -897,7 +897,7 @@ export function buildImageGenerationSubmissionPlan({ const workflow = getPublicationMaterialsWorkflow( dialog.publicationWorkflowId ?? 'publication-cover-image', ); - const imageModel = IMAGE_MODEL_GPT_IMAGE_2; + const imageModel = IMAGE_MODEL_GPT_IMAGE_2_5; const publicationPrompt = buildPublicationMaterialsPrompt(dialog.publicationGameInfo) || normalizedPrompt; diff --git a/src/components/image-editor/ImageCanvasPublicationMaterialsDemoPanelView.tsx b/src/components/image-editor/ImageCanvasPublicationMaterialsDemoPanelView.tsx index 74c491470..e9ae251f3 100644 --- a/src/components/image-editor/ImageCanvasPublicationMaterialsDemoPanelView.tsx +++ b/src/components/image-editor/ImageCanvasPublicationMaterialsDemoPanelView.tsx @@ -26,7 +26,7 @@ import { buildPublicationMaterialsPrompt, calculateEditorImageModelPrice, DEFAULT_PUBLICATION_GAME_INFO, - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, } from './ImageCanvasGenerationModel'; import type { PublicationMaterialsWorkflow } from './ImageCanvasPublicationMaterialsModel'; import { ImageCanvasReferenceSlot } from './ImageCanvasReferenceSlot'; @@ -299,10 +299,10 @@ export function ImageCanvasPublicationMaterialsDemoPanelView({ includeDimensions={false} onRememberImageModel={onRememberImageModel} hasPendingImageReferenceUploads={hasPendingImageReferenceUploads} - lockedModel={IMAGE_MODEL_GPT_IMAGE_2} + lockedModel={IMAGE_MODEL_GPT_IMAGE_2_5} optionLabelPrefix="宣发素材" cost={calculateEditorImageModelPrice( - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, workflow.imageSize, )} submitLabel="生成" diff --git a/src/components/image-editor/ImageCanvasSpecGenerationPanelView.tsx b/src/components/image-editor/ImageCanvasSpecGenerationPanelView.tsx index 877fea08a..160910e94 100644 --- a/src/components/image-editor/ImageCanvasSpecGenerationPanelView.tsx +++ b/src/components/image-editor/ImageCanvasSpecGenerationPanelView.tsx @@ -51,7 +51,7 @@ import { calculateEditorUiDesignPrice, CHARACTER_SPEC_VIEW_OPTIONS, getEditorImageModelDisplayName, - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, resolveEditorImageSizeLabel, SPEC_GENERATION_ASPECT_RATIO, SPEC_GENERATION_IMAGE_SIZE, @@ -758,9 +758,9 @@ export function ImageCanvasSpecGenerationPanelView({ includeDimensions onRememberImageModel={onRememberImageModel} hasPendingImageReferenceUploads={hasPendingImageReferenceUploads} - lockedModel={IMAGE_MODEL_GPT_IMAGE_2} + lockedModel={IMAGE_MODEL_GPT_IMAGE_2_5} cost={calculateEditorUiDesignPrice( - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, dialog.imageSize, )} submitLabel="生成" diff --git a/src/components/image-editor/useImageCanvasGenerationWorkflow.ts b/src/components/image-editor/useImageCanvasGenerationWorkflow.ts index 67341c4c6..6b2ecf8f5 100644 --- a/src/components/image-editor/useImageCanvasGenerationWorkflow.ts +++ b/src/components/image-editor/useImageCanvasGenerationWorkflow.ts @@ -99,7 +99,7 @@ import { decodeCanvasGenerationInputs, DEFAULT_IMAGE_MODEL, EDITOR_IMAGE_DIMENSION_OPTIONS, - IMAGE_MODEL_GPT_IMAGE_2, + IMAGE_MODEL_GPT_IMAGE_2_5, isCanvasGenerationDialog, isQuickEditSupportedLayer, normalizeEditorImageModel, @@ -1702,7 +1702,7 @@ export function useImageCanvasGenerationWorkflow({ const draft = createUiDesignGenerationDialogDraft({ canvasSize, viewport, - imageModel: IMAGE_MODEL_GPT_IMAGE_2, + imageModel: IMAGE_MODEL_GPT_IMAGE_2_5, }); openPlacedCanvasGenerationDialog({ ...draft,