Files
Genarrative/src/services/match3d-works/match3dWorksClient.ts
高物 74fd9a33ac Increase VectorEngine timeouts and add image UI
Add VectorEngine image generation config and raise request timeouts (env + scripts) from 180000 to 1000000ms. Introduce a reusable CreativeImageInputPanel component with tests and wire up mobile keyboard-focus helpers; update generation views and related tests (CustomWorldGenerationView, BarkBattle editor, Match3D, Puzzle flows). Improve API error handling / VectorEngine request guidance (packages/shared http.ts and docs), and apply multiple backend/frontend fixes for puzzle/match3d/prompt handling. Also include extensive docs and decision-log updates describing UI/UX decisions and verification steps.
2026-05-15 02:40:59 +08:00

285 lines
7.9 KiB
TypeScript

import type {
GenerateMatch3DBackgroundImageRequest,
GenerateMatch3DBackgroundImageResponse,
GenerateMatch3DContainerImageRequest,
GenerateMatch3DContainerImageResponse,
GenerateMatch3DCoverImageRequest,
GenerateMatch3DCoverImageResponse,
GenerateMatch3DItemAssetsRequest,
GenerateMatch3DItemAssetsResponse,
GenerateMatch3DWorkTagsRequest,
GenerateMatch3DWorkTagsResponse,
Match3DWorkDetailResponse,
Match3DWorkMutationResponse,
Match3DWorksResponse,
PersistMatch3DGeneratedModelRequest,
PersistMatch3DGeneratedModelResponse,
PutMatch3DAudioAssetsRequest,
PutMatch3DWorkRequest,
} from '../../../packages/shared/src/contracts/match3dWorks';
import { type ApiRetryOptions, requestJson } from '../apiClient';
const MATCH3D_WORKS_API_BASE = '/api/creation/match3d/works';
const MATCH3D_GALLERY_API_BASE = '/api/runtime/match3d/gallery';
const VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS = 1_000_000;
const MATCH3D_WORKS_READ_RETRY: ApiRetryOptions = {
maxRetries: 1,
baseDelayMs: 120,
maxDelayMs: 360,
};
const MATCH3D_WORKS_WRITE_RETRY: ApiRetryOptions = {
maxRetries: 1,
baseDelayMs: 120,
maxDelayMs: 360,
retryUnsafeMethods: true,
};
/**
* 读取当前用户的抓大鹅作品列表。
*/
export function listMatch3DWorks() {
return requestJson<Match3DWorksResponse>(
MATCH3D_WORKS_API_BASE,
{ method: 'GET' },
'读取抓大鹅作品列表失败',
{ retry: MATCH3D_WORKS_READ_RETRY },
);
}
/**
* 读取公开抓大鹅作品列表。
*/
export function listMatch3DGallery() {
return requestJson<Match3DWorksResponse>(
MATCH3D_GALLERY_API_BASE,
{ method: 'GET' },
'读取抓大鹅广场失败',
{
retry: MATCH3D_WORKS_READ_RETRY,
skipAuth: true,
skipRefresh: true,
},
);
}
/**
* 读取抓大鹅作品详情。
*/
export function getMatch3DWorkDetail(profileId: string) {
return requestJson<Match3DWorkDetailResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}`,
{ method: 'GET' },
'读取抓大鹅作品详情失败',
{ retry: MATCH3D_WORKS_READ_RETRY },
);
}
/**
* 保存结果页可编辑字段。
*/
export function updateMatch3DWork(
profileId: string,
payload: PutMatch3DWorkRequest,
) {
return requestJson<Match3DWorkMutationResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}`,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'更新抓大鹅作品失败',
{ retry: MATCH3D_WORKS_WRITE_RETRY },
);
}
/**
* 保存抓大鹅结果页生成的素材快照。
*/
export function updateMatch3DGeneratedItemAssets(
profileId: string,
payload: PutMatch3DAudioAssetsRequest,
) {
return requestJson<Match3DWorkMutationResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/audio-assets`,
{
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'更新抓大鹅生成素材失败',
{ retry: MATCH3D_WORKS_WRITE_RETRY },
);
}
export const updateMatch3DAudioAssets = updateMatch3DGeneratedItemAssets;
/**
* 将历史外部 GLB 链接转存为抓大鹅私有模型资产;新草稿不再调用。
*/
export function persistMatch3DGeneratedModel(
profileId: string,
payload: PersistMatch3DGeneratedModelRequest,
) {
return requestJson<PersistMatch3DGeneratedModelResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/generated-models`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'保存抓大鹅历史模型失败',
{
retry: MATCH3D_WORKS_WRITE_RETRY,
timeoutMs: 240_000,
},
);
}
/**
* 生成并保存抓大鹅作品封面图。
*/
export function generateMatch3DCoverImage(
profileId: string,
payload: GenerateMatch3DCoverImageRequest,
) {
return requestJson<GenerateMatch3DCoverImageResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/cover-image`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成抓大鹅封面图失败',
{
retry: MATCH3D_WORKS_WRITE_RETRY,
timeoutMs: VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS,
},
);
}
/**
* 按画面描述重新生成并保存抓大鹅局内 UI 背景图。
*/
export function generateMatch3DBackgroundImage(
profileId: string,
payload: GenerateMatch3DBackgroundImageRequest,
) {
return requestJson<GenerateMatch3DBackgroundImageResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/background-image`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成抓大鹅背景图失败',
{
retry: MATCH3D_WORKS_WRITE_RETRY,
timeoutMs: VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS,
},
);
}
/**
* 按画面描述重新生成并保存抓大鹅局内容器形象。
*/
export function generateMatch3DContainerImage(
profileId: string,
payload: GenerateMatch3DContainerImageRequest,
) {
return requestJson<GenerateMatch3DContainerImageResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/container-image`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成抓大鹅容器形象失败',
{
retry: MATCH3D_WORKS_WRITE_RETRY,
timeoutMs: VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS,
},
);
}
/**
* 按名称批量生成抓大鹅 2D 五视角物品图片。
*/
export function generateMatch3DItemAssets(
profileId: string,
payload: GenerateMatch3DItemAssetsRequest,
) {
return requestJson<GenerateMatch3DItemAssetsResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/item-assets`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成抓大鹅物品素材失败',
{
retry: MATCH3D_WORKS_WRITE_RETRY,
timeoutMs: 20 * 60 * 1000,
},
);
}
/**
* 根据当前作品名称与题材生成发布标签。
*/
export function generateMatch3DWorkTags(
payload: GenerateMatch3DWorkTagsRequest,
) {
return requestJson<GenerateMatch3DWorkTagsResponse>(
`${MATCH3D_WORKS_API_BASE}/tags`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成抓大鹅作品标签失败',
{ retry: MATCH3D_WORKS_WRITE_RETRY },
);
}
/**
* 发布抓大鹅作品。发布门槛由后端最终确认。
*/
export function publishMatch3DWork(profileId: string) {
return requestJson<Match3DWorkMutationResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}/publish`,
{ method: 'POST' },
'发布抓大鹅作品失败',
{ retry: MATCH3D_WORKS_WRITE_RETRY },
);
}
/**
* 删除当前用户的抓大鹅作品,并返回删除后的列表。
*/
export function deleteMatch3DWork(profileId: string) {
return requestJson<Match3DWorksResponse>(
`${MATCH3D_WORKS_API_BASE}/${encodeURIComponent(profileId)}`,
{ method: 'DELETE' },
'删除抓大鹅作品失败',
{ retry: MATCH3D_WORKS_WRITE_RETRY },
);
}
export const match3dWorksClient = {
delete: deleteMatch3DWork,
generateBackgroundImage: generateMatch3DBackgroundImage,
generateContainerImage: generateMatch3DContainerImage,
generateCoverImage: generateMatch3DCoverImage,
generateItemAssets: generateMatch3DItemAssets,
generateTags: generateMatch3DWorkTags,
getDetail: getMatch3DWorkDetail,
listGallery: listMatch3DGallery,
list: listMatch3DWorks,
persistGeneratedModel: persistMatch3DGeneratedModel,
publish: publishMatch3DWork,
updateAudioAssets: updateMatch3DAudioAssets,
updateGeneratedItemAssets: updateMatch3DGeneratedItemAssets,
update: updateMatch3DWork,
};