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) import { FLxuAPIImageType } from '../define/enum/image' import JianyingService from './Service/jianying/jianyingService' import VideoHandle from './Service/videoService/videoHandle' import { successMessage } from './Public/generalTools' /** * 获取对应的轨道 */ 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 jianying = new JianyingService() await jianying.GetDraftFrameAndText(draft_path, out_dir) global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { code: 1, message: '剪映关键帧抽取成功' }) return { code: 1, 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() } } } /** * 反推调用脚本的方法 * @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_crop" "${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 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 } 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) { 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 videoHandle = new VideoHandle() await videoHandle.StartStoryboarding(value.video_path, value.sensitivity) return successMessage(null, '分镜、抽帧、语音识别完成!') } 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 }