Files
Genarrative/src/services/rpg-creation/rpgCreationAssetClient.ts

154 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ASSET_API_PATHS } from '../../editor/shared/editorApiClient';
import type {
CustomWorldLandmark,
CustomWorldNpc,
CustomWorldPlayableNpc,
CustomWorldProfile,
} from '../../types';
import type {
CustomWorldSceneImageRequest,
CustomWorldSceneImageResult,
} from '../aiTypes';
import { requestJson } from '../apiClient';
import {
generateCustomWorldCoverImage,
uploadCustomWorldCoverImage,
} from '../customWorldCoverAssetService';
import { requestRpgCreationPostJson } from './rpgCreationRequestHelpers';
const RPG_CREATION_ASSET_API_BASE = '/api/runtime/custom-world';
export type RpgCreationHistoryAssetKind = 'character_visual' | 'scene_image';
export type RpgCreationHistoryAsset = {
assetObjectId: string;
assetKind: RpgCreationHistoryAssetKind;
imageSrc: string;
ownerUserId?: string | null;
ownerLabel: string;
profileId?: string | null;
entityId?: string | null;
createdAt: string;
updatedAt: string;
};
export async function generateRpgWorldSceneImage(
payload: CustomWorldSceneImageRequest,
) {
return requestJson<CustomWorldSceneImageResult>(
`${RPG_CREATION_ASSET_API_BASE}/scene-image`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
},
'生成自定义世界场景图失败',
);
}
export async function listRpgCreationHistoryAssets(payload: {
kind: RpgCreationHistoryAssetKind;
limit?: number;
}) {
const params = new URLSearchParams({ kind: payload.kind });
if (payload.limit) {
params.set('limit', String(payload.limit));
}
const response = await requestJson<{ assets: RpgCreationHistoryAsset[] }>(
`${ASSET_API_PATHS.assetHistory}?${params.toString()}`,
{ method: 'GET' },
'读取历史素材失败',
);
return response.assets;
}
export async function generateRpgWorldSceneNpc(payload: {
profile: CustomWorldProfile;
landmarkId: string;
}) {
const response = await requestRpgCreationPostJson<{ npc: CustomWorldNpc }>(
`${RPG_CREATION_ASSET_API_BASE}/scene-npc`,
payload,
'生成场景 NPC 失败',
);
return response.npc;
}
async function requestRpgWorldEntity<T>(
payload: {
profile: CustomWorldProfile;
kind: 'playable' | 'story' | 'landmark';
},
fallbackMessage: string,
) {
return requestRpgCreationPostJson<{
kind: 'playable' | 'story' | 'landmark';
entity: T;
}>(`${RPG_CREATION_ASSET_API_BASE}/entity`, payload, fallbackMessage);
}
export async function generateRpgWorldPlayableNpc(payload: {
profile: CustomWorldProfile;
}) {
const response = await requestRpgWorldEntity<CustomWorldPlayableNpc>(
{
...payload,
kind: 'playable',
},
'生成可扮演角色失败',
);
return response.entity;
}
export async function generateRpgWorldStoryNpc(payload: {
profile: CustomWorldProfile;
}) {
const response = await requestRpgWorldEntity<CustomWorldNpc>(
{
...payload,
kind: 'story',
},
'生成场景角色失败',
);
return response.entity;
}
export async function generateRpgWorldLandmark(payload: {
profile: CustomWorldProfile;
}) {
const response = await requestRpgWorldEntity<CustomWorldLandmark>(
{
...payload,
kind: 'landmark',
},
'生成场景失败',
);
return response.entity;
}
/**
* 工作包 D 把结果页与编辑器依赖的资产请求迁入 RPG 创作域 client
* 保留封面资产服务的既有边界,不把逻辑重新塞回 `aiService.ts`。
*/
export const rpgCreationAssetClient = {
listHistoryAssets: listRpgCreationHistoryAssets,
generateSceneImage: generateRpgWorldSceneImage,
generateSceneNpc: generateRpgWorldSceneNpc,
generatePlayableNpc: generateRpgWorldPlayableNpc,
generateStoryNpc: generateRpgWorldStoryNpc,
generateLandmark: generateRpgWorldLandmark,
generateCoverImage: generateCustomWorldCoverImage,
uploadCoverImage: uploadCustomWorldCoverImage,
};
export {
generateCustomWorldCoverImage as generateRpgWorldCoverImage,
uploadCustomWorldCoverImage as uploadRpgWorldCoverImage,
};