LaiTool/src/main/Original/MJOriginalImageGenerate.js

480 lines
20 KiB
JavaScript
Raw Normal View History

2024-05-15 12:57:15 +08:00
import { DEFINE_STRING } from "../../define/define_string";
import { AsyncQueue } from '../quene'
import { PublicMethod } from '../Public/publicMethod'
import { ImageStyleDefine } from '../../define/iamgeStyleDefine'
import { DiscordSimple } from "../discord/discordSimple";
import { DiscordWorker } from "../discord/discordWorker";
import { Tools } from "../tools";
import path from 'path'
import sharp from 'sharp'
import { define } from "../../define/define";
import { AwesomeRegx } from "awesome-js";
2024-06-01 15:08:22 +08:00
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');
2024-05-15 12:57:15 +08:00
/**
* MJ原创生图的类
*/
export class MJOriginalImageGenerate {
constructor(global) {
this.global = global;
this.pm = new PublicMethod(global);
this.discordWorker = new DiscordWorker();
this.tools = new Tools();
2024-06-01 15:08:22 +08:00
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];
2024-05-15 12:57:15 +08:00
}
/**
* 下载指定的图片地址并且分割
* @param {*} value
*/
async DownloadImageUrlAndSplit(value) {
try {
2024-06-01 15:08:22 +08:00
console.log(value)
2024-05-15 12:57:15 +08:00
value = JSON.parse(value);
let element = value[0];
let iamge_url = value[1];
let image_path = "";
if (value.length > 2) {
image_path = value[2];
} else {
image_path = path.join(global.config.project_path, `data\\MJOriginalImage\\${element.id}.png`);
}
// 判断是不是一个链接
const urlRegex = /^(http|https):\/\/[^ "]+$/;
if (!urlRegex.test(iamge_url)) {
throw new Error("指定的图片地址不是一个链接");
}
// 这边开始下载对应的图片
await this.tools.downloadFileUrl(iamge_url, image_path);
// 将下载的图片进行分割
let split_res = await this.ImageSplit(JSON.stringify([image_path, element.name]));
if (split_res.code == 0) {
throw new Error(split_res.message);
}
element.image_click = iamge_url;
element.subImagePath = split_res.data.subImagePath;
element.outImagePath = split_res.data.outImagePath;
element['image_path'] = image_path
return {
code: 1,
data: element
}
} catch (error) {
return {
code: 0,
message: "下载指定的图片地址并且分割错误,错误信息如下:" + error.message
}
}
}
/**
* 获取已经生图完成的数据并获取图片
* @param {*} value
* @returns
*/
async GetGeneratedMJImageAndSplit(value) {
try {
value = JSON.parse(value);
2024-06-01 15:08:22 +08:00
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
}
2024-05-15 12:57:15 +08:00
2024-06-01 15:08:22 +08:00
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
})
}
}
2024-05-15 12:57:15 +08:00
let res = [];
2024-06-01 15:08:22 +08:00
// 判断返回的数据是不是一个字符串
if (typeof result == "string") {
result = JSON.parse(result);
}
2024-05-15 12:57:15 +08:00
// 将返回的数据进行分割
for (let i = 0; i < result.length; i++) {
const element = result[i];
2024-06-01 15:08:22 +08:00
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]));
2024-05-15 12:57:15 +08:00
if (ds.code == 0) {
throw new Error(ds.message);
}
2024-06-01 15:08:22 +08:00
// 修改数据。
ds.data["progress"] = 100;
ds.data["status"] = "success";
2024-05-15 12:57:15 +08:00
res.push(ds.data);
}
// 全部分割完毕,返回
2024-06-01 15:08:22 +08:00
return successMessage(res);
2024-05-15 12:57:15 +08:00
} catch (error) {
2024-06-01 15:08:22 +08:00
return errorMessage("获取已经生图完成的数据,并获取图片错误,错误信息如下" + error.message)
2024-05-15 12:57:15 +08:00
}
}
// MJ生成的图片分割
async ImageSplit(value) {
try {
value = JSON.parse(value);
let inputPath = value[0];
let r_name = value[1];
let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`);
const metadata = await sharp(inputPath).metadata();
const smallWidth = metadata.width / 2;
const smallHeight = metadata.height / 2;
let times = new Date().getTime();
let imgs = [];
let first_p = path.join(this.global.config.project_path, `tmp\\output_crop_00001\\${r_name}`);
for (let i = 0; i < 4; i++) {
const xOffset = i % 2 === 0 ? 0 : smallWidth;
const yOffset = Math.floor(i / 2) * smallHeight;
let out_file = path.join(outputDir, `/${r_name}_${times}_${i}.png`);
await sharp(inputPath)
.extract({
left: xOffset,
top: yOffset,
width: smallWidth,
height: smallHeight
})
.resize(smallWidth, smallHeight)
.toFile(out_file);
imgs.push(out_file);
// 将第一个图片复制一个到指定的位置
if (i == 0) {
await this.tools.copyFileOrDirectory(out_file, first_p);
// 复制一份到input
let input_p = path.join(this.global.config.project_path, `tmp\\input_crop\\${r_name}`);
await this.tools.copyFileOrDirectory(out_file, input_p);
}
}
return {
code: 1,
data: {
subImagePath: imgs,
outImagePath: first_p
}
}
} catch (err) {
return {
code: 0,
message: "MJ图片切割错误错误信息如下" + err.message
}
}
}
2024-06-01 15:08:22 +08:00
/**
* 调用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)
}
}
2024-05-15 12:57:15 +08:00
/**
* MJ 原创生图
* @param {*} value
*/
async OriginalMJImageGenerate(value) {
try {
let data = value[0];
if (value[1]) {
data = JSON.parse(data);
}
let show_global_message = value[2];
let batch = DEFINE_STRING.QUEUE_BATCH.MJ_ORIGINAL_GENERATE_IMAGE;
// 判断存放的文件夹是不是存在,不存在的话创建
let outputDir = path.join(this.global.config.project_path, `data\\MJOriginalImage`);
await this.tools.checkFolderExistsOrCreate(outputDir);
let fileExist = await this.tools.checkExists(outputDir);
if (!fileExist) {
await this.tools.createDirectory(outputDir);
}
2024-05-24 13:46:19 +08:00
// 判断该当前tmp\output_crop_00001文件夹是不是存在不存在创建
let output_crop_00001 = path.join(this.global.config.project_path, `tmp\\output_crop_00001`);
await this.tools.checkFolderExistsOrCreate(output_crop_00001);
2024-06-01 15:08:22 +08:00
// 获取MJ配置
let mjSetting = await this.InitMjSetting();
2024-05-15 12:57:15 +08:00
// 检查this.global中是不是又mj队列没有的话创建一个
if (!this.global.mjGenerateQuene) {
this.global.mjGenerateQuene = new AsyncQueue(this.global, 1, true);
}
let style_ids = await this.pm.GetConfigJson(JSON.stringify(["image_style", []]), false);
2024-05-24 13:46:19 +08:00
let image_styles = await ImageStyleDefine.getImageStyleStringByIds(style_ids.data);
2024-05-15 12:57:15 +08:00
// 替换风格的逻辑
let current_task = null;
for (let i = 0; i < data.length; i++) {
const element = data[i];
let tasK_id = `${batch}_${element.name}_${element.id}`;
2024-05-24 13:46:19 +08:00
let old_prompt = element.prompt;
// 拼接提示词
// 图生图的链接
2024-06-01 15:08:22 +08:00
// 获取风格词 + 命令后缀
let prompt = " " + image_styles + old_prompt + (mjSetting.image_suffix ? mjSetting.image_suffix : "");
// 判断当前生图模式
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;
}
2024-05-15 12:57:15 +08:00
}
// 判断该当前正在执行的人物队列数(小于设置的数量,开始一个任务)
2024-06-01 15:08:22 +08:00
this.global.mjGenerateQuene.startNextTask(mjSetting.task_count ? mjSetting.task_count : 3);
2024-05-15 12:57:15 +08:00
this.global.requestQuene.setBatchCompletionCallback(batch, (failedTasks) => {
if (failedTasks.length > 0) {
let message = `
MJ生图任务都已完成
但是以下任务执行失败
`
failedTasks.forEach(({ taskId, error }) => {
message += `${taskId}-, \n 错误信息: ${error}` + '\n';
});
2024-06-01 15:08:22 +08:00
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, errorMessage(message))
2024-05-15 12:57:15 +08:00
} else {
if (show_global_message) {
2024-06-01 15:08:22 +08:00
this.global.newWindow[0].win.webContents.send(DEFINE_STRING.SHOW_MESSAGE_DIALOG, successMessage(null, '所有MJ生图任务完成'))
2024-05-15 12:57:15 +08:00
}
}
});
2024-06-01 15:08:22 +08:00
return successMessage(null)
2024-05-15 12:57:15 +08:00
} catch (error) {
2024-06-01 15:08:22 +08:00
return errorMessage("MJ生图错误错误信息如下" + error.message)
2024-05-15 12:57:15 +08:00
}
}
}