244 lines
7.9 KiB
TypeScript
244 lines
7.9 KiB
TypeScript
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { queryKeys } from '../keys'
|
|
import { apiFetch } from '@/lib/api-fetch'
|
|
import {
|
|
clearTaskTargetOverlay,
|
|
upsertTaskTargetOverlay,
|
|
} from '../task-target-overlay'
|
|
import {
|
|
invalidateQueryTemplates,
|
|
requestJsonWithError,
|
|
requestTaskResponseWithError,
|
|
} from './mutation-shared'
|
|
import { resolveTaskResponse } from '@/lib/task/client'
|
|
|
|
export function useModifyProjectCharacterImage(projectId: string) {
|
|
const queryClient = useQueryClient()
|
|
const invalidateProjectAssetAndProjectData = () =>
|
|
invalidateQueryTemplates(queryClient, [
|
|
queryKeys.projectAssets.all(projectId),
|
|
queryKeys.projectData(projectId),
|
|
])
|
|
|
|
return useMutation({
|
|
mutationFn: async (params: {
|
|
characterId: string
|
|
appearanceId: string
|
|
imageIndex: number
|
|
modifyPrompt: string
|
|
extraImageUrls?: string[]
|
|
}) => {
|
|
const response = await requestTaskResponseWithError(`/api/assets/${params.characterId}/modify-render`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
scope: 'project',
|
|
kind: 'character',
|
|
projectId,
|
|
...params,
|
|
}),
|
|
}, 'Failed to modify image')
|
|
return await resolveTaskResponse(response)
|
|
},
|
|
onMutate: ({ appearanceId }) => {
|
|
upsertTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
intent: 'modify',
|
|
})
|
|
},
|
|
onError: (_error, { appearanceId }) => {
|
|
clearTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
})
|
|
},
|
|
onSettled: invalidateProjectAssetAndProjectData,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 修改项目场景图片
|
|
*/
|
|
|
|
export function useRegenerateCharacterGroup(projectId: string) {
|
|
const queryClient = useQueryClient()
|
|
const invalidateProjectAssets = () =>
|
|
invalidateQueryTemplates(queryClient, [queryKeys.projectAssets.all(projectId)])
|
|
|
|
return useMutation({
|
|
mutationFn: async ({
|
|
characterId,
|
|
appearanceId,
|
|
count,
|
|
}: {
|
|
characterId: string
|
|
appearanceId: string
|
|
count?: number
|
|
}) => {
|
|
return await requestJsonWithError(`/api/assets/${characterId}/generate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
scope: 'project',
|
|
kind: 'character',
|
|
projectId,
|
|
appearanceId,
|
|
count,
|
|
})
|
|
}, 'Failed to regenerate group')
|
|
},
|
|
onMutate: ({ appearanceId }) => {
|
|
upsertTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
intent: 'regenerate',
|
|
})
|
|
},
|
|
onError: (_error, { appearanceId }) => {
|
|
clearTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
})
|
|
},
|
|
onSettled: invalidateProjectAssets,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 重新生成单张角色图片
|
|
*/
|
|
|
|
export function useRegenerateSingleCharacterImage(projectId: string) {
|
|
const queryClient = useQueryClient()
|
|
const invalidateProjectAssets = () =>
|
|
invalidateQueryTemplates(queryClient, [queryKeys.projectAssets.all(projectId)])
|
|
|
|
return useMutation({
|
|
mutationFn: async ({
|
|
characterId,
|
|
appearanceId,
|
|
imageIndex,
|
|
}: {
|
|
characterId: string
|
|
appearanceId: string
|
|
imageIndex: number
|
|
}) => {
|
|
return await requestJsonWithError(`/api/assets/${characterId}/generate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
scope: 'project',
|
|
kind: 'character',
|
|
projectId,
|
|
appearanceId,
|
|
imageIndex,
|
|
})
|
|
}, 'Failed to regenerate image')
|
|
},
|
|
onMutate: ({ appearanceId }) => {
|
|
upsertTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
intent: 'regenerate',
|
|
})
|
|
},
|
|
onError: (_error, { appearanceId }) => {
|
|
clearTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: appearanceId,
|
|
})
|
|
},
|
|
onSettled: invalidateProjectAssets,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 重新生成场景组图片
|
|
*/
|
|
|
|
export function useUpdateProjectAppearanceDescription(projectId: string) {
|
|
const queryClient = useQueryClient()
|
|
const invalidateProjectAssets = () =>
|
|
invalidateQueryTemplates(queryClient, [queryKeys.projectAssets.all(projectId)])
|
|
|
|
return useMutation({
|
|
mutationFn: async ({
|
|
characterId,
|
|
appearanceId,
|
|
description,
|
|
descriptionIndex,
|
|
}: {
|
|
characterId: string
|
|
appearanceId: string
|
|
description: string
|
|
descriptionIndex?: number
|
|
}) => {
|
|
return await requestJsonWithError(`/api/assets/${characterId}/variants/${appearanceId}`, {
|
|
method: 'PATCH',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
scope: 'project',
|
|
kind: 'character',
|
|
projectId,
|
|
description,
|
|
descriptionIndex: typeof descriptionIndex === 'number' ? descriptionIndex : 0,
|
|
}),
|
|
}, 'Failed to update appearance description')
|
|
},
|
|
onSuccess: invalidateProjectAssets,
|
|
})
|
|
}
|
|
|
|
export function useBatchGenerateCharacterImages(projectId: string) {
|
|
const queryClient = useQueryClient()
|
|
|
|
return useMutation({
|
|
mutationFn: async (items: Array<{ characterId: string; appearanceId: string }>) => {
|
|
const results = await Promise.allSettled(
|
|
items.map(item =>
|
|
apiFetch(`/api/assets/${item.characterId}/generate`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
scope: 'project',
|
|
kind: 'character',
|
|
projectId,
|
|
appearanceId: item.appearanceId
|
|
})
|
|
})
|
|
)
|
|
)
|
|
return results
|
|
},
|
|
onMutate: (items) => {
|
|
for (const item of items) {
|
|
upsertTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: item.appearanceId,
|
|
intent: 'generate',
|
|
})
|
|
}
|
|
},
|
|
onError: (_error, items) => {
|
|
for (const item of items) {
|
|
clearTaskTargetOverlay(queryClient, {
|
|
projectId,
|
|
targetType: 'CharacterAppearance',
|
|
targetId: item.appearanceId,
|
|
})
|
|
}
|
|
},
|
|
onSettled: () => {
|
|
invalidateQueryTemplates(queryClient, [queryKeys.projectAssets.all(projectId)])
|
|
}
|
|
})
|
|
}
|