feat: add wooden fish play template
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
buildMatch3DGenerationAnchorEntries,
|
||||
buildMiniGameDraftGenerationProgress,
|
||||
buildPuzzleGenerationAnchorEntries,
|
||||
buildWoodenFishGenerationAnchorEntries,
|
||||
createMiniGameDraftGenerationState,
|
||||
type MiniGameDraftGenerationState,
|
||||
} from './miniGameDraftGenerationProgress';
|
||||
@@ -355,6 +356,55 @@ describe('miniGameDraftGenerationProgress', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('wooden fish draft generation exposes hit object and sound pipeline', () => {
|
||||
const state = createMiniGameDraftGenerationState('wooden-fish');
|
||||
|
||||
const progress = buildMiniGameDraftGenerationProgress(
|
||||
state,
|
||||
state.startedAtMs + 28_000,
|
||||
);
|
||||
|
||||
expect(progress?.steps.map((step) => step.id)).toEqual([
|
||||
'wooden-fish-draft',
|
||||
'wooden-fish-hit-object',
|
||||
'wooden-fish-hit-sound',
|
||||
'wooden-fish-write-draft',
|
||||
]);
|
||||
expect(progress?.phaseId).toBe('wooden-fish-hit-object');
|
||||
expect(progress?.phaseLabel).toBe('生成敲击物图案');
|
||||
expect(progress?.estimatedRemainingMs).toBe(272_000);
|
||||
});
|
||||
|
||||
test('wooden fish generation anchors expose hit object, sound and words', () => {
|
||||
const entries = buildWoodenFishGenerationAnchorEntries(null, {
|
||||
templateId: 'wooden-fish',
|
||||
workTitle: '每日一敲',
|
||||
workDescription: '敲一下,好事发生。',
|
||||
themeTags: ['解压'],
|
||||
hitObjectPrompt: '金色小木鱼',
|
||||
hitSoundPrompt: '清脆木鱼声',
|
||||
floatingWords: ['幸运+1', '功德+1'],
|
||||
});
|
||||
|
||||
expect(entries).toEqual([
|
||||
{
|
||||
id: 'wooden-fish-hit-object',
|
||||
label: '敲击物',
|
||||
value: '金色小木鱼',
|
||||
},
|
||||
{
|
||||
id: 'wooden-fish-hit-sound',
|
||||
label: '音效',
|
||||
value: '清脆木鱼声',
|
||||
},
|
||||
{
|
||||
id: 'wooden-fish-words',
|
||||
label: '飘字',
|
||||
value: '幸运+1、功德+1',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('puzzle generation anchors expose form payload as the display source', () => {
|
||||
const entries = buildPuzzleGenerationAnchorEntries({
|
||||
sessionId: 'puzzle-session-1',
|
||||
|
||||
@@ -16,6 +16,10 @@ import type {
|
||||
CustomWorldGenerationStep,
|
||||
} from '../../packages/shared/src/contracts/runtime';
|
||||
import type { SquareHoleSessionSnapshot } from '../../packages/shared/src/contracts/squareHoleAgent';
|
||||
import type {
|
||||
WoodenFishSessionSnapshotResponse,
|
||||
WoodenFishWorkspaceCreateRequest,
|
||||
} from '../../packages/shared/src/contracts/woodenFish';
|
||||
import type { CustomWorldStructuredAnchorEntry } from './customWorldAgentGenerationProgress';
|
||||
import type {
|
||||
CreateJumpHopSessionRequest,
|
||||
@@ -28,7 +32,8 @@ export type MiniGameDraftGenerationKind =
|
||||
| 'square-hole'
|
||||
| 'match3d'
|
||||
| 'baby-object-match'
|
||||
| 'jump-hop';
|
||||
| 'jump-hop'
|
||||
| 'wooden-fish';
|
||||
|
||||
export type MiniGameDraftGenerationPhase =
|
||||
| 'idle'
|
||||
@@ -59,6 +64,10 @@ export type MiniGameDraftGenerationPhase =
|
||||
| 'jump-hop-tile-atlas'
|
||||
| 'jump-hop-slice-tiles'
|
||||
| 'jump-hop-write-draft'
|
||||
| 'wooden-fish-draft'
|
||||
| 'wooden-fish-hit-object'
|
||||
| 'wooden-fish-hit-sound'
|
||||
| 'wooden-fish-write-draft'
|
||||
| 'puzzle-images'
|
||||
| 'puzzle-ui-background'
|
||||
| 'puzzle-select-image'
|
||||
@@ -313,6 +322,35 @@ const JUMP_HOP_STEPS = [
|
||||
|
||||
const JUMP_HOP_ESTIMATED_WAIT_MS = 5 * 60_000;
|
||||
|
||||
const WOODEN_FISH_STEPS = [
|
||||
{
|
||||
id: 'wooden-fish-draft',
|
||||
label: '整理玩法草稿',
|
||||
detail: '保存作品信息、敲击物、音效和飘字配置。',
|
||||
weight: 10,
|
||||
},
|
||||
{
|
||||
id: 'wooden-fish-hit-object',
|
||||
label: '生成敲击物图案',
|
||||
detail: '使用 image2 生成最终运行态敲击物图案。',
|
||||
weight: 48,
|
||||
},
|
||||
{
|
||||
id: 'wooden-fish-hit-sound',
|
||||
label: '准备敲击音效',
|
||||
detail: '生成或写回短促敲击音效资产。',
|
||||
weight: 30,
|
||||
},
|
||||
{
|
||||
id: 'wooden-fish-write-draft',
|
||||
label: '写入正式草稿',
|
||||
detail: '保存图案、音效、飘字和封面摘要。',
|
||||
weight: 12,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
|
||||
|
||||
const WOODEN_FISH_ESTIMATED_WAIT_MS = 5 * 60_000;
|
||||
|
||||
function clampProgress(value: number) {
|
||||
return Math.max(0, Math.min(100, Math.round(value)));
|
||||
}
|
||||
@@ -333,6 +371,9 @@ function getStepDefinitions(kind: MiniGameDraftGenerationKind) {
|
||||
if (kind === 'jump-hop') {
|
||||
return JUMP_HOP_STEPS;
|
||||
}
|
||||
if (kind === 'wooden-fish') {
|
||||
return WOODEN_FISH_STEPS;
|
||||
}
|
||||
return BIG_FISH_STEPS;
|
||||
}
|
||||
|
||||
@@ -390,8 +431,10 @@ export function createMiniGameDraftGenerationState(
|
||||
? 'match3d-work-title'
|
||||
: kind === 'baby-object-match'
|
||||
? 'baby-object-draft'
|
||||
: kind === 'jump-hop'
|
||||
? 'jump-hop-draft'
|
||||
: kind === 'jump-hop'
|
||||
? 'jump-hop-draft'
|
||||
: kind === 'wooden-fish'
|
||||
? 'wooden-fish-draft'
|
||||
: 'compile',
|
||||
startedAtMs: Date.now(),
|
||||
completedAssetCount: 0,
|
||||
@@ -481,6 +524,21 @@ function resolveJumpHopPhaseByElapsedMs(
|
||||
return 'jump-hop-draft';
|
||||
}
|
||||
|
||||
function resolveWoodenFishPhaseByElapsedMs(
|
||||
elapsedMs: number,
|
||||
): MiniGameDraftGenerationPhase {
|
||||
if (elapsedMs >= 270_000) {
|
||||
return 'wooden-fish-write-draft';
|
||||
}
|
||||
if (elapsedMs >= 185_000) {
|
||||
return 'wooden-fish-hit-sound';
|
||||
}
|
||||
if (elapsedMs >= 12_000) {
|
||||
return 'wooden-fish-hit-object';
|
||||
}
|
||||
return 'wooden-fish-draft';
|
||||
}
|
||||
|
||||
function resolvePuzzleTimelineByElapsedMs(elapsedMs: number) {
|
||||
let elapsedBeforePhase = 0;
|
||||
|
||||
@@ -566,6 +624,13 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
...state,
|
||||
phase: resolveJumpHopPhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state.kind === 'wooden-fish' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveWoodenFishPhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state;
|
||||
|
||||
const steps = getStepDefinitions(normalizedState.kind);
|
||||
@@ -597,6 +662,8 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
? 0.52
|
||||
: normalizedState.kind === 'jump-hop'
|
||||
? 0.5
|
||||
: normalizedState.kind === 'wooden-fish'
|
||||
? 0.5
|
||||
: 0;
|
||||
const overallProgress =
|
||||
normalizedState.phase === 'failed'
|
||||
@@ -630,6 +697,8 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
? '宝贝识物草稿已准备完成,可进入结果页继续发布。'
|
||||
: normalizedState.kind === 'jump-hop'
|
||||
? '跳一跳草稿已准备完成,可进入结果页试玩或发布。'
|
||||
: normalizedState.kind === 'wooden-fish'
|
||||
? '敲木鱼草稿已准备完成,可进入结果页试玩或发布。'
|
||||
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
|
||||
: activeStep.detail),
|
||||
batchLabel: activeStep.label,
|
||||
@@ -655,6 +724,8 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
)
|
||||
: normalizedState.kind === 'jump-hop'
|
||||
? Math.max(0, JUMP_HOP_ESTIMATED_WAIT_MS - elapsedMs)
|
||||
: normalizedState.kind === 'wooden-fish'
|
||||
? Math.max(0, WOODEN_FISH_ESTIMATED_WAIT_MS - elapsedMs)
|
||||
: null,
|
||||
activeStepIndex,
|
||||
steps: buildMiniGameProgressSteps(
|
||||
@@ -725,6 +796,57 @@ export function buildJumpHopGenerationAnchorEntries(
|
||||
.filter((entry) => entry.value.trim());
|
||||
}
|
||||
|
||||
export function buildWoodenFishGenerationAnchorEntries(
|
||||
session: WoodenFishSessionSnapshotResponse | null | undefined,
|
||||
formPayload: WoodenFishWorkspaceCreateRequest | null | undefined = null,
|
||||
): CustomWorldStructuredAnchorEntry[] {
|
||||
const draft = session?.draft;
|
||||
const entries: Array<MiniGameAnchorSource | null> = [
|
||||
{
|
||||
key: 'wooden-fish-hit-object',
|
||||
label: '敲击物',
|
||||
value:
|
||||
formPayload?.hitObjectPrompt?.trim() ||
|
||||
draft?.hitObjectPrompt?.trim() ||
|
||||
'',
|
||||
},
|
||||
{
|
||||
key: 'wooden-fish-hit-sound',
|
||||
label: '音效',
|
||||
value:
|
||||
formPayload?.hitSoundPrompt?.trim() ||
|
||||
draft?.hitSoundPrompt?.trim() ||
|
||||
draft?.hitSoundAsset?.prompt?.trim() ||
|
||||
'',
|
||||
},
|
||||
{
|
||||
key: 'wooden-fish-words',
|
||||
label: '飘字',
|
||||
value:
|
||||
formPayload?.floatingWords
|
||||
?.map((word) => word.trim())
|
||||
.filter(Boolean)
|
||||
.slice(0, 8)
|
||||
.join('、') ||
|
||||
draft?.floatingWords
|
||||
?.map((word) => word.trim())
|
||||
.filter(Boolean)
|
||||
.slice(0, 8)
|
||||
.join('、') ||
|
||||
'',
|
||||
},
|
||||
];
|
||||
|
||||
return entries
|
||||
.filter((entry): entry is MiniGameAnchorSource => Boolean(entry))
|
||||
.map((entry) => ({
|
||||
id: entry.key,
|
||||
label: entry.label,
|
||||
value: entry.value,
|
||||
}))
|
||||
.filter((entry) => entry.value.trim());
|
||||
}
|
||||
|
||||
export function buildPuzzleGenerationAnchorEntries(
|
||||
session: PuzzleAgentSessionSnapshot | null | undefined,
|
||||
formPayload: CreatePuzzleAgentSessionRequest | null | undefined = null,
|
||||
|
||||
24
src/services/publicWorkCode.test.ts
Normal file
24
src/services/publicWorkCode.test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import {
|
||||
buildWoodenFishPublicWorkCode,
|
||||
isSameWoodenFishPublicWorkCode,
|
||||
} from './publicWorkCode';
|
||||
|
||||
test('builds wooden fish public work codes with WF prefix', () => {
|
||||
expect(buildWoodenFishPublicWorkCode('wooden-fish-profile-1234abcd')).toBe(
|
||||
'WF-1234ABCD',
|
||||
);
|
||||
});
|
||||
|
||||
test('matches wooden fish public work codes and raw profile ids', () => {
|
||||
expect(
|
||||
isSameWoodenFishPublicWorkCode('wf-1234abcd', 'wooden-fish-profile-1234abcd'),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isSameWoodenFishPublicWorkCode(
|
||||
'wooden-fish-profile-1234abcd',
|
||||
'wooden-fish-profile-1234abcd',
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
@@ -61,6 +61,14 @@ export function buildJumpHopPublicWorkCode(profileId: string) {
|
||||
return `JH-${suffix}`;
|
||||
}
|
||||
|
||||
export function buildWoodenFishPublicWorkCode(profileId: string) {
|
||||
const normalized = normalizePublicCodeText(profileId);
|
||||
const fallback = normalized || '00000000';
|
||||
const suffix = fallback.slice(-8).padStart(8, '0');
|
||||
|
||||
return `WF-${suffix}`;
|
||||
}
|
||||
|
||||
export function isSamePuzzlePublicWorkCode(keyword: string, profileId: string) {
|
||||
const normalizedKeyword = normalizePublicCodeText(keyword);
|
||||
|
||||
@@ -142,3 +150,16 @@ export function isSameJumpHopPublicWorkCode(keyword: string, profileId: string)
|
||||
normalizedKeyword === normalizePublicCodeText(profileId)
|
||||
);
|
||||
}
|
||||
|
||||
export function isSameWoodenFishPublicWorkCode(
|
||||
keyword: string,
|
||||
profileId: string,
|
||||
) {
|
||||
const normalizedKeyword = normalizePublicCodeText(keyword);
|
||||
|
||||
return (
|
||||
normalizedKeyword ===
|
||||
normalizePublicCodeText(buildWoodenFishPublicWorkCode(profileId)) ||
|
||||
normalizedKeyword === normalizePublicCodeText(profileId)
|
||||
);
|
||||
}
|
||||
|
||||
274
src/services/wooden-fish/woodenFishClient.ts
Normal file
274
src/services/wooden-fish/woodenFishClient.ts
Normal file
@@ -0,0 +1,274 @@
|
||||
import type {
|
||||
WoodenFishActionRequest,
|
||||
WoodenFishActionResponse,
|
||||
WoodenFishCheckpointRunRequest,
|
||||
WoodenFishFinishRunRequest,
|
||||
WoodenFishGalleryCardResponse,
|
||||
WoodenFishGalleryDetailResponse,
|
||||
WoodenFishGalleryResponse,
|
||||
WoodenFishRunResponse,
|
||||
WoodenFishRuntimeRunSnapshotResponse,
|
||||
WoodenFishSessionResponse,
|
||||
WoodenFishSessionSnapshotResponse,
|
||||
WoodenFishWorkDetailResponse,
|
||||
WoodenFishWorkMutationResponse,
|
||||
WoodenFishWorkProfileResponse,
|
||||
WoodenFishWorkspaceCreateRequest,
|
||||
WoodenFishWorkSummaryResponse,
|
||||
} from '../../../packages/shared/src/contracts/woodenFish';
|
||||
import { type ApiRetryOptions, requestJson } from '../apiClient';
|
||||
import { createCreationAgentClient } from '../creation-agent';
|
||||
|
||||
const WOODEN_FISH_API_BASE = '/api/creation/wooden-fish/sessions';
|
||||
const WOODEN_FISH_WORKS_API_BASE = '/api/creation/wooden-fish/works';
|
||||
const WOODEN_FISH_RUNTIME_API_BASE = '/api/runtime/wooden-fish';
|
||||
const WOODEN_FISH_RUNTIME_READ_RETRY: ApiRetryOptions = {
|
||||
maxRetries: 1,
|
||||
baseDelayMs: 120,
|
||||
maxDelayMs: 360,
|
||||
};
|
||||
|
||||
export type {
|
||||
WoodenFishActionRequest,
|
||||
WoodenFishActionResponse,
|
||||
WoodenFishCheckpointRunRequest,
|
||||
WoodenFishFinishRunRequest,
|
||||
WoodenFishGalleryCardResponse,
|
||||
WoodenFishGalleryDetailResponse,
|
||||
WoodenFishGalleryResponse,
|
||||
WoodenFishRunResponse,
|
||||
WoodenFishRuntimeRunSnapshotResponse,
|
||||
WoodenFishSessionResponse,
|
||||
WoodenFishSessionSnapshotResponse,
|
||||
WoodenFishWorkDetailResponse,
|
||||
WoodenFishWorkMutationResponse,
|
||||
WoodenFishWorkProfileResponse,
|
||||
WoodenFishWorkspaceCreateRequest,
|
||||
};
|
||||
export type CreateWoodenFishSessionRequest = WoodenFishWorkspaceCreateRequest;
|
||||
export type WoodenFishSessionSnapshot = WoodenFishSessionSnapshotResponse;
|
||||
|
||||
const woodenFishCreationClient = createCreationAgentClient<
|
||||
WoodenFishWorkspaceCreateRequest,
|
||||
WoodenFishSessionResponse,
|
||||
WoodenFishSessionResponse,
|
||||
WoodenFishSessionSnapshotResponse,
|
||||
never,
|
||||
never,
|
||||
WoodenFishActionRequest,
|
||||
WoodenFishActionResponse
|
||||
>({
|
||||
apiBase: WOODEN_FISH_API_BASE,
|
||||
messages: {
|
||||
createSession: '创建敲木鱼共创会话失败',
|
||||
getSession: '读取敲木鱼共创会话失败',
|
||||
sendMessage: '发送敲木鱼共创消息失败',
|
||||
streamIncomplete: '敲木鱼共创消息流式结果不完整',
|
||||
executeAction: '执行敲木鱼共创操作失败',
|
||||
},
|
||||
});
|
||||
|
||||
type FlattenedWoodenFishWorkProfileResponse = Omit<
|
||||
WoodenFishWorkProfileResponse,
|
||||
'summary'
|
||||
> &
|
||||
WoodenFishWorkSummaryResponse;
|
||||
|
||||
function normalizeWoodenFishWorkProfile(
|
||||
work:
|
||||
| WoodenFishWorkProfileResponse
|
||||
| FlattenedWoodenFishWorkProfileResponse,
|
||||
): WoodenFishWorkProfileResponse {
|
||||
if ('summary' in work && work.summary) {
|
||||
return work;
|
||||
}
|
||||
|
||||
const flattened = work as FlattenedWoodenFishWorkProfileResponse;
|
||||
const summary: WoodenFishWorkProfileResponse['summary'] = {
|
||||
runtimeKind: flattened.runtimeKind,
|
||||
workId: flattened.workId,
|
||||
profileId: flattened.profileId,
|
||||
ownerUserId: flattened.ownerUserId,
|
||||
sourceSessionId: flattened.sourceSessionId ?? null,
|
||||
workTitle: flattened.workTitle,
|
||||
workDescription: flattened.workDescription,
|
||||
themeTags: flattened.themeTags,
|
||||
coverImageSrc: flattened.coverImageSrc ?? null,
|
||||
publicationStatus: flattened.publicationStatus,
|
||||
playCount: flattened.playCount,
|
||||
updatedAt: flattened.updatedAt,
|
||||
publishedAt: flattened.publishedAt ?? null,
|
||||
publishReady: flattened.publishReady,
|
||||
generationStatus: flattened.generationStatus,
|
||||
};
|
||||
|
||||
return {
|
||||
summary,
|
||||
draft: flattened.draft,
|
||||
hitObjectAsset: flattened.hitObjectAsset,
|
||||
hitSoundAsset: flattened.hitSoundAsset,
|
||||
floatingWords: flattened.floatingWords,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeWoodenFishActionResponse(
|
||||
response: WoodenFishActionResponse,
|
||||
): WoodenFishActionResponse {
|
||||
return {
|
||||
...response,
|
||||
work: response.work ? normalizeWoodenFishWorkProfile(response.work) : null,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeWoodenFishWorkDetailResponse(
|
||||
response: WoodenFishWorkDetailResponse,
|
||||
): WoodenFishWorkDetailResponse {
|
||||
return {
|
||||
...response,
|
||||
item: normalizeWoodenFishWorkProfile(response.item),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeWoodenFishWorkMutationResponse(
|
||||
response: WoodenFishWorkMutationResponse,
|
||||
): WoodenFishWorkMutationResponse {
|
||||
return {
|
||||
...response,
|
||||
item: normalizeWoodenFishWorkProfile(response.item),
|
||||
};
|
||||
}
|
||||
|
||||
export function createWoodenFishCreationSession(
|
||||
payload: WoodenFishWorkspaceCreateRequest,
|
||||
) {
|
||||
return woodenFishCreationClient.createSession(payload);
|
||||
}
|
||||
|
||||
export function getWoodenFishCreationSession(sessionId: string) {
|
||||
return woodenFishCreationClient.getSession(sessionId);
|
||||
}
|
||||
|
||||
export function executeWoodenFishCreationAction(
|
||||
sessionId: string,
|
||||
payload: WoodenFishActionRequest,
|
||||
) {
|
||||
return woodenFishCreationClient
|
||||
.executeAction(sessionId, payload)
|
||||
.then(normalizeWoodenFishActionResponse);
|
||||
}
|
||||
|
||||
export async function getWoodenFishWorkDetail(profileId: string) {
|
||||
const response = await requestJson<WoodenFishWorkDetailResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/works/${encodeURIComponent(profileId)}`,
|
||||
{ method: 'GET' },
|
||||
'读取敲木鱼作品详情失败',
|
||||
);
|
||||
return normalizeWoodenFishWorkDetailResponse(response);
|
||||
}
|
||||
|
||||
export async function listWoodenFishGallery() {
|
||||
return requestJson<WoodenFishGalleryResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/gallery`,
|
||||
{ method: 'GET' },
|
||||
'读取敲木鱼广场失败',
|
||||
{
|
||||
retry: WOODEN_FISH_RUNTIME_READ_RETRY,
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function getWoodenFishGalleryDetail(publicWorkCode: string) {
|
||||
const response = await requestJson<WoodenFishGalleryDetailResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/gallery/${encodeURIComponent(publicWorkCode)}`,
|
||||
{ method: 'GET' },
|
||||
'读取敲木鱼广场详情失败',
|
||||
{
|
||||
retry: WOODEN_FISH_RUNTIME_READ_RETRY,
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
},
|
||||
);
|
||||
return normalizeWoodenFishWorkDetailResponse(response);
|
||||
}
|
||||
|
||||
export async function publishWoodenFishWork(profileId: string) {
|
||||
const response = await requestJson<WoodenFishWorkMutationResponse>(
|
||||
`${WOODEN_FISH_WORKS_API_BASE}/${encodeURIComponent(profileId)}/publish`,
|
||||
{ method: 'POST' },
|
||||
'发布敲木鱼作品失败',
|
||||
);
|
||||
return normalizeWoodenFishWorkMutationResponse(response);
|
||||
}
|
||||
|
||||
export async function startWoodenFishRuntimeRun(profileId: string) {
|
||||
return requestJson<WoodenFishRunResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/runs`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ profileId }),
|
||||
},
|
||||
'启动敲木鱼运行态失败',
|
||||
);
|
||||
}
|
||||
|
||||
export async function checkpointWoodenFishRun(
|
||||
runId: string,
|
||||
payload: Omit<WoodenFishCheckpointRunRequest, 'clientEventId'>,
|
||||
) {
|
||||
const requestPayload: WoodenFishCheckpointRunRequest = {
|
||||
...payload,
|
||||
clientEventId: `checkpoint-${runId}-${Date.now()}`,
|
||||
};
|
||||
|
||||
return requestJson<WoodenFishRunResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/checkpoint`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestPayload),
|
||||
},
|
||||
'保存敲木鱼进度失败',
|
||||
);
|
||||
}
|
||||
|
||||
export async function finishWoodenFishRun(
|
||||
runId: string,
|
||||
payload: Omit<WoodenFishFinishRunRequest, 'clientEventId'>,
|
||||
) {
|
||||
const requestPayload: WoodenFishFinishRunRequest = {
|
||||
...payload,
|
||||
clientEventId: `finish-${runId}-${Date.now()}`,
|
||||
};
|
||||
|
||||
return requestJson<WoodenFishRunResponse>(
|
||||
`${WOODEN_FISH_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/finish`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestPayload),
|
||||
},
|
||||
'结束敲木鱼运行失败',
|
||||
);
|
||||
}
|
||||
|
||||
export const woodenFishClient = {
|
||||
checkpointRun: checkpointWoodenFishRun,
|
||||
createSession: createWoodenFishCreationSession,
|
||||
executeAction: executeWoodenFishCreationAction,
|
||||
finishRun: finishWoodenFishRun,
|
||||
getGalleryDetail: getWoodenFishGalleryDetail,
|
||||
getSession: getWoodenFishCreationSession,
|
||||
getWorkDetail: getWoodenFishWorkDetail,
|
||||
listGallery: listWoodenFishGallery,
|
||||
publishWork: publishWoodenFishWork,
|
||||
startRun: startWoodenFishRuntimeRun,
|
||||
};
|
||||
5
src/services/wooden-fish/woodenFishDefaults.ts
Normal file
5
src/services/wooden-fish/woodenFishDefaults.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const WOODEN_FISH_DEFAULT_HIT_OBJECT_SRC =
|
||||
'/wooden-fish/default-hit-object.png';
|
||||
|
||||
export const WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT =
|
||||
'默认敲击物图案,圆润木质质感,透明背景';
|
||||
Reference in New Issue
Block a user