diff --git a/src/features/subject-images/model.ts b/src/features/subject-images/model.ts index c750956..715599e 100644 --- a/src/features/subject-images/model.ts +++ b/src/features/subject-images/model.ts @@ -19,6 +19,33 @@ export function coverImage(form: SubjectFormAsset): SubjectImage | undefined { return primaryImage(form.images) ?? form.images.find(image => image.status === 'completed' && image.imageUrl) } +/** 当前主体正在使用的 Identity Anchor ID。 */ +export function currentIdentityAnchorId(form: SubjectFormAsset): string | undefined { + return form.subject.identity?.images[0]?.id +} + +/** 读取形态图生成时实际使用的 Identity Anchor ID。 */ +export function imageIdentityAnchorId(image: SubjectImage | undefined): string | undefined { + if (!image?.rawJson) return undefined + try { + const raw = JSON.parse(image.rawJson) as { identityAnchorImageId?: unknown } + return typeof raw.identityAnchorImageId === 'string' ? raw.identityAnchorImageId : undefined + } catch { + return undefined + } +} + +/** + * 当前主形态图是否由旧 Identity Anchor 生成。 + * 有当前 Anchor 但旧图没有追溯 ID,也按过期处理,避免历史图片继续进入后续 Keyframe。 + */ +export function isPrimaryIdentityStale(form: SubjectFormAsset): boolean { + const anchorId = currentIdentityAnchorId(form) + const primary = primaryImage(form.images) + if (!anchorId || !primary) return false + return imageIdentityAnchorId(primary) !== anchorId +} + /** 查询发现后台仍在运行时也阻止重复提交,不只依赖本地 loading。 */ export function hasRunningImages(images: Pick[]): boolean { return images.some(image => image.status === 'pending' || image.status === 'generating')