import { post, streamJsonPost } from "./request"; import { ProjectTypeEnum } from "@/app/model/enums"; import { ApiResponse } from "@/api/common"; import { BASE_URL } from "./constants"; import { AITextEntity, RoleEntity, SceneEntity, VideoSegmentEntity, } from "@/app/service/domain/Entities"; import { TagValueObject } from "@/app/service/domain/valueObject"; import { ContentItem, LensType, ScriptSlice, } from "@/app/service/domain/valueObject"; import { task_item, VideoSegmentEntityAdapter } from "@/app/service/adapter/oldErrAdapter"; import { VideoFlowProjectResponse, NewCharacterItem, NewCharacterListResponse, CharacterListByProjectWithHighlightResponse, CharacterUpdateAndRegenerateRequest, CharacterUpdateAndRegenerateResponse } from "./DTO/movieEdit"; import { RoleResponse } from "./DTO/movieEdit"; import { RoleRecognitionResponse } from "./DTO/movieEdit"; /** * 任务项接口定义 */ export interface TaskItem { /** 计划ID */ plan_id: string; /** 任务ID */ task_id: string; /** 任务名称 */ task_name: string; /** 任务状态 */ task_status: 'COMPLETED' | 'IN_PROGRESS' | 'PENDING' | 'FAILED'; /** 任务结果 */ task_result: { /** 数据数组 */ data?: any[]; /** 总数量 */ total_count?: number; /** 已完成数量 */ completed_count?: number; /** 剩余数量 */ remaining_count?: number; /** 进度百分比 */ progress_percentage?: number; }; /** 任务参数 */ task_params?: any; /** 任务消息 */ task_message: string; /** 创建时间 */ created_at: string; /** 更新时间 */ updated_at: string; } /** * 角色替换参数接口 */ export interface CharacterReplacement { /** 原始角色名称 */ original_name: string; /** 原始角色描述 */ original_description: string; /** 新角色名称 */ new_name: string; /** 新角色描述 */ new_description: string; } // API 响应类型 interface BaseApiResponse { 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: T; 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; /** * 将剧本或视频转换为分镜头提示词 * @param request - 请求参数,根据 project_type 自动判断是剧本还是视频模式 * @returns Promise */ export const convertScenePrompt = async ( request: ConvertScenePromptRequest ): Promise => { // return post('/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 */ export const convertScriptToScene = async ( script: string, episode_id: number, script_id: number ): Promise => { return convertScenePrompt({ script, episode_id, script_id, project_type: ProjectTypeEnum.SCRIPT_TO_VIDEO, }); }; /** * 视频转分镜头提示词 * @param video_url - 视频链接 * @returns Promise */ export const convertVideoToScene = async ( video_url: string, episode_id: number, script_id: number ): Promise => { return convertScenePrompt({ video_url, episode_id, script_id, project_type: ProjectTypeEnum.VIDEO_TO_VIDEO, }); }; // 新-获取剧集详情 export const detailScriptEpisodeNew = async (data: { project_id: string; }): Promise> => { return post("/movie/get_movie_project_detail", data); }; // 获取 title 接口 export const getScriptTitle = async (data: { project_id: string; }): Promise> => { return post>("/movie/get_movie_project_description", data); }; // 获取 数据 全量(需轮询) export const getRunningStreamData = async (data: { project_id: string; }): Promise> => { return post>("/movie/get_status", data); }; // 新增:获取项目任务列表接口 export const getProjectTaskList = async (data: { project_id: string; }): Promise> => { // 使用完整的URL,因为这个接口在不同的服务器上 const fullUrl = "https://77.smartvideo.py.qikongjian.com/task/get_project_task_list"; try { const response = await fetch(fullUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage?.getItem('token') || 'mock-token'}`, }, body: JSON.stringify(data), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error('获取任务列表失败:', error); throw error; } }; // 获取 脚本 接口 export const getScriptTags = async (data: { project_id: string; }): Promise => { return post("/movie/text_to_script_tags", data); }; // 获取 loading-场景 接口 export const getSceneJson = async (data: { project_id: string; }): Promise> => { return post("/movie/scene_json", data); }; // 获取 loading-分镜 接口 export const getShotSketchJson = async (data: { project_id: string; }): Promise> => { return post("/movie/shot_sketch_json", data); }; // 获取 loading-视频 接口 export const getVideoJson = async (data: { project_id: string; }): Promise> => { return post("/movie/video_json", data); }; /** * 重新生成角色 * @param request - 重新生成角色请求参数 * @returns Promise> */ export const regenerateRole = async (request: { /** 角色提示词 */ prompt: string; /** 标签列表 */ tagTypes: TagValueObject[]; /** 角色ID(可选,如果重新生成现有角色) */ roleId?: string; }): Promise> => { return post>("/movie/regenerate_role", request); }; /** * 应用角色到分镜 * @param request - 应用角色请求参数 * @returns Promise> */ export const applyRoleToShots = async (request: { /** 项目ID */ project_id: string; /** 分镜ID列表 */ shot_id: string; /** 角色替换参数列表 */ character_replacements: CharacterReplacement[]; /** 是否等待完成 */ wait_for_completion?: boolean; /** 数据缓存 */ character_draft: string; }): Promise> => { return post("/movie/regenerate_shot_video", request); }; /** * 获取角色应用到的分镜列表 * @param request - 获取角色分镜列表请求参数 * @returns Promise> */ export const getRoleShots = async (request: { /** 角色ID */ roleId: string; }): Promise< ApiResponse<{ /** 分镜列表 */ shots: VideoSegmentEntity[]; /** 已应用的分镜ID列表 */ appliedShotIds: string[]; }> > => { return post>("/movie/get_role_shots", request); }; /** * 获取角色列表 * @param request - 获取角色列表请求参数 * @returns Promise> */ export const getRoleList = async (request: { /** 项目ID */ projectId: string; }): Promise> => { return post>("/movie/get_role_list", request); }; /** * 获取角色数据 * @param request - 获取角色数据请求参数 * @returns Promise> */ export const getRoleData = async (request: { /** 角色ID */ roleId: string; }): Promise< ApiResponse<{ /** AI文本数据 */ text: AITextEntity; /** 标签列表 */ tags: TagValueObject[]; }> > => { return post>("/movie/get_role_data", request); }; /** * 获取用户角色库 * @returns Promise> */ export const getUserRoleLibrary = async (): Promise< ApiResponse > => { return post>("/movie/get_user_role_library", {}); }; /** * 替换角色 * @param request - 替换角色请求参数 * @returns Promise> */ export const replaceRole = async (request: { /** 当前角色ID */ currentRoleId: string; /** 替换的角色ID */ replaceRoleId: string; }): Promise> => { return post>("/movie/replace_role", request); }; /** * 修改标签 * @param request - 修改标签请求参数 * @returns Promise> */ export const updateTag = async (request: { /** 标签ID */ tagId: string; /** 新的标签内容 */ content: string | number; }): Promise> => { return post>("/movie/update_tag", request); }; /** * 修改文案 * @param request - 修改文案请求参数 * @returns Promise> */ export const updateText = async (request: { /** 文案ID */ textId: string; /** 新的文案内容 */ content: string; }): Promise> => { return post>("/movie/update_text", request); }; /** * 重新生成场景 * @param request - 重新生成场景请求参数 * @returns Promise> */ export const regenerateScene = async (request: { /** 场景提示词 */ prompt: string; /** 标签列表 */ tagTypes: TagValueObject[]; /** 场景ID(可选,如果重新生成现有场景) */ sceneId?: string; }): Promise> => { return post>("/movie/regenerate_scene", request); }; /** * 应用场景到分镜 * @param request - 应用场景请求参数 * @returns Promise> */ export const applySceneToShots = async (request: { /** 场景ID */ sceneId: string; /** 分镜ID列表 */ shotIds: string[]; }): Promise> => { return post>("/movie/apply_scene_to_shots", request); }; /** * 获取场景数据 * @param request - 获取场景数据请求参数 * @returns Promise> */ export const getSceneData = async (request: { /** 场景ID */ sceneId: string; }): Promise< ApiResponse<{ /** AI文本数据 */ text: AITextEntity; /** 标签列表 */ tags: TagValueObject[]; }> > => { return post>("/movie/get_scene_data", request); }; /** * 获取场景列表 * @param request - 获取场景列表请求参数 * @returns Promise> */ export const getSceneList = async (request: { /** 项目ID */ projectId: string; }): Promise> => { return post>("/movie/get_scene_list", request); }; /** * 获取场景应用到的分镜列表 * @param request - 获取场景分镜列表请求参数 * @returns Promise> */ export const getSceneShots = async (request: { /** 场景ID */ sceneId: string; }): Promise< ApiResponse<{ /** 分镜列表 */ shots: VideoSegmentEntity[]; /** 已应用的分镜ID列表 */ appliedShotIds: string[]; }> > => { return post>("/movie/get_scene_shots", request); }; /** * 获取分镜关联的角色信息列表 * @param request - 获取分镜角色信息请求参数 * @returns Promise> */ export const getShotRoles = async (request: { /** 分镜ID */ shotId: string; }): Promise> => { return post>("/movie/get_shot_roles", request); }; /** * 获取分镜关联的场景信息列表 * @param request - 获取分镜场景信息请求参数 * @returns Promise> */ export const getShotScenes = async (request: { /** 分镜ID */ shotId: string; }): Promise> => { return post>("/movie/get_shot_scenes", request); }; /** * 获取分镜详细数据 * @param request - 获取分镜数据请求参数 * @returns Promise> */ export const getShotData = async (request: { /** 分镜ID */ shotId: string; }): Promise< ApiResponse<{ /** AI文本数据 */ text: AITextEntity; /** 标签列表 */ tags: TagValueObject[]; }> > => { return post>("/movie/get_shot_data", request); }; /** * 重新生成分镜 * @param request - 重新生成分镜请求参数 * @returns Promise> */ export const regenerateShot = async (request: { /** 项目ID */ project_id:string; /** 分镜ID */ shot_id?: string; /** 镜头描述 */ shot_descriptions?: task_item; // /** 角色ID替换参数,格式为{oldId:string,newId:string}[] */ // roleReplaceParams?: { oldId: string; newId: string }[]; // /** 场景ID替换参数,格式为{oldId:string,newId:string}[] */ // sceneReplaceParams?: { oldId: string; newId: string }[]; }): Promise> => { return post("/movie/regenerate_shot_video", request); }; /** * 获取分镜列表 * @param request - 获取分镜列表请求参数 * @returns Promise> */ export const getShotList = async (request: { /** 项目ID */ project_id: string; }): Promise> => { return post>("/movie_cut/get_task_list", request); }; /** * 替换分镜角色 * @param request - 替换分镜角色请求参数 * @returns Promise> */ export const replaceShotRole = async (request: { /** 分镜ID */ shotId: string; /** 旧角色ID */ oldRoleId: string; /** 新角色ID */ newRoleId: string; }): Promise> => { return post>("/movie/replace_shot_role", request); }; /** * 获取分镜视频剧本内容 * @param request - 获取分镜视频剧本请求参数 * @returns Promise> */ export const getShotVideoScript = async (request: { /** 分镜ID */ shotId: string; }): Promise> => { return post>("/movie/get_shot_video_script", request); }; /** * AI生成剧本流式接口 * @param request - AI生成剧本请求参数 * @returns Promise> */ export const generateScriptStream = ( request: { /** 剧本提示词 */ text: string; }, onData: (data: any) => void ): Promise => { return new Promise((resolve, reject) => { streamJsonPost("/text_to_script/stream", request, (data) => { switch(data.status) { case 'streaming': onData(data.content); break; case 'completed': console.log('生成完成:', data.message); resolve() return; case 'error': console.error('生成失败:', data.message); reject(data.message) return; } }) }) }; /** * 应用剧本 * @param request - 应用剧本请求参数 * @returns Promise> */ export const applyScriptToShot = async (request: { /** 项目ID */ project_id: string; })=> { return post>("/movie/create_movie_project_plan_v1", request); }; /** * 获取项目剧本数据 * @param request 请求参数 */ export const getProjectScript = async (request: { /** 项目ID */ project_id: string; })=> { return post< ApiResponse<{ /** 项目id */ project_id: string; /** 生成的剧本文本 */ generated_script: string; }> >("/movie/get_generated_script_by_project_id", request); }; /** * 保存剧本 * @param request 保存剧本请求参数 * @returns Promise> */ export const saveScript = async (request: { /** 项目ID */ project_id: string; /**用户id */ user_id:string; /** 剧本文本 */ generated_script: string; }): Promise> => { return post>("/movie/update_generated_script", request); }; /** * 中断视频任务 * @returns Promise> */ export const abortVideoTask = async (request: { /** 项目ID */ project_id: string; }): Promise> => { return post("/movie/abort_video_task", request); }; export const pausePlanFlow = async (request: { /** 项目ID */ project_id: string; /** 计划ID */ plan_id: string; }): Promise> => { return post("/api/v1/video/pause", request); }; export const resumePlanFlow = async (request: { /** 项目ID */ project_id: string; /** 计划ID */ plan_id: string; }): Promise> => { return post("/api/v1/video/resume", request); }; export const createMovieProjectV1 = async (request: { /** 剧本内容 */ script: string; /** 用户ID */ user_id: string; /** 模式:automatic | manual */ mode: "automatic" | "manual"; /** 分辨率:720p | 1080p | 4k */ resolution: "720p" | "1080p" | "4k"; /** 语言 */ language: string; /** 视频时长 */ video_duration: string; }) => { return post>("/movie/create_movie_project_v1", request); }; /** * 增强剧本流式接口 * @param request - 增强剧本请求参数 * @param onData - 流式数据回调 * @returns Promise */ export const enhanceScriptStream = ( request: { /** 原始剧本文本 */ original_script: string; /** AI优化要求 */ aiOptimizing: string; }, onData: (data: any) => void ): Promise => { return new Promise((resolve, reject) => { streamJsonPost("/movie/enhance_script", request, (data) => { switch(data.status) { case 'streaming': onData(data.content); break; case 'completed': console.log('剧本增强完成:', data.message); resolve() return; case 'error': console.error('剧本增强失败:', data.message); reject(data.message) return; } }) }) }; /** * AI优化镜头内容接口 * @param request - AI优化请求参数 * @returns Promise> 优化后的镜头数据 */ export const optimizeShotContent = async (request: { /** 视频片段ID */ shotId: string; /** 用户优化需求 */ userRequirement: string; /** 镜头数据数组 */ lensData: LensType[]; }): Promise> => { return post>("/api/v1/shot/optimize_content", request); }; /** * 暂停电影项目计划 * @param request - 暂停项目请求参数 * @returns Promise> */ export const pauseMovieProjectPlan = async (request: { /** 项目ID */ project_id: string; }): Promise> => { return post("/movie/pause_movie_project_plan", request); }; /** * 继续电影项目计划 * @param request - 继续项目请求参数 * @returns Promise> */ export const resumeMovieProjectPlan = async (request: { /** 项目ID */ project_id: string; }): Promise> => { return post("/movie/resume_movie_project_plan", request); }; /** * AI优化角色描述 * @param request - AI优化角色描述请求参数 * @returns Promise> */ export const optimizeRoleDescription = async (request: { /** 角色ID */ roleId: string; /** 用户优化建议 */ userSuggestion: string; /** 角色描述文本 */ roleDescription: string; }): Promise> => { return post("/movie/optimize_role_description", request); }; /** * 更新分镜提示词数据 * @param request - 更新分镜提示词请求参数 * @returns Promise> 更新结果 */ export const updateShotPrompt = async (request: { /** 项目ID */ project_id: string; /** 分镜ID */ shot_id: string; /** 镜头描述 */ shot_descriptions: task_item; }): Promise> => { // 过滤掉第一层的空字符串字段 const filteredDesc = Object.entries(request.shot_descriptions).reduce>((acc, [key, value]) => { if (value !== '') { acc[key] = value; } return acc; }, {}); return post("/movie/update_shot_prompt", { ...request, shot_descriptions: filteredDesc }); }; /** * 人脸识别接口 * @param request - 人脸识别请求参数 * @returns Promise> 人脸识别结果 */ export const faceRecognition = async (request: { /** 项目ID */ project_id: string; /** 视频ID */ video_id: string; /** 目标图片URL */ target_image_url: string; }): Promise> => { return post("/character/face_recognition", request); }; /** * 获取所有角色列表接口 * @returns Promise> 所有角色列表 */ export const getAllCharacterList = async (request:{ user_id:string; }): Promise> => { return post>("/character/list_all", request); }; /** * 获取相似角色列表接口 * @param request - 获取相似角色请求参数 * @returns Promise> */ export const getSimilarCharacters = async (request: { /** 用户ID */ userId: string; /** 用户描述(角色描述) */ user_description: string; /** 相似度限制 */ similar_limit: number; }): Promise; /** 总数量 */ total_count: number; }>> => { return post("/character/search_and_recommend", request); }; /** * 获取项目角色列表(含高亮关键词)接口 * @param request - 项目角色列表请求参数 * @returns Promise> 项目角色列表 */ export const getCharacterListByProjectWithHighlight = async (request: { /** 项目ID */ project_id: string; /** 每个角色最多提取的高亮关键词数量 */ max_keywords?: number; }): Promise> => { return post("/character/list_by_project_with_highlight", request); }; /** * 角色更新和重新生成接口 * @param request - 角色更新和重新生成请求参数 * @returns Promise> 更新后的角色信息 */ export const updateAndRegenerateCharacter = async (request: CharacterUpdateAndRegenerateRequest) => { return post>("/character/update_and_regenerate", request); }; /** * 角色描述智能优化接口 * @param request - 角色描述优化请求参数 * @returns Promise> */ export const generateCharacterDescription = async (request: { /** 前端提供的原始文字描述 */ original_text: string; }): Promise> => { return post("/character/generate_description", request); }; /** * 批量更新视频片段状态和视频地址接口 * @param request - 批量更新视频片段请求参数 * @returns Promise> */ export const batchUpdateVideoSegments = async (request: { /** 项目ID */ project_id: string; /** 要更新的视频片段列表 */ segments: Array<{ /** 视频片段ID */ shot_id: string; /** 新的视频地址列表 */ video_urls: string[]; /** 新的状态 0:视频加载中 1:任务已完成 2:任务失败 */ status: number | null; /** 优化后的描述文本 */ optimized_description?: string; /** 关键词列表 */ keywords?: string[]; }>; }): Promise; }>> => { return post("/movie/batch_update_video_segments", request); }; /** * 获取角色在项目中的视频片段列表接口 * @param request - 获取角色视频片段请求参数 * @returns Promise> */ export const getCharacterShots = async (request: { /** 项目ID */ project_id: string; /** 角色名称 */ character_name: string; }): Promise; /** 总数量 */ total_count: number; }>> => { return post("/character/get_character_scenes", request); }; /** * 保存重新生成的角色到角色库 * @param request - 保存重新生成角色请求参数 * @returns Promise> */ export const saveRegeneratedCharacter = async (request: { /** 用户ID */ user_id: string; /** 项目ID,用于从项目脚本中提取角色信息 */ project_id: string; /** 修改前的用户名称,用于在脚本中查找对应角色 */ original_character_name: string; /** 角色描述文本 */ character_description: string; /** 角色图片URL */ character_image: string; /** 多个视频地址(支持任意数量) */ video_urls: string[]; }): Promise> => { return post("/character/save_regenerated_character", request); }; /** * 分析图片并生成描述 * @description 接收图片URL,调用AI服务分析图片并生成详细描述 * @param request - 图片分析请求参数 * @returns Promise> */ export const analyzeImageDescription = async (request: { /** 图片的URL地址,必须是有效的HTTP/HTTPS链接 */ image_url: string; }): Promise> => { return post>("/character/analyze_image_description", request); }; /** * 生成角色简介 * @description 接收图片URL,调用AI服务分析图片并生成角色简介 * @param request - 角色简介生成请求参数 * @returns Promise> */ export const generateCharacterBrief = async (request: { /** 图片的URL地址,必须是有效的HTTP/HTTPS链接 */ image_url: string; }) => { return post }>>("/movie_story/generate_character_brief", request); }; /** * 检查分镜视频状态 * @description 保存当前项目数据 * @param request - 请求参数 * @returns Promise> 保存结果 */ export const checkShotVideoStatus = async (request: { /** 项目ID */ project_id: string; }): Promise> => { return post>("/check_shot_video_status", request); }; /** * 检查分镜视频状态 * @description 保存当前项目数据 * @param request - 请求参数 * @returns Promise> 保存结果 */ export const getNewShotVideo = async (request: { /** 项目ID */ task_id: string; }): Promise> => { return post>("/movie/check_shot_video_status", request); }; /** * 智能检测修改类型并进行相应的修改操作 * @description 支持角色修改和分镜修改的自动判断与批量处理 * @param request - 请求参数 * @returns Promise> */ export const modifyCharacterOrScene = async (request: { /** 项目ID */ project_id: string; /** 新的角色库角色 */ character_id: { /** 角色ID */ character_id: string; /** 角色名称 */ name: string; }[]; /** 视频任务关联列表 */ video_tasks: Array<{ /** 生成视频的任务ID */ task_id: string; /** 该任务对应的video_id列表 */ video_ids: string[]; }>; }) => { return post; message: string; details: Record; warning: string | null; video_check_tasks: Array<{ task_id: string; video_ids: string[]; }>; video_check_started: number; }>>("/character/modify_character_or_scene", request); };