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( `${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( 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( { ...payload, kind: 'playable', }, '生成可扮演角色失败', ); return response.entity; } export async function generateRpgWorldStoryNpc(payload: { profile: CustomWorldProfile; }) { const response = await requestRpgWorldEntity( { ...payload, kind: 'story', }, '生成场景角色失败', ); return response.entity; } export async function generateRpgWorldLandmark(payload: { profile: CustomWorldProfile; }) { const response = await requestRpgWorldEntity( { ...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, };