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

192 lines
7.2 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 { cloneDeep, head, isEmpty } from "lodash";
import { RunawayModel, RunwaySeconds, VideoStatus } from "@/define/enum/video";
import { BookTaskDetail } from "@/model/book/bookTaskDetail";
import { GetImageBase64 } from "@/define/Tools/image";
import axios from "axios";
import { GetBaseUrl } from "@/define/Tools/common";
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 RunwayService {
bookServiceBasic: BookServiceBasic
constructor() {
this.bookServiceBasic = new BookServiceBasic();
}
/**
* runway合成视频
* @param task 任务
* @param gptUrl 调用地址
* @param gptApiKey Key
*/
async ImageToVideo(task: TaskModal.Task, gptUrl: string, gptApiKey: string) {
try {
let bookTaskDetail = await this.bookServiceBasic.GetBookTaskDetailDataById(task.bookTaskDetailId);
let runwayOptionsString = bookTaskDetail.videoMessage.runwayOptions;
if (!ValidateJson(runwayOptionsString)) {
throw new Error("runwayOptions参数错误请检查");
}
let runwayOptions: BookTaskDetail.RunwayOption = JSON.parse(runwayOptionsString);
// console.log("runwayOptions", runwayOptions, "gptUrl", gptUrl, "gptApiKey", gptApiKey);
// 开始调用runway做请求体
let data: BookTaskDetail.RunwayOption = {
callback_url: runwayOptions.callback_url,
image: runwayOptions.image,
model: runwayOptions.model,
prompt: runwayOptions.prompt,
options: {
seconds: runwayOptions.options.seconds ?? RunwaySeconds.TEN,
}
}
if (!isEmpty(runwayOptions.style)) {
data.style = runwayOptions.style;
}
if (runwayOptions.options.flip) {
data.options.flip = runwayOptions.options.flip;
}
if (runwayOptions.options.motion_vector && runwayOptions.options.motion_vector.isUse) {
data.options.motion_vector = {
x: runwayOptions.options.motion_vector.x,
y: runwayOptions.options.motion_vector.y,
z: runwayOptions.options.motion_vector.z,
r: runwayOptions.options.motion_vector.r,
bg_x_pan: runwayOptions.options.motion_vector.bg_x_pan,
bg_y_pan: runwayOptions.options.motion_vector.bg_y_pan,
}
}
if (runwayOptions.options.image_as_end_frame) {
data.options.image_as_end_frame = runwayOptions.options.image_as_end_frame;
}
// 单独处理image
//判断是不是本地图片还是网络图片。不是网络图片需要转为base64
let image = runwayOptions.image;
if (!image.startsWith("http")) {
let imageBase = await GetImageBase64(image);
data.image = imageBase;
}
// 开始请求
let baseUrl = GetBaseUrl(gptUrl);
let res = await axios.post(baseUrl + "/runway/pro/generate", data, {
headers: {
Authorization: gptApiKey
}
});
// console.log("runway合成视频结果", res.data);
let resData = res.data;
if (resData.code != 200) {
throw new Error(res.data.msg);
}
// 修改数据
let videoMessage = cloneDeep(bookTaskDetail.videoMessage);
videoMessage.taskId = resData.data.task_id;
videoMessage.status = VideoStatus.PROCESSING;
videoMessage.messageData = JSON.stringify(resData.data);
delete videoMessage.id;
await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(task.bookTaskDetailId, videoMessage);
resData.data.status == "" ? "0" : resData.data.status;
// 返回前端数据
SendMessageToRenderer({
code: 1,
id: task.bookTaskDetailId,
message: "runway合成任务提交成功正在合成中",
type: ResponseMessageType.RUNWAY_VIDEO,
data: JSON.stringify(resData.data)
}, task.messageName);
await this.FetchRunwayVideoResult(bookTaskDetail, task, resData.data.task_id, baseUrl, gptApiKey);
} catch (error) {
throw new Error("runway合成视频失败错误信息如下" + error.toString());
}
}
async FetchRunwayVideoResult(bookTaskDetail: Book.SelectBookTaskDetail, task: TaskModal.Task, taskId: string, baseUrl: string, gptApiKey: string) {
while (true) {
try {
let url = baseUrl + "/runway/feed";
let res = await axios.post(url, {
"task_id": taskId
}, {
headers: {
Authorization: gptApiKey
}
});
let data = res.data;
if (data.code != 200) {
throw new Error(data.msg);
}
if (data.data.status == '3') {
// 完成
let videoMessage = cloneDeep(bookTaskDetail.videoMessage);
delete videoMessage.id;
videoMessage.status = VideoStatus.SUCCESS;
videoMessage.taskId = taskId;
videoMessage.videoUrl = data.data.video_url;
videoMessage.messageData = JSON.stringify(data.data);
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: "runway合成视频完成",
type: ResponseMessageType.RUNWAY_VIDEO,
data: JSON.stringify(data.data)
}, task.messageName);
break;
} else if (data.data.status == '1') {
// 处理中
SendMessageToRenderer({
code: 1,
id: bookTaskDetail.id,
message: "runway合成视频处理中",
type: ResponseMessageType.RUNWAY_VIDEO,
data: JSON.stringify(data.data)
}, task.messageName);
} else {
// 没有完成
if (data.data.status == '2') {
// 有报错信息直接返回错误
let videoMessage = cloneDeep(bookTaskDetail.videoMessage);
delete videoMessage.id;
videoMessage.status = VideoStatus.FAIL;
videoMessage.msg = data.data.msg;
videoMessage.taskId = taskId;
videoMessage.messageData = JSON.stringify(data.data);
await this.bookServiceBasic.UpdateBookTaskDetailVideoMessage(bookTaskDetail.id, videoMessage);
SendMessageToRenderer({
code: 0,
id: bookTaskDetail.id,
message: "runway合成视频失败错误信息如下" + data.data.msg,
type: ResponseMessageType.RUNWAY_VIDEO,
data: JSON.stringify(data.data)
}, task.messageName);
throw new Error(data.data.msg);
}
}
// 等待20秒后再次请求
await new Promise(resolve => setTimeout(resolve, 20000));
} catch (e) {
throw e;
}
}
}
}