lq1405 f17de033e1 V 3.2.2
1. 文案处理后端服务迁移(此版本之前的后端服务持续到12月1日)
2. 新增默认动图方式
3. (聚合推文)实现原创分类的图生视频(runway,luma,可灵)
4. 修复软件内配音
5. 删除旧的原创生图(原创,SD反推,MJ反推等操作在聚合推文中)
6. 导出剪映适配(视频)
7. 新增四个单句推理模式
2024-11-19 20:28:31 +08:00

230 lines
8.9 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 { 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<void> {
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<string> {
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;
}
}
}
}