diff --git a/.gitignore b/.gitignore index 131a398..74120db 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ resources/scripts/dist resources/scripts/model resources/scripts/Temp resources/image/Temp* -resources/package/ffmpeg* +resources/package/ffmpeg-2023* resources/config* *Lai.exe* .DS_Store diff --git a/package-lock.json b/package-lock.json index 7c2e53b..e465cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "2.2.4", + "version": "2.2.5", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 701a4b7..2e7fbf2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "2.2.4", + "version": "2.2.5", "description": "An Electron application with Vue", "main": "./out/main/index.js", "author": "example.com", diff --git a/resources/package/ffmpeg-7.0-full_build.7z b/resources/package/ffmpeg-7.0-full_build.7z new file mode 100644 index 0000000..b220eb3 Binary files /dev/null and b/resources/package/ffmpeg-7.0-full_build.7z differ diff --git a/resources/scripts/Lai.py b/resources/scripts/Lai.py index 56b5add..8c6906a 100644 --- a/resources/scripts/Lai.py +++ b/resources/scripts/Lai.py @@ -11,7 +11,7 @@ import shotSplit sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") -# sys.argv = ["C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe","-c","C:/Users/27698/Desktop/测试/123/scripts/output_crop_00001.json"] +sys.argv = ["C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe","-c","C:/Users/27698/Desktop/测试/mjTest/scripts/output_crop_00001.json"] print(sys.argv) if len(sys.argv) < 2: diff --git a/resources/scripts/__pycache__/getgrame.cpython-310.pyc b/resources/scripts/__pycache__/getgrame.cpython-310.pyc index 3294654..fbf963d 100644 Binary files a/resources/scripts/__pycache__/getgrame.cpython-310.pyc and b/resources/scripts/__pycache__/getgrame.cpython-310.pyc differ diff --git a/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc b/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc index eb2b492..2436aa0 100644 Binary files a/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc and b/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc differ diff --git a/resources/scripts/iamge_to_video.py b/resources/scripts/iamge_to_video.py index b0f059a..ab82774 100644 --- a/resources/scripts/iamge_to_video.py +++ b/resources/scripts/iamge_to_video.py @@ -174,6 +174,7 @@ class ImageToVideo: # 计算偏移变化率 offset_change_per_frame = float(end_offset - start_offset) / total_frames current_offset = start_offset + scale = img_resized.shape[0] / video_size[1] for _ in range(int(duration * fps)): # 创建一个空白画布 @@ -194,13 +195,15 @@ class ImageToVideo: # 安全检查,确保不会复制超出边界的区域 src_x1 = max(-start_x, 0) dst_x1 = max(start_x, 0) - copy_height = min(img_resized.shape[0] - src_x1, video_size[1] - dst_x1) + copy_width = min(img_resized.shape[1] - src_x1, video_size[0] - dst_x1) # copy_width = min(video_size[0], img_resized.shape[1]) # 调整图片复制区域的计算 src_y1 = max(-start_y, 0) dst_y1 = max(start_y, 0) - copy_width = min(img_resized.shape[1] - src_y1, video_size[0] - dst_y1) + copy_height = min(img_resized.shape[0] - src_y1, video_size[1] - dst_y1) + + # copy_width = min(copy_width, img_resized.shape[1]) if copy_height > 0 and copy_width > 0: canvas[dst_y1 : dst_y1 + copy_height, dst_x1 : dst_x1 + copy_width] = ( @@ -238,6 +241,7 @@ class ImageToVideo: # 计算偏移变化率 offset_change_per_frame = float(end_offset - start_offset) / total_frames current_offset = start_offset + scale = img_resized.shape[1] / video_size[0] for _ in range(int(duration * fps)): # 创建一个空白画布 diff --git a/src/define/define_string.js b/src/define/define_string.js index ea429c0..f0ccc89 100644 --- a/src/define/define_string.js +++ b/src/define/define_string.js @@ -1,4 +1,6 @@ export const DEFINE_STRING = { + OPEN_DEV_TOOLS_PASSWORD: "OPEN_DEV_TOOLS_PASSWORD", + OPEN_DEV_TOOLS: "OPEN_DEV_TOOLS", GET_FILE_BASE64: "GET_FILE_BASE64", SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY: "SAVE_DEFINE_CONFIG_JSON_BY_PROPERTY", GET_DEFINE_CONFIG_JSON_BY_PROPERTY: "GET_DEFINE_CONFIG_JSON_BY_PROPERTY", diff --git a/src/main/IPCEvent/globalIpc.js b/src/main/IPCEvent/globalIpc.js index d34b09e..7fb69d6 100644 --- a/src/main/IPCEvent/globalIpc.js +++ b/src/main/IPCEvent/globalIpc.js @@ -27,6 +27,18 @@ function GlobalIpc() { return errorMessage("获取文件失败" + error) } }); + + ipcMain.on(DEFINE_STRING.OPEN_DEV_TOOLS, (event) => { + global.newWindow[0].win.webContents.openDevTools(); + }) + + ipcMain.handle(DEFINE_STRING.OPEN_DEV_TOOLS_PASSWORD, (event, value) => { + if (value === "297ab55d41e9f5d3eba95b9df432f991") { + return successMessage("打开成功") + } else { + return errorMessage("管理控制台密码错误") + } + }) } export { diff --git a/src/main/IPCEvent/settingIpc.js b/src/main/IPCEvent/settingIpc.js index f4696d4..2461f43 100644 --- a/src/main/IPCEvent/settingIpc.js +++ b/src/main/IPCEvent/settingIpc.js @@ -1,5 +1,5 @@ const { - ipcMain + ipcMain, app } = require("electron") import { DEFINE_STRING } from '../../define/define_string' import { @@ -7,7 +7,7 @@ import { } from '../setting/setting' let setting = new Setting(global); -function SettingIpc() { +async function SettingIpc() { // 获取背景音乐配置列表 ipcMain.handle(DEFINE_STRING.GET_BACKGROUND_MUSIC_CONFIG_LIST, async (event) => await setting.GetBackGroundMusicConfigList()); diff --git a/src/main/backPrompt/imageGenerate.js b/src/main/backPrompt/imageGenerate.js index 888d1b1..e6dcca5 100644 --- a/src/main/backPrompt/imageGenerate.js +++ b/src/main/backPrompt/imageGenerate.js @@ -246,19 +246,23 @@ export class ImageGenerate { let task_list_json = JSON.parse(await fspromises.readFile(taskPath, 'utf-8')); let auto_save_image = await this.tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false); let png_files = []; + + let images = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.png'); + + if (images.length <= 0) { + throw new Error("未检测到抽帧图片。请检查"); + } + + if (auto_save_image.save_match_count && auto_save_image.auto_match && images.length > auto_save_image.save_match_count && auto_save_image.main_save_folder) { + png_files = await this.tools.getFilesWithExtensions(auto_save_image.main_save_folder, '.png'); + } + // 读取队列中的任务,然后添加队列 for (let i = 0; i < value.length; i++) { const element = value[i]; let task_list = task_list_json.task_list.filter(item => item.id == element)[0]; let seed = -1; - let images = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.png'); await fspromises.mkdir(path.join(this.global.config.project_path, 'tmp/' + task_list.out_folder), { recursive: true }); - if (images.length <= 0) { - throw new Error("未检测到抽帧图片。请检查"); - } - if (auto_save_image.save_match_count && auto_save_image.auto_match && images.length > auto_save_image.save_match_count) { - png_files = await this.tools.getFilesWithExtensions(auto_save_image.main_save_folder, '.png'); - } this.global.requestQuene.enqueue(async () => { let res = await this.sd.OneImageGeneration(images[0], task_list, seed); let tmp_seed = -1; @@ -267,11 +271,13 @@ export class ImageGenerate { } for (let j = 1; j < images.length; j++) { const item = images[j]; - + // 判断item是不是一个图片的地址 + if (!item.endsWith('.png')) { + continue; + } let has_permission = false; // 判断权限 let permission = this.global.permission; - if (permission && permission.length >= 0) { if (permission.indexOf(DEFINE_STRING.PERMISSIONS.AUTO_SAVE_IMAGE_PERMISSION) >= 0) { has_permission = true; @@ -279,7 +285,6 @@ export class ImageGenerate { } else { has_permission = true; } - if (auto_save_image.save_match_count && j >= auto_save_image.save_match_count && has_permission && auto_save_image.auto_match) { // 现在随机匹配视频 // 获取指定的文件夹中的图片 diff --git a/src/main/backPrompt/videoGenerate.js b/src/main/backPrompt/videoGenerate.js index a1be12a..e360e35 100644 --- a/src/main/backPrompt/videoGenerate.js +++ b/src/main/backPrompt/videoGenerate.js @@ -67,30 +67,31 @@ export class VideoGenerate { await this.pm.AddWebuiJson(); let batch = DEFINE_STRING.QUEUE_BATCH.AUTO_VIDEO_GENERATE; let taskPath = path.join(this.global.config.project_path, "scripts/task_list.json"); + // 获取自动保存相关的配置数据 + let auto_save_image = await this.tools.getJsonFilePropertyValue(define.img_base, "auto_save_image", {}, false); - // // 修改数据(保存srt字幕文件位置。配音文件位置。背景音乐文件) - // this.global.fileQueue.enqueue(async () => { - // let config_json = JSON.parse(await fspromises.readFile(path.join(this.global.config.project_path, "scripts/config.json"), 'utf-8')); - // config_json.srt_path = value[1].srt_path; - // config_json.audio_path = value[1].audio_path; - // config_json.background_music = value[1].background_music; - // await fspromises.writeFile(path.join(this.global.config.project_path, "scripts/config.json"), JSON.stringify(config_json)); - // }) - + // 保存基础配置(文案,配音,背景音乐等) await this.tools.writeJsonFilePropertyValue(path.join(this.global.config.project_path, "scripts/config.json"), "video_config", value[1]); - // 便利所有的队列任务 + let images = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.png'); + if (images.length <= 0) { + throw new Error("未检测到抽帧图片。请检查"); + } + + let png_files = []; + // 获取图片文件夹 + if (auto_save_image.save_match_count && auto_save_image.auto_match && images.length > auto_save_image.save_match_count && auto_save_image.main_save_folder) { + png_files = await this.tools.getFilesWithExtensions(auto_save_image.main_save_folder, '.png'); + } + // 遍历所有的队列任务 for (let i = 0; i < value[0].length; i++) { // 将所有的数据天添加到队列(总的大队列,有很多的小队列) // 将所有生图任务添加到队列中 const task_list = value[0][i]; let seed = -1; let subBatchId = `${task_list.out_folder}_image` - let images = await this.tools.getFilesWithExtensions(path.join(this.global.config.project_path, 'tmp/input_crop'), '.png'); await fspromises.mkdir(path.join(this.global.config.project_path, 'tmp/' + task_list.out_folder), { recursive: true }); - if (images.length <= 0) { - throw new Error("未检测到抽帧图片。请检查"); - } + this.global.requestQuene.enqueue(async () => { let res = await this.sd.OneImageGeneration(images[0], task_list, seed); let tmp_seed = -1; @@ -99,9 +100,31 @@ export class VideoGenerate { } for (let j = 1; j < images.length; j++) { const element = images[j]; - this.global.requestQuene.enqueue(async () => { - await this.sd.OneImageGeneration(element, task_list, tmp_seed); - }, `${task_list.out_folder}_${images[j]}`, batch, subBatchId) + if (!element.endsWith('.png')) { + continue; + } + let has_permission = false; + // 判断权限 + let permission = this.global.permission; + if (permission && permission.length >= 0) { + if (permission.indexOf(DEFINE_STRING.PERMISSIONS.AUTO_SAVE_IMAGE_PERMISSION) >= 0) { + has_permission = true; + } + } else { + has_permission = true; + } + if (auto_save_image.save_match_count && auto_save_image.auto_match && j >= auto_save_image.save_match_count && has_permission) { + // 现在随机匹配视频 + // 获取指定的文件夹中的图片 + let randomData = png_files[Math.floor(Math.random() * png_files.length)]; + let base_name = path.basename(element); + let copy_path = path.join(this.global.config.project_path, 'tmp/' + task_list.out_folder, base_name); + await this.tools.copyFileOrDirectory(randomData, copy_path); + } else { + this.global.requestQuene.enqueue(async () => { + await this.sd.OneImageGeneration(element, task_list, tmp_seed); + }, `${task_list.out_folder}_${images[j]}`, batch, subBatchId) + } } }, `${task_list.out_folder}_${images[0]}`, batch, subBatchId) diff --git a/src/main/index.js b/src/main/index.js index 7c216f9..175e41a 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -196,11 +196,12 @@ app.whenReady().then(async () => { tools.checkFolderExistsOrCreate(path.normalize(define.temp_sd_image)); tools.checkFolderExistsOrCreate(path.normalize(path.join(define.image_path, "c_s"))); - app.on('activate', function () { + app.on('activate', async function () { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. - if (BrowserWindow.getAllWindows().length === 0) mainWindow = createWindow('ShowMessage', null) - + if (BrowserWindow.getAllWindows().length === 0) { + mainWindow = createWindow('ShowMessage', null) + } }) }) @@ -213,6 +214,7 @@ app.on('window-all-closed', () => { } }) + SettingIpc(); ImageGenerateIpc(); WritingIpc(); diff --git a/src/preload/index.js b/src/preload/index.js index 10cf00f..03a14d3 100644 --- a/src/preload/index.js +++ b/src/preload/index.js @@ -395,6 +395,10 @@ const api = { // 知道文件地址,获取文件base64编码 GetFileBase64: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.GET_FILE_BASE64, value)), + + OpenDevTools: () => ipcRenderer.send(DEFINE_STRING.OPEN_DEV_TOOLS), + OpenDevToolsPassword: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.OPEN_DEV_TOOLS_PASSWORD, value)), + } // Use `contextBridge` APIs to expose Electron APIs to diff --git a/src/renderer/src/App.vue b/src/renderer/src/App.vue index 60d2eb6..8fa699b 100644 --- a/src/renderer/src/App.vue +++ b/src/renderer/src/App.vue @@ -14,18 +14,27 @@ import { defineComponent, ref, onMounted } from 'vue' import hljs from 'highlight.js/lib/core' import javascript from 'highlight.js/lib/languages/javascript' -import { NMessageProvider, NDialogProvider, NConfigProvider, darkTheme, NNotificationProvider } from "naive-ui" +import { + NMessageProvider, + NDialogProvider, + NConfigProvider, + darkTheme, + NNotificationProvider +} from 'naive-ui' hljs.registerLanguage('javascript', javascript) export default defineComponent({ components: { - NConfigProvider, NDialogProvider, NMessageProvider, NNotificationProvider + NConfigProvider, + NDialogProvider, + NMessageProvider, + NNotificationProvider }, setup() { - let themeData = ref(""); + let themeData = ref('') onMounted(() => { window.api.getSettingDafultData(async (value) => { - themeData.value = value.theme; + themeData.value = value.theme await window.darkMode.toggle(value.theme) }) }) @@ -34,7 +43,7 @@ export default defineComponent({ javascript, hljs, darkTheme, - themeData + themeData, } } }) diff --git a/src/renderer/src/components/Backstep/OneKeyMatrix.vue b/src/renderer/src/components/Backstep/OneKeyMatrix.vue index 0d93bae..ec8172b 100644 --- a/src/renderer/src/components/Backstep/OneKeyMatrix.vue +++ b/src/renderer/src/components/Backstep/OneKeyMatrix.vue @@ -1,387 +1,452 @@ \ No newline at end of file + diff --git a/src/renderer/src/components/Components/CheckMachineId.vue b/src/renderer/src/components/Components/CheckMachineId.vue index 7587831..08b82cc 100644 --- a/src/renderer/src/components/Components/CheckMachineId.vue +++ b/src/renderer/src/components/Components/CheckMachineId.vue @@ -55,7 +55,7 @@ export default defineComponent({ }) function OpenTeachDoc() { - window.api.OpenUrl("https://pvwu1oahp5m.feishu.cn/docx/CAjGdTDlboJ3nVx0cQccOuNHnvd?from=from_copylink"); + window.api.OpenUrl("https://rvgyir5wk1c.feishu.cn/docx/RZYCdG7ZpoKsIzxBEzccNEIFn8f?from=from_copylink"); } function OpenQueDoc() { diff --git a/src/renderer/src/components/Home/Home.vue b/src/renderer/src/components/Home/Home.vue index bcd6dde..a42b5f5 100644 --- a/src/renderer/src/components/Home/Home.vue +++ b/src/renderer/src/components/Home/Home.vue @@ -1,327 +1,411 @@ - \ No newline at end of file + diff --git a/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue b/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue index 5418536..deb5fd5 100644 --- a/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue +++ b/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue @@ -32,7 +32,8 @@ v-if="outImagePath" :src="outImagePath" fit="cover" - style="width: 120px; height: 120px" + width="120" + height="120" />
diff --git a/src/renderer/src/components/Original/Components/InputDialogContent.vue b/src/renderer/src/components/Original/Components/InputDialogContent.vue index 3c3f952..e31699e 100644 --- a/src/renderer/src/components/Original/Components/InputDialogContent.vue +++ b/src/renderer/src/components/Original/Components/InputDialogContent.vue @@ -1,6 +1,6 @@ @@ -12,17 +12,19 @@ export default defineComponent({ components: { NInput }, - props: ['initData', 'placeholder'], + props: ['initData', 'placeholder', 'type'], setup(props) { let message = useMessage() let data = ref(props.initData) let placeholder = ref(props.placeholder) + let type = ref(props.type ? props.type : 'text') onMounted(async () => {}) return { data, - placeholder + placeholder, + type } } }) diff --git a/src/renderer/src/components/Original/DataTable.vue b/src/renderer/src/components/Original/DataTable.vue index 09eb449..7475122 100644 --- a/src/renderer/src/components/Original/DataTable.vue +++ b/src/renderer/src/components/Original/DataTable.vue @@ -366,7 +366,7 @@ export default defineComponent({ selectStyle.value = value.data }) - for (let i = 0; i < customize_image_style_list.length; i++) { + for (let i = 0; i < customize_image_style_list && customize_image_style_list.length; i++) { const element = customize_image_style_list[i] selectStyle.value.push({ key: element, @@ -395,6 +395,7 @@ export default defineComponent({ window.api.setEventListen( [DEFINE_STRING.SD_ORIGINAL_GENERATE_IMAGE_RETURN, window.id], (value) => { + debugger if (value.code == 0) { message.error('生成图片错误,错误信息如下:' + value.message) return @@ -914,7 +915,10 @@ export default defineComponent({ cref_url = checkStringValueAddPrefix(cref_url, ' --cref ') if (element.character_tags && element.character_tags.length > 0) { - cref_url = checkStringValueAddSuffix(cref_url, ` --cw ${element.character_tags[0].cref_cw} `) + cref_url = checkStringValueAddSuffix( + cref_url, + ` --cw ${element.character_tags[0].cref_cw} ` + ) } // 判断 character_string 有数据,有的话删除第一个逗号 character_string = checkStringValueDeletePrefix(character_string, ',') diff --git a/src/renderer/src/components/Setting/SDSetting.vue b/src/renderer/src/components/Setting/SDSetting.vue index f45207b..a76da17 100644 --- a/src/renderer/src/components/Setting/SDSetting.vue +++ b/src/renderer/src/components/Setting/SDSetting.vue @@ -14,9 +14,10 @@ @@ -51,7 +52,12 @@
- +
@@ -161,13 +167,15 @@ export default defineComponent({ onMounted(async () => { await window.api.InitSDConfig((value) => { + debugger if (value.code == 0) { message.error(value.message) return } formValue.value = value.data - let samplers = value.data.samplers + let samplers = value.data.sampler + samplers_options.value = [] for (let i = 0; i < samplers.length; i++) { const element = samplers[i] samplers_options.value.push({ @@ -175,7 +183,8 @@ export default defineComponent({ value: element.name }) } - let loras = value.data.loras + let loras = value.data.lora + lora_options.value = [] for (let i = 0; i < loras.length; i++) { const element = loras[i] lora_options.value.push({ @@ -183,7 +192,8 @@ export default defineComponent({ value: element.name }) } - let sd_models = value.data.sd_models + let sd_models = value.data.sd_model + sd_models_options.value = [] for (let i = 0; i < sd_models.length; i++) { const element = sd_models[i] sd_models_options.value.push({ @@ -221,11 +231,40 @@ export default defineComponent({ */ async function LoadSDServiceData() { await window.sd.LoadSDServiceData(toRaw(formValue.value).webui_api_url, (value) => { + debugger if (value.code == 0) { message.error(value.message) return } // formValue.value = value.data + // 获取当前的配置信息 + let samplers = value.data.sampler + samplers_options.value = [] + for (let i = 0; i < samplers.length; i++) { + const element = samplers[i] + samplers_options.value.push({ + label: element.name, + value: element.name + }) + } + let loras = value.data.lora + lora_options.value = [] + for (let i = 0; i < loras.length; i++) { + const element = loras[i] + lora_options.value.push({ + label: element.name, + value: element.name + }) + } + let sd_models = value.data.sd_model + sd_models_options.value = [] + for (let i = 0; i < sd_models.length; i++) { + const element = sd_models[i] + sd_models_options.value.push({ + label: element.title, + value: element.title + }) + } message.success('加载成功') }) }