forked from 77media/video-flow
592 lines
16 KiB
TypeScript
592 lines
16 KiB
TypeScript
import { post } from './request';
|
||
import { ProjectTypeEnum } from '@/app/model/enums';
|
||
import { ApiResponse } from '@/api/common';
|
||
import { BASE_URL } from './constants'
|
||
import { AITextEntity, RoleEntity, SceneEntity, ShotEntity, TagEntity, ScriptSliceEntity } from '@/app/service/domain/Entities';
|
||
|
||
// API 响应类型
|
||
interface BaseApiResponse<T> {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: T;
|
||
}
|
||
|
||
// 剧集详情数据类型
|
||
interface EpisodeDetail {
|
||
project_id: string;
|
||
name: string;
|
||
status: 'running' | 'completed';
|
||
step: 'sketch' | 'character' | 'video' | 'music' | 'final_video';
|
||
last_message: string;
|
||
data: TaskData | null;
|
||
mode: 'auto' | 'manual';
|
||
resolution: '1080p' | '4k';
|
||
}
|
||
|
||
// 任务数据类型
|
||
interface TaskData {
|
||
sketch?: Array<{
|
||
url: string;
|
||
script: string;
|
||
bg_rgb: string[];
|
||
}>;
|
||
roles?: Array<{
|
||
name: string;
|
||
url: string;
|
||
sound: string;
|
||
soundDescription: string;
|
||
roleDescription: string;
|
||
}>;
|
||
videos?: Array<{
|
||
url: string;
|
||
script: string;
|
||
audio: string;
|
||
}>;
|
||
music?: Array<{
|
||
url: string;
|
||
script: string;
|
||
name: string;
|
||
duration: string;
|
||
totalDuration: string;
|
||
isLooped: boolean;
|
||
}>;
|
||
final?: {
|
||
url: string;
|
||
};
|
||
}
|
||
|
||
// 流式数据类型
|
||
export interface StreamData {
|
||
category: 'sketch' | 'character' | 'video' | 'music' | 'final_video';
|
||
message: string;
|
||
data: any;
|
||
status: 'running' | 'completed';
|
||
total?: number;
|
||
completed?: number;
|
||
all_completed?: boolean;
|
||
}
|
||
|
||
// 场景/分镜头数据结构
|
||
export interface Scene {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
plot: string;
|
||
dialogue: string;
|
||
narration: string;
|
||
imageUrl?: string;
|
||
}
|
||
|
||
// 角色数据结构
|
||
export interface Character {
|
||
name: string;
|
||
desc: string;
|
||
}
|
||
|
||
// 剧本到分镜头提示词模型
|
||
export interface ScenePrompts {
|
||
scenes: Scene[]; // 分场景列表
|
||
characters?: Character[]; // 角色列表
|
||
summary?: string; // 剧情概要
|
||
scene?: string; // 场景描述
|
||
atmosphere?: string; // 氛围描述
|
||
episode_id?: number; // 剧集ID
|
||
total_shots?: string; // 总镜头数
|
||
}
|
||
|
||
// 剧本转分镜头请求接口
|
||
export interface ScriptToSceneRequest {
|
||
script: string;
|
||
episode_id: number;
|
||
script_id: number;
|
||
project_type: ProjectTypeEnum.SCRIPT_TO_VIDEO;
|
||
}
|
||
|
||
// 视频转分镜头请求接口
|
||
export interface VideoToSceneRequest {
|
||
video_url: string;
|
||
episode_id: number;
|
||
script_id: number;
|
||
project_type: ProjectTypeEnum.VIDEO_TO_VIDEO;
|
||
}
|
||
|
||
// 转换分镜头请求类型
|
||
export type ConvertScenePromptRequest = ScriptToSceneRequest | VideoToSceneRequest;
|
||
|
||
// 转换分镜头响应接口
|
||
export type ConvertScenePromptResponse = BaseApiResponse<ScenePrompts>;
|
||
|
||
/**
|
||
* 将剧本或视频转换为分镜头提示词
|
||
* @param request - 请求参数,根据 project_type 自动判断是剧本还是视频模式
|
||
* @returns Promise<ConvertScenePromptResponse>
|
||
*/
|
||
export const convertScenePrompt = async (
|
||
request: ConvertScenePromptRequest
|
||
): Promise<ConvertScenePromptResponse> => {
|
||
// return post<ConvertScenePromptResponse>('/video_flow/convert-scene-prompts', request);
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
resolve({
|
||
code: 0,
|
||
message: 'success',
|
||
data: {
|
||
scenes: [],
|
||
characters: [],
|
||
summary: '',
|
||
scene: '',
|
||
atmosphere: '',
|
||
episode_id: 0,
|
||
total_shots: ''
|
||
},
|
||
successful: true
|
||
});
|
||
}, 0);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 剧本转分镜头提示词
|
||
* @param script - 剧本内容
|
||
* @returns Promise<ConvertScenePromptResponse>
|
||
*/
|
||
export const convertScriptToScene = async (
|
||
script: string,
|
||
episode_id: number,
|
||
script_id: number
|
||
): Promise<ConvertScenePromptResponse> => {
|
||
return convertScenePrompt({
|
||
script,
|
||
episode_id,
|
||
script_id,
|
||
project_type: ProjectTypeEnum.SCRIPT_TO_VIDEO
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 视频转分镜头提示词
|
||
* @param video_url - 视频链接
|
||
* @returns Promise<ConvertScenePromptResponse>
|
||
*/
|
||
export const convertVideoToScene = async (
|
||
video_url: string,
|
||
episode_id: number,
|
||
script_id: number
|
||
): Promise<ConvertScenePromptResponse> => {
|
||
return convertScenePrompt({
|
||
video_url,
|
||
episode_id,
|
||
script_id,
|
||
project_type: ProjectTypeEnum.VIDEO_TO_VIDEO
|
||
});
|
||
};
|
||
|
||
// 新-获取剧集详情
|
||
export const detailScriptEpisodeNew = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/get_movie_project_detail', data);
|
||
};
|
||
|
||
// 获取 title 接口
|
||
export const getScriptTitle = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/get_movie_project_description', data);
|
||
}
|
||
|
||
// 获取 数据 全量(需轮询)
|
||
export const getRunningStreamData = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/get_status', data);
|
||
};
|
||
|
||
// 获取 脚本 接口
|
||
export const getScriptTags = async (data: { project_id: string }): Promise<any> => {
|
||
return post<any>('/movie/text_to_script_tags', data);
|
||
};
|
||
|
||
// 获取 loading-场景 接口
|
||
export const getSceneJson = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<any>('/movie/scene_json', data);
|
||
};
|
||
|
||
// 获取 loading-分镜 接口
|
||
export const getShotSketchJson = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<any>('/movie/shot_sketch_json', data);
|
||
};
|
||
|
||
// 获取 loading-视频 接口
|
||
export const getVideoJson = async (data: { project_id: string }): Promise<ApiResponse<any>> => {
|
||
return post<any>('/movie/video_json', data);
|
||
};
|
||
|
||
/**
|
||
* 重新生成角色
|
||
* @param request - 重新生成角色请求参数
|
||
* @returns Promise<ApiResponse<RoleEntity>>
|
||
*/
|
||
export const regenerateRole = async (request: {
|
||
/** 角色提示词 */
|
||
prompt: string;
|
||
/** 标签类型列表 */
|
||
tagTypes: (number | string)[];
|
||
/** 角色ID(可选,如果重新生成现有角色) */
|
||
roleId?: string;
|
||
}): Promise<ApiResponse<RoleEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/regenerate_role', request);
|
||
};
|
||
|
||
/**
|
||
* 应用角色到分镜
|
||
* @param request - 应用角色请求参数
|
||
* @returns Promise<ApiResponse<应用结果>>
|
||
*/
|
||
export const applyRoleToShots = async (request: {
|
||
/** 角色ID */
|
||
roleId: string;
|
||
/** 分镜ID列表 */
|
||
shotIds: string[];
|
||
}): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/apply_role_to_shots', request);
|
||
};
|
||
|
||
/**
|
||
* 获取角色应用到的分镜列表
|
||
* @param request - 获取角色分镜列表请求参数
|
||
* @returns Promise<ApiResponse<分镜列表>>
|
||
*/
|
||
export const getRoleShots = async (request: {
|
||
/** 角色ID */
|
||
roleId: string;
|
||
}): Promise<ApiResponse<{
|
||
/** 分镜列表 */
|
||
shots: ShotEntity[];
|
||
/** 已应用的分镜ID列表 */
|
||
appliedShotIds: string[];
|
||
}>> => {
|
||
return post<ApiResponse<any>>('/movie/get_role_shots', request);
|
||
};
|
||
|
||
/**
|
||
* 获取角色列表
|
||
* @param request - 获取角色列表请求参数
|
||
* @returns Promise<ApiResponse<角色实体列表>>
|
||
*/
|
||
export const getRoleList = async (request: {
|
||
/** 项目ID */
|
||
projectId: string;
|
||
}): Promise<ApiResponse<RoleEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_role_list', request);
|
||
};
|
||
|
||
/**
|
||
* 获取角色数据
|
||
* @param request - 获取角色数据请求参数
|
||
* @returns Promise<ApiResponse<{ AI文本数据, 标签列表 }>>
|
||
*/
|
||
export const getRoleData = async (request: {
|
||
/** 角色ID */
|
||
roleId: string;
|
||
}): Promise<ApiResponse<{
|
||
/** AI文本数据 */
|
||
text: AITextEntity;
|
||
/** 标签列表 */
|
||
tags: TagEntity[];
|
||
}>> => {
|
||
return post<ApiResponse<any>>('/movie/get_role_data', request);
|
||
};
|
||
|
||
/**
|
||
* 获取用户角色库
|
||
* @returns Promise<ApiResponse<角色实体列表>>
|
||
*/
|
||
export const getUserRoleLibrary = async (): Promise<ApiResponse<RoleEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_user_role_library', {});
|
||
};
|
||
|
||
/**
|
||
* 替换角色
|
||
* @param request - 替换角色请求参数
|
||
* @returns Promise<ApiResponse<替换结果>>
|
||
*/
|
||
export const replaceRole = async (request: {
|
||
/** 当前角色ID */
|
||
currentRoleId: string;
|
||
/** 替换的角色ID */
|
||
replaceRoleId: string;
|
||
}): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/replace_role', request);
|
||
};
|
||
|
||
|
||
/**
|
||
* 修改标签
|
||
* @param request - 修改标签请求参数
|
||
* @returns Promise<ApiResponse<修改后的标签>>
|
||
*/
|
||
export const updateTag = async (request: {
|
||
/** 标签ID */
|
||
tagId: string;
|
||
/** 新的标签内容 */
|
||
content: string|number;
|
||
}): Promise<ApiResponse<TagEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/update_tag', request);
|
||
};
|
||
|
||
/**
|
||
* 修改文案
|
||
* @param request - 修改文案请求参数
|
||
* @returns Promise<ApiResponse<修改后的文案>>
|
||
*/
|
||
export const updateText = async (request: {
|
||
/** 文案ID */
|
||
textId: string;
|
||
/** 新的文案内容 */
|
||
content: string;
|
||
}): Promise<ApiResponse<AITextEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/update_text', request);
|
||
};
|
||
|
||
/**
|
||
* 重新生成场景
|
||
* @param request - 重新生成场景请求参数
|
||
* @returns Promise<ApiResponse<重新生成的场景>>
|
||
*/
|
||
export const regenerateScene = async (request: {
|
||
/** 场景提示词 */
|
||
prompt: string;
|
||
/** 标签类型列表 */
|
||
tagTypes: (number | string)[];
|
||
/** 场景ID(可选,如果重新生成现有场景) */
|
||
sceneId?: string;
|
||
}): Promise<ApiResponse<SceneEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/regenerate_scene', request);
|
||
};
|
||
|
||
/**
|
||
* 应用场景到分镜
|
||
* @param request - 应用场景请求参数
|
||
* @returns Promise<ApiResponse<应用结果>>
|
||
*/
|
||
export const applySceneToShots = async (request: {
|
||
/** 场景ID */
|
||
sceneId: string;
|
||
/** 分镜ID列表 */
|
||
shotIds: string[];
|
||
}): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/apply_scene_to_shots', request);
|
||
};
|
||
|
||
/**
|
||
* 获取场景数据
|
||
* @param request - 获取场景数据请求参数
|
||
* @returns Promise<ApiResponse<{ AI文本数据, 标签列表 }>>
|
||
*/
|
||
export const getSceneData = async (request: {
|
||
/** 场景ID */
|
||
sceneId: string;
|
||
}): Promise<ApiResponse<{
|
||
/** AI文本数据 */
|
||
text: AITextEntity;
|
||
/** 标签列表 */
|
||
tags: TagEntity[];
|
||
}>> => {
|
||
return post<ApiResponse<any>>('/movie/get_scene_data', request);
|
||
};
|
||
|
||
/**
|
||
* 获取场景列表
|
||
* @param request - 获取场景列表请求参数
|
||
* @returns Promise<ApiResponse<场景实体列表>>
|
||
*/
|
||
export const getSceneList = async (request: {
|
||
/** 项目ID */
|
||
projectId: string;
|
||
}): Promise<ApiResponse<SceneEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_scene_list', request);
|
||
};
|
||
|
||
/**
|
||
* 获取场景应用到的分镜列表
|
||
* @param request - 获取场景分镜列表请求参数
|
||
* @returns Promise<ApiResponse<分镜列表>>
|
||
*/
|
||
export const getSceneShots = async (request: {
|
||
/** 场景ID */
|
||
sceneId: string;
|
||
}): Promise<ApiResponse<{
|
||
/** 分镜列表 */
|
||
shots: ShotEntity[];
|
||
/** 已应用的分镜ID列表 */
|
||
appliedShotIds: string[];
|
||
}>> => {
|
||
return post<ApiResponse<any>>('/movie/get_scene_shots', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜关联的角色信息列表
|
||
* @param request - 获取分镜角色信息请求参数
|
||
* @returns Promise<ApiResponse<角色实体列表>>
|
||
*/
|
||
export const getShotRoles = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<RoleEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_roles', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜关联的场景信息列表
|
||
* @param request - 获取分镜场景信息请求参数
|
||
* @returns Promise<ApiResponse<场景实体列表>>
|
||
*/
|
||
export const getShotScenes = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<SceneEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_scenes', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜详细数据
|
||
* @param request - 获取分镜数据请求参数
|
||
* @returns Promise<ApiResponse<{ AI文本数据, 标签列表 }>>
|
||
*/
|
||
export const getShotData = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<{
|
||
/** AI文本数据 */
|
||
text: AITextEntity;
|
||
/** 标签列表 */
|
||
tags: TagEntity[];
|
||
}>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_data', request);
|
||
};
|
||
|
||
/**
|
||
* 重新生成分镜
|
||
* @param request - 重新生成分镜请求参数
|
||
* @returns Promise<ApiResponse<重新生成的分镜>>
|
||
*/
|
||
export const regenerateShot = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
/** 镜头描述 */
|
||
shotPrompt: string;
|
||
/** 对话内容 */
|
||
dialogueContent: string;
|
||
/** 角色ID替换参数,格式为{oldId:string,newId:string}[] */
|
||
roleReplaceParams: { oldId: string; newId: string }[];
|
||
/** 场景ID替换参数,格式为{oldId:string,newId:string}[] */
|
||
sceneReplaceParams: { oldId: string; newId: string }[];
|
||
}): Promise<ApiResponse<ShotEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/regenerate_shot', request);
|
||
};
|
||
|
||
/**
|
||
* 修改分镜对话内容
|
||
* @param request - 修改分镜对话内容请求参数
|
||
* @returns Promise<ApiResponse<修改后的分镜>>
|
||
*/
|
||
export const updateShotContent = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
/** 新的对话内容,ContentItem数量和ID顺序不能变,只能修改content字段 */
|
||
content: Array<{
|
||
/** 角色ID */
|
||
roleId: string;
|
||
/** 对话内容 */
|
||
content: string;
|
||
}>;
|
||
}): Promise<ApiResponse<ShotEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/update_shot_content', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜列表
|
||
* @param request - 获取分镜列表请求参数
|
||
* @returns Promise<ApiResponse<分镜实体列表>>
|
||
*/
|
||
export const getShotList = async (request: {
|
||
/** 项目ID */
|
||
projectId: string;
|
||
}): Promise<ApiResponse<ShotEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_list', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜详情
|
||
* @param request - 获取分镜详情请求参数
|
||
* @returns Promise<ApiResponse<分镜实体>>
|
||
*/
|
||
export const getShotDetail = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<ShotEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_detail', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜草图数据
|
||
* @param request - 获取分镜草图数据请求参数
|
||
* @returns Promise<ApiResponse<草图数据URL>>
|
||
*/
|
||
export const getShotSketchData = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<string>> => {
|
||
return post<ApiResponse<string>>('/movie/get_shot_sketch_data', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜视频数据
|
||
* @param request - 获取分镜视频数据请求参数
|
||
* @returns Promise<ApiResponse<视频数据URL>>
|
||
*/
|
||
export const getShotVideoData = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<string>> => {
|
||
return post<ApiResponse<string>>('/movie/get_shot_video_data', request);
|
||
};
|
||
|
||
/**
|
||
* 修改分镜镜头
|
||
* @param request - 修改分镜镜头请求参数
|
||
* @returns Promise<ApiResponse<修改后的分镜>>
|
||
*/
|
||
export const updateShotShot = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
/** 新的镜头数据 */
|
||
shot: string[];
|
||
}): Promise<ApiResponse<ShotEntity>> => {
|
||
return post<ApiResponse<any>>('/movie/update_shot_shot', request);
|
||
};
|
||
|
||
/**
|
||
* 替换分镜角色
|
||
* @param request - 替换分镜角色请求参数
|
||
* @returns Promise<ApiResponse<替换结果>>
|
||
*/
|
||
export const replaceShotRole = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
/** 旧角色ID */
|
||
oldRoleId: string;
|
||
/** 新角色ID */
|
||
newRoleId: string;
|
||
}): Promise<ApiResponse<any>> => {
|
||
return post<ApiResponse<any>>('/movie/replace_shot_role', request);
|
||
};
|
||
|
||
/**
|
||
* 获取分镜视频剧本内容
|
||
* @param request - 获取分镜视频剧本请求参数
|
||
* @returns Promise<ApiResponse<剧本片段列表>>
|
||
*/
|
||
export const getShotVideoScript = async (request: {
|
||
/** 分镜ID */
|
||
shotId: string;
|
||
}): Promise<ApiResponse<ScriptSliceEntity[]>> => {
|
||
return post<ApiResponse<any>>('/movie/get_shot_video_script', request);
|
||
};
|