1. 新增MJ V7 模型
2. 添加MJ生图包
This commit is contained in:
lq1405 2025-04-08 14:37:35 +08:00
parent c43abd6908
commit 863ac4d7f4
19 changed files with 320 additions and 44 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "laitool",
"version": "3.3.3",
"version": "3.3.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "laitool",
"version": "3.3.3",
"version": "3.3.4",
"hasInstallScript": true,
"dependencies": {
"@alicloud/alimt20181012": "^1.2.0",

View File

@ -1,6 +1,6 @@
{
"name": "laitool",
"version": "3.3.3",
"version": "3.3.4",
"description": "An AI tool for image processing, video processing, and other functions.",
"main": "./out/main/index.js",
"author": "laitool.cn",

Binary file not shown.

View File

@ -3,6 +3,7 @@ let apiUrl = [
label: 'LAI API - 香港',
value: 'b44c6f24-59e4-4a71-b2c7-3df0c4e35e65',
gpt_url: 'https://api.laitool.cc/v1/chat/completions',
isPackage: false,
mj_url: {
imagine: 'https://api.laitool.cc/mj/submit/imagine',
describe: 'https://api.laitool.cc/mj/submit/describe',
@ -18,6 +19,7 @@ let apiUrl = [
label: 'LAI API - 美国',
value: '2b443f53-ba12-42b3-a57c-e4df92685c73',
gpt_url: 'https://laitool.net/v1/chat/completions',
isPackage: false,
mj_url: {
imagine: 'https://laitool.net/mj/submit/imagine',
describe: 'https://laitool.net/mj/submit/describe',
@ -58,7 +60,20 @@ let apiUrl = [
mj_url: null,
d3_url: null,
buy_url: 'https://www.volcengine.com/product/doubao'
}
},
{
label: 'MJ生图包-1',
value: 'babe557a-bbb8-4aed-acca-70ea068c156f',
isPackage: true,
mj_url: {
imagine: 'https://mjapi.bzu.cn/mj/submit/imagine',
describe: 'https://mjapi.bzu.cn/mj/submit/describe',
update_file: 'https://mjapi.bzu.cn/mj/submit/upload-discord-images',
once_get_task: 'https://mjapi.bzu.cn/mj/task/${id}/fetch',
query_url: "https://mjapi.bzu.cn/"
},
buy_url: 'https://rvgyir5wk1c.feishu.cn/wiki/P94OwwHuCi2qh8kADutcUuw4nUe'
},
]
/**
@ -71,4 +86,19 @@ function getApiMessageByID(id) {
throw new Error('没有找到对应的MJ API的配置请先检查配置')
}
}
export { apiUrl, getApiMessageByID }
/**
* MJ API URL Options
* @returns
*/
function GetMJUrlOptions(type: string) {
if (type != 'api' && type != 'package') {
throw new Error('没有找到对应的MJ API的配置请先检查配置')
}
if (type == 'api') {
return apiUrl.filter((item) => item.mj_url && item.isPackage == false)
} else if (type == 'package') {
return apiUrl.filter((item) => item.mj_url && item.isPackage == true)
}
}
export { apiUrl, getApiMessageByID, GetMJUrlOptions }

View File

@ -0,0 +1,33 @@
/**
*
*/
export let ImagePackageProxyOptions = [
{
label: "香港代理",
value: "https://hk.bzu.cn",
apiId: "babe557a-bbb8-4aed-acca-70ea068c156f"
}
, {
label: "美国代理",
value: "https://mj_jp.bzu.cn",
apiId: "babe557a-bbb8-4aed-acca-70ea068c156f"
},
{
label: "LaiTool默认代理",
value: "https://mj_us.bzu.cn",
}
]
export function GetImageProxyUrlOptions(apiId?: string) {
debugger
if (!apiId) {
return ImagePackageProxyOptions
}
let imageProxyUrl = ImagePackageProxyOptions.filter((item) => item.apiId == apiId || item.apiId == null)
if (imageProxyUrl) {
return imageProxyUrl
} else {
return []
}
}

View File

@ -8,6 +8,9 @@ export enum MJImageType {
// 浏览器模式
BROWSER_MJ = 'browser_mj',
// MJ生图包
PACKAGE_MJ = 'package_mj',
// API模式
API_MJ = 'api_mj',

View File

@ -8,7 +8,7 @@ import MJApi from "./mjApi"
import { BookBackTaskStatus, BookBackTaskType, BookTaskStatus, BookType, DialogType, MJAction, OperateBookType, TaskExecuteType } from "../../../define/enum/bookEnum";
import { DEFINE_STRING } from "../../../define/define_string";
import { MJ } from "../../../model/mj";
import { MJRespoonseType } from "../../../define/enum/mjEnum";
import { MJImageType, MJRespoonseType } from "../../../define/enum/mjEnum";
import { MJSettingModel } from "../../../model/Setting/mjSetting";
import { GeneralResponse } from "../../../model/generalResponse"
import { LoggerStatus, ResponseMessageType } from "../../../define/enum/softwareEnum";
@ -610,6 +610,13 @@ export class MJOpt {
});
// 下载图片
let imagePath = path.join(book.bookFolderPath, `data\\MJOriginalImage\\${task_res.messageId}.png`);
// 判断是不是生图包是的话需要替换图片的baseurl
if (this.mj_globalSetting.mj_simpleSetting.type == MJImageType.PACKAGE_MJ) {
let imageBaseUrl = this.mj_globalSetting.mj_imagePackageSetting.selectedProxy;
if (imageBaseUrl && imageBaseUrl != '') {
task_res.imageClick = task_res.imageClick.replace(/https?:\/\/[^/]+/, imageBaseUrl)
}
}
await CheckFolderExistsOrCreate(path.dirname(imagePath))
await this.tools.downloadFileUrl(task_res.imageClick, imagePath)
// 进行图片裁剪

View File

@ -92,6 +92,18 @@ class MJApi {
this.imagineUrl = localRemoteBaseUrl + ":" + localRemotePort + '/mj/submit/imagine'
this.describeUrl = localRemoteBaseUrl + ":" + localRemotePort + '/mj/submit/describe'
this.fetchTaskUrl = localRemoteBaseUrl + ":" + localRemotePort + '/mj/task/${id}/fetch'
} else if (this.mjSimpleSetting.type == MJImageType.PACKAGE_MJ) {
let apiUrlIndex = apiUrl.findIndex(item => item.value == this.mj_globalSetting.mj_imagePackageSetting.selectPackage);
if (apiUrlIndex == -1) {
throw new Error('没有找到MJ 生图包对应的请求URL请检查配置');
}
let apiUrlItem = apiUrl[apiUrlIndex];
if (apiUrlItem.mj_url == null) {
throw new Error('没有找到MJ API对应的请求URL请检查配置');
}
this.imagineUrl = apiUrlItem.mj_url.imagine
this.describeUrl = apiUrlItem.mj_url.describe
this.fetchTaskUrl = apiUrlItem.mj_url.once_get_task
} else {
let apiUrlIndex = apiUrl.findIndex(item => item.value == this.mj_globalSetting.mj_apiSetting.mjApiUrl);
if (apiUrlIndex == -1) {
@ -101,7 +113,6 @@ class MJApi {
if (apiUrlItem.mj_url == null) {
throw new Error('没有找到MJ API对应的请求URL请检查配置');
}
this.imagineUrl = apiUrlItem.mj_url.imagine
this.describeUrl = apiUrlItem.mj_url.describe
this.fetchTaskUrl = apiUrlItem.mj_url.once_get_task
@ -131,6 +142,11 @@ class MJApi {
'mj-api-secret': this.mj_globalSetting.mj_localRemoteSimpleSetting.token
}
useTransfer = false;
} else if (this.mjSimpleSetting.type == MJImageType.PACKAGE_MJ) {
headers = {
Authorization: this.mj_globalSetting.mj_imagePackageSetting.token
}
useTransfer = false;
} else {
headers = {
Authorization: this.mj_globalSetting.mj_apiSetting.apiKey
@ -232,7 +248,7 @@ class MJApi {
res = await this.SubmitMJDescribeAPI(param)
break
default:
throw new Error("MJ出图的类型不支持")
throw new Error("MJ反推的类型不支持反推只支持API和代理模式")
}
return res
}
@ -320,6 +336,7 @@ class MJApi {
switch (this.mjSimpleSetting.type) {
case MJImageType.REMOTE_MJ:
case MJImageType.API_MJ:
case MJImageType.PACKAGE_MJ:
case MJImageType.LOCAL_MJ:
res = await this.SubmitMJImagineAPI(taskId, prompt)
break
@ -370,8 +387,15 @@ class MJApi {
delete data.accountFilter.instanceId;
config.headers["Authorization"] = this.mj_globalSetting.mj_apiSetting.apiKey;
useTransfer = this.mj_globalSetting.mj_apiSetting.useTransfer
} else if (this.mjSimpleSetting.type == MJImageType.PACKAGE_MJ) {
delete data.accountFilter.remark
delete data.accountFilter.instanceId;
delete data.accountFilter.modes;
config.headers["Authorization"] = this.mj_globalSetting.mj_imagePackageSetting.token;
useTransfer = false;
} else if (this.mjSimpleSetting.type == MJImageType.LOCAL_MJ) {
delete data.accountFilter.remark
delete data.accountFilter.modes;
let instanceId = await this.GetRemoteMJAccountAndRandom('local');
data.accountFilter.instanceId = instanceId;
useTransfer = false;
@ -414,6 +438,12 @@ class MJApi {
resData = res.data
}
if (this.mjSimpleSetting.type == MJImageType.PACKAGE_MJ) {
if (resData.code == -1 || resData.success == false) {
throw new Error(resData.message)
}
}
if (resData == null) {
throw new Error("返回的数据为空")
}

View File

@ -12,14 +12,17 @@ function GetMJRequestModelOptions() {
value: "api_mj",
disable: false
}, {
label: "本地代理模式",
value: "local_mj",
disable: false
},
{
label: "代理MJtoken",
value: "remote_mj",
disable: false
}, {
label: "MJ生图包",
value: "package_mj",
disable: false
}, {
label: "本地代理模式",
value: "local_mj",
disable: false
},
{
label: "浏览器模式",
@ -49,6 +52,18 @@ function GetMJRobotOptions() {
*/
function GetMJRobotModelOptions(mjRobot?: MJRobotType) {
let allRobotModel = [
{
label: "MJ V7.0",
text: "v 7",
type: MJRobotType.MJ,
value: "a26fc136-4558-4426-b827-fa7d0c189fc9"
},
{
label: "MJ V6.1",
text: "v 6.1",
type: MJRobotType.MJ,
value: "08ffca01-5c8d-4f93-be97-05615fac1a8f"
},
{
label: "MJ V6.0",
text: "v 6",
@ -137,7 +152,7 @@ function GetMJImageScaleOptions() {
* @returns
*/
function GetMJAPIUrlOptions() {
return apiUrl.filter((item) => item.mj_url)
return apiUrl.filter((item) => item.mj_url && item.isPackage == false)
}
/**

View File

@ -107,6 +107,15 @@ declare namespace MJSettingModel {
token: string
}
/**
* MJ
*/
type MJImagePackageModel = {
selectPackage: string
token: string
selectedProxy: string
}
/**
* MJ
*/
@ -116,5 +125,6 @@ declare namespace MJSettingModel {
mj_browserSetting: BrowserMJSettingModel
mj_remoteSimpleSetting: MJRemoteSimpleSettingModel
mj_localRemoteSimpleSetting: MJLocalRemoteSimpleSettingModel
mj_imagePackageSetting: MJImagePackageModel
}
}

View File

@ -138,3 +138,26 @@ defineProps({
color: #0055cc;
}
</style>
<style>
/* 这些样式类将全局可用,可以在插槽内容中使用 */
.clickable-link {
color: #0077ff;
text-decoration: underline;
cursor: pointer;
transition: color 0.2s ease;
}
.clickable-link:hover {
color: #0055cc;
}
.notes-content p {
margin: 4px 0;
color: #5c3c10;
}
.notes-content strong {
font-weight: bold;
}
</style>

View File

@ -134,6 +134,3 @@ function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>

View File

@ -0,0 +1,106 @@
<template>
<n-card title="生图包设置" hoverable style="margin-top: 10px; min-width: 850px" size="medium">
<n-form inline>
<n-space align="center" :size="12">
<n-form-item label="套餐选择">
<n-select
v-model:value="optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage"
:options="GetMJUrlOptions('package')"
placeholder="选择套餐"
style="min-width: 200px"
/>
</n-form-item>
<n-form-item>
<n-button type="primary" @click="handleBuy"> 购买 </n-button>
</n-form-item>
<n-form-item label="Token">
<n-input
type="password"
v-model:value="optionStore.MJ_GlobalSetting.mj_imagePackageSetting.token"
placeholder="输入Token"
show-password-on="mousedown"
style="min-width: 200px"
/>
</n-form-item>
<n-form-item label="出图代理">
<n-select
v-model:value="optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy"
:options="ImagePackageProxyOptions"
placeholder="选择出图代理"
style="min-width: 200px"
/>
</n-form-item>
<!-- <n-form-item>
<n-button @click="handleQuery"> 查询 </n-button>
</n-form-item> -->
</n-space>
</n-form>
<NotesCollapse title="注意事项">
<p>
1. 使用生图包前请确保您已完成套餐购买<strong>未购买套餐将无法使用相关功能</strong>
</p>
<p>2. 标准生图包最大并发数为3具体并发数量以您所购买的套餐规格为准</p>
<p>3. 出图代理支持香港和美国节点选择也兼容系统默认代理设置与代理模式保持一致</p>
<p>
4. 您可随时点击 <strong>"查询"</strong> 按钮实时查看当前套餐已使用的出图数量及剩余额度
</p>
</NotesCollapse>
</n-card>
</template>
<script setup>
import { useMessage, NCard, NForm, NFormItem, NButton, NSelect, NInput, NSpace } from 'naive-ui'
import { GetMJUrlOptions } from '@/define/api/apiUrlDefine'
import { useOptionStore } from '@/stores/option'
import { ImagePackageProxyOptions } from '@/define/data/settingData'
import { isEmpty } from 'lodash'
import NotesCollapse from '../../Common/NotesCollapse.vue'
const optionStore = useOptionStore()
const message = useMessage()
/**
* 打开购买网址
*/
const handleBuy = async () => {
let selectAPIUrl = GetMJUrlOptions('package').filter(
(item) => item.value == optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage
)
if (selectAPIUrl.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
}
let buy_url = selectAPIUrl[0].buy_url
if (isEmpty(buy_url)) {
message.error('当前选择的服务商没有购买地址!')
} else {
window.api.OpenUrl(buy_url)
}
}
/**
* 查询地址
*/
const handleQuery = () => {
let selectAPIUrl = GetMJUrlOptions('package').filter(
(item) => item.value == optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage
)
if (selectAPIUrl.length == 0) {
message.error('当前选择的服务商没有购买地址!')
return
}
let queryUrl = selectAPIUrl[0]?.mj_url?.query_url
if (isEmpty(queryUrl)) {
message.error('当前选择的服务商没有查询地址!')
} else {
window.api.OpenUrl(queryUrl)
}
}
</script>
<style scoped>
/* 可以添加自定义样式 */
</style>

View File

@ -1,6 +1,10 @@
<template>
<div class="mj-remote-setting">
<n-card title="本地代理模式设置-自行部署服务" hoverable style="margin-top: 10px; min-width: 850px">
<n-card
title="本地代理模式设置-自行部署服务"
hoverable
style="margin-top: 10px; min-width: 850px"
>
<n-form inline :model="optionStore.MJ_GlobalSetting.mj_localRemoteSimpleSetting">
<n-form-item label="服务地址" path="baseUrl">
<n-input
@ -53,7 +57,9 @@
<p>
1. 本地代理模式支持本地部署和服务器部署需要自己进行部署<span
class="clickable-link"
@click="openExternalLink('https://rvgyir5wk1c.feishu.cn/wiki/N7uuwsO5piB8F6kpvDScUNBGnpd')"
@click="
openExternalLink('https://rvgyir5wk1c.feishu.cn/wiki/N7uuwsO5piB8F6kpvDScUNBGnpd')
"
>
本地代理模式部署教程
</span>
@ -76,24 +82,13 @@
<script setup>
import { ref, h } from 'vue'
import {
NCard,
NButton,
useDialog,
NForm,
NFormItem,
NInput,
useMessage,
NTooltip,
NIcon
} from 'naive-ui'
import { NCard, NButton, useDialog, NForm, NFormItem, NInput, NTooltip, NIcon } from 'naive-ui'
import AddMultiRemoteMj from '../Components/AddMultiRemoteMj.vue'
import { useOptionStore } from '@/stores/option'
import NotesCollapse from '../../Common/NotesCollapse.vue'
const optionStore = useOptionStore()
const dialog = useDialog()
const message = useMessage()
/**
* 添加多个账号这样可以同时跑多个账号
@ -118,7 +113,3 @@ function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>

View File

@ -71,7 +71,3 @@ function openExternalLink(url) {
window.api.OpenUrl(url)
}
</script>
<style scoped>
@import '../../../assets//css//note.less';
</style>

View File

@ -3,6 +3,7 @@
<MJSimpleSetting />
<MJAPISetting />
<MJRemoteSetting />
<MJImagePackage />
<!-- <MJBrowserSetting /> -->
<MJLocalRemoteSetting />
<n-button type="info" @click="SaveMjSetting" style="margin-top: 10px">保存MJ配置</n-button>
@ -10,7 +11,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onMounted } from 'vue'
import { useMessage, NButton } from 'naive-ui'
import { useSoftwareStore } from '@/stores/software'
import { useOptionStore } from '@/stores/option'
@ -19,10 +20,12 @@ import { OptionKeyName, OptionType } from '@/define/enum/option'
import MJSimpleSetting from './MJSimpleSetting.vue'
import MJAPISetting from './MJAPISetting.vue'
import MJRemoteSetting from './MJRemoteSetting.vue'
import MJBrowserSetting from './MJBrowserSetting.vue'
import MJLocalRemoteSetting from './MJLocalRemoteSetting.vue'
import MJImagePackage from './MJImagePackage.vue'
import { MJImageType } from '@/define/enum/mjEnum'
import { isEmpty } from 'lodash'
import { GetMJUrlOptions } from '@/define/api/apiUrlDefine'
import { GetImageProxyUrlOptions, ImagePackageProxyOptions } from '@/define/data/settingData'
let softwareStore = useSoftwareStore()
let optionStore = useOptionStore()
@ -37,6 +40,7 @@ onMounted(async () => {
*/
async function InitMJSettingData() {
try {
debugger
softwareStore.spin.spinning = true
softwareStore.spin.tip = '正在加载数据,请稍等...'
@ -112,6 +116,14 @@ async function InitMJSettingData() {
token: 'admin'
}
}
if (optionStore.MJ_GlobalSetting.mj_imagePackageSetting == null) {
optionStore.MJ_GlobalSetting.mj_imagePackageSetting = {
selectPackage: GetMJUrlOptions('package')[0].value,
token: '',
selectedProxy: GetImageProxyUrlOptions(GetMJUrlOptions('package')[0].value)[0].value
}
}
message.success('加载MJSetting信息成功')
}
await TimeDelay(1000)
@ -178,6 +190,19 @@ async function SaveMjSetting() {
}
}
if (request_model == MJImageType.PACKAGE_MJ) {
//
if (
optionStore.MJ_GlobalSetting.mj_imagePackageSetting == null ||
isEmpty(optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectPackage) ||
isEmpty(optionStore.MJ_GlobalSetting.mj_imagePackageSetting.token) ||
isEmpty(optionStore.MJ_GlobalSetting.mj_imagePackageSetting.selectedProxy)
) {
message.error('请检查生图包设置的必填字段生图包选择token代理地址等')
return
}
}
optionStore.MJ_GlobalSetting.mj_simpleSetting.type =
optionStore.MJ_GlobalSetting.mj_simpleSetting.requestModel

View File

@ -72,7 +72,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, computed } from 'vue'
import { NCard, NForm, NFormItem, NInputNumber, NSelect, NInput } from 'naive-ui'
import { useOptionStore } from '@/stores/option'
import MJDefine from '@/main/Service/MJ/mjDefine'
@ -92,6 +92,10 @@ let sampleRules = {
selectRobot: [{ required: true, message: '请选择生图机器人', trigger: 'blur' }]
}
mjRobotModelOptions.value = computed(() =>
MJDefine.GetMJRobotModelOptions(optionStore.MJ_GlobalSetting.mj_simpleSetting.selectRobot)
)
onMounted(() => {
mjRequestModelOptions.value = MJDefine.GetMJRequestModelOptions()
mjRobotOptions.value = MJDefine.GetMJRobotOptions()

View File

@ -1,3 +1,4 @@
import { GetMJUrlOptions } from "@/define/api/apiUrlDefine";
import { MJImageType, MJRobotType, MJSpeed } from "@/define/enum/mjEnum";
import { OptionKeyName } from "@/define/enum/option";
import { OptionModel } from "@/model/option/option";
@ -118,6 +119,11 @@ export const useOptionStore = defineStore('option', {
baseUrl: "http://127.0.0.1",
port: "8080",
token: "admin",
},
mj_imagePackageSetting: {
selectPackage: GetMJUrlOptions('package')[0].value,
token: "",
imageProxyId: "",
}
},