From 8b011856c2b01c64c9034f0e5ab240027f204ead Mon Sep 17 00:00:00 2001 From: lq1405 <2769838458@qq.com> Date: Sat, 1 Jun 2024 15:08:22 +0800 Subject: [PATCH] =?UTF-8?q?V=202.2.6=20=E5=A2=9E=E5=8A=A0=E4=BA=86MJ?= =?UTF-8?q?=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .vs/define_string.js | 3 + .vscode/settings.json | 3 +- electron.vite.config.mjs | 2 +- package-lock.json | 32 +- package.json | 5 +- resources/scripts/Lai.py | 14 +- .../scripts/__pycache__/clip.cpython-310.pyc | Bin 10830 -> 11533 bytes .../__pycache__/getgrame.cpython-310.pyc | Bin 3601 -> 3601 bytes .../iamge_to_video.cpython-310.pyc | Bin 8769 -> 9029 bytes .../__pycache__/shotSplit.cpython-310.pyc | Bin 4793 -> 5039 bytes resources/scripts/clip.py | 133 +- resources/scripts/iamge_to_video.py | 51 +- resources/scripts/shotSplit.py | 52 +- src/api/apiBasic.js | 47 +- src/api/discordApi.js | 98 ++ src/api/sdApi.js | 1 + src/define/api/apiUrlDefine.js | 56 + src/define/define_string.js | 8 +- src/define/gptDefine.js | 13 +- src/define/setting/mjSetting.js | 103 +- src/main/IPCEvent/imageIpc.js | 14 + src/main/IPCEvent/mjIpc.js | 6 + src/main/Original/MJOriginalImageGenerate.js | 340 +++- src/main/Original/OriginalImageGenerate.js | 5 +- src/main/Public/GPT.js | 29 +- src/main/Public/Image.js | 48 + src/main/backPrompt/videoGenerate.js | 2 +- src/main/discord/discordApi.js | 482 ----- src/main/discord/discordSimple.js | 12 +- src/main/discord/mjSimple.js | 42 +- src/main/func.js | 13 +- src/main/generalTools.js | 2 - src/main/index.js | 30 +- src/main/quene.js | 18 +- src/main/tools.js | 33 +- src/preload/img.js | 11 + src/preload/index.js | 3 + src/preload/mj.js | 10 + .../Backstep/BatchSaveImageSetting.vue | 6 +- .../src/components/Backstep/ReGenerate.vue | 1004 ++++++----- .../components/Components/CheckMachineId.vue | 150 +- .../Components/GenerateAllImages.vue | 1 + .../src/components/Home/ReDrawImageWD.vue | 1547 +++++++++-------- .../Components/DataTableShowGenerateImage.vue | 57 +- .../Original/Components/PromptSetting.vue | 137 +- .../src/components/Original/DataTable.vue | 133 +- .../src/components/Original/MainPage.vue | 2 +- .../src/components/Original/MenuButton.vue | 4 +- .../Setting/Components/AddGptOption.vue | 4 +- .../src/components/Setting/MJSetting.vue | 848 +++++---- .../src/components/Setting/Setting.vue | 16 +- 52 files changed, 3255 insertions(+), 2376 deletions(-) create mode 100644 .vs/define_string.js create mode 100644 src/api/discordApi.js create mode 100644 src/define/api/apiUrlDefine.js create mode 100644 src/main/IPCEvent/imageIpc.js create mode 100644 src/main/Public/Image.js delete mode 100644 src/main/discord/discordApi.js create mode 100644 src/preload/img.js diff --git a/.gitignore b/.gitignore index 74120db..225cb64 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ resources/image/Temp* resources/package/ffmpeg-2023* resources/config* *Lai.exe* +*Lai_1.exe* .DS_Store *.log* diff --git a/.vs/define_string.js b/.vs/define_string.js new file mode 100644 index 0000000..56cd0df --- /dev/null +++ b/.vs/define_string.js @@ -0,0 +1,3 @@ +export const DEFINE_STRING = { + SYSTEM: {} +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 97685ce..4b90404 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,6 @@ "./resources/scripts/000_", "./resources/scripts/000_" ], - "vue3snippets.enable-compile-vue-file-on-did-save-code": false + "vue3snippets.enable-compile-vue-file-on-did-save-code": false, + "typescript.tsdk": "node_modules\\typescript\\lib" } diff --git a/electron.vite.config.mjs b/electron.vite.config.mjs index eff8ee5..aba2ad8 100644 --- a/electron.vite.config.mjs +++ b/electron.vite.config.mjs @@ -19,6 +19,6 @@ export default defineConfig({ '@renderer': resolve('src/renderer/src') } }, - plugins: [vue()] + plugins: [vue(), Jsx()] } }) diff --git a/package-lock.json b/package-lock.json index e465cb4..df5b82e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "laitool", - "version": "2.2.5", + "version": "2.2.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "laitool", - "version": "2.2.2", + "version": "2.2.5", "hasInstallScript": true, "dependencies": { "@alicloud/alimt20181012": "^1.2.0", @@ -34,6 +34,7 @@ "node-reg": "^0.2.4", "npm": "^10.7.0", "sharp": "^0.33.2", + "systeminformation": "^5.22.10", "tencentcloud-sdk-nodejs": "^4.0.821", "uuid": "^9.0.1", "vue-router": "^4.2.5", @@ -10012,6 +10013,31 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/systeminformation": { + "version": "5.22.10", + "resolved": "https://registry.npmmirror.com/systeminformation/-/systeminformation-5.22.10.tgz", + "integrity": "sha512-RJ3oed80NkqgHtpB0TLkxEKEpQ3pUm2lgVolkHeoaExPidkWsj2D/hO6Rwwi9i+Odl1vm8TMiRNIKK7hBaqDsw==", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, "node_modules/tar": { "version": "6.2.0", "devOptional": true, @@ -10860,4 +10886,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 2e7fbf2..21cd043 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laitool", - "version": "2.2.5", + "version": "2.2.6", "description": "An Electron application with Vue", "main": "./out/main/index.js", "author": "example.com", @@ -42,6 +42,7 @@ "node-reg": "^0.2.4", "npm": "^10.7.0", "sharp": "^0.33.2", + "systeminformation": "^5.22.10", "tencentcloud-sdk-nodejs": "^4.0.821", "uuid": "^9.0.1", "vue-router": "^4.2.5", @@ -85,4 +86,4 @@ "icon": "./resources/icon.ico" } } -} \ No newline at end of file +} diff --git a/resources/scripts/Lai.py b/resources/scripts/Lai.py index 8c6906a..750ec29 100644 --- a/resources/scripts/Lai.py +++ b/resources/scripts/Lai.py @@ -11,7 +11,15 @@ 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/测试/mjTest/scripts/output_crop_00001.json"] +# 判断sys.argv 的长度,如果小于2,说明没有传入参数,设置初始参数 +if len(sys.argv) < 2: + sys.argv = [ + "C:\\Users\\27698\\Desktop\\LAITool\\resources\\scripts\\Lai.exe", + "-c", + "C:/Users/27698/Desktop/测试/mjTest/scripts/output_crop_00001.json", + "NVIDIA", + ] + print(sys.argv) if len(sys.argv) < 2: @@ -46,7 +54,7 @@ set_ffmpeg_env() # 执行剪辑的方法 if sys.argv[1] == "-c": - clip = clip.Clip(cript_directory, sys.argv[2]) + clip = clip.Clip(cript_directory, sys.argv[2], sys.argv[3]) clip.MergeVideosAndClip() pass # 获取字体 @@ -79,4 +87,4 @@ elif sys.argv[1] == "-k": # 智能分镜。字幕识别 elif sys.argv[1] == "-a": print("开始算法分镜:" + sys.argv[2] + " -- 输出文件夹:" + sys.argv[3]) - shotSplit.init(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) + shotSplit.init(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]) diff --git a/resources/scripts/__pycache__/clip.cpython-310.pyc b/resources/scripts/__pycache__/clip.cpython-310.pyc index 8d5f2db7fd245b78fee822844ba8fe0c021e18fa..5ecb3eb4917365ab9286be880b2350d0cf0e216b 100644 GIT binary patch delta 3688 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 delta 20 acmbOzGf{>+pO=@50SNrh`EBH8;{yOL6a+K? diff --git a/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc b/resources/scripts/__pycache__/iamge_to_video.cpython-310.pyc index 2436aa0d155719b280ff2e1722d9d6a08159b02f..8ff1a2d9a7416db82688ffb3fa2f715fcfecf8f3 100644 GIT binary patch delta 2118 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 None: + def __init__(self, cript_directory, config_path, gpu_type) -> None: self.audio_duration = None self.cript_directory = cript_directory self.ID = str(uuid.uuid4()) @@ -31,6 +31,7 @@ class Clip: self.TEMP_FOLDER, self.ASS_ID + ".ass" ).replace("\\", "/") self.config_path = config_path + self.gpu_type = gpu_type self.ffmpeg_path = ( "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" ) @@ -68,7 +69,7 @@ class Clip: self.bitRate = self.config_json["bitRate"] # 图片数据 - self.iamge_to_video = iamge_to_video.ImageToVideo() + self.iamge_to_video = iamge_to_video.ImageToVideo(self.gpu_type) self.iamge_to_video.fps = self.config_json["frameRate"] self.iamge_to_video.video_size = ( self.video_resolution_x, @@ -236,32 +237,46 @@ class Clip: # 添加txtlist表 txt_list.append(f"file '{os.path.abspath(output_file)}'") # 删除开头,结尾,镜像,加速,放大 + command = [] + command.append(self.ffmpeg_path) + if self.gpu_type == "NVIDIA": + command.append("-hwaccel") + command.append("cuda") # 启用 CUDA 硬件加速 + command.append("-c:v") + command.append("h264_cuvid") # 使用 NVIDIA CUVID 解码器进行解码 + elif self.gpu_type == "AMD": + command.append("-hwaccel") + command.append("vaapi") + command.append("-c:v") + command.append("h264_vaapi") + command.append("-i") + command.append(random_path) + command.append("-ss") + command.append(str(start_time)) + command.append("-t") + command.append(str(duration)) + command.append("-vf") + command.append( + "hflip,setpts=1*PTS,format=yuv420p,scale=iw*1.1:ih*1.1,crop=iw/1.1:ih/1.1" + ) + command.append("-an") + command.append("-b:v") + command.append("5000k") + command.append("-c:v") + if self.gpu_type == "NVIDIA": + command.append("h264_nvenc") + elif self.gpu_type == "AMD": + command.append("h264_vaapi") + else: + command.append("libx264") + command.append("-preset") + command.append("fast") + command.append("-loglevel") + command.append("error") + command.append(output_file) + subprocess.run( - [ - self.ffmpeg_path, - "-hwaccel", - "cuda", # 启用 CUDA 硬件加速 - "-c:v", - "h264_cuvid", # 使用 NVIDIA CUVID 解码器进行解码 - "-i", - random_path, - "-ss", - str(start_time), - "-t", - str(duration), - "-vf", - "hflip,setpts=1*PTS,format=yuv420p,scale=iw*1.1:ih*1.1,crop=iw/1.1:ih/1.1", - "-an", - "-b:v", - "5000k", - "-c:v", - "h264_nvenc", - "-preset", - "fast", - "-loglevel", - "error", - output_file, - ], + command, check=True, stderr=subprocess.PIPE, ) @@ -453,35 +468,41 @@ class Clip: # 合并视频并添加音乐和字幕 def MergeVideoAndAudio(self): - command = [ - self.ffmpeg_path, - "-f", - "concat", - "-safe", - "0", - "-i", - self.mp4_file_txt, - "-i", - self.mix_audio, - "-vf", - f"subtitles=./Temp/{self.ID}/{self.ASS_ID}.ass", - # f"subtitles= {ASS_FILE_PATH}", - "-c:v", - "h264_nvenc", - "-preset", - "fast", - "-rc:v", - "cbr", - "-b:v", - str(self.bitRate) + "k", - "-c:a", - "aac", - "-strict", - "-2", - "-loglevel", - "error", - self.outpue_file, - ] + command = [] + command.append(self.ffmpeg_path) + command.append("-f") + command.append("concat") + command.append("-safe") + command.append("0") + command.append("-i") + command.append(self.mp4_file_txt) + command.append("-i") + command.append(self.mix_audio) + command.append("-vf") + command.append(f"subtitles=./Temp/{self.ID}/{self.ASS_ID}.ass") + command.append("-c:v") + + if self.gpu_type == "NVIDIA": + command.append("h264_nvenc") + elif self.gpu_type == "AMD": + command.append("h264_vaapi") + else: + command.append("libx264") + + command.append("-preset") + command.append("fast") + command.append("-rc:v") + command.append("cbr") + command.append("-b:v") + command.append(str(self.bitRate) + "k") + command.append("-c:a") + command.append("aac") + command.append("-strict") + command.append("-2") + command.append("-loglevel") + command.append("error") + command.append(self.outpue_file) + subprocess.run(command, check=True, stderr=subprocess.PIPE) # subprocess.run(command) pass diff --git a/resources/scripts/iamge_to_video.py b/resources/scripts/iamge_to_video.py index ab82774..80bb936 100644 --- a/resources/scripts/iamge_to_video.py +++ b/resources/scripts/iamge_to_video.py @@ -9,8 +9,9 @@ import json class ImageToVideo: - def __init__(self) -> None: + def __init__(self, gpu_type) -> None: self.frames = 0 + self.gpu_type = gpu_type self.public_tools = public_tools.PublicTools() self.ffmpeg_path = ( "../package/ffmpeg-2023-12-07-git-f89cff96d0-full_build/bin/ffmpeg" @@ -202,7 +203,7 @@ class ImageToVideo: src_y1 = max(-start_y, 0) dst_y1 = max(start_y, 0) 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: @@ -455,29 +456,37 @@ class ImageToVideo: ) temp_mp4_path = os.path.join(image_dir, "temp_" + str(number) + ".mp4") # 开始微调 - cmd = [ - self.ffmpeg_path, - "-i", - mp4_path, - "-filter:v", + cmd = [] + cmd.append(self.ffmpeg_path) + cmd.append("-i") + cmd.append(mp4_path) + cmd.append("-filter:v") + cmd.append( "setpts=PTS*" + str( (filtered_data[0]["end_time"] - filtered_data[0]["start_time"]) / duration_ms - ), - "-c:v", - "h264_nvenc", - "-preset", - "fast", - "-rc:v", - "cbr", - "-b:v", - str(self.bitRate) + "k", - temp_mp4_path, - "-loglevel", - "error", - "-an", - ] + ) + ) + cmd.append("-c:v") + + if self.gpu_type == "NVIDIA": + cmd.append("h264_nvenc") + elif self.gpu_type == "AMD": + cmd.append("h264_vaapi") + else: + cmd.append("libx264") + + cmd.append("-preset") + cmd.append("fast") + cmd.append("-rc:v") + cmd.append("cbr") + cmd.append("-b:v") + cmd.append(str(self.bitRate) + "k") + cmd.append(temp_mp4_path) + cmd.append("-loglevel") + cmd.append("error") + cmd.append("-an") subprocess.run(cmd, check=True) os.remove(mp4_path) diff --git a/resources/scripts/shotSplit.py b/resources/scripts/shotSplit.py index 7813ebe..b647a06 100644 --- a/resources/scripts/shotSplit.py +++ b/resources/scripts/shotSplit.py @@ -62,7 +62,7 @@ def createDir(file_dir): # 切分一个视频 -def ClipVideo(video_path, out_folder, image_out_folder, sensitivity): +def ClipVideo(video_path, out_folder, image_out_folder, sensitivity, gpu_type): shijian_list = find_scenes(video_path, sensitivity) # 多组时间列表 shijian_list_len = len(shijian_list) @@ -87,25 +87,33 @@ def ClipVideo(video_path, out_folder, image_out_folder, sensitivity): ) # 使用 ffmpeg 裁剪视频 + command = [] + command.append("ffmpeg") + command.append("-i") + command.append(video_path) + command.append("-ss") + command.append(start_time_str) + command.append("-to") + command.append(end_time_str) + command.append("-c:v") + + if gpu_type == "NVIDIA": + command.append("h264_nvenc") + elif gpu_type == "AMD": + command.append("h264_vaapi") + else: + command.append("libx264") + + command.append("-preset") + command.append("fast") + command.append("-c:a") + command.append("copy") + command.append(out_video_file) + command.append("-loglevel") + command.append("error") + subprocess.run( - [ - "ffmpeg", - "-i", - video_path, - "-ss", - start_time_str, - "-to", - end_time_str, - "-c:v", - "h264_nvenc", - "-preset", - "fast", - "-c:a", - "copy", - out_video_file, - "-loglevel", - "error", - ], + command, check=True, stderr=subprocess.PIPE, ) @@ -220,8 +228,10 @@ def GetText(out_folder, mp3_list): sys.stdout.flush() -def init(video_path, video_out_folder, image_out_folder, sensitivity): - v_l = ClipVideo(video_path, video_out_folder, image_out_folder, sensitivity) +def init(video_path, video_out_folder, image_out_folder, sensitivity, gpu_type): + v_l = ClipVideo( + video_path, video_out_folder, image_out_folder, sensitivity, gpu_type + ) # 开始分离音频 m_l = SplitAudio(video_out_folder, v_l) diff --git a/src/api/apiBasic.js b/src/api/apiBasic.js index d393ec9..b17189f 100644 --- a/src/api/apiBasic.js +++ b/src/api/apiBasic.js @@ -60,10 +60,9 @@ let basicApi = { const request = net.request({ method: 'POST', url: url, - headers: { + headers: Object.assign({ 'Content-Type': 'application/json', - ...headers - } + }, headers) }); request.write(JSON.stringify(data)); @@ -108,6 +107,48 @@ let basicApi = { request.end(); }); + }, + + /** + * 下载指定的文件,返回buffer + * @param {*} url + * @param {*} headers + */ + downloadFileByURL: (url, headers = {}) => { + return new Promise((resolve, reject) => { + const request = net.request({ + method: 'GET', + url: url, + headers: headers + }); + request.on('response', (response) => { + const chunks = []; + response.on('data', (chunk) => chunks.push(chunk)); + response.on('end', async () => { + try { + console.log('File downloaded successfully'); + resolve({ + data: Buffer.concat(chunks), + status: response.statusCode, + statusText: response.statusMessage, + headers: response.headers + }); + } catch (err) { + reject(err); + } + }); + response.on('error', (error) => { + console.log('error', error); + reject(error); + }); + }); + + request.on('error', (error) => { + reject(error); + }); + + request.end(); + }); } } diff --git a/src/api/discordApi.js b/src/api/discordApi.js new file mode 100644 index 0000000..891b86a --- /dev/null +++ b/src/api/discordApi.js @@ -0,0 +1,98 @@ + +import { basicApi } from "./apiBasic"; +import { Tools } from "../main/tools"; + +export class DiscordAPI { + constructor() { + this.tools = new Tools(); + } + + + /** + * 通过设置的ID获取MJ API的任务 + * @param {*} id + */ + async GetMJAPITaskByID(id, url, key) { + try { + let res; + url = url.replace("${id}", id); + let headers = { + "Authorization": key + } + res = await basicApi.get(url, headers); + + let progress = res.data.progress && res.data.progress.length > 0 ? parseInt(res.data.progress.slice(0, -1)) : 0; + let status = res.data.status.toLowerCase(); + // let code = (status == "success" || status == "in_progress" || status == "not_start") ? 1 : 0; + let code = (status == "failure" || status == "cancel") ? 0 : 1; + // 返回前端 + let res_data = { + type: "updated", + progress: progress, + category: "api_mj", + image_click: res.data.imageUrl, + image_show: res.data.imageUrl, + message_id: res.data.id, + action: res.data.action, + status: status, + code: code, + } + + // 判断当前的API是哪个 + if (url.includes("mjapi.deepwl.net")) { + if (res_data.code == 0) { + res_data["message"] = res.data.failReason + } + } else if (url.includes("api.ephone.ai")) { + // ePhoneAPI + if (res_data.code == 0) { + res_data["message"] = res.data.failReason + } + } + return res_data; + } catch (error) { + throw error + } + + } + + /** + * MJ使用API进行生图 + */ + async mjApiImagine(url, data, headers) { + try { + // 判断是不是需要垫图,将指定的图片转换为base64 + for (let i = 0; data.base64Array && i < data.base64Array.length; i++) { + const element = data.base64Array[i]; + // 将指定的图片转换为base64 + // 判断图片是本地图片还是网络图片 + if (element.indexOf("http") == -1) { + // 本地图片 + let base64 = await this.tools.readFileBase64(element); + data.base64Array[i] = `data:image/png;base64,${base64}` + } else { + // 网络图片 + // 请求对应的图片 + let image_buffer = await basicApi.get(element); + // 将返回来的数据转为base64 + let base64 = image_buffer.data.toString('base64'); + data.base64Array[i] = `data:image/png;base64,${base64}` + } + } + + let res = await basicApi.post(url, data, headers); + console.log(res) + let res_data = res.data; + // 判断res_data 是不是json格式的字符串,是就序列化为json对象 + if (typeof res_data == "string") { + res_data = JSON.parse(res_data); + } + if (res_data && res_data.code != 1) { + throw new Error(res_data.message); + } + return res_data; + } catch (error) { + throw error; + } + } +} diff --git a/src/api/sdApi.js b/src/api/sdApi.js index af6c5f2..e463ab4 100644 --- a/src/api/sdApi.js +++ b/src/api/sdApi.js @@ -70,6 +70,7 @@ export class SdApi { data.steps = this.sd_setting.webui.steps; data.save_images = false; data.batch_size = data.batch_size ? data.batch_size : 1; + if (data.width == null) { data.width = 512; } diff --git a/src/define/api/apiUrlDefine.js b/src/define/api/apiUrlDefine.js new file mode 100644 index 0000000..b0ce905 --- /dev/null +++ b/src/define/api/apiUrlDefine.js @@ -0,0 +1,56 @@ +let apiUrl = [{ + label: "openai-hk", + value: "3d64e50e-79c0-49ec-a72d-7dfdf508dd04", + gpt_url: "https://api.openai-hk.com/v1/chat/completions", + mj_url: null, + buy_url: "https://openai-hk.com/?i=10196" +}, { + label: "通义千问", + value: "b630c69a-99e9-46bc-8d88-39a00bcc3d2a", + gpt_url: "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", + mj_url: null, + buy_url: null +}, { + label: "DrawAPI(MJ)", + value: "2cabf684-ac48-4733-a427-8c41626f7d8f", + gpt_url: null, + mj_url: { + imagine: "https://mjapi.deepwl.net/api/mj/submit/imagine", + describe: "https://mjapi.deepwl.net/api/mj/submit/describe", + update_file: "https://mjapi.deepwl.net/api/mj/submit/upload-discord-images", + once_get_task: "https://mjapi.deepwl.net/api/mj/query/task/${id}", + get_task_list: "https://mjapi.deepwl.net/api/mj/task/list-by-condition" + }, + d3_url: null, + buy_url: "https://mjapi.deepwl.net/#/home" +}, { + label: "ePhoneAPI", + value: "b8866543-8c27-4888-869c-00aa1eb31272", + gpt_url: "https://api.ephone.ai/v1/chat/completions", + mj_url: { + imagine: "https://api.ephone.ai/mj/submit/imagine", + describe: "https://api.ephone.ai/mj/submit/describe", + update_file: "https://api.ephone.ai/mj/submit/upload-discord-images", + once_get_task: "https://api.ephone.ai/mj/task/${id}/fetch", + }, + d3_url: { + image: "https://api.ephone.ai/v1/images/generations" + }, + buy_url: "https://ephone.ai/register?aff=55XT" +}] + +/** + * 通过ID获取指定的数据(value) + * @param {*} id + */ +function getApiMessageByID(id) { + let mj_api_url_index = apiUrl.findIndex(item => item.value == id) + if (mj_api_url_index == -1) { + throw new Error("没有找到对应的MJ API的配置,请先检查配置") + } + +} +export { + apiUrl, + getApiMessageByID +} diff --git a/src/define/define_string.js b/src/define/define_string.js index f0ccc89..6145df7 100644 --- a/src/define/define_string.js +++ b/src/define/define_string.js @@ -132,6 +132,7 @@ export const DEFINE_STRING = { TRANSLATE_RETURN_NOW_TASK: "TRANSLATE_RETURN_NOW_TASK", IMAGE_SAVE_TO_OTHER_FOLDER: "IMAGE_SAVE_TO_OTHER_FOLDER", SAVE_FILE_QUEUE: "SAVE_FILE_QUEUE", + AUTO_SAVE_DATA_JSON: "AUTO_SAVE_DATA_JSON" }, PERMISSIONS: { NORMAL_PERMISSION: "NORMAL_PERMISSION", @@ -156,7 +157,9 @@ export const DEFINE_STRING = { ADD_MJ_BAD_PROMPT: "ADD_MJ_BAD_PROMPT", MJ_BAD_PROMPT_CHECK: "MJ_BAD_PROMPT_CHECK", GET_GENERATED_MJ_IMAGE_AND_SPLIT: "GET_GENERATED_MJ_IMAGE_AND_SPLIT", - DOWNLOAD_IMAGE_URL_AND_SPLIT: "DOWNLOAD_IMAGE_URL_AND_SPLIT" + DOWNLOAD_IMAGE_URL_AND_SPLIT: "DOWNLOAD_IMAGE_URL_AND_SPLIT", + GET_MJ_IMAGE_SCALE: 'GET_MJ_IMAGE_SCALE', + GET_MJ_IMAGE_ROBOT_MODEL: "GET_MJ_IMAGE_ROBOT_MODEL" }, DISCORD: { OPERATE_REFRASH_DISCORD_URL: "OPERATE_REFRASH_DISCORD_URL", @@ -175,5 +178,8 @@ export const DEFINE_STRING = { }, MAIN: { OPEN_DISCORD_WINDOW: "OPEN_DISCORD_WINDOW" + }, + IMG: { + ONE_SPLIT_FOUR: "ONE_SPLIT_FOUR" } } \ No newline at end of file diff --git a/src/define/gptDefine.js b/src/define/gptDefine.js index 04a9b00..7db31ee 100644 --- a/src/define/gptDefine.js +++ b/src/define/gptDefine.js @@ -2,6 +2,7 @@ let fspromises = require('fs').promises; import { cloneDeep, get } from "lodash"; import { define } from "./define"; const { v4: uuidv4 } = require('uuid'); +import { apiUrl } from "./api/apiUrlDefine"; // Create a shared object export const gptDefine = { @@ -271,13 +272,7 @@ export const gptDefine = { } }, - gpt_options: [{ - label: "openai-hk", - value: "https://api.openai-hk.com/v1/chat/completions" - }, { - label: "通义千问", - value: "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" - }], + gpt_options: apiUrl, gpt_model_options: [{ label: "gpt-3.5-turbo-16k", @@ -377,7 +372,9 @@ export const gptDefine = { gpt[index] = value; } } else { - value.id = uuidv4(); + let tmp_id = uuidv4(); + value.id = tmp_id; + value.value = tmp_id; gpt.push(value); } tmp_gpt[property] = gpt; diff --git a/src/define/setting/mjSetting.js b/src/define/setting/mjSetting.js index 50eac8c..ccff0bf 100644 --- a/src/define/setting/mjSetting.js +++ b/src/define/setting/mjSetting.js @@ -1,16 +1,89 @@ -import { Tools } from "../../main/tools"; -import { define } from "../define"; -import path from "path"; -import { DEFINE_STRING } from "../define_string"; -import { get, has } from "lodash"; -let tools = new Tools(); -const { v4: uuidv4 } = require('uuid'); // 引入UUID库来生成唯一标识符 +import { successMessage } from "../../main/generalTools"; export class MjSetting { constructor(golbal) { this.golbal = golbal; } + /** + * 获取MJ生成图片的机器人模型 + */ + GetMJImageRobotModel() { + return successMessage([ + { + label: "MJ V6.0", + text: "v 6", + type: "mj", + value: "3e6473ab-9a64-4574-9a38-f5c75af552b6" + }, + { + label: "MJ V5.2", + text: "v 5.2", + type: "mj", + value: "27a0d30e-f46c-4684-96c8-d91334deb94f" + }, + { + label: "MJ V5.1", + text: "v 5.1", + type: "mj", + value: "e1226715-e969-44c4-b18b-f2ad5dae5d2f" + }, { + label: "MJ V5.0", + text: "v 5", + type: "mj", + value: "afb7bea1-4eda-46ea-8165-34701b4566bf" + }, { + label: "MJ V4.0", + text: "v 4", + type: "mj", + value: "d05b8497-7f4a-4890-8fac-89f1803984d2" + }, { + label: "NIJI V6", + text: "niji 6", + type: "niji", + value: "99377cad-c103-4cee-a958-86a104879328" + }, { + label: "NIJI V5", + text: "niji 5", + type: "niji", + value: "53cec077-9885-4635-ab18-e021066b2c4c" + }, { + label: "NIJI V4", + text: "niji 4", + type: "niji", + value: "6a7199fe-6e0d-40a9-9772-b5eb3d2e2e66" + }, + ]) + } + + /** + * 获取生图的比例 + * @returns + */ + GetMJImageScale() { + return successMessage([{ + label: "1:1", + text: "1:1", + value: "3e2772f2-041c-49c6-ba13-d0ed120310b8" + }, { + label: "4:3", + text: "4:3", + value: "fcef555c-1958-4082-88fe-434782aa8151" + }, { + label: "3:4", + text: "3:4", + value: "13f71d53-73a3-4c9b-9c1e-6e7e939aee73" + }, { + label: "16:9", + text: "16:9", + value: "bf33ce1a-15cd-4901-b38e-89543cf14a1f" + }, { + label: "9:16", + text: "9:16", + value: "fd4641e2-97f4-4a86-8616-4965e05f3348" + }]) + } + /** * 返回mj生成图片方式的分类 */ @@ -18,20 +91,24 @@ export class MjSetting { return { code: 1, data: [{ - label: "本地MJ", - value: "local_mj" + label: "本地MJ(待开发)", + value: "local_mj", + disable: true }, { label: "代理MJ(待开发)", - value: "remote_mj" + value: "remote_mj", + disable: true }, { label: "浏览器模式", - value: "browser_mj" + value: "browser_mj", + disable: false }, { - label: "API模式(待开发)", - value: "api_mj" + label: "API模式", + value: "api_mj", + disable: false } ] } diff --git a/src/main/IPCEvent/imageIpc.js b/src/main/IPCEvent/imageIpc.js new file mode 100644 index 0000000..68d32a0 --- /dev/null +++ b/src/main/IPCEvent/imageIpc.js @@ -0,0 +1,14 @@ +import { ipcMain } from "electron"; +import { DEFINE_STRING } from '../../define/define_string' +import { Image } from "../Public/Image"; +let image = new Image(global); + + +function ImageIpc() { + + // 一拆四 + ipcMain.handle(DEFINE_STRING.IMG.ONE_SPLIT_FOUR, async (event, value) => await image.OneSplitFour(value)); +} +export { + ImageIpc +} \ No newline at end of file diff --git a/src/main/IPCEvent/mjIpc.js b/src/main/IPCEvent/mjIpc.js index 796bdbd..c08092d 100644 --- a/src/main/IPCEvent/mjIpc.js +++ b/src/main/IPCEvent/mjIpc.js @@ -57,6 +57,12 @@ function MjIpc() { // 给图片链接,下载指定的图片并分割保存 ipcMain.handle(DEFINE_STRING.MJ.DOWNLOAD_IMAGE_URL_AND_SPLIT, async (event, value) => await mJOriginalImageGenerate.DownloadImageUrlAndSplit(value)); + // 获取MJ图片的所有的分割尺寸 + ipcMain.handle(DEFINE_STRING.MJ.GET_MJ_IMAGE_SCALE, async (event) => await mjSimple.GetMJImageScale()); + + // 获取所有的MJ生图模型 + ipcMain.handle(DEFINE_STRING.MJ.GET_MJ_IMAGE_ROBOT_MODEL, async (event) => await mjSimple.GetMJImageRobotModel()); + /** * 监听DISCORD界面创建消息,并修改数据 */ diff --git a/src/main/Original/MJOriginalImageGenerate.js b/src/main/Original/MJOriginalImageGenerate.js index 4551f70..52a0115 100644 --- a/src/main/Original/MJOriginalImageGenerate.js +++ b/src/main/Original/MJOriginalImageGenerate.js @@ -9,7 +9,11 @@ import path from 'path' import sharp from 'sharp' import { define } from "../../define/define"; import { AwesomeRegx } from "awesome-js"; -import { checkStringValueAddSuffix } from "../generalTools"; +import { checkStringValueAddSuffix, errorMessage, successMessage } from "../generalTools"; +import { ImageSetting } from "../../define/setting/imageSetting"; +import { DiscordAPI } from "../../api/discordApi"; +import { GPT } from "../Public/GPT"; +const { v4: uuidv4 } = require('uuid'); /** * MJ原创生图的类 @@ -20,6 +24,39 @@ export class MJOriginalImageGenerate { this.pm = new PublicMethod(global); this.discordWorker = new DiscordWorker(); this.tools = new Tools(); + this.discordAPI = new DiscordAPI(); + this.gpt = new GPT(global); + } + /** + * 返回指定的人物到前端 + * @param {*} data + */ + sendChangeMessage(data) { + this.global.newWindow[0].win.webContents.send(DEFINE_STRING.DISCORD.MAIN_DISCORD_MESSAGE_CHANGE, data); + } + + /** + * 初始化MJ设置 + */ + async InitMjSetting() { + let mjSetting_res = await ImageSetting.GetDefineConfigJsonByProperty(JSON.stringify(['img_base', 'mj_config', false, null])); + if (mjSetting_res.code == 0 || !mjSetting_res.data) { + throw new Error("请先添加MJ配置") + } + let mjSetting = mjSetting_res.data; + return mjSetting; + } + + /** + * 初始化MJ API的URL + */ + async InitMJAPIUrl(id) { + let mj_api = (await this.gpt.GetGPTBusinessOption("all", (value) => value.mj_url)).data; + let mj_api_url_index = mj_api.findIndex(item => item.value == id); + if (mj_api_url_index == -1) { + throw new Error("没有找到对应的MJ API的配置,请先检查配置") + } + return mj_api[mj_api_url_index]; } /** @@ -28,6 +65,7 @@ export class MJOriginalImageGenerate { */ async DownloadImageUrlAndSplit(value) { try { + console.log(value) value = JSON.parse(value); let element = value[0]; let iamge_url = value[1]; @@ -77,52 +115,97 @@ export class MJOriginalImageGenerate { async GetGeneratedMJImageAndSplit(value) { try { value = JSON.parse(value); - let param = []; - // 循环数据,直传需要的数据 - for (let i = 0; i < value.length; i++) { - const element = value[i]; - param.push({ - id: element.id, - image_id: element.mj_message.image_id, - name: element.name, - }); + let mjSetting = await this.InitMjSetting(); + let request_model = mjSetting.request_model; + let result = []; + // 浏览器生图模式 + if (request_model == "browser_mj") { + let param = []; + // 循环数据,直传需要的数据 + for (let i = 0; i < value.length; i++) { + const element = value[i]; + // 一般进度大于 50 会出现图片, + if (!element.mj_message) { + continue; + } + if (element.mj_message.progress && element.mj_message.progress == 100) { + // 判断 image_path 是不是存在。 + if (item.mj_message.image_id && !element.mj_message.image_path) { + // 通过当前的image_id获取图片 + param.push({ + id: element.id, + image_id: element.mj_message.image_id, + name: element.name, + }); + } + } + } + + // 判断窗口是不是开启 + let discordWin = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); + // 执行采集图片的脚本 + // 开始写入 + let discordSimple = new DiscordSimple(discordWin); + // 开始执行脚本 + result = await discordSimple.ExecuteScript(define.discordScript, `GetGeneratedMJImageAndSplit(${JSON.stringify(param)})`); + + } else if (request_model == "api_mj") { + let mj_api = await this.InitMJAPIUrl(mjSetting.mj_api_url); + let once_get_task = mj_api.mj_url.once_get_task; + + // 请求 + for (let i = 0; i < value.length; i++) { + const element = value[i]; + if (element.mj_message.progress == 100) { + continue + } + if (element.mj_message.progress.status == "success") { + continue + } + + let task_res = await this.discordAPI.GetMJAPITaskByID(element.mj_message.message_id, once_get_task, mjSetting.api_key); + if (task_res.code == 0) { + task_res["id"] = element.id; + task_res["mj_api_url"] = mjSetting.mj_api_url; + this.sendChangeMessage() + } + // 判断进度是不是百分百 + if (task_res.progress != 100) { + continue + } + + result.push({ + id: element.id, + image_id: null, + result: task_res.image_click, + name: element.name + }) + } } - // 判断窗口是不是开启 - let discordWin = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); - // 执行采集图片的脚本 - // 开始写入 - let discordSimple = new DiscordSimple(discordWin); - // 开始执行脚本 - let result = await discordSimple.ExecuteScript(define.discordScript, `GetGeneratedMJImageAndSplit(${JSON.stringify(param)})`); - let res = []; - result = JSON.parse(result); + // 判断返回的数据是不是一个字符串 + if (typeof result == "string") { + result = JSON.parse(result); + } + // 将返回的数据进行分割 for (let i = 0; i < result.length; i++) { const element = result[i]; - let image_path = path.join(global.config.project_path, `data\\MJOriginalImage\\${element.image_id}.png`); - - - let ds = this.DownloadImageUrlAndSplit(JSON.stringify[element, element.result, image_path]); + let image_path = path.join(global.config.project_path, `data\\MJOriginalImage\\${uuidv4()}.png`); + let ds = await this.DownloadImageUrlAndSplit(JSON.stringify([element, element.result, image_path])); if (ds.code == 0) { throw new Error(ds.message); } - + // 修改数据。 + ds.data["progress"] = 100; + ds.data["status"] = "success"; res.push(ds.data); } - // 全部分割完毕,返回 - return { - code: 1, - data: res - } - + return successMessage(res); } catch (error) { - return { - code: 0, - message: "获取已经生图完成的数据,并获取图片错误,错误信息如下" + error.message - } + return errorMessage("获取已经生图完成的数据,并获取图片错误,错误信息如下" + error.message) } } @@ -182,6 +265,114 @@ export class MJOriginalImageGenerate { } + /** + * 调用API生图的方法 + * @param {*} element + * @param {*} mjSetting + */ + async MJImagineRequest(element, mjSetting, prompt) { + try { + // 获取当前的API url + let apiUrl = await this.InitMJAPIUrl(mjSetting.mj_api_url); + let imagine_url = apiUrl.mj_url.imagine; + let once_get_task = apiUrl.mj_url.once_get_task; + let task_count = mjSetting.task_count ? mjSetting.task_count : 3; + let request_model = mjSetting.request_model ? mjSetting.request_model : "relaxed"; + let res; + // 判断当前的API是哪个 + if (imagine_url.includes("mjapi.deepwl.net")) { + // DrawAPI(MJ) + let data = { + prompt: prompt, + mode: request_model == "fast" ? "FAST" : "RELAX", + } + let headers = { + "Authorization": mjSetting.api_key + } + res = await this.discordAPI.mjApiImagine(imagine_url, data, headers); + } else if (imagine_url.includes("api.ephone.ai")) { + // ePhoneAPI + let headers = { + "Authorization": mjSetting.api_key + } + let data = { + prompt: prompt, + botType: "MID_JOURNEY", + accountFilter: { + modes: [ + request_model == "fast" ? "FAST" : "RELAX" + ] + } + } + res = await this.discordAPI.mjApiImagine(imagine_url, data, headers); + } + // 创建成功,开始下一个 + this.sendChangeMessage({ + code: 1, + type: "created", + category: "api_mj", + message_id: res.result, + image_click: null, + image_show: null, + id: element.id, + progress: 0, + mj_api_url: mjSetting.mj_api_url + }); + this.global.mjGenerateQuene.setCurrentCreateItem(null); + // 开始监听当前ID是不是的生图任务完成 + // 这边设置一个循环监听,每隔一段时间去请求一次 + let timeoutId; + let startInterval = () => { + timeoutId = setTimeout(async () => { + // 执行你的操作 + let task_res = await this.discordAPI.GetMJAPITaskByID(res.result, once_get_task, mjSetting.api_key) + console.log(task_res) + // 判断他的状态是不是成功 + if (task_res.code == 0) { + // 将但钱任务删除 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter(item => item?.id != element.id) + }); + // 停止当前循环 + clearTimeout(timeoutId); + } else { + if (task_res.progress == 100) { + // 将但钱任务删除 + this.global.mjGenerateQuene.removeTaskProgress((taskProgress) => { + return taskProgress.filter(item => item?.id != element.id) + }); + task_res.type = "finished"; + // 下载对应的图片 + let image_path = path.join(this.global.config.project_path, `data\\MJOriginalImage\\${task_res.message_id}.png`); + // 这边开始下载对应的图片 + await this.tools.downloadFileUrl(task_res.image_click, image_path); + task_res["image_path"] = image_path; + // 开始下一个任务 + this.global.mjGenerateQuene.startNextTask(task_count); + } else { + // 当获取的图片的进度小于100的时候,继续监听 + startInterval(); + } + } + task_res['id'] = element.id; + task_res["mj_api_url"] = mjSetting.mj_api_url; + this.sendChangeMessage(task_res); + }, 5000); + } + startInterval(); + this.global.mjGenerateQuene.startNextTask(task_count); + + } catch (error) { + this.sendChangeMessage({ + code: 0, + status: "error", + message: error.message, + id: element.id + }) + throw new Error("MJ API 出图错误,错误信息如下:" + error.message) + } + } + /** * MJ 原创生图 * @param {*} value @@ -206,6 +397,8 @@ export class MJOriginalImageGenerate { let output_crop_00001 = path.join(this.global.config.project_path, `tmp\\output_crop_00001`); await this.tools.checkFolderExistsOrCreate(output_crop_00001); + // 获取MJ配置 + let mjSetting = await this.InitMjSetting(); // 检查this.global中是不是又mj队列,没有的话创建一个 if (!this.global.mjGenerateQuene) { @@ -225,35 +418,41 @@ export class MJOriginalImageGenerate { let old_prompt = element.prompt; // 拼接提示词 // 图生图的链接 - // 获取风格词 - let prompt = " " + image_styles + old_prompt; + // 获取风格词 + 命令后缀 + let prompt = " " + image_styles + old_prompt + (mjSetting.image_suffix ? mjSetting.image_suffix : ""); - - this.global.mjGenerateQuene.enqueue(async () => { - try { - this.global.mjGenerateQuene.setCurrentCreateItem(element) - // 开始进行mj生图 - current_task = element.name; - // 判断窗口是不是开启 - - let discordW = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); - - // 开始写入 - let discordSimple = new DiscordSimple(discordW); - await discordSimple.WritePromptToInput(prompt); - - // 发送命令完成(删除当前正在执行。开始下一个任务) - - } catch (error) { - throw error; - } - - - }, tasK_id, batch); + // 判断当前生图模式 + let request_model = mjSetting.request_model + switch (request_model) { + case "api_mj": + this.global.mjGenerateQuene.enqueue(async () => { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + await this.MJImagineRequest(element, mjSetting, prompt) + }, tasK_id, batch) + break; + case "browser_mj": + this.global.mjGenerateQuene.enqueue(async () => { + try { + this.global.mjGenerateQuene.setCurrentCreateItem(element) + // 开始进行mj生图 + current_task = element.name; + // 判断窗口是不是开启 + let discordW = await this.discordWorker.CheckDiscordWindowIsOpenAndLoad(); + // 开始写入 + let discordSimple = new DiscordSimple(discordW, mjSetting); + await discordSimple.WritePromptToInput(prompt); + // 发送命令完成(删除当前正在执行。开始下一个任务) + } catch (error) { + throw error; + } + }, tasK_id, batch); + default: + break; + } } // 判断该当前正在执行的人物队列数(小于设置的数量,开始一个任务) - this.global.mjGenerateQuene.startNextTask(); + this.global.mjGenerateQuene.startNextTask(mjSetting.task_count ? mjSetting.task_count : 3); this.global.requestQuene.setBatchCompletionCallback(batch, (failedTasks) => { if (failedTasks.length > 0) { @@ -265,31 +464,16 @@ export class MJOriginalImageGenerate { message += `${taskId}-, \n 错误信息: ${error}` + '\n'; }); - this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { - code: 0, - message: message - }) + this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, errorMessage(message)) } else { if (show_global_message) { - this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, { - code: 1, - message: "所有MJ生图任务完成" - }) + this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, successMessage(null, '所有MJ生图任务完成')) } } }); - - - return { - code: 1, - } - - + return successMessage(null) } catch (error) { - return { - code: 0, - message: "MJ生图错误,错误信息如下" + error.message - } + return errorMessage("MJ生图错误,错误信息如下" + error.message) } } diff --git a/src/main/Original/OriginalImageGenerate.js b/src/main/Original/OriginalImageGenerate.js index 2db1091..3957f3d 100644 --- a/src/main/Original/OriginalImageGenerate.js +++ b/src/main/Original/OriginalImageGenerate.js @@ -214,7 +214,6 @@ export class OriginalImageGenerate { } } - /** * 自动保存数据到json文件 * @param {*} value 自动保存数据到json文件 @@ -223,9 +222,11 @@ export class OriginalImageGenerate { try { // 目前自动保存的信息,中文提示词,英文提示词,前缀,后缀 value = JSON.parse(value); + let batch = DEFINE_STRING.QUEUE_BATCH.AUTO_SAVE_DATA_JSON; for (let i = 0; i < value.length; i++) { const element = value[i]; // 将修改文件的的方法添加到修改文件队列中 + this.global.fileQueue.enqueue(async () => { try { if (element.prompt_json) { @@ -244,7 +245,7 @@ export class OriginalImageGenerate { } catch (error) { throw new Error(error); } - }); + }, `${batch}_${element.id}`, batch); // 判断是不是有图片。判断图片是不是符合格式(有些格式是file:// 开头的, 以时间结尾(都要删除)) // 判断是不是有图片 diff --git a/src/main/Public/GPT.js b/src/main/Public/GPT.js index cd359a4..f2c0c31 100644 --- a/src/main/Public/GPT.js +++ b/src/main/Public/GPT.js @@ -4,6 +4,8 @@ import { DEFINE_STRING } from "../../define/define_string"; import { define } from "../../define/define"; let fspromises = require("fs").promises; import { gptDefine } from "../../define/gptDefine"; +import { apiUrl } from "../../define/api/apiUrlDefine"; +import { successMessage } from "../generalTools"; export class GPT { constructor(global) { @@ -255,6 +257,18 @@ export class GPT { gpt_key = this.global.config.gpt_key, gpt_model = this.global.config.gpt_model) { try { + // 还有自定义的 + let all_options = (await this.GetGPTBusinessOption("all", (value) => value.gpt_url)).data; + // 判断gpt_business 是不是一个http开头的 + if (!gpt_url.includes("http")) { + // 获取对应Id的gpt_url + let index = all_options.findIndex(item => item.value == gpt_url && item.gpt_url); + if (index < 0) { + throw new Error("获取GPT的服务商配置失败"); + } + gpt_url = all_options[index].gpt_url; + } + let data = { "model": gpt_model, @@ -268,7 +282,8 @@ export class GPT { url: gpt_url, headers: { 'Authorization': `Bearer ${gpt_key}`, - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + "Accept": "application/json" }, data: JSON.stringify(data) }; @@ -317,8 +332,16 @@ export class GPT { * 获取GPT的服务商配置,默认的和自定义的 * @returns */ - async GetGPTBusinessOption(value) { - return await gptDefine.getGptDataByTypeAndProperty(value, "gpt_options", []); + async GetGPTBusinessOption(value, callback = null) { + let res = await gptDefine.getGptDataByTypeAndProperty(value, "gpt_options", []); + if (res.code == 0) { + return res; + } else { + if (callback) { + callback(res.data) + } + return successMessage(res.data) + } } /** diff --git a/src/main/Public/Image.js b/src/main/Public/Image.js new file mode 100644 index 0000000..6359f41 --- /dev/null +++ b/src/main/Public/Image.js @@ -0,0 +1,48 @@ +import { errorMessage, successMessage } from "../generalTools"; +import path from "path"; +import { Tools } from "../tools"; + +export class Image { + constructor(global) { + this.global = global; + this.tools = new Tools(); + } + + // 将指定的文件夹复制到四个文件夹中 + async OneSplitFour(value) { + try { + value = JSON.parse(value); + let count = value[1]; + let data = value[0]; + // 先创建输出文件 + if (count <= 1) { + throw new Error("可选择的图片的数量必须大于1"); + } + for (let i = 1; i < count; i++) { + let out_folder = path.join(this.global.config.project_path, `tmp/output_crop_0000${i + 1}`); + // 判断当前的文件夹是不是存在,存在删除 + let isH = await this.tools.checkExists(out_folder); + if (isH) { + await this.tools.deleteFileOrDirectory(out_folder); + } + await this.tools.checkFolderExistsOrCreate(out_folder) + } + for (let i = 0; i < data.length; i++) { + const element = data[i]; + let subImagePath = element.subImagePath; + for (let j = 1; j < count; j++) { + let out_file = path.join(this.global.config.project_path, `tmp/output_crop_0000${j + 1}/${element.name}`); + if (subImagePath[j] && subImagePath[j].startsWith("file")) { + subImagePath[j] = subImagePath[j].replace("file://", ""); + subImagePath[j] = subImagePath[j].replace(/\?time=.*$/, ''); + } + await this.tools.copyFileOrDirectory(subImagePath[j], out_file); + } + } + return successMessage("拆分成功"); + + } catch (error) { + return errorMessage(error.message); + } + } +} \ No newline at end of file diff --git a/src/main/backPrompt/videoGenerate.js b/src/main/backPrompt/videoGenerate.js index e360e35..b5b9aa1 100644 --- a/src/main/backPrompt/videoGenerate.js +++ b/src/main/backPrompt/videoGenerate.js @@ -365,7 +365,7 @@ export class VideoGenerate { // let task_list = JSON.parse(await fspromises.readFile(path.join(this.global.config.project_path,'scripts/task_'))); let scriptPath = path.join(define.scripts_path, 'Lai.exe'); // 执行生成图片的脚本 - let script = `cd "${define.scripts_path}" && "${scriptPath}" -c "${project_config_path.replaceAll('\\', '/')}"`; + let script = `cd "${define.scripts_path}" && "${scriptPath}" -c "${project_config_path.replaceAll('\\', '/')}" "${this.global.gpu.type}"`; const output = await execAsync(script, { maxBuffer: 1024 * 1024 * 10, encoding: 'utf-8' }); if (output.stderr != '') { obj.status = "video_error"; diff --git a/src/main/discord/discordApi.js b/src/main/discord/discordApi.js deleted file mode 100644 index 973cf0d..0000000 --- a/src/main/discord/discordApi.js +++ /dev/null @@ -1,482 +0,0 @@ -const axios = require('axios'); -const fetch = require("node-fetch"); - -export class DiscordAPI { - constructor(mj_setting) { - // https://discord.com/api/v9/channels/1208362852482809939/messages?limit=20 - this.apiClient = axios.create({ - baseURL: 'https://discord.com' - }); - this.DiscordBaseUrl = 'https://discord.com'; - this.ServerId = mj_setting.serviceID; - this.ChannelId = mj_setting.channelID; - this.userToken = mj_setting.token; - this.botId = mj_setting.select_robot?.botId; - this.commandId = mj_setting.select_robot?.commandId; - this.versionId = mj_setting.select_robot?.versionId; - this.versionName = mj_setting.select_robot?.versionName; - this.botName = mj_setting.select_robot?.botName; - } - - // 提交任务 - async imagine(data) { - - // let req_data = { - // "token": this.userToken, - // "method": "post", - // "api_url": "/mj/submit/imagine", - // "data":data - // } - - // const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - // await this.interactions(data.prompt); - return await this.interactions(data.prompt) - // return { - // code:1, - // result:'taskid_'+new Date().getTime() - // } - // return response.data; - - } - async channelList() { - axios.get(`https://discord.com/api/v9/channels/${this.ChannelId}/messages?limit=20`, { - method: 'get', - headers: { - "Authorization": this.userToken - } - }) - .then(response => { - // 请求成功处理 - console.log(typeof response.data); - let eList = [] - let flg = false; - let job_id = ''; - let type = ''; - if (response && response.data) { - try { - response.data.forEach(element => { - flg = false; - type = ''; - if (element.attachments && element.attachments.length) { - const arr = element.attachments[0].filename.split("_"); - job_id = arr[arr.length - 1].replace(".png", ''); - if (element.components) { - element.components.forEach(e2 => { - e2.components.forEach(e3 => { - if (e3.label == 'U1') { - flg = true; - type = 'U1' - } else if (e3.label && e3.label.indexOf('Upscale') > -1) { - flg = true; - type = 'Upscale' - } - }) - }); - } - let t = eList.find((e) => { - return e.filename == element.attachments[0].filename; - }) - - if (!t) { - eList.push( - { - flg: flg, job_id: job_id, filename: element.attachments[0].filename, - url: element.attachments[0].url, - proxy_url: element.attachments[0].proxy_url, - type: type, - timestamp: element.timestamp - }) - } - - // console.log({flg:flg,job_id:job_id,filename:element.attachments[0].filename}) - } else { - console.log({ flg: flg }) - } - - }); - } catch (error) { - console.log('异常2', error) - } - // console.log(eList) - // 8e7406df-bf0c-4e3d-8e49-b2bb8e2c263d - // 5abedc71-ba80-4756-8ddc-489c927d3acd - } - }).catch(error => { - // 请求失败处理 - console.error(error); - }); - } - // 混合 - async blend(data) { - - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": "/mj/submit/blend", - "data": data - } - - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - - } - - - // 反推 - async describe(data) { - - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": "/mj/submit/describe", - "data": data - } - - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - - } - - // 获取任务 - async getTaskId(task_id) { - let req_data = { - "token": this.userToken, - "method": "get", - "api_url": `/mj/task/${task_id}/fetch`, - "data": {} - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - } - - //获取seed - async imageSeed(task_id) { - let req_data = { - "token": this.userToken, - "method": "get", - "api_url": `/mj/task/${task_id}/image-seed`, - "data": {} - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - - } - - //账号创建 - async account_create(data) { - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": '/mj/account/create', - "data": data - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data, { timeout: 20000 }); - return response.data; - } - - //账号创建 - async account_fetch(cid) { - let req_data = { - "token": this.userToken, - "method": "get", - "api_url": `/mj/account/${cid}/fetch`, - "data": {} - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - - } - - //账号同步信息 - async account_asyn_info(cid) { - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": `/mj/account/${cid}/sync-info`, - "data": {} - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data, { timeout: 20000 }); - return response.data; - } - - //账号删除信息 - async account_del_info(cid) { - let req_data = { - "token": this.userToken, - "method": "delete", - "api_url": `/mj/account/${cid}/delete`, - "data": {} - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - } - - - //执行动作 - async action(data) { - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": '/mj/submit/action', - "data": data - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - } - - // 确认弹窗 - async modal(data) { - let req_data = { - "token": this.userToken, - "method": "post", - "api_url": '/mj/submit/modal', - "data": data - } - const response = await this.apiClient.post('/api/v3/req_mj_api', req_data); - return response.data; - - } - - async interactions(prompt) { - // 直接自己调用 - prompt = prompt.trim(); - // prompt = "4k,8k,best quality, masterpiece, woman, divorced, leaving fast-paced city life, serene expression, walking away from cityscape, bustling streets, entering tranquil countryside, peaceful surroundings, rejuvenating atmosphere, , --niji 5 --ar 4:3" - var payload = {}; - if (this.botName == 'niji') { - payload = { - "type": 2, - "application_id": this.botId, - "guild_id": this.ServerId, - "channel_id": this.ChannelId, - "session_id": this.userToken, - "data": { - "version": this.versionId, - "id": this.commandId, - "name": "imagine", - "type": 1, - "options": [ - { - "type": 3, - "name": "prompt", - "value": prompt - } - ], - "application_command": { - "id": this.commandId, - "type": 1, - "application_id": this.botId, - "version": this.versionId, - "name": "imagine", - "description": "Create images with Midjourney", - "options": [ - { - "type": 3, - "name": "prompt", - "description": "The prompt to imagine", - "required": true, - "description_localized": "The prompt to imagine", - "name_localized": "prompt" - } - ], - "integration_types": [ - 0 - ], - "global_popularity_rank": 1, - "description_localized": "Create images with Midjourney", - "name_localized": "imagine" - }, - "attachments": [ - - ] - }, - // "nonce": "1210857131343872000", - "analytics_location": "slash_ui" - } - } else { - payload = { - "type": 2, - // "application_id":"1022952195194359889",//niji - "application_id": this.botId, - "guild_id": this.ServerId, - "channel_id": this.ChannelId, - "session_id": this.userToken, - "data": { - "version": this.versionId, - "id": this.commandId, - "name": "imagine", "type": 1, - "options": - [{ - "type": 3, - "name": "prompt", - "value": prompt - }], - "application_command": { - "id": this.commandId, - "type": 1, - "application_id": this.botId, - "version": this.versionId, - "name": "imagine", - "description": "Create images with Niji journey", - "options": [{ "type": 3, "name": "prompt", "description": "The prompt to imagine", "required": true, "description_localized": "The prompt to imagine", "name_localized": "prompt" }], - "integration_types": [0], "global_popularity_rank": 1, "description_localized": "Create images with Niji journey", "name_localized": "imagine" - }, - "attachments": [] - }, - "analytics_location": "slash_ui" - } - } - - let response = { - status: 200, - data: {} - }; - - - try { - const headers = { - "Content-Type": "application/json", - Authorization: this.userToken, - }; - await fetch(`${this.DiscordBaseUrl}/api/v9/interactions`, { - method: "POST", - body: JSON.stringify(payload), - headers: headers, - }).then(res => res.json()).then(res => { - response.data = res; - }).catch(e => { - console.error("请求失败了,详细信息:" + JSON.stringify(e)); - response = { - status: 500, - data: JSON.stringify(e) - }; - }); - console.log('response结果') - console.log(response) - // if (response.status == 204) { - // //成功 - - // } - if (response.status >= 400) { - console.error("api.error.config", { - payload: JSON.stringify(payload) - }); - } - return { - code: response.status, - response: response - }; - } - catch (error) { - console.error(error); - return 500; - } - return; - const client = new Midjourney.Midjourney({ - ServerId: this.ServerId, - ChannelId: this.ChannelId, - SalaiToken: this.userToken, - Debug: true, - fetch: fetch, - Ws: true, //enable ws is required for remix mode (and custom zoom) - }); - await client.init(); - console.log('mjmj_begin2', prompt); - // const prompt = - // "Christmas dinner with spaghetti with family in a cozy house, we see interior details , simple blue&white illustration"; - //imagine - const Imagine = await client.Imagine( - prompt, - (uri, progress) => { - client.Close(); - - console.log("loading", uri, "progress", progress); - return - } - ); - console.log(Imagine); - if (!Imagine) { - console.log("no message"); - console.log('mjmj_end2') - return; - } - console.log('mjmj_end') - client.Close(); - return - - } - - /** - * 获取频道内的机器人 - * @returns 返回机器人列表 - */ - async getBotList() { - try { - - const headers = { - 'Host': 'discord.com', - 'Connection': 'keep-alive', - 'authorization': this.userToken, - } - - await fetch('https://discord.com/api/v9/guilds/1182523906855284826/application-command-index', { - method: 'GET', - headers: headers, - }) - .then(response => { - response.json() - } - ) - .then(data => { - console.log(data) - }) - .catch(error => { - console.error('Error:', error) - }) - - - } catch (error) { - throw new Error(error); - } - } - - - async getMjMsgList() { - // const headers = { - // "Content-Type": "application/json", - // Authorization:this.userToken, - // }; - let response = { - status: 200, - data: {} - }; - // // `https://discord.com/api/v9/channels/${mj_channelId}/messages?limit=10 - // await fetch(`${this.DiscordBaseUrl}/api/v9/channels/${this.ChannelId}/messages?limit=50`, { - // method: "GET", - // headers: headers, - // }).then(res => res.json()).then(res => { - // response.data=res; - // }).catch(e => { - // console.error("请求失败了,详细信息:" + JSON.stringify(e)); - // response ={ - // status:500, - // data:JSON.stringify(e) - // }; - // }); - // console.log('getMjMsgList_response结果') - // // console.log(response) - - // return response; - axios.get(`https://discord.com/api/v9/channels/${this.ChannelId}/messages?limit=20`, { - method: 'get', - headers: { - "Authorization": this.userToken - } - }).then(res => { - response.data = res; - }).catch(error => { - // 请求失败处理 - console.error(error); - }); - - } -} diff --git a/src/main/discord/discordSimple.js b/src/main/discord/discordSimple.js index e82cfc1..35ba607 100644 --- a/src/main/discord/discordSimple.js +++ b/src/main/discord/discordSimple.js @@ -10,10 +10,11 @@ import { DEFINE_STRING } from "../../define/define_string"; * 对DisCord窗口进行操作的方法 */ export class DiscordSimple { - constructor(win) { + constructor(win, mjSetting) { this.win = win; this.tools = new Tools(); this.script = define.discordScript; + this.mjSetting = mjSetting; } @@ -103,7 +104,7 @@ export class DiscordSimple { async GetInputPosition() { try { await this.InitData(); - await this.tools.delay(10000) + await this.tools.delay(this.mjSetting.space_time ? this.mjSetting.space_time * 1000 : 10000) let result = await this.ExecuteScript(this.script, 'GetMessageInputPosition()'); this.x = result.mouseX; this.y = result.mouseY; @@ -641,6 +642,7 @@ export class DiscordSimple { let currentCreateItem = global.mjGenerateQuene.getCurrentCreateItem(); console.log("LAITOOL 创建数据: ", value); value.type = "created" + value.category = "browser_mj" // 判断是不是是不是错误数据 if (value.error) { @@ -652,7 +654,7 @@ export class DiscordSimple { // 在将当前任务设置为空 global.mjGenerateQuene.setCurrentCreateItem(null); // 开始下一个任务 - global.mjGenerateQuene.startNextTask(); + global.mjGenerateQuene.startNextTask(this.mjSetting.task_count ? this.mjSetting.task_count : 3); } @@ -702,7 +704,7 @@ export class DiscordSimple { global.mjGenerateQuene.setCurrentCreateItem(null); } - global.mjGenerateQuene.startNextTask(); + global.mjGenerateQuene.startNextTask(this.mjSetting.task_count ? this.mjSetting.task_count : 3); } catch (error) { this.sendChangeMessage({ @@ -722,6 +724,7 @@ export class DiscordSimple { // 接收到discord的消息 console.log("LAITOOL 更新数据: ", value); value.type = "updated"; + value.category = "browser_mj" // 更新的时候,修改数据(判断是不是有进度) let regex = /\((\d+)%\)/; @@ -760,6 +763,7 @@ export class DiscordSimple { } console.log("LAITOOL 删除数据: ", value) value.type = "delete" + value.category = "browser_mj" this.sendChangeMessage(value) // 这边可能要做判断(判断是不是开启下一个) diff --git a/src/main/discord/mjSimple.js b/src/main/discord/mjSimple.js index e2da33b..651ccd2 100644 --- a/src/main/discord/mjSimple.js +++ b/src/main/discord/mjSimple.js @@ -1,9 +1,10 @@ let path = require('path'); import { Tools } from "../tools"; -import { DiscordAPI } from "./discordApi"; +import { DiscordAPI } from "../../api/discordApi"; import { MjSetting } from "../../define/setting/mjSetting"; import { DynamicSetting } from "../../define/setting/dynamicSetting"; import { AwesomeHelp } from "awesome-js" +import { errorMessage, successMessage } from "../generalTools"; export class MjSimple { constructor(global) { @@ -58,8 +59,6 @@ export class MjSimple { value = JSON.parse(value); let discordAPI = new DiscordAPI(value); let res = await discordAPI.getBotList(); - - } catch (error) { return { code: 0, @@ -102,7 +101,10 @@ export class MjSimple { } } - // 获取MJ所有的敏感词 + /** + * 获取MJ所有的敏感词 + * @returns + */ async GetMJBadPrompt() { try { let default_bad_prompt = this.mjSetting.GetMJBadPrompt().data; @@ -119,6 +121,34 @@ export class MjSimple { } } + + /** + * 获取所有的MJ的图片比例 + */ + async GetMJImageScale() { + try { + let default_image_scale = this.mjSetting.GetMJImageScale().data; + let data = await this.dynamicSetting.getDataByTypeAndProperty("all", 'mj', 'image_scale', default_image_scale, []); + return successMessage(data.data) + } catch (error) { + return errorMessage("获取图片比例失败, 错误信息如下:" + error.toString()); + } + } + + /** + * 获取所有的生图机器人模型 + */ + async GetMJImageRobotModel() { + try { + let default_image_robot_model = this.mjSetting.GetMJImageRobotModel().data; + let data = await this.dynamicSetting.getDataByTypeAndProperty("all", 'mj', 'image_robot_model', default_image_robot_model, []); + return successMessage(data.data) + } catch (error) { + return errorMessage("获取生图机器人模型失败, 错误信息如下:" + error.toString()); + } + } + + /** * 检查当前出入数据所有的敏感词 * @param {*} data @@ -175,10 +205,6 @@ export class MjSimple { } } } - - console.log(res); - - } console.log(bad_prompt_ids) diff --git a/src/main/func.js b/src/main/func.js index 7e0ff83..6db293c 100644 --- a/src/main/func.js +++ b/src/main/func.js @@ -144,7 +144,7 @@ async function ReGenerateImageOne(window, value) { } prompt += value[1].prompt; - + let model = value[1].model; // 判断当前是不是有开修脸修手 @@ -626,12 +626,12 @@ 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; @@ -970,10 +970,7 @@ async function DeleteBadPrompt() { * 打开购买 GPT 的网址 */ async function openGptBuyUrl(value) { - // console.log(value) - if (value == "https://api.openai-hk.com/v1/chat/completions") { - OpenUrl('https://openai-hk.com/?i=10196') - } + OpenUrl(value) } /** @@ -1055,7 +1052,7 @@ async function StartStoryboarding(value) { global.newWindow[0].win.webContents.send(DEFINE_STRING.GET_FRAME_RETUN, { code: 1, data: "正在调用进程。请勿关闭程序" }) let cc = `${path.join(define.scripts_path, 'Lai.exe')}`; - let child = spawn(cc, ["-a", value.video_path, frame_path, input_path, value.sensitivity], { encoding: 'utf-8' }); + let child = spawn(cc, ["-a", value.video_path, frame_path, input_path, value.sensitivity, global.gpu.type], { encoding: 'utf-8' }); child.on('error', console.error) child.stdout.on('data', (data) => { console.log(data.toString()); diff --git a/src/main/generalTools.js b/src/main/generalTools.js index a468f24..eb03c30 100644 --- a/src/main/generalTools.js +++ b/src/main/generalTools.js @@ -66,7 +66,6 @@ function checkStringValueDeletePrefix(value, prefix) { } /** * 返回成功的消息,包含code,data,message - * @param {*} code * @param {*} data * @param {*} message * @returns @@ -81,7 +80,6 @@ function successMessage(data, message = null) { /** * 返回失败的消息,包含code,message - * @param {*} code * @param {*} message * @returns */ diff --git a/src/main/index.js b/src/main/index.js index 175e41a..884d046 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1,6 +1,7 @@ import fspromises from "fs/promises"; import { v4 as uuidv4 } from 'uuid'; import { version } from '../../package.json' +import { graphics } from "systeminformation" import { app, shell, BrowserWindow, ipcMain, dialog, nativeTheme } from 'electron' @@ -29,6 +30,8 @@ import { SdIpc } from './IPCEvent/sdIpc.js' import { DiscordIpc, RemoveDiscordIpc } from './IPCEvent/discordIpc.js' import { MainIpc } from './IPCEvent/mainIpc.js' import { GlobalIpc } from "./IPCEvent/globalIpc.js"; +import { ImageIpc } from "./IPCEvent/imageIpc.js"; +import { system } from "systeminformation"; let tools = new Tools(); let imageGenerate = new ImageGenerate(global); @@ -226,6 +229,7 @@ MjIpc(); MainIpc(createWindow); OriginalImageGenerateIpc(); GlobalIpc(); +ImageIpc(); ipcMain.handle('dark-mode:toggle', (event, value) => { @@ -313,7 +317,31 @@ ipcMain.handle(DEFINE_STRING.ADD_DRAFT, async (event, value) => { }) // 获取当前版本 -ipcMain.handle(DEFINE_STRING.GET_VERSION, async (event) => version); +ipcMain.handle(DEFINE_STRING.GET_VERSION, async (event) => { + // 获取当前电脑的显卡信息 + let da = await graphics(); + for (let i = 0; i < da.controllers.length; i++) { + // 获取第一个英伟达或者是AMD的显卡信息 + const element = da.controllers[i]; + if (element.vendor.startsWith("NVIDIA")) { + global.gpu = element; + global.gpu.type = "NVIDIA"; + break; + } else if (element.vendor.startsWith("AMD") || element.vendor.startsWith("Advanced")) { + global.gpu = element; + global.gpu.type = "AMD"; + break; + } else { + global.gpu = { + name: "OTHER" + }; + global.gpu.type = "OTHER"; + } + } + + return version + " " + (global.gpu?.name ? global.gpu.name : ""); + +}); // 监听保存SD配置 ipcMain.handle(DEFINE_STRING.SAVE_SD_CONFIG, async (event, value) => await func.SaveSDConfig(value)) diff --git a/src/main/quene.js b/src/main/quene.js index d8ca11a..2316d7f 100644 --- a/src/main/quene.js +++ b/src/main/quene.js @@ -19,6 +19,14 @@ export class AsyncQueue { } async enqueue(task, taskId, batchId, subBatchId = 'default') { + + if (batchId && batchId != DEFINE_STRING.QUEUE_BATCH.IMAGE_SAVE_TO_OTHER_FOLDER) { + // 判断当前的任务是否已经存在,存在则不添加 + let index = this.tasks.findIndex(item => item.taskId === taskId && item.batchId === batchId && item.subBatchId === subBatchId); + if (index != -1) { + throw new Error(`Task ${taskId} in batch ${batchId} already exists.`); + } + } if (!this.batchCompletion[batchId]) { this.batchCompletion[batchId] = { remaining: 0, subBatches: {}, callback: null, failedTasks: [] }; } @@ -50,7 +58,7 @@ export class AsyncQueue { this.taskDeadline = deadline; } - async process() { + async process(task_count = 0) { // 判断是不是有机器码检测的标识 if (!this.global.CheckMachineId) { @@ -68,7 +76,7 @@ export class AsyncQueue { return; } - while (this.tasks.length > 0 && this.currentConcurrency < this.concurrencyLimit) { + while (this.tasks.length > 0 && (this.manualMode ? this.taskProgress.length < task_count : this.currentConcurrency < this.concurrencyLimit)) { const { task, taskId, batchId, subBatchId } = this.tasks.shift(); this.currentConcurrency++; task().then(() => { @@ -244,14 +252,14 @@ export class AsyncQueue { } // 手动开启下一个任务 - async startNextTask() { + async startNextTask(taskCount = 3) { // 判断当前是不是有任务正在执行 if (this.currentCreateItem) { return; } console.log("调用开始下一个任务", this.taskProgress) - if (this.manualMode && this.tasks.length > 0 && this.currentConcurrency < this.concurrencyLimit && this.taskProgress.length < 3) { - this.process(); + if (this.manualMode && this.tasks.length > 0 && this.taskProgress.length < taskCount) { + this.process(taskCount); } } diff --git a/src/main/tools.js b/src/main/tools.js index 2be6805..8786d2b 100644 --- a/src/main/tools.js +++ b/src/main/tools.js @@ -6,7 +6,7 @@ const { spawn, exec } = require('child_process'); const execAsync = util.promisify(exec); import { define } from "../define/define"; import { get, has, set } from "lodash"; -import axios from "axios"; +import { basicApi } from "../api/apiBasic"; export class Tools { constructor() { } @@ -311,31 +311,12 @@ export class Tools { * @returns */ async downloadFileUrl(url, filePath) { - return new Promise((resolve, reject) => { - const request = net.request({ - method: 'GET', - url: url - }); - request.on('response', (response) => { - const chunks = []; - response.on('data', (chunk) => chunks.push(chunk)); - response.on('end', async () => { - try { - await fspromises.writeFile(filePath, Buffer.concat(chunks)); - console.log('File downloaded successfully'); - resolve(); - } catch (err) { - reject(err); - } - }); - }); - - request.on('error', (error) => { - reject(error); - }); - - request.end(); - }); + try { + let data = await basicApi.downloadFileByURL(url); + await fspromises.writeFile(filePath, data.data); + } catch (error) { + throw error; + } } /** diff --git a/src/preload/img.js b/src/preload/img.js new file mode 100644 index 0000000..546cdb3 --- /dev/null +++ b/src/preload/img.js @@ -0,0 +1,11 @@ +import { ipcRenderer } from "electron" +import { DEFINE_STRING } from "../define/define_string" + + +const img = { + // 加载当前链接的SD服务数据 + OneSplitFour: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.IMG.ONE_SPLIT_FOUR, value)), +} +export { + img +} \ No newline at end of file diff --git a/src/preload/index.js b/src/preload/index.js index 03a14d3..a4bd1a6 100644 --- a/src/preload/index.js +++ b/src/preload/index.js @@ -4,6 +4,7 @@ import { DEFINE_STRING } from '../define/define_string.js'; import { discord } from './discord.js'; import { mj } from './mj.js'; import { sd } from './sd.js'; +import { img } from './img.js'; // Custom APIs for renderer let events = []; @@ -411,6 +412,7 @@ if (process.contextIsolated) { contextBridge.exposeInMainWorld('mj', mj) contextBridge.exposeInMainWorld('discord', discord) contextBridge.exposeInMainWorld("sd", sd) + contextBridge.exposeInMainWorld("img", img) contextBridge.exposeInMainWorld('darkMode', { toggle: (value) => ipcRenderer.invoke('dark-mode:toggle', value), }) @@ -423,5 +425,6 @@ if (process.contextIsolated) { window.mj = mj; window.discord = discord; window.sd = sd; + window.img = img; } diff --git a/src/preload/mj.js b/src/preload/mj.js index 8a2bdb4..7ecb5b8 100644 --- a/src/preload/mj.js +++ b/src/preload/mj.js @@ -6,6 +6,7 @@ const mj = { SvaeMJWordSrt: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.SAVE_WORD_SRT, value)), // 获取MJ配置文件的字幕信息 GetMJConfigSrtInformation: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_MJ_CONFIG_SRT_INFORMATION)), + // 获取标签集的基础信息 GetTagDataByTypeAndProperty: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_TAG_DATA_BY_TYPE_AND_PROPERTY, value)), // 保存数据到标签集中 @@ -14,10 +15,12 @@ const mj = { DeleteTagPropertyData: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.DELETE_TAG_PROPERTY_DATA, value)), // 获取选择标签的模式option列表 GetTagSelectModel: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_TAG_SELECT_MODEL)), + // 将翻译任务添加到后台队列中 TranslateReturnNowTask: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.TRANSLATE_RETURN_NOW_TASK, value)), // MJ原创生图 OriginalMJImageGenerate: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.ORIGINAL_MJ_IMAGE_GENERATE, value)), + // 获取当前对话频道的机器人列表 GetChannelRobots: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_CHANNEL_ROBOTS, value)), @@ -29,6 +32,7 @@ const mj = { // 添加MJ敏感词 AddMjBadPrompt: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.ADD_MJ_BAD_PROMPT, value)), + // 添加MJ敏感词检查 MJBadPromptCheck: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.MJ_BAD_PROMPT_CHECK, value)), @@ -37,6 +41,12 @@ const mj = { // 给图片链接,下载指定的图片并分割保存 DownloadImageUrlAndSplit: async (value, callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.DOWNLOAD_IMAGE_URL_AND_SPLIT, value)), + + // 获取图片的所有的分割尺寸 + GetMJImageScale: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_MJ_IMAGE_SCALE)), + + // 获取所有的MJ生图模型 + GetMJImageRobotModel: async (callback) => callback(await ipcRenderer.invoke(DEFINE_STRING.MJ.GET_MJ_IMAGE_ROBOT_MODEL)), } export { diff --git a/src/renderer/src/components/Backstep/BatchSaveImageSetting.vue b/src/renderer/src/components/Backstep/BatchSaveImageSetting.vue index a7be859..52eb416 100644 --- a/src/renderer/src/components/Backstep/BatchSaveImageSetting.vue +++ b/src/renderer/src/components/Backstep/BatchSaveImageSetting.vue @@ -47,8 +47,8 @@
-
选择保存到的文件夹
- 选择手动保存的文件夹
+ 选择文件夹
@@ -169,7 +169,7 @@ export default defineComponent({ async function SaveImage() { debugger if (isEmpty(save_setting.value.save_folder)) { - message.error("请选择保存到的文件夹") + message.error("请选择手动保存的文件夹") return } if (save_setting.value.save_match_count == 0) { diff --git a/src/renderer/src/components/Backstep/ReGenerate.vue b/src/renderer/src/components/Backstep/ReGenerate.vue index e8f20f2..ceaa84c 100644 --- a/src/renderer/src/components/Backstep/ReGenerate.vue +++ b/src/renderer/src/components/Backstep/ReGenerate.vue @@ -1,495 +1,539 @@ \ 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 08b82cc..bd2ef67 100644 --- a/src/renderer/src/components/Components/CheckMachineId.vue +++ b/src/renderer/src/components/Components/CheckMachineId.vue @@ -1,83 +1,109 @@ \ No newline at end of file + diff --git a/src/renderer/src/components/Components/GenerateAllImages.vue b/src/renderer/src/components/Components/GenerateAllImages.vue index 842592a..b580198 100644 --- a/src/renderer/src/components/Components/GenerateAllImages.vue +++ b/src/renderer/src/components/Components/GenerateAllImages.vue @@ -232,6 +232,7 @@ export default defineComponent({ window.api.setEventListen( [DEFINE_STRING.REGENERATE_IMAGE_RETUN, window.id], (value) => { + debugger if (value.type != 1) { return; } diff --git a/src/renderer/src/components/Home/ReDrawImageWD.vue b/src/renderer/src/components/Home/ReDrawImageWD.vue index 8c63860..e42d207 100644 --- a/src/renderer/src/components/Home/ReDrawImageWD.vue +++ b/src/renderer/src/components/Home/ReDrawImageWD.vue @@ -1,744 +1,857 @@ \ 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 deb5fd5..aca0be6 100644 --- a/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue +++ b/src/renderer/src/components/Original/Components/DataTableShowGenerateImage.vue @@ -17,9 +17,39 @@ @click="MJGetImage" >MJ采集图片 + 1拆4
-
进度:{{ data.mj_message?.progress }}%
+
+
进度:{{ data.mj_message?.progress }}%
+ {{ + data.mj_message?.status != null && data.mj_message?.status != '' + ? data.mj_message?.status + : 'wait' + }} +
+ + + {{ data.mj_message?.message }} + +
+
{{ data.mj_message?.message_id }}
+
+
import { ref, h, onMounted, defineComponent, onUnmounted, toRaw, watch } from 'vue' -import { NImage, useMessage, NDivider, NImageGroup, NButton, NSelect } from 'naive-ui' +import { + NImage, + useMessage, + NDivider, + NImageGroup, + NButton, + NSelect, + NPopover, + NTag +} from 'naive-ui' export default defineComponent({ components: { @@ -72,7 +111,9 @@ export default defineComponent({ NDivider, NImageGroup, NButton, - NSelect + NSelect, + NPopover, + NTag }, props: ['initData', 'type', 'image_generate_category', 'func'], setup(props) { @@ -234,6 +275,13 @@ export default defineComponent({ props.func.mJGetImage() } + /** + * 1拆4 + */ + async function OneSplitFour() { + await props.func.oneSplitFour() + } + return { data, type, @@ -247,7 +295,8 @@ export default defineComponent({ imageDragOver, select_image_category, UpdateImageGenerateCategory, - MJGetImage + MJGetImage, + OneSplitFour } } }) diff --git a/src/renderer/src/components/Original/Components/PromptSetting.vue b/src/renderer/src/components/Original/Components/PromptSetting.vue index ed89c4c..d1f0965 100644 --- a/src/renderer/src/components/Original/Components/PromptSetting.vue +++ b/src/renderer/src/components/Original/Components/PromptSetting.vue @@ -80,8 +80,56 @@
- - 添加敏感词 +
出图模式
+ + +
+
+
出图机器人
+ + +
+ +
+
出图速度模式
+ + +
+ +
+
MJ并发数量
+ +
+ +
+ 添加敏感词
@@ -149,6 +197,15 @@ export default defineComponent({ let character_select_model = ref(window.config.character_select_model) let character_select_model_options = ref([]) + let mjSetting = ref({ + select_robot: null, + task_count: 1, + request_model: null, + mj_speed: 'relaxed' + }) + let request_model_options = ref([]) + let select_robot_options = ref([]) + let mj_speed_options = ref([]) /** * 初始化GPT的option @@ -187,6 +244,60 @@ export default defineComponent({ }) } + /** + * 初始化MJ的option + */ + async function InitMjOptions() { + // 获取当前mj配置信息 + await window.api.GetDefineConfigJsonByProperty( + JSON.stringify(['img_base', 'mj_config', false, null]), + (value) => { + debugger + console.log(value) + if (value.code == 0) { + message.error(value.message) + return + } + // 判断是不是有数据 + if (value.data) { + mjSetting.value = value.data + } + } + ) + + await window.mj.GetMJGenerateCategory((value) => { + if (value.code == 0) { + message.error(value.message) + return + } + request_model_options.value = value.data.filter((item) => !item.disable) + if (request_model_options.value.length > 0 && mjSetting.value.request_model == null) { + mjSetting.value.request_model = request_model_options.value[0].value + } + }) + select_robot_options.value = [ + { + label: 'MJ', + value: 'mj' + }, + { + label: 'NIJI', + value: 'niji' + } + ] + + mj_speed_options.value = [ + { + label: 'RELAXED', + value: 'relaxed' + }, + { + label: 'FAST', + value: 'fast' + } + ] + } + onMounted(async () => { // 加载全局配置 // 获取SD配置 @@ -200,8 +311,10 @@ export default defineComponent({ sd_image_width.value = value.data.width sd_image_height.value = value.data.height }) - await InitGptOptions() + + // 获取MJ相关配置 + await InitMjOptions() }) /** @@ -236,6 +349,18 @@ export default defineComponent({ } }) + // 保存MJ配置 + + await window.api.SaveDefineConfigJsonByProperty( + JSON.stringify(['img_base', 'mj_config', toRaw(mjSetting.value), false]), + (value) => { + if (value.code == 0) { + message.error(value.message) + return + } + } + ) + message.success('保存成功') } catch (error) { debugger @@ -300,7 +425,11 @@ export default defineComponent({ character_select_model_options, character_select_model, AddMjBadPrompt, - bad_prompt_ref + bad_prompt_ref, + mjSetting, + request_model_options, + select_robot_options, + mj_speed_options } } }) diff --git a/src/renderer/src/components/Original/DataTable.vue b/src/renderer/src/components/Original/DataTable.vue index 7475122..e70cb47 100644 --- a/src/renderer/src/components/Original/DataTable.vue +++ b/src/renderer/src/components/Original/DataTable.vue @@ -115,7 +115,6 @@ export default defineComponent({ watch( () => props.tags, async (newVal) => { - debugger tags.value = newVal // 同步修改 selectStyle.value 的值 for (let i = 0; i < selectStyle.value.length; i++) { @@ -126,7 +125,8 @@ export default defineComponent({ selectStyle.value[i] = tags.value.style_tags[index] } } - } + }, + { deep: true } ) watch( @@ -315,7 +315,8 @@ export default defineComponent({ type: 'title', image_generate_category: image_generate_category, func: { - mJGetImage: MJGetImage + mJGetImage: MJGetImage, + oneSplitFour: OneSplitFour } }) }, @@ -324,6 +325,7 @@ export default defineComponent({ width: '300', render(row, index) { return h(DataTableShowGenerateImage, { + image_generate_category: image_generate_category, initData: row, index: index, type: 'data' @@ -335,7 +337,6 @@ export default defineComponent({ let isSaved = false // 监听control+s 保存数据 let saveListener = function (event) { - debugger if (event.ctrlKey && event.key === 's') { event.preventDefault() if (!isSaved) { @@ -366,7 +367,7 @@ export default defineComponent({ selectStyle.value = value.data }) - for (let i = 0; i < customize_image_style_list && customize_image_style_list.length; i++) { + for (let i = 0; customize_image_style_list && i < customize_image_style_list.length; i++) { const element = customize_image_style_list[i] selectStyle.value.push({ key: element, @@ -431,19 +432,25 @@ export default defineComponent({ mainDiscordMessageChanged(value) } ) - await props.InitTags() }) onBeforeUnmount(async () => { - debugger await AutoSaveDataJson() }) // 接收Discord的修改信息 async function mainDiscordMessageChanged(value) { + console.log(value) if (value.code == 0) { message.error('Discord返回错误,错误信息如下:' + value.message) + // 判断当前的数据是不是有ID + if (value.id) { + let index = data.value.findIndex((item) => item.id == value.id) + data.value[index]['mj_message']['status'] = 'error' + data.value[index]['mj_message']['message'] = value.message + } + AutoSaveDataJsonDebounced() return } @@ -461,6 +468,7 @@ export default defineComponent({ delete value.type delete value.code data.value[index]['mj_message'] = value + AutoSaveDataJsonDebounced() } else if (value.type == 'updated') { console.log('接收Discord的更新消息', value) // 修改对应的数据 @@ -475,15 +483,18 @@ export default defineComponent({ } delete value.type delete value.code - data.value[index]['mj_message'] = value } else if (value.type == 'delete') { console.log('接收Discord的删除消息', value) } else if (value.type == 'finished') { console.log('接收Discord的完成消息', value) - // 修改对应的数据 - let index = data.value.findIndex((item) => item.mj_message?.image_id == value.image_id) - if (index < 0) { + let index + if (value.category == 'api_mj') { + index = data.value.findIndex((item) => item.id == value.id) + } else if (value.category == 'browser_mj') { + index = data.value.findIndex((item) => item.mj_message?.image_id == value.image_id) + } + if (index == null || index < 0) { message.error('未找到对应的数据') return } @@ -494,20 +505,32 @@ export default defineComponent({ delete value.code value.progress = 100 value.message_id = value.message_id + value.message = null data.value[index]['mj_message'] = value + AutoSaveDataJsonDebounced() // 返回后端分割图片(传入图片地址,返回分割后的图片地址数组) await window.mj.ImageSplit( - JSON.stringify([value.image_path, data.value[index].name]), + JSON.stringify([ + value.image_path, + data.value[index].name == null ? '' : data.value[index].name + ]), (value) => { if (value.code == 0) { message.error(value.message) return } // 修改数据 - data.value[index]['outImagePath'] = value.data.outImagePath - data.value[index]['subImagePath'] = value.data.subImagePath + data.value[index]['outImagePath'] = + 'file://' + + value.data.outImagePath.replaceAll('\\', '/') + + '?time=' + + new Date().getTime() + data.value[index]['subImagePath'] = value.data.subImagePath.map( + (item) => 'file://' + item.replaceAll('\\', '/') + '?time=' + new Date().getTime() + ) + AutoSaveDataJsonDebounced() } ) } else { @@ -1018,23 +1041,22 @@ export default defineComponent({ } /** - * + * 采集图片 */ async function MJGetImage() { + // 判断是什么方式获取图片 + // 判断当前是不是有MJ_message,并且状态不为error,并且有message_id let pa = [] - // MJ采集图片 for (let i = 0; i < data.value.length; i++) { const item = data.value[i] - // 一般进度大于 50 会出现图片, if (!item.mj_message) { - return + continue } - if (item.mj_message.progress && item.mj_message.progress == 100) { - // 判断 image_path 是不是存在。 - if (item.mj_message.image_id && !item.mj_message.image_path) { - // 通过当前的image_id获取图片 - pa.push(item) - } + if (item.mj_message.status && item.mj_message.status == 'error') { + continue + } + if (item.mj_message.message_id && !isEmpty(item.mj_message.message_id)) { + pa.push(item) } } @@ -1053,11 +1075,22 @@ export default defineComponent({ message.error('未找到对应的数据') return } - data.value[index].outImagePath = element.outImagePath - data.value[index].subImagePath = element.subImagePath + + data.value[index].outImagePath = + 'file://' + + element.outImagePath.replaceAll('\\', '/') + + '?time=' + + new Date().getTime() + + data.value[index].subImagePath = element.subImagePath.map( + (item) => 'file://' + item.replaceAll('\\', '/') + '?time=' + new Date().getTime() + ) data.value[index].mj_message.image_click = element.result data.value[index].mj_message.image_path = element.image_path + data.value[index].mj_message.progress = 100 + data.value[index].mj_message.status = 'success' } + AutoSaveDataJsonDebounced() }) } else { message.error('没有找到可以自动下载图片的数据,可以手动粘贴链接分割') @@ -1065,6 +1098,54 @@ export default defineComponent({ } } + /** + * 一拆四 + */ + async function OneSplitFour() { + debugger + // 判断当前的data中是不是都有图片 + let min + let pra = [] + for (let i = 0; i < data.value.length; i++) { + const element = data.value[i] + if (element.outImagePath == null || element.outImagePath == '') { + message.error('当前数据没有图片,无法进行一拆四') + return + } + if (element.subImagePath == null || element.subImagePath.length == 0) { + message.error('当前数据没有图片,无法进行一拆四') + return + } + if (min == null) { + min = element.subImagePath.length + } + if (element.subImagePath.length < min) { + min = element.subImagePath.length + } + pra.push({ + id: element.id, + name: element.name, + outImagePath: element.outImagePath, + subImagePath: element.subImagePath + }) + } + + // 判断最小的min + if (min <= 1) { + message.error('当前最小图片小于等于1,无法进行一拆四') + return + } + + // 将当前数据传到后端进行一拆四 + await window.img.OneSplitFour(JSON.stringify([pra, min]), (value) => { + debugger + if (value.code == 0) { + message.error('一拆四失败,错误信息如下:' + value.message) + return + } + }) + } + return { data, columns: createColumns({}), diff --git a/src/renderer/src/components/Original/MainPage.vue b/src/renderer/src/components/Original/MainPage.vue index 3013693..e5ce218 100644 --- a/src/renderer/src/components/Original/MainPage.vue +++ b/src/renderer/src/components/Original/MainPage.vue @@ -84,7 +84,7 @@ export default defineComponent({ message.error(value.message) promptError = false } - data.value[i].prompt = value.data.webui_config.prompt + data.value[i].prompt = value.data?.webui_config.prompt data.value[i].chinese_prompt = value.data?.chinese_prompt // data.value[i].gpt_prompt = value.data?.gpt_prompt; data.value[i].adetailer = value.data?.adetailer diff --git a/src/renderer/src/components/Original/MenuButton.vue b/src/renderer/src/components/Original/MenuButton.vue index 0e6e4eb..b49e5ad 100644 --- a/src/renderer/src/components/Original/MenuButton.vue +++ b/src/renderer/src/components/Original/MenuButton.vue @@ -217,8 +217,6 @@ export default defineComponent({ * 生成所有的图片 */ async function GenerateImageAll() { - debugger - console.log(data.value) let tmpData = cloneDeep(toRaw(data.value)) tmpData = tmpData.filter((item) => { return item.outImagePath == null || item.outImagePath == '' @@ -230,7 +228,7 @@ export default defineComponent({ } // 判断当前是mj还是sd - let ca = window.config.image_generate_category + let ca = window.config.image_generate_category ? window.config.image_generate_category : 'sd' if (ca == 'sd') { // 将所有的人物添加到后台队列任务中 await window.api.OriginalSDImageGenerate([JSON.stringify(tmpData), true, true], (value) => { diff --git a/src/renderer/src/components/Setting/Components/AddGptOption.vue b/src/renderer/src/components/Setting/Components/AddGptOption.vue index 15b6818..7888c94 100644 --- a/src/renderer/src/components/Setting/Components/AddGptOption.vue +++ b/src/renderer/src/components/Setting/Components/AddGptOption.vue @@ -15,7 +15,7 @@ - +
保存 @@ -234,7 +234,7 @@ export default defineComponent({ let rules = { label: ruleObj("必填GPT名称"), - value: ruleObj("必填GPT请求网址"), + gpt_url: ruleObj("必填GPT请求网址"), }; let modelRules = { diff --git a/src/renderer/src/components/Setting/MJSetting.vue b/src/renderer/src/components/Setting/MJSetting.vue index 095dc82..5a9644b 100644 --- a/src/renderer/src/components/Setting/MJSetting.vue +++ b/src/renderer/src/components/Setting/MJSetting.vue @@ -1,346 +1,556 @@ \ No newline at end of file + diff --git a/src/renderer/src/components/Setting/Setting.vue b/src/renderer/src/components/Setting/Setting.vue index 355ea75..950fc80 100644 --- a/src/renderer/src/components/Setting/Setting.vue +++ b/src/renderer/src/components/Setting/Setting.vue @@ -197,6 +197,7 @@ import { import AddGptOption from './Components/AddGptOption.vue' import { FolderOpenSharp as FolderOpen } from '@vicons/ionicons5' import AddGptPrompts from './Components/AddGptPrompts.vue' +import { isEmpty } from 'lodash' export default defineComponent({ components: { @@ -250,7 +251,7 @@ export default defineComponent({ message.error(value.message) return } - gpt_options.value = value.data + gpt_options.value = value.data.filter((item) => item.gpt_url) }) await window.api.getGptModelOption('all', (value) => { @@ -367,7 +368,18 @@ export default defineComponent({ * 打开购买GPT的地址 */ async function openGptBuyUrl() { - window.api.openGptBuyUrl(toRaw(formValue.value.gpt_business)) + debugger + let tmp_gb = gpt_options.value.filter((item) => item.value == formValue.value.gpt_business) + if (tmp_gb.length == 0) { + message.error('当前选择的服务商没有购买地址!') + return + } + let buy_url = tmp_gb[0].buy_url + if (isEmpty(buy_url)) { + message.error('当前选择的服务商没有购买地址!') + } else { + window.api.openGptBuyUrl(buy_url) + } } /**