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"; const { machineId } = require('node-machine-id') 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); /** * 获取对应的轨道 */ 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 : []); let prompt = sd_setting.webui.prompt + image_styles; // 拼接提示词 if (value[1].image_style != null) { prompt += `((${value[1].image_style})),`; } if (value[1].lora != null) { prompt += `${value[1].lora},`; } prompt += value[1].prompt; 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; 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; 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; 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; sd_config.webui.adetailer = value.hasOwnProperty("adetailer") ? value.adetailer : sd_config.webui.adetailer; 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 GetMachineId() { try { let id = await machineId(true); return { code: 1, value: id } } 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) { OpenUrl(value) } /** * 打开传入的网址 * @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')}`; // 获取生成视频设置 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' }); 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, GetMachineId, GetBadPrompt, SaveBadPrompt, DeleteBadPrompt, openGptBuyUrl, GetADetailerList, SaveADetailerConfig, OpenUrl, StartStoryboarding }