2024-05-15 12:57:15 +08:00
|
|
|
|
const fspromises = require("fs").promises;
|
|
|
|
|
|
const { clipboard, shell, ipcRenderer } = require('electron');
|
|
|
|
|
|
const sharp = require('sharp');
|
|
|
|
|
|
const path = require("path");
|
|
|
|
|
|
const util = require('util');
|
|
|
|
|
|
const { spawn, exec } = require('child_process');
|
|
|
|
|
|
const execAsync = util.promisify(exec);
|
|
|
|
|
|
const { v4: uuidv4 } = require('uuid'); // 引入UUID库来生成唯一标识符
|
|
|
|
|
|
const EventEmitter = require('events');
|
|
|
|
|
|
import { define } from "../define/define";
|
|
|
|
|
|
import axios from "axios";
|
|
|
|
|
|
import { DEFINE_STRING } from "../define/define_string";
|
|
|
|
|
|
import { ClipDraft } from "./Public/clipDraft";
|
|
|
|
|
|
import { Tools } from "./tools";
|
|
|
|
|
|
import { PublicMethod } from "./Public/publicMethod"
|
|
|
|
|
|
import { ImageStyleDefine } from "../define/iamgeStyleDefine";
|
|
|
|
|
|
let tools = new Tools();
|
|
|
|
|
|
let pm = new PublicMethod(global);
|
2024-09-12 14:13:09 +08:00
|
|
|
|
import { FLxuAPIImageType } from '../define/enum/image'
|
2024-05-15 12:57:15 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取对应的轨道
|
|
|
|
|
|
*/
|
|
|
|
|
|
function find_draft_node(nodes, type, value) {
|
|
|
|
|
|
for (let index = 0; index < nodes.length; index++) {
|
|
|
|
|
|
let node = nodes[index];
|
|
|
|
|
|
if (node[type] == value) {
|
|
|
|
|
|
return node
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 判断文件夹是不是存在
|
|
|
|
|
|
* @param {文件夹地址} folderPath
|
|
|
|
|
|
* @returns true/false
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function isDirectory(folderPath) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const stats = await fspromises.stat(folderPath);
|
|
|
|
|
|
return stats.isDirectory();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
throw error;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 保存新的字幕
|
|
|
|
|
|
* @param {洗稿后的值} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveNewWord(value) {
|
|
|
|
|
|
let new_txt = path.join(global.config.project_path, "new_word.txt")
|
|
|
|
|
|
// 写到一个新的txt文件里面
|
|
|
|
|
|
let dataString = await tools.writeArrayToFile(value, new_txt);
|
|
|
|
|
|
clipboard.writeText(dataString);
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 提取草稿中的温馨提示,全部提取直接用
|
|
|
|
|
|
* @param {} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function GetDraftFriendlyReminder(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// console.log(value);
|
|
|
|
|
|
let draft_content_json_path = path.join(global.config.draft_path, `${value[0]}/draft_content.json`);
|
|
|
|
|
|
let old_friendly_reminder_json = await getClipSetting("friendly_reminder_setting");
|
|
|
|
|
|
// 判断当前的名称是不是存在
|
|
|
|
|
|
if (old_friendly_reminder_json.code == 0) {
|
|
|
|
|
|
throw new Error(old_friendly_reminder_json.message)
|
|
|
|
|
|
}
|
|
|
|
|
|
let filter_value = old_friendly_reminder_json.value.filter(item => item.name == value[1]);
|
|
|
|
|
|
if (filter_value.length > 0) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: "名字重复"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 开始提取
|
|
|
|
|
|
let draft_json = JSON.parse(await fspromises.readFile(draft_content_json_path));
|
|
|
|
|
|
// console.log(draft_json)
|
|
|
|
|
|
let material_animations = draft_json.materials.material_animations[0];
|
|
|
|
|
|
let texts = draft_json.materials.texts[0];
|
|
|
|
|
|
let tracks = draft_json.tracks[1];
|
|
|
|
|
|
let text_value = JSON.parse(texts.content).text;
|
|
|
|
|
|
let obj = {
|
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
|
name: value[1],
|
|
|
|
|
|
material_animations,
|
|
|
|
|
|
texts,
|
|
|
|
|
|
tracks,
|
|
|
|
|
|
text_value: text_value
|
|
|
|
|
|
}
|
|
|
|
|
|
// console.log(obj)
|
|
|
|
|
|
// 开始写入
|
|
|
|
|
|
let clip_setting_json = JSON.parse(await fspromises.readFile(define.clip_setting));
|
|
|
|
|
|
clip_setting_json.friendly_reminder_setting.push(obj);
|
|
|
|
|
|
await fspromises.writeFile(define.clip_setting, JSON.stringify(clip_setting_json));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
throw new Error(error);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 执行单张重绘的任务
|
|
|
|
|
|
* @param {执行操作的window} window
|
|
|
|
|
|
* @param {传入的值} value
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function ReGenerateImageOne(window, value) {
|
|
|
|
|
|
// console.log(value)
|
|
|
|
|
|
// 将任务加入队列
|
|
|
|
|
|
|
|
|
|
|
|
let sd_setting = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
global.requestQuene.enqueue(async () => {
|
|
|
|
|
|
let id = value[1].id;
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 请求一次
|
|
|
|
|
|
let headers = { "Accept": "application/json", "Content-Type": "application/json" };
|
|
|
|
|
|
let image_path = value[1].image;
|
|
|
|
|
|
let json_path = path.join(path.dirname(path.dirname(image_path)), "input_crop/" + value[1].name + ".json");
|
|
|
|
|
|
let json = JSON.parse(await fspromises.readFile(json_path, 'utf-8'));
|
|
|
|
|
|
|
|
|
|
|
|
let tmp_image_path = image_path.split(".png")[0] + "_tmp.png";
|
|
|
|
|
|
|
|
|
|
|
|
let image_styles = await ImageStyleDefine.getImageStyleStringByIds(value[1].image_style_list ? value[1].image_style_list : []);
|
|
|
|
|
|
|
2024-05-24 13:46:19 +08:00
|
|
|
|
let prompt = sd_setting.webui.prompt + image_styles;
|
2024-05-15 12:57:15 +08:00
|
|
|
|
// 拼接提示词
|
|
|
|
|
|
if (value[1].image_style != null) {
|
|
|
|
|
|
prompt += `((${value[1].image_style})),`;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value[1].lora != null) {
|
|
|
|
|
|
prompt += `${value[1].lora},`;
|
|
|
|
|
|
}
|
|
|
|
|
|
prompt += value[1].prompt;
|
2024-05-24 13:46:19 +08:00
|
|
|
|
|
2024-06-01 15:08:22 +08:00
|
|
|
|
|
2024-05-15 12:57:15 +08:00
|
|
|
|
let model = value[1].model;
|
|
|
|
|
|
|
|
|
|
|
|
// 判断当前是不是有开修脸修手
|
|
|
|
|
|
let ADetailer = {
|
|
|
|
|
|
args: sd_setting.adetailer
|
|
|
|
|
|
};
|
|
|
|
|
|
// 判断请求的模式
|
|
|
|
|
|
if (model == "img2img") {
|
|
|
|
|
|
let web_api = global.config.webui_api_url + 'sdapi/v1/img2img'
|
|
|
|
|
|
let sd_config = json["webui_config"];
|
|
|
|
|
|
sd_config["seed"] = -1
|
|
|
|
|
|
// 拼接后的提示词
|
|
|
|
|
|
sd_config.prompt = prompt;
|
|
|
|
|
|
let init_image = sd_config.init_images;
|
|
|
|
|
|
let im = await fspromises.readFile(init_image, 'binary');
|
|
|
|
|
|
|
|
|
|
|
|
sd_config.init_images = [new Buffer.from(im, 'binary').toString('base64')];
|
|
|
|
|
|
|
|
|
|
|
|
sd_config.denoising_strength = value[1].denoising_strength;
|
|
|
|
|
|
|
|
|
|
|
|
if (value[1].adetailer) {
|
|
|
|
|
|
let ta = {
|
|
|
|
|
|
ADetailer: ADetailer
|
|
|
|
|
|
}
|
|
|
|
|
|
sd_config.alwayson_scripts = ta;
|
|
|
|
|
|
}
|
|
|
|
|
|
sd_config.height = sd_setting.webui.height;
|
|
|
|
|
|
sd_config.width = sd_setting.webui.width;
|
|
|
|
|
|
|
|
|
|
|
|
const response = await axios.post(web_api, sd_config);
|
|
|
|
|
|
// console.log(response);
|
|
|
|
|
|
|
|
|
|
|
|
// 目前是单图出图
|
|
|
|
|
|
let images = response.data.images;
|
|
|
|
|
|
let imageData = Buffer.from(images[0].split(",", 1)[0], 'base64');
|
|
|
|
|
|
sharp(imageData)
|
|
|
|
|
|
.toFile(tmp_image_path)
|
|
|
|
|
|
.then(async () => {
|
|
|
|
|
|
// console.log("图生图成功" + image_path);
|
|
|
|
|
|
await tools.deletePngAndDeleteExifData(tmp_image_path, image_path);
|
|
|
|
|
|
window[0].win.webContents.send(DEFINE_STRING.REGENERATE_IMAGE_RETUN, { id, code: 1, type: value[2] });
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(err => {
|
|
|
|
|
|
throw new Error(err);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
} else if (model == "txt2img") {
|
|
|
|
|
|
let body = {
|
|
|
|
|
|
"prompt": prompt,
|
|
|
|
|
|
"negative_prompt": value[1].negative_prompt,
|
|
|
|
|
|
"seed": -1,
|
|
|
|
|
|
"sampler_name": value[1].sampler_name,
|
|
|
|
|
|
// 提示词相关性
|
|
|
|
|
|
"cfg_scale": json.webui_config.cfg_scale,
|
|
|
|
|
|
"width": sd_setting.webui.width,
|
|
|
|
|
|
"height": sd_setting.webui.height,
|
|
|
|
|
|
"batch_size": 1,
|
|
|
|
|
|
"n_iter": 1,
|
|
|
|
|
|
"steps": json.webui_config.steps,
|
|
|
|
|
|
"save_images": false,
|
|
|
|
|
|
}
|
|
|
|
|
|
let web_api = global.config.webui_api_url + 'sdapi/v1/txt2img'
|
|
|
|
|
|
if (value[1].adetailer) {
|
|
|
|
|
|
let ta = {
|
|
|
|
|
|
ADetailer: ADetailer
|
|
|
|
|
|
}
|
|
|
|
|
|
body.alwayson_scripts = ta;
|
|
|
|
|
|
}
|
|
|
|
|
|
const response = await axios.post(web_api, body);
|
|
|
|
|
|
// console.log(response);
|
|
|
|
|
|
|
|
|
|
|
|
// 目前是单图出图
|
|
|
|
|
|
let images = response.data.images;
|
|
|
|
|
|
let imageData = Buffer.from(images[0].split(",", 1)[0], 'base64');
|
|
|
|
|
|
sharp(imageData)
|
|
|
|
|
|
.toFile(tmp_image_path)
|
|
|
|
|
|
.then(async () => {
|
|
|
|
|
|
// // console.log("生图成功" + image_path);
|
|
|
|
|
|
await tools.deletePngAndDeleteExifData(tmp_image_path, image_path);
|
|
|
|
|
|
window[0].win.webContents.send(DEFINE_STRING.REGENERATE_IMAGE_RETUN, { id, code: 1, type: value[2] });
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(err => {
|
|
|
|
|
|
throw new Error(err);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error("SD 模式错误");
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
window[0].win.webContents.send(DEFINE_STRING.REGENERATE_IMAGE_RETUN, {
|
|
|
|
|
|
id,
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
type: value[2],
|
|
|
|
|
|
message: `Error Message ${error}`
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}, value[1].id, DEFINE_STRING.QUEUE_BATCH.SD_BACKSTEP_GENERATE_IMAGE)
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "加入队列成功"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 添加草稿
|
|
|
|
|
|
* @param {*} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function addDraft(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let clip = new ClipDraft(global, value);
|
|
|
|
|
|
let res = await clip.addDraft();
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: `An error occurred: ${error}`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
*
|
|
|
|
|
|
* @returns 返回获取的字体样式的列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function getClipSetting(style_name) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let clip_setting = JSON.parse(await fspromises.readFile(define.clip_setting));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
value: clip_setting[style_name]
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: `Error message ${error, toString()}`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取剪映的草稿字体设置
|
|
|
|
|
|
* @param {传入草稿文件夹} value
|
|
|
|
|
|
* @returns 返回样式字符串
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function getDraftTextStyle(value) {
|
|
|
|
|
|
let draft_path = path.join(global.config.draft_path, value[1].toString());
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 判断当前的名字是不是存在
|
|
|
|
|
|
let name = value[0];
|
|
|
|
|
|
// 直接保存
|
|
|
|
|
|
let clip_setting = await fspromises.readFile(define.clip_setting);
|
|
|
|
|
|
let clip_setting_json = JSON.parse(clip_setting);
|
|
|
|
|
|
let exist_style = clip_setting_json.text_style;
|
|
|
|
|
|
let isExist = false;
|
|
|
|
|
|
exist_style.forEach(item => {
|
|
|
|
|
|
if (item.name == name) {
|
|
|
|
|
|
isExist = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
if (isExist) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: "预设样式名称已存在"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let draft_config = JSON.parse(await fspromises.readFile(path.join(draft_path, 'draft_content.json')));
|
|
|
|
|
|
let text = draft_config.materials.texts[0]
|
|
|
|
|
|
let content = text.content;
|
|
|
|
|
|
let text_json = JSON.parse(content);
|
|
|
|
|
|
let style = text_json.styles;
|
|
|
|
|
|
let srt_node = find_draft_node(draft_config.tracks, "type", "text").segments[0];
|
|
|
|
|
|
let clip = srt_node.clip;
|
|
|
|
|
|
|
|
|
|
|
|
let obj = {
|
|
|
|
|
|
name: value[0],
|
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
|
style,
|
|
|
|
|
|
font_size: text.font_size,
|
|
|
|
|
|
fonts: text.fonts.length > 0 ? text.fonts[0].title : "",
|
|
|
|
|
|
style_name: text.style_name,
|
|
|
|
|
|
clip,
|
|
|
|
|
|
ratio: draft_config.canvas_config.ratio
|
|
|
|
|
|
}
|
|
|
|
|
|
let text_style = clip_setting_json.text_style;
|
|
|
|
|
|
text_style.push(obj);
|
|
|
|
|
|
await fspromises.writeFile(define.clip_setting, JSON.stringify(clip_setting_json));
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: `Error message ${error.toString()}`
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 文案对齐
|
|
|
|
|
|
* @param {分镜的数据} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function alginDraftImgToText(value) {
|
|
|
|
|
|
let draft_path = path.join(global.config.draft_path, value[0]);
|
|
|
|
|
|
let text_value = value[1];
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 读取草稿
|
|
|
|
|
|
let draft_config = await fspromises.readFile(path.join(draft_path, 'draft_content.json'));
|
|
|
|
|
|
// 获取字幕轨道
|
|
|
|
|
|
let draft_config_json = JSON.parse(draft_config);
|
|
|
|
|
|
|
|
|
|
|
|
// 所有的字幕轨道里面的数据,读取出来
|
|
|
|
|
|
// 循环的时候,判断当前字幕是不是在第一行
|
|
|
|
|
|
let srt_nodes = find_draft_node(draft_config_json.tracks, "type", "text").segments;
|
|
|
|
|
|
let img_nodes = find_draft_node(draft_config_json.tracks, "type", "video").segments;
|
|
|
|
|
|
|
|
|
|
|
|
let srt_list = [];
|
|
|
|
|
|
let srt_obj = null
|
|
|
|
|
|
let new_srt_list = []
|
|
|
|
|
|
let text_count = 0;
|
|
|
|
|
|
for (let i = 0; i < srt_nodes.length;) {
|
|
|
|
|
|
const element = srt_nodes[i];
|
|
|
|
|
|
let material_id = element.material_id;
|
|
|
|
|
|
// 获取字幕内容,里面包含样式和内容
|
|
|
|
|
|
let srt_content = JSON.parse(find_draft_node(draft_config_json.materials.texts, "id", material_id).content);
|
|
|
|
|
|
let srt_value = srt_content.text;
|
|
|
|
|
|
// console.log(srt_value)
|
|
|
|
|
|
let start_time = element.target_timerange.start;
|
|
|
|
|
|
let end_time = element.target_timerange.start + element.target_timerange.duration;
|
|
|
|
|
|
let obj = {
|
|
|
|
|
|
start_time,
|
|
|
|
|
|
end_time,
|
|
|
|
|
|
srt_value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 判断当前字幕是不是在当前句
|
|
|
|
|
|
if (tools.removePunctuationIncludingEllipsis(value[1][text_count]).includes(tools.removePunctuationIncludingEllipsis(srt_value))) {
|
|
|
|
|
|
if (srt_obj == null) {
|
|
|
|
|
|
srt_obj = {}
|
|
|
|
|
|
srt_obj.start_time = start_time;
|
|
|
|
|
|
srt_obj.value = srt_value;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
srt_obj.value = srt_obj.value + srt_value;
|
|
|
|
|
|
}
|
|
|
|
|
|
srt_list.push(obj);
|
|
|
|
|
|
i++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
srt_obj.end_time = srt_list[srt_list.length - 1].end_time;
|
|
|
|
|
|
text_count++;
|
|
|
|
|
|
new_srt_list.push(srt_obj)
|
|
|
|
|
|
srt_obj = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 最后要和音频对齐
|
|
|
|
|
|
srt_obj.end_time = srt_list[srt_list.length - 1].end_time
|
|
|
|
|
|
let audio_nodes = find_draft_node(draft_config_json.tracks, "type", "audio");
|
|
|
|
|
|
if (audio_nodes != null) {
|
|
|
|
|
|
let endTime = audio_nodes.segments[0].target_timerange.duration;
|
|
|
|
|
|
srt_obj.end_time = endTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
new_srt_list.push(srt_obj)
|
|
|
|
|
|
|
|
|
|
|
|
// 开始对齐
|
|
|
|
|
|
for (let i = 0; i < new_srt_list.length; i++) {
|
|
|
|
|
|
if (img_nodes.length < i) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (i == 96) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
const element = new_srt_list[i];
|
|
|
|
|
|
let duration = 0;
|
|
|
|
|
|
if (i + 1 < new_srt_list.length) {
|
|
|
|
|
|
duration = new_srt_list[i + 1].start_time - element.start_time - 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
duration = element.end_time - element.start_time;
|
|
|
|
|
|
}
|
|
|
|
|
|
img_nodes[i].source_timerange.duration = duration;
|
|
|
|
|
|
img_nodes[i].target_timerange.duration = duration;
|
|
|
|
|
|
img_nodes[i].target_timerange.start = element.start_time;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let draft_config_string = JSON.stringify(draft_config_json);
|
|
|
|
|
|
await fspromises.writeFile(path.join(draft_path, 'draft_content.json'), draft_config_string);
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
// console.log(error)
|
|
|
|
|
|
return define.error = {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: `error message ${error}`
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let pyrunner;
|
|
|
|
|
|
|
|
|
|
|
|
function createPythonRunner(mainWindow, define) {
|
|
|
|
|
|
if (!pyrunner) {
|
|
|
|
|
|
pyrunner = new func.PythonRunner(mainWindow, define);
|
|
|
|
|
|
}
|
|
|
|
|
|
return pyrunner;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 执行剪映图片对齐脚本
|
|
|
|
|
|
*/
|
|
|
|
|
|
function alignDraftImage(mainWindow, value) {
|
|
|
|
|
|
pyrunner = createPythonRunner(mainWindow, define);
|
|
|
|
|
|
let draft_path = path.join(global.config.draft_path, value)
|
|
|
|
|
|
pyrunner.runScript(path.join(define.scripts_path, "03_align_draft_image.py"), [draft_path])
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 抽取关键帧
|
|
|
|
|
|
* @param {窗口} mainWindow
|
|
|
|
|
|
* @param {数组,第一个值为剪映草稿位置,第二个值为,输出目录} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function getFrame(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// let scriptPath = path.join(define.scripts_path, '00_clip.py');
|
|
|
|
|
|
// // 执行生成图片的脚本
|
|
|
|
|
|
// let script = `cd ${define.scripts_path} && python ${scriptPath} "${project_config_path}"`;
|
|
|
|
|
|
let draft_path = path.join(global.config.draft_path, value[0]).replaceAll("\\", "/");
|
|
|
|
|
|
let out_dir = path.join(value[1]).replaceAll("\\", "/")
|
|
|
|
|
|
let package_path = define.package_path.replaceAll("\\", "/");
|
|
|
|
|
|
// let command = `${path.join(define.scripts_path, "05_getgrame.exe")} "${draft_path}" "${out_dir}" "${package_path}"`
|
|
|
|
|
|
let command = `"${path.join(define.scripts_path, "Lai.exe")}" -k "${draft_path}" "${out_dir}" "${package_path}"`
|
|
|
|
|
|
const output = await execAsync(command, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' });
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "剪映关键帧抽取成功"
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: output.stdout
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 反推调用脚本的方法
|
|
|
|
|
|
* @param {调用的窗口} win
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function PushBackPrompt() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let py_path = path.join(define.scripts_path, "Lai.exe");
|
|
|
|
|
|
let sd_config_path = define.sd_setting;
|
|
|
|
|
|
let script = `cd "${define.scripts_path}" && "${py_path}" -p "${sd_config_path.replaceAll('\\', '/')}" "input" "${global.config.project_path}"`;
|
|
|
|
|
|
const output = await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' });
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "反推成功"
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
data: output.stdout
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: "反推错误。详情请见错误信息!"
|
|
|
|
|
|
})
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 执行Python脚本的类,包括了对python脚本的监听
|
|
|
|
|
|
*/
|
|
|
|
|
|
class PythonRunner extends EventEmitter {
|
|
|
|
|
|
constructor(mainWindow, define) {
|
|
|
|
|
|
super();
|
|
|
|
|
|
this.mainWindow = mainWindow;
|
|
|
|
|
|
this.define = define;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
runScript(scriptPath, args = []) {
|
|
|
|
|
|
const pythonProcess = spawn('python', [scriptPath, ...args]);
|
|
|
|
|
|
|
|
|
|
|
|
// 监听Python脚本的标准输出
|
|
|
|
|
|
pythonProcess.stdout.on('data', (data) => {
|
|
|
|
|
|
// console.log(data.toString("utf-8"))
|
|
|
|
|
|
this.mainWindow.webContents.send(DEFINE_STRING.PYTHON_OUTPUT, data.toString("utf-8"));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听Python脚本的标准错误输出
|
|
|
|
|
|
pythonProcess.stderr.on('data', (data) => {
|
|
|
|
|
|
this.mainWindow.webContents.send(DEFINE_STRING.PYTHON_OUTPUT, data.toString("utf-8"));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听子进程关闭事件
|
|
|
|
|
|
pythonProcess.on('close', (code) => {
|
|
|
|
|
|
let closeMessage = `Python script exited with code ${code}`;
|
|
|
|
|
|
// console.log(closeMessage);
|
|
|
|
|
|
this.mainWindow.webContents.send(DEFINE_STRING.PYTHON_CLOSE, closeMessage);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听子进程错误事件
|
|
|
|
|
|
pythonProcess.on('error', (err) => {
|
|
|
|
|
|
let errorMessage = `Python script error: ${err}`;
|
|
|
|
|
|
this.mainWindow.webContents.send(DEFINE_STRING.PYTHON_OUTPUT, errorMessage);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 判断当前文件夹下面的所有文件夹
|
|
|
|
|
|
* @param {需要获取的文件地址} srcPath
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function getDirectories(srcPath) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const filesAndDirectories = await fspromises.readdir(srcPath, { withFileTypes: true });
|
|
|
|
|
|
const directories = filesAndDirectories
|
|
|
|
|
|
.filter(dirent => dirent.isDirectory())
|
|
|
|
|
|
.map(dirent => fspromises.stat(path.join(srcPath, dirent.name)));
|
|
|
|
|
|
|
|
|
|
|
|
const directoryStats = await Promise.all(directories);
|
|
|
|
|
|
// 将目录和它们的状态对象组合成一个数组
|
|
|
|
|
|
const directoriesWithStats = filesAndDirectories
|
|
|
|
|
|
.filter(dirent => dirent.isDirectory())
|
|
|
|
|
|
.map((dirent, index) => ({
|
|
|
|
|
|
name: dirent.name,
|
|
|
|
|
|
ctime: directoryStats[index].ctime
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// 按创建时间排序,最新的在前
|
|
|
|
|
|
directoriesWithStats.sort((a, b) => b.ctime - a.ctime);
|
|
|
|
|
|
|
|
|
|
|
|
// 提取排序后的目录名称
|
|
|
|
|
|
const sortedDirectories = directoriesWithStats.map(dirent => dirent.name);
|
|
|
|
|
|
return sortedDirectories;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error reading directories:', error);
|
|
|
|
|
|
throw error; // 或者根据需要处理错误
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 读取剪映草稿列表
|
|
|
|
|
|
* @returns 返回剪映草稿列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function getDraftFileList() {
|
|
|
|
|
|
let draft_path = global.config.draft_path
|
|
|
|
|
|
let res = await getDirectories(draft_path)
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改SD配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveSDConfig(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let sd_config = JSON.parse((await fspromises.readFile(define.sd_setting, "utf-8")).toString());
|
|
|
|
|
|
global.config.webui_api_url = value.webui_api_url || value.webui_api_url == '' ? value.webui_api_url : global.config.webui_api_url;
|
2024-06-01 15:08:22 +08:00
|
|
|
|
|
2024-05-15 12:57:15 +08:00
|
|
|
|
sd_config.setting.webui_api_url = value.webui_api_url || value.webui_api_url == "" ? value.webui_api_url : sd_config.setting.webui_api_url;
|
|
|
|
|
|
sd_config.setting.type = value.type ? value.type : sd_config.setting.type;
|
2024-05-24 13:46:19 +08:00
|
|
|
|
sd_config.setting.batch_size = value.batch_size ? value.batch_size : sd_config.setting.batch_size;
|
|
|
|
|
|
sd_config.setting.style_weight = value.style_weight ? value.style_weight : sd_config.setting.style_weight;
|
2024-06-01 15:08:22 +08:00
|
|
|
|
|
2024-05-15 12:57:15 +08:00
|
|
|
|
sd_config.webui.prompt = value.prompt || value.prompt == "" ? value.prompt : sd_config.webui.prompt;
|
|
|
|
|
|
sd_config.webui.negative_prompt = value.negative_prompt || value.negative_prompt == "" ? value.negative_prompt : sd_config.webui.negative_prompt;
|
|
|
|
|
|
sd_config.webui.denoising_strength = value.denoising_strength || value.denoising_strength == "" ? value.denoising_strength : sd_config.webui.denoising_strength;
|
|
|
|
|
|
sd_config.webui.sampler_name = value.sampler_name ? value.sampler_name : sd_config.webui.sampler_name;
|
|
|
|
|
|
sd_config.webui.steps = value.steps ? value.steps : sd_config.webui.steps;
|
|
|
|
|
|
sd_config.webui.width = value.width ? value.width : sd_config.webui.width;
|
|
|
|
|
|
sd_config.webui.height = value.height ? value.height : sd_config.webui.height;
|
|
|
|
|
|
sd_config.webui.cfg_scale = value.cfg_scale ? value.cfg_scale : sd_config.webui.cfg_scale;
|
2024-06-06 13:12:04 +08:00
|
|
|
|
sd_config.webui.adetailer = value.hasOwnProperty("adetailer") ? value.adetailer : sd_config.webui.adetailer;
|
2024-09-12 14:13:09 +08:00
|
|
|
|
|
|
|
|
|
|
if(!sd_config.flux){
|
|
|
|
|
|
let model = {
|
|
|
|
|
|
model : value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX
|
|
|
|
|
|
}
|
|
|
|
|
|
sd_config.flux = model
|
|
|
|
|
|
}else{
|
|
|
|
|
|
sd_config.flux.model = value.flux_model ? value.flux_model : FLxuAPIImageType.FLUX;
|
|
|
|
|
|
}
|
2024-05-15 12:57:15 +08:00
|
|
|
|
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "保存成功"
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 保存生成视频的简单配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveGeneralSetting(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 先读取
|
|
|
|
|
|
let config_data = JSON.parse((await fspromises.readFile(define.video_config, 'utf-8')).toString());
|
|
|
|
|
|
await fspromises.writeFile(define.video_config, JSON.stringify(value));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "保存成功"
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取合成视频的配置信息。包含基本设置。字幕设置。音频设置。水印设置
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function GetVideoConfigMessage() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let data = JSON.parse((await fspromises.readFile(define.video_config, 'utf-8')).toString());
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
data: data
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.message
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取当前系统安装了的字体
|
|
|
|
|
|
* 使用python脚本实现
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function GetSystemInstallFontName() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 执行python
|
|
|
|
|
|
let scriptPath = path.join(define.scripts_path, 'Lai.exe');
|
|
|
|
|
|
// let scriptPath = path.join(define.scripts_path, '00_clip.exe');
|
|
|
|
|
|
// 执行生成图片的脚本
|
|
|
|
|
|
let script = `cd "${define.scripts_path}" && "${scriptPath}" -f "${define.video_config.replaceAll("\\", "/")}"`;
|
|
|
|
|
|
const output = await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' });
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 保存字幕的配置信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveAssConfig(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
|
|
let video_config = JSON.parse(await fspromises.readFile(define.video_config, 'utf8'));
|
|
|
|
|
|
// 判断ID是不是存在。存在的话直接修改。不存在创建
|
|
|
|
|
|
if (value[1].id == null) {
|
|
|
|
|
|
value[1].id = uuidv4();
|
|
|
|
|
|
video_config[value[0]].push(value[1]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let index = video_config[value[0]].findIndex(item => item.id == value[1].id);
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
let old = video_config[value[0]][index];
|
|
|
|
|
|
old.fontName = value[1].fontName;
|
|
|
|
|
|
old.fontSize = value[1].fontSize;
|
|
|
|
|
|
old.fontColor = value[1].fontColor;
|
|
|
|
|
|
old.transparent = value[1].transparent;
|
|
|
|
|
|
old.positionX = value[1].positionX;
|
|
|
|
|
|
old.positionY = value[1].positionY;
|
|
|
|
|
|
if (value[0] == "watermarkConfig") {
|
|
|
|
|
|
old.showText = value[1].showText;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
await fspromises.writeFile(define.video_config, JSON.stringify(video_config));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "添加成功"
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除视频配置的指定ID
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function DeleteVideoConfig(value) {
|
|
|
|
|
|
// console.log(value)
|
|
|
|
|
|
try {
|
|
|
|
|
|
let video_config = JSON.parse(await fspromises.readFile(define.video_config, 'utf-8'));
|
|
|
|
|
|
video_config[value[0]] = video_config[value[0]].filter(item => item.id != value[1]);
|
|
|
|
|
|
await fspromises.writeFile(define.video_config, JSON.stringify(video_config));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 添加生图任务队列
|
|
|
|
|
|
* @param {传入的值} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function AddImageTask(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
|
|
// 判断文件目录是不是存在
|
|
|
|
|
|
let json_path = path.join(global.config.project_path, "scripts/task_list.json");
|
|
|
|
|
|
// 判断文件是不是存在
|
|
|
|
|
|
let isExit = await tools.checkExists(json_path);
|
|
|
|
|
|
let json_data = {};
|
|
|
|
|
|
if (!isExit) {
|
|
|
|
|
|
const dirPath = path.dirname(json_path);
|
|
|
|
|
|
let dirIsExit = await tools.checkExists(dirPath);
|
|
|
|
|
|
if (!dirIsExit) {
|
|
|
|
|
|
await fspromises.mkdir(dirPath, { recursive: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
await fspromises.writeFile(json_path, '{}');
|
|
|
|
|
|
}
|
|
|
|
|
|
let task_list = [];
|
|
|
|
|
|
let task_list_data = await pm.GetImageTask();
|
|
|
|
|
|
if (task_list_data.code == 0) {
|
|
|
|
|
|
return task_list_data;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 获取当前的最大的任务编号
|
|
|
|
|
|
let current_no = 0;
|
|
|
|
|
|
if (task_list_data.data != null && task_list_data.data.task_list != null) {
|
|
|
|
|
|
|
|
|
|
|
|
if (task_list_data.data.task_list.length > 0) {
|
|
|
|
|
|
const maxNoObject = task_list_data.data.task_list.reduce((max, obj) => obj.no > max.no ? obj : max, task_list_data.data.task_list[0]);
|
|
|
|
|
|
current_no = maxNoObject.no;
|
|
|
|
|
|
task_list = task_list_data.data.task_list;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 循环输出轮次,往里面添加数据
|
|
|
|
|
|
for (let i = 0; i < value.output_rounds; i++) {
|
|
|
|
|
|
task_list.push({
|
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
|
no: current_no + i + 1,
|
|
|
|
|
|
lora: value.lora,
|
|
|
|
|
|
out_folder: 'output_crop_' + String(current_no + i + 1).padStart(5, '0'),
|
|
|
|
|
|
image_style: value.image_style,
|
|
|
|
|
|
image_style_list: value.image_style_list,
|
|
|
|
|
|
status: "wait"
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
// 写入
|
|
|
|
|
|
task_list_data.data.task_list = task_list;
|
|
|
|
|
|
let write_data = task_list_data.data;
|
|
|
|
|
|
await fspromises.writeFile(json_path, JSON.stringify(write_data));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
data: write_data
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 删除指定ID的值
|
|
|
|
|
|
* @param {ID} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function DeleteImageTaskList(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 判断当前的状态。是不是可以删除。正在生成的文件不能删除
|
|
|
|
|
|
// 目前先是直接删除
|
|
|
|
|
|
let task_list = JSON.parse(await fspromises.readFile(path.join(global.config.project_path, 'scripts/task_list.json'), 'utf-8'));
|
|
|
|
|
|
|
|
|
|
|
|
// 判断状态,删除指定的输出文件夹
|
|
|
|
|
|
let d_t = task_list.task_list.filter(item => item.id == value)[0];
|
|
|
|
|
|
// ok 状态删除对应的输出文件夹
|
|
|
|
|
|
if (d_t.status == "ok" || d_t.status == "error" || d_t.status.startsWith("video")) {
|
|
|
|
|
|
await fspromises.rm(path.join(global.config.project_path, 'tmp/' + d_t.out_folder), { recursive: true, force: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let new_data = task_list.task_list.filter(item => item.id != value);
|
|
|
|
|
|
task_list.task_list = new_data;
|
|
|
|
|
|
await fspromises.writeFile(path.join(global.config.project_path, 'scripts/task_list.json'), JSON.stringify(task_list));
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取不想要的提示词
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function GetBadPrompt() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
value: sd_config.tag.badPrompt
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 保存不想要的提示词
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveBadPrompt(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let tag = value.join(',');
|
|
|
|
|
|
// 写入
|
|
|
|
|
|
let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
sd_config.tag.badPrompt = tag;
|
|
|
|
|
|
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 一键删除不想要的值
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function DeleteBadPrompt() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
let badPrompt = sd_config.tag.badPrompt;
|
|
|
|
|
|
let badPrompts = [];
|
|
|
|
|
|
if (badPrompt != null) {
|
|
|
|
|
|
badPrompts = badPrompt.split(',');
|
|
|
|
|
|
}
|
|
|
|
|
|
// 修改所有的提示词
|
|
|
|
|
|
let promptPath = await tools.getFilesWithExtensions(path.join(global.config.project_path, 'tmp/input_crop'), '.txt');
|
|
|
|
|
|
for (let i = 0; i < promptPath.length; i++) {
|
|
|
|
|
|
const item = promptPath[i];
|
|
|
|
|
|
let txtStr = await fspromises.readFile(item, 'utf-8');
|
|
|
|
|
|
let tags = txtStr.split(',');
|
|
|
|
|
|
tags = tags.filter(d => !badPrompts.includes(d));
|
|
|
|
|
|
// 重新写入
|
|
|
|
|
|
await fspromises.writeFile(item, tags.join(','));
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打开购买 GPT 的网址
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function openGptBuyUrl(value) {
|
2024-06-01 15:08:22 +08:00
|
|
|
|
OpenUrl(value)
|
2024-05-15 12:57:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打开传入的网址
|
|
|
|
|
|
* @param {} value
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function OpenUrl(value) {
|
|
|
|
|
|
shell.openExternal(value)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取ADetailer配置列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function GetADetailerList() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log(123);
|
|
|
|
|
|
let sd_setting = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
data: sd_setting.adetailer
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 保存ADetailer数据信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function SaveADetailerConfig(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let sd_config = JSON.parse(await fspromises.readFile(define.sd_setting, 'utf-8'));
|
|
|
|
|
|
sd_config.adetailer = value;
|
|
|
|
|
|
await fspromises.writeFile(define.sd_setting, JSON.stringify(sd_config));
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 1,
|
|
|
|
|
|
message: "保存成功"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0,
|
|
|
|
|
|
message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 开始分镜
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function StartStoryboarding(value) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 判断文件夹是不是存在,不存在创建
|
|
|
|
|
|
let frame_path = path.join(global.config.project_path, "data/frame");
|
|
|
|
|
|
let isExist = await tools.checkExists(frame_path);
|
|
|
|
|
|
if (isExist) {
|
|
|
|
|
|
await tools.deleteFileOrDirectory(frame_path);
|
|
|
|
|
|
await fspromises.mkdir(frame_path, { recursive: true });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await fspromises.mkdir(frame_path, { recursive: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
let tmp_path = path.join(global.config.project_path, "tmp");
|
|
|
|
|
|
isExist = await tools.checkExists(tmp_path);
|
|
|
|
|
|
if (!isExist) {
|
|
|
|
|
|
await fspromises.mkdir(tmp_path, { recursive: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
let input_path = path.join(global.config.project_path, "tmp/input_crop");
|
|
|
|
|
|
isExist = await tools.checkExists(input_path);
|
|
|
|
|
|
if (isExist) {
|
|
|
|
|
|
await tools.deleteFileOrDirectory(input_path);
|
|
|
|
|
|
await fspromises.mkdir(input_path, { recursive: true });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await fspromises.mkdir(input_path, { recursive: true });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.GET_FRAME_RETUN, { code: 1, data: "正在调用进程。请勿关闭程序" })
|
|
|
|
|
|
let cc = `${path.join(define.scripts_path, 'Lai.exe')}`;
|
2024-06-13 00:37:31 +08:00
|
|
|
|
// 获取生成视频设置
|
|
|
|
|
|
let video_config = JSON.parse(await fspromises.readFile(define.video_config, 'utf-8'));
|
|
|
|
|
|
let gpu = global.gpu.type;
|
|
|
|
|
|
if (video_config.libx264) {
|
|
|
|
|
|
gpu = "OTHER";
|
|
|
|
|
|
}
|
|
|
|
|
|
let child = spawn(cc, ["-a", value.video_path, frame_path, input_path, value.sensitivity, gpu], { encoding: 'utf-8' });
|
2024-05-15 12:57:15 +08:00
|
|
|
|
child.on('error', console.error)
|
|
|
|
|
|
child.stdout.on('data', (data) => {
|
|
|
|
|
|
console.log(data.toString());
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.GET_FRAME_RETUN, { code: 1, data: data.toString() })
|
|
|
|
|
|
})
|
|
|
|
|
|
child.stderr.on('data', (data) => {
|
|
|
|
|
|
console.log('stderr=', data.toString())
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.GET_FRAME_RETUN, { code: 1, data: data.toString() })
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
child.on('close', async (data) => {
|
|
|
|
|
|
console.log('data=', data.toString())
|
|
|
|
|
|
// 判断该当前文件夹下面是不是有文案文件。有的话判断最后一行是不是空
|
|
|
|
|
|
let isE = await tools.checkExists(path.join(global.config.project_path, "data/文案.txt"));
|
|
|
|
|
|
if (isE) {
|
|
|
|
|
|
let lines = (await fspromises.readFile(path.join(global.config.project_path, "data/文案.txt"), 'utf-8')).split(/\r?\n/);
|
|
|
|
|
|
let lastLine = lines[lines.length - 1];
|
|
|
|
|
|
if (lastLine == "") {
|
|
|
|
|
|
lines = lines.slice(0, -1);
|
|
|
|
|
|
}
|
|
|
|
|
|
await fspromises.writeFile(path.join(global.config.project_path, "文案.txt"), lines.join('\n'), 'utf-8');
|
|
|
|
|
|
}
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.GET_FRAME_RETUN, { code: 1, data: data.toString(), type: 0 })
|
|
|
|
|
|
if (data == 0) {
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { code: 1, message: "分镜、抽帧、语音识别完成!" })
|
|
|
|
|
|
} else {
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { code: 0, message: "分镜错误。请看详细信息!" })
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { code: 0, message: error.toString() })
|
|
|
|
|
|
return {
|
|
|
|
|
|
code: 0, message: error.toString()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const func = {
|
|
|
|
|
|
getDraftFileList,
|
|
|
|
|
|
PythonRunner,
|
|
|
|
|
|
getFrame,
|
|
|
|
|
|
alignDraftImage,
|
|
|
|
|
|
alginDraftImgToText,
|
|
|
|
|
|
getDraftTextStyle,
|
|
|
|
|
|
getClipSetting,
|
|
|
|
|
|
addDraft,
|
|
|
|
|
|
ReGenerateImageOne,
|
|
|
|
|
|
PushBackPrompt,
|
|
|
|
|
|
GetDraftFriendlyReminder,
|
|
|
|
|
|
SaveNewWord,
|
|
|
|
|
|
SaveSDConfig,
|
|
|
|
|
|
SaveGeneralSetting,
|
|
|
|
|
|
GetVideoConfigMessage,
|
|
|
|
|
|
GetSystemInstallFontName,
|
|
|
|
|
|
SaveAssConfig,
|
|
|
|
|
|
DeleteVideoConfig,
|
|
|
|
|
|
AddImageTask,
|
|
|
|
|
|
DeleteImageTaskList,
|
|
|
|
|
|
GetBadPrompt,
|
|
|
|
|
|
SaveBadPrompt,
|
|
|
|
|
|
DeleteBadPrompt,
|
|
|
|
|
|
openGptBuyUrl,
|
|
|
|
|
|
GetADetailerList,
|
|
|
|
|
|
SaveADetailerConfig,
|
|
|
|
|
|
OpenUrl,
|
|
|
|
|
|
StartStoryboarding
|
|
|
|
|
|
}
|