import { TaskModal } from "@/model/task"; import { BookServiceBasic } from "../ServiceBasic/bookServiceBasic"; import { ValidateJson } from "@/define/Tools/validate"; import { BookTaskDetail } from "@/model/book/bookTaskDetail"; import { GetImageBase64 } from "@/define/Tools/image"; import { GetBaseUrl } from "@/define/Tools/common"; import axios from "axios"; import { cloneDeep, isEmpty } from "lodash"; import { VideoStatus } from "@/define/enum/video"; import { SendMessageToRenderer } from "../globalService"; import { ResponseMessageType } from "@/define/enum/softwareEnum"; import { Book } from "@/model/book/book"; import { BookBackTaskStatus, BookTaskStatus } from "@/define/enum/bookEnum"; export class LumaService { bookServiceBasic: BookServiceBasic constructor() { this.bookServiceBasic = new BookServiceBasic(); } async LumaImageToVideo(task: TaskModal.Task, gptUrl: string, gptApiKey: string): Promise { try { let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId); let lumaOptionsString = bookTaskDetail.videoMessage.lumaOptions; if (!ValidateJson(lumaOptionsString)) { throw new Error("lumaOptions参数错误,请检查"); } let lumaOptions: BookTaskDetail.lumaOptions = JSON.parse(lumaOptionsString); // console.log("lumaOptions", lumaOptions, "gptUrl", gptUrl, "gptApiKey", gptApiKey); let data: BookTaskDetail.lumaOptions = { user_prompt: lumaOptions.user_prompt, aspect_ratio: lumaOptions.aspect_ratio, loop: lumaOptions.loop, } // 是不是需要拓展提示词 if (lumaOptions.hasOwnProperty("expand_prompt")) { data.expand_prompt = lumaOptions.expand_prompt; } // 图片地址(可以不传) if (lumaOptions.hasOwnProperty("image_url")) { if (!lumaOptions.image_url.startsWith("http")) { let imageBase = await GetImageBase64(lumaOptions.image_url); data.image_url = imageBase; } else { data.image_url = lumaOptions.image_url; } } // 尾帧图片地址(可以不传) if (lumaOptions.hasOwnProperty("image_end_url") && !isEmpty(lumaOptions.image_end_url)) { if (!lumaOptions.image_end_url.startsWith("http")) { let imageBase = await GetImageBase64(lumaOptions.image_end_url); data.image_end_url = imageBase; } else { data.image_end_url = lumaOptions.image_end_url; } } // 开始请求 let baseUrl = GetBaseUrl(gptUrl); let url = baseUrl + "/luma/generations"; let res = await axios.post(url, data, { headers: { "Authorization": gptApiKey } }); // console.log("luma合成视频结果", res); let returnData = res.data; // console.log("luma合成视频结果", returnData); let id = returnData.id; // 修改数据 let videoMessage = cloneDeep(bookTaskDetail.videoMessage); videoMessage.taskId = id; videoMessage.status = VideoStatus.PROCESSING; videoMessage.messageData = JSON.stringify(returnData); delete videoMessage.id; await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage); // 返回前端数据 SendMessageToRenderer({ code: 1, id: task.bookTaskDetailId, message: "runway合成任务提交成功,正在合成中", type: ResponseMessageType.LUMA_VIDEO, data: JSON.stringify(returnData) }, task.messageName); await this.FetchLumaVideoResult(bookTaskDetail, task, id, baseUrl, gptApiKey); } catch (error) { throw new Error("Luma合成视频失败,错误信息如下:" + error.toString()); } } /** * 获取指定无水印的视频地址 * @param taskId 人任务ID * @param baseUrl baseUrl * @param gptApiKey Key * @returns */ async GetVideoUri(taskId: string, baseUrl: string, gptApiKey: string): Promise { let url = baseUrl + "/luma/generations/" + taskId + "/download_video_url"; let res = await axios.get(url, { headers: { Authorization: gptApiKey } }); let resData = res.data; // console.log("luma获取视频地址", resData); return resData.url; } /** * 循环获取数据 * @param bookTaskDetail 小说详细数据 * @param task 任务实体 * @param taskId 任务ID(合成视频的) * @param baseUrl 请求的网址 * @param gptApiKey APIKey */ async FetchLumaVideoResult(bookTaskDetail: Book.SelectBookTaskDetail, task: TaskModal.Task, taskId: string, baseUrl: string, gptApiKey: string) { while (true) { try { let url = baseUrl + "/luma/generations/" + taskId; let res = await axios.get(url, { headers: { Authorization: gptApiKey } }); // console.log("luma合成视频结果", res.data); let resData = res.data; if (resData.state == "completed") { let video_url = resData.video.download_url; if (isEmpty(video_url)) { // 完成 let vr = await this.GetVideoUri(taskId, baseUrl, gptApiKey); // console.log("luma合成视频结果", vr); video_url = vr; } // 保存数据 let videoMessage = cloneDeep(bookTaskDetail.videoMessage); delete videoMessage.id; videoMessage.status = VideoStatus.SUCCESS; videoMessage.taskId = taskId; videoMessage.videoUrl = video_url; videoMessage.messageData = JSON.stringify(resData); await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage); await this.bookServiceBasic.UpdetedBookTaskData(task.bookTaskId, { status: BookTaskStatus.IMAGE_TO_VIDEO_SUCCESS, }) await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.DONE, }) SendMessageToRenderer({ code: 1, id: bookTaskDetail.id, message: "Luma合成视频完成", type: ResponseMessageType.LUMA_VIDEO, data: JSON.stringify(resData) }, task.messageName); break; } else { if (resData.state == "pending") { // 任务再等待 let videoMessage = cloneDeep(bookTaskDetail.videoMessage); delete videoMessage.id; videoMessage.status = VideoStatus.WAIT; videoMessage.taskId = taskId; videoMessage.messageData = JSON.stringify(resData); await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage); SendMessageToRenderer({ code: 1, id: bookTaskDetail.id, message: "Luma合成视频等待中", type: ResponseMessageType.LUMA_VIDEO, data: JSON.stringify(resData) }, task.messageName); } else if (resData.state == "processing") { // 任务进行中 let videoMessage = cloneDeep(bookTaskDetail.videoMessage); delete videoMessage.id; videoMessage.status = VideoStatus.PROCESSING; videoMessage.taskId = taskId; videoMessage.messageData = JSON.stringify(resData); await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage); SendMessageToRenderer({ code: 1, id: bookTaskDetail.id, message: "Luma合成视频进行中", type: ResponseMessageType.LUMA_VIDEO, data: JSON.stringify(resData) }, task.messageName); } else { // 任务失败 let videoMessage = cloneDeep(bookTaskDetail.videoMessage); delete videoMessage.id; videoMessage.status = VideoStatus.FAIL; videoMessage.taskId = taskId; videoMessage.messageData = JSON.stringify(resData); await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage); await this.bookServiceBasic.UpdetedBookTaskData(task.bookTaskId, { status: BookTaskStatus.IMAGE_TO_VIDEO_ERROR, }) await this.bookServiceBasic.UpdateTaskStatus({ id: task.id, status: BookBackTaskStatus.FAIL, }) SendMessageToRenderer({ code: 1, id: bookTaskDetail.id, message: "Luma合成视频失败", type: ResponseMessageType.LUMA_VIDEO, data: JSON.stringify(resData) }, task.messageName); throw new Error("Luma合成视频失败,失败信息请查看API后台"); } } // 等待20秒后再次请求 await new Promise(resolve => setTimeout(resolve, 15000)); } catch (error) { throw error; } } } }