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'; import { buildRuntimeGuestAuthOptions, buildRuntimeGuestHeaders, type RuntimeGuestRequestOptions, } from '../runtimeGuestAuth'; 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, }; const WOODEN_FISH_RUNTIME_WRITE_RETRY: ApiRetryOptions = { maxRetries: 1, baseDelayMs: 120, maxDelayMs: 360, retryUnsafeMethods: true, }; type WoodenFishRuntimeRequestOptions = RuntimeGuestRequestOptions; 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, backgroundAsset: flattened.backgroundAsset ?? flattened.draft?.backgroundAsset ?? null, 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( `${WOODEN_FISH_RUNTIME_API_BASE}/works/${encodeURIComponent(profileId)}`, { method: 'GET' }, '读取敲木鱼作品详情失败', ); return normalizeWoodenFishWorkDetailResponse(response); } export async function listWoodenFishGallery() { return requestJson( `${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( `${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( `${WOODEN_FISH_WORKS_API_BASE}/${encodeURIComponent(profileId)}/publish`, { method: 'POST' }, '发布敲木鱼作品失败', ); return normalizeWoodenFishWorkMutationResponse(response); } export async function startWoodenFishRuntimeRun( profileId: string, options: WoodenFishRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); return requestJson( `${WOODEN_FISH_RUNTIME_API_BASE}/runs`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify({ profileId }), }, '启动敲木鱼运行态失败', { retry: WOODEN_FISH_RUNTIME_WRITE_RETRY, ...requestOptions, }, ); } export async function checkpointWoodenFishRun( runId: string, payload: Omit, options: WoodenFishRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); const requestPayload: WoodenFishCheckpointRunRequest = { ...payload, clientEventId: `checkpoint-${runId}-${Date.now()}`, }; return requestJson( `${WOODEN_FISH_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/checkpoint`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify(requestPayload), }, '保存敲木鱼进度失败', { retry: WOODEN_FISH_RUNTIME_WRITE_RETRY, ...requestOptions, }, ); } export async function finishWoodenFishRun( runId: string, payload: Omit, options: WoodenFishRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); const requestPayload: WoodenFishFinishRunRequest = { ...payload, clientEventId: `finish-${runId}-${Date.now()}`, }; return requestJson( `${WOODEN_FISH_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/finish`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify(requestPayload), }, '结束敲木鱼运行失败', { retry: WOODEN_FISH_RUNTIME_WRITE_RETRY, ...requestOptions, }, ); } export const woodenFishClient = { checkpointRun: checkpointWoodenFishRun, createSession: createWoodenFishCreationSession, executeAction: executeWoodenFishCreationAction, finishRun: finishWoodenFishRun, getGalleryDetail: getWoodenFishGalleryDetail, getSession: getWoodenFishCreationSession, getWorkDetail: getWoodenFishWorkDetail, listGallery: listWoodenFishGallery, publishWork: publishWoodenFishWork, startRun: startWoodenFishRuntimeRun, };