1330 lines
35 KiB
Vue
1330 lines
35 KiB
Vue
<template>
|
||
<q-page>
|
||
<!-- <article></article>
|
||
|
||
<div class="gallery-track">
|
||
<div class="card">
|
||
<div class="card-image-wrapper">
|
||
<img src="https://source.unsplash.com/kL3u4Tqfn1s" />
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-image-wrapper">
|
||
<img src="https://source.unsplash.com/yVUQlyRlJSw" />
|
||
</div>
|
||
</div>
|
||
</div> -->
|
||
<div class="silder">
|
||
<div class="menu-box">
|
||
<div class="menu-bg"></div>
|
||
<div class="menu-button" @click="setActiveButton(1)">
|
||
<div class="no-act" v-show="activeButton === 2">
|
||
<img src="../../assets/image/ai/ttp.png" />
|
||
<div>AI生图</div>
|
||
</div>
|
||
<div class="act" v-show="activeButton === 1">
|
||
<img src="../../assets/image/ai/ttpact.png" />
|
||
<div>AI生图</div>
|
||
</div>
|
||
</div>
|
||
<div class="menu-button" @click="setActiveButton(2)">
|
||
<div class="no-act" v-show="activeButton === 1">
|
||
<img src="../../assets/image/ai/ptp.png" />
|
||
<div>生图PLUS</div>
|
||
</div>
|
||
<div class="act" v-show="activeButton === 2">
|
||
<img src="../../assets/image/ai/ptpact.png" />
|
||
<div>生图PLUS</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="display: flex; width: 100%">
|
||
<div class="setting-content">
|
||
<q-scroll-area style="height: 87%">
|
||
<div class="setting">
|
||
<div class="prompt-title">
|
||
<div style="display: flex; align-items: center">
|
||
<img class="cirl" src="../../assets/image/ai/cirl.png" />
|
||
<span
|
||
style="
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 10px;
|
||
font-size: 16px;
|
||
"
|
||
>描述内容</span
|
||
>
|
||
</div>
|
||
<n-popover trigger="hover" content-class="popover">
|
||
<template #trigger>
|
||
<img
|
||
@click="beautify"
|
||
src="../../assets/image/ai/run.png"
|
||
class="cursor-pointer runse"
|
||
/>
|
||
</template>
|
||
<span>润色</span>
|
||
</n-popover>
|
||
</div>
|
||
<div class="card ms-content">
|
||
<n-spin :show="beautifyLoading">
|
||
<template #icon>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<g
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
>
|
||
<path d="M12 6V3"></path>
|
||
<path d="M16.25 7.75L18.4 5.6"></path>
|
||
<path d="M18 12h3"></path>
|
||
<path d="M16.25 16.25l2.15 2.15"></path>
|
||
<path d="M12 18v3"></path>
|
||
<path d="M7.75 16.25L5.6 18.4"></path>
|
||
<path d="M6 12H3"></path>
|
||
<path d="M7.75 7.75L5.6 5.6"></path>
|
||
</g>
|
||
</svg>
|
||
</template>
|
||
<n-input
|
||
v-model:value="prompt"
|
||
type="textarea"
|
||
class="content-input"
|
||
:maxlength="200"
|
||
show-count
|
||
placeholder="请输入一段话或短语、词汇,描述你的想法,用逗号隔开。可以是中文或英文"
|
||
/>
|
||
</n-spin>
|
||
</div>
|
||
<div
|
||
ref="fadeOut1"
|
||
class="prompt-title animate__animated animate__fadeInLeft animate__fast"
|
||
v-if="activeButton === 2"
|
||
>
|
||
<div style="display: flex; align-items: center">
|
||
<img class="cirl" src="../../assets/image/ai/cirl.png" />
|
||
<span
|
||
style="
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 10px;
|
||
font-size: 16px;
|
||
"
|
||
>反向词</span
|
||
>
|
||
</div>
|
||
</div>
|
||
<div
|
||
ref="fadeOut2"
|
||
v-if="activeButton === 2"
|
||
class="ms-content animate__animated animate__fadeInLeft animate__fast"
|
||
style="border: 1px solid #7e7e7e; height: 100px"
|
||
>
|
||
<n-input
|
||
v-model:value="negative_prompt"
|
||
type="textarea"
|
||
class="content-input"
|
||
:bordered="false"
|
||
:maxlength="50"
|
||
show-count
|
||
placeholder="输入你画面中不想要的内容,中文或英文的短语、词汇"
|
||
/>
|
||
</div>
|
||
<div
|
||
ref="fadeOut3"
|
||
class="prompt-title animate__animated animate__fadeInLeft animate__fast"
|
||
v-if="activeButton === 2"
|
||
>
|
||
<div style="display: flex; align-items: center">
|
||
<img class="cirl" src="../../assets/image/ai/cirl.png" />
|
||
<span
|
||
style="
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 10px;
|
||
font-size: 16px;
|
||
"
|
||
>参考图</span
|
||
>
|
||
</div>
|
||
</div>
|
||
<div
|
||
ref="fadeOut4"
|
||
v-if="activeButton === 2"
|
||
class="animate__animated animate__fadeInLeft animate__fast"
|
||
>
|
||
<n-upload
|
||
list-type="image-card"
|
||
:max="1"
|
||
:on-finish="handleChange"
|
||
action="http://192.168.1.244:8085/api/ai/upload-file"
|
||
>
|
||
<n-upload-dragger>
|
||
<div style="margin-bottom: 12px">
|
||
<img src="../../assets/image/ai/plus.png" />
|
||
</div>
|
||
<div
|
||
style="font-size: 16px; color: #7e7e7e; font-weight: bold"
|
||
>
|
||
拖拽图片至此或点击上传
|
||
</div>
|
||
</n-upload-dragger>
|
||
</n-upload>
|
||
</div>
|
||
<div class="prompt-title" style="margin-top: 10px">
|
||
<div style="display: flex; align-items: center">
|
||
<img class="cirl" src="../../assets/image/ai/cirl.png" />
|
||
<span
|
||
style="
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 10px;
|
||
font-size: 16px;
|
||
"
|
||
>画风类型</span
|
||
>
|
||
</div>
|
||
</div>
|
||
<div class="model-box">
|
||
<div class="row animate__animated animate__bounceIn">
|
||
<div
|
||
class="style-box card cursor-pointer"
|
||
v-for="(n, index) in modelArr"
|
||
:key="`lg-${n}`"
|
||
:class="n.nowSelect ? 'border-change' : 'border-default'"
|
||
@click="chooseModel(n)"
|
||
:style="{
|
||
marginLeft: index === 0 || index === 4 ? '0' : '32px',
|
||
marginBottom: '25px',
|
||
}"
|
||
>
|
||
<img style="width: 100%; height: 100%" :src="n.replaceImg" />
|
||
</div>
|
||
<div class="all-box cursor-pointer" @click="openAll">
|
||
全部模型
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="prompt-title">
|
||
<div style="display: flex; align-items: center">
|
||
<img class="cirl" src="../../assets/image/ai/cirl.png" />
|
||
<span
|
||
style="
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 10px;
|
||
font-size: 16px;
|
||
"
|
||
>图片尺寸</span
|
||
>
|
||
</div>
|
||
</div>
|
||
<div class="model-box">
|
||
<div class="row">
|
||
<div
|
||
class="size-box card cursor-pointer"
|
||
v-for="(n, index) in sizeArr"
|
||
:key="`lg-${n}`"
|
||
:class="n.nowSelect ? 'border-change' : 'border-default'"
|
||
@click="chooseSize(n)"
|
||
:style="{
|
||
marginLeft: index === 0 || index === 3 ? '0' : '18px',
|
||
marginBottom: '10px',
|
||
}"
|
||
>
|
||
<div
|
||
style="
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #212121;
|
||
width: 128px;
|
||
height: 65px;
|
||
margin-top: 5px;
|
||
"
|
||
>
|
||
<div style="position: relative">
|
||
<span
|
||
style="
|
||
position: absolute;
|
||
top: 45%;
|
||
left: 38%;
|
||
transform: translate(-50%, -50%);
|
||
font-size: 10px;
|
||
"
|
||
>{{ n.proportion }}</span
|
||
>
|
||
<img class="left-img" :src="n.img" />
|
||
</div>
|
||
|
||
<div>
|
||
<div>{{ n.word }}</div>
|
||
<div>{{ n.sizeWord }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="wh-box">
|
||
宽
|
||
<n-input-number
|
||
v-model:value="width"
|
||
:bordered="false"
|
||
placeholder="请输入数值"
|
||
></n-input-number>
|
||
px
|
||
<q-separator
|
||
vertical
|
||
style="
|
||
background: #383838;
|
||
margin-left: 16px;
|
||
margin-right: 40px;
|
||
"
|
||
/>
|
||
高
|
||
<n-input-number
|
||
v-model:value="height"
|
||
:bordered="false"
|
||
placeholder="请输入数值"
|
||
></n-input-number>
|
||
px
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</q-scroll-area>
|
||
<div class="bottom-box">
|
||
<div class="num-box">
|
||
<n-select
|
||
class="num-select"
|
||
v-model:value="batch_size"
|
||
:options="numOptions"
|
||
placeholder="请选择"
|
||
/>
|
||
<div>图片数量</div>
|
||
</div>
|
||
<div class="btn-box">
|
||
<n-spin :show="createLoading">
|
||
<template #icon> </template>
|
||
<n-button @click="generate" class="create" quaternary>
|
||
<img
|
||
style="width: 24px; height: 28px; margin-right: 10px"
|
||
src="../../assets/image/ai/star.png"
|
||
/>
|
||
<div style="display: grid" v-show="!createLoading">
|
||
<div
|
||
style="
|
||
color: #fff;
|
||
font-weight: bolder;
|
||
font-size: 17px;
|
||
margin-bottom: 5px;
|
||
"
|
||
>
|
||
立即生成
|
||
</div>
|
||
<div style="color: #fff; font-size: 12px">
|
||
消耗{{ batch_size }}积分
|
||
</div>
|
||
</div>
|
||
<div
|
||
v-show="createLoading"
|
||
style="
|
||
color: #fff;
|
||
font-weight: bolder;
|
||
font-size: 17px;
|
||
margin-bottom: 5px;
|
||
"
|
||
>
|
||
正在生成中
|
||
</div>
|
||
</n-button>
|
||
</n-spin>
|
||
<div>当前剩余积分:{{ coin }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="img-content">
|
||
<div class="plane" v-if="noImgData">
|
||
<img
|
||
ref="plane"
|
||
class="animate__animated animate__fadeInBottomLeft"
|
||
src="../../assets/image/ai/plane.png"
|
||
/>
|
||
<div ref="planeWord" class="word animate__animated animate__zoomIn">
|
||
快开启您的AI之旅吧~
|
||
</div>
|
||
</div>
|
||
<div class="created-img-box" v-else>
|
||
<q-scroll-area style="height: 820px" ref="scrollAreaRef">
|
||
<div
|
||
class="img-list-page"
|
||
v-for="(n, index) in historyList"
|
||
:key="index"
|
||
>
|
||
<div
|
||
class="animate__animated animate__slideInUp"
|
||
style="display: flex; align-items: center"
|
||
>
|
||
<span style="color: #7e7e7e; margin-right: 10px">{{
|
||
n.dateTime
|
||
}}</span
|
||
><q-separator style="width: 86%; background-color: #7e7e7e" />
|
||
</div>
|
||
<div
|
||
class="animate__animated animate__slideInUp"
|
||
style="color: #bebebe"
|
||
>
|
||
{{ n.prompt }}
|
||
</div>
|
||
<div class="img-list-box">
|
||
<div
|
||
v-for="(item, index2) in n.imgList"
|
||
:key="index2"
|
||
class="img-detail-box animate__animated animate__slideInUp"
|
||
>
|
||
<n-spin :show="item.length < 1">
|
||
<template #icon>
|
||
<svg
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<g
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
>
|
||
<path d="M12 6V3"></path>
|
||
<path d="M16.25 7.75L18.4 5.6"></path>
|
||
<path d="M18 12h3"></path>
|
||
<path d="M16.25 16.25l2.15 2.15"></path>
|
||
<path d="M12 18v3"></path>
|
||
<path d="M7.75 16.25L5.6 18.4"></path>
|
||
<path d="M6 12H3"></path>
|
||
<path d="M7.75 7.75L5.6 5.6"></path>
|
||
</g>
|
||
</svg>
|
||
</template>
|
||
<template #description>
|
||
<span style="color: #bebebe">正在生成中,请稍等</span>
|
||
</template>
|
||
|
||
<q-parallax
|
||
@click="checkDetail(item)"
|
||
v-show="item.length"
|
||
:src="item"
|
||
>
|
||
</q-parallax>
|
||
</n-spin>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</q-scroll-area>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<image-detail
|
||
:show="showModal"
|
||
:detailSrc="detailSrc"
|
||
@close-dialog="closeModal"
|
||
/>
|
||
<mode-list
|
||
:show="showListModal"
|
||
@handCloseDialog="closeListModal"
|
||
@selectModal="selectedModel"
|
||
/>
|
||
</q-page>
|
||
</template>
|
||
<script setup>
|
||
import "animate.css";
|
||
import { ref, onMounted, onBeforeMount, computed, reactive, watch } from "vue";
|
||
import { ModelApi,UserApi } from "src/api";
|
||
import { processError, processSuccess } from "../../utils/message";
|
||
import moment from "moment";
|
||
import { LocalStorage, SessionStorage } from "quasar";
|
||
import imageDetail from "./components/imageDetail.vue";
|
||
import modeList from "./components/modeList.vue";
|
||
import { useRoute, useRouter } from "vue-router";
|
||
import img34 from "../../assets/image/ai/34.png";
|
||
import img43 from "../../assets/image/ai/43.png";
|
||
import img916 from "../../assets/image/ai/169.png";
|
||
const router = useRouter();
|
||
const scrollAreaRef = ref(null);
|
||
const plane = ref(null);
|
||
const planeWord = ref(null);
|
||
const activeButton = ref(1);
|
||
const createLoading = ref(false);
|
||
const beautifyLoading = ref(false);
|
||
const noImgData = ref(true);
|
||
const prompt = ref("");
|
||
const negative_prompt = ref("");
|
||
const apiprompt = ref("");
|
||
const init_images = ref([]);
|
||
const seletedModel = ref({});
|
||
const fadeOut1 = ref(null);
|
||
const fadeOut2 = ref(null);
|
||
const fadeOut3 = ref(null);
|
||
const fadeOut4 = ref(null);
|
||
const showModal = ref(false);
|
||
const detailSrc = ref("");
|
||
const coin = ref(0);
|
||
const showListModal = ref(false);
|
||
const selectedSize = ref({
|
||
nowSelect: true,
|
||
img: img34,
|
||
word: "社交媒体",
|
||
sizeWord: "600*800",
|
||
proportion: "3:4",
|
||
width: 600,
|
||
height: 800,
|
||
});
|
||
const width = ref(0);
|
||
const height = ref(0);
|
||
const apiWidth = ref(0);
|
||
const apiHeight = ref(0);
|
||
const imgList = ref([]);
|
||
const historyList = ref([]);
|
||
//每次张数
|
||
const batch_size = ref(1);
|
||
const numOptions = ref([
|
||
{
|
||
label: "1",
|
||
value: 1,
|
||
},
|
||
{
|
||
label: "2",
|
||
value: 2,
|
||
},
|
||
{
|
||
label: "3",
|
||
value: 3,
|
||
},
|
||
{
|
||
label: "4",
|
||
value: 4,
|
||
},
|
||
{
|
||
label: "5",
|
||
value: 5,
|
||
},
|
||
{
|
||
label: "6",
|
||
value: 6,
|
||
},
|
||
{
|
||
label: "7",
|
||
value: 7,
|
||
},
|
||
{
|
||
label: "8",
|
||
value: 8,
|
||
},
|
||
{
|
||
label: "9",
|
||
value: 9,
|
||
},
|
||
{
|
||
label: "10",
|
||
value: 10,
|
||
},
|
||
]);
|
||
const modelArr = ref([]);
|
||
const sizeArr = ref([
|
||
{
|
||
nowSelect: true,
|
||
img: img34,
|
||
word: "社交媒体",
|
||
sizeWord: "600*800",
|
||
proportion: "3:4",
|
||
width: 600,
|
||
height: 800,
|
||
},
|
||
{
|
||
nowSelect: false,
|
||
img: img43,
|
||
word: "文章配图",
|
||
sizeWord: "800*600",
|
||
proportion: "4:3",
|
||
width: 800,
|
||
height: 600,
|
||
},
|
||
{
|
||
nowSelect: false,
|
||
img: img916,
|
||
word: "海报",
|
||
sizeWord: "468*832",
|
||
proportion: "9:16",
|
||
width: 468,
|
||
height: 832,
|
||
},
|
||
{
|
||
nowSelect: false,
|
||
img: img34,
|
||
word: "电脑桌面",
|
||
sizeWord: "832*468",
|
||
proportion: "16:9",
|
||
width: 832,
|
||
height: 468,
|
||
},
|
||
{
|
||
nowSelect: false,
|
||
img: img34,
|
||
word: "正方形",
|
||
sizeWord: "512*512",
|
||
proportion: "1:1",
|
||
width: 512,
|
||
height: 512,
|
||
},
|
||
]);
|
||
// 打开详情弹窗
|
||
const checkDetail = (item) => {
|
||
showModal.value = true;
|
||
detailSrc.value = item;
|
||
};
|
||
// 关闭详情弹窗
|
||
const closeModal = () => {
|
||
showModal.value = false;
|
||
};
|
||
// 打开模型列表
|
||
const openAll = () => {
|
||
showListModal.value = true;
|
||
};
|
||
// 关闭模型列表
|
||
const closeListModal = () => {
|
||
showListModal.value = false;
|
||
};
|
||
// 获取用户信息
|
||
const getUserInfo = async() => {
|
||
try {
|
||
await UserApi.getUserInfo().then((res) => {
|
||
if (res.status === 0) {
|
||
coin.value = res.data.coin;
|
||
} else {
|
||
processError(res.msg);
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
|
||
|
||
};
|
||
// 模型列表中选择模型
|
||
const selectedModel = (model) => {
|
||
console.log(model,111);
|
||
seletedModel.value = model;
|
||
// 将所有模型的nowSelect设置为false
|
||
modelArr.value.forEach((item) => {
|
||
item.nowSelect = false;
|
||
});
|
||
// 判断列表中选择的模型是否在初始化的七个模型中
|
||
const isExist = modelArr.value.some((item) => item.hash === model.hash);
|
||
// 如果存在,则将选中的模型放到第一个
|
||
if (isExist) {
|
||
modelArr.value.forEach((item) => {
|
||
if (item.hash === model.hash) {
|
||
item.nowSelect = true;
|
||
} else {
|
||
item.nowSelect = false;
|
||
}
|
||
});
|
||
} else {
|
||
// 如果不存在,则将选中的模型放到第一个,并将其他模型放到后面
|
||
modelArr.value = [model, ...modelArr.value.slice(0, 6)];
|
||
modelArr.value.forEach((item, index) => {
|
||
item.nowSelect = index === 0;
|
||
});
|
||
}
|
||
};
|
||
// 上传完毕
|
||
const handleChange = (file, List) => {
|
||
showModal.value = true;
|
||
let resData = JSON.parse(file.event.currentTarget.response);
|
||
if (resData.status === 0) {
|
||
processSuccess("上传成功");
|
||
init_images.value = [resData.data.ori_url];
|
||
} else {
|
||
processError(resData.msg);
|
||
}
|
||
};
|
||
// 获取模型列表
|
||
const getModelList = async () => {
|
||
try {
|
||
await ModelApi.getModelList({
|
||
page: 1,
|
||
pageSize: 10,
|
||
}).then((res) => {
|
||
if (res.status === 0) {
|
||
modelArr.value = res.data.list.slice(0, 7).map((item, index) => ({
|
||
...item,
|
||
nowSelect: index === 0,
|
||
}));
|
||
seletedModel.value = modelArr.value[0];
|
||
} else {
|
||
processError(res.msg);
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
};
|
||
// 美化
|
||
const beautify = async () => {
|
||
beautifyLoading.value = true;
|
||
try {
|
||
await ModelApi.beautify({
|
||
txt: prompt.value,
|
||
}).then((res) => {
|
||
if (res.status === 0) {
|
||
beautifyLoading.value = false;
|
||
processSuccess("美化成功");
|
||
prompt.value = res.data.content;
|
||
} else {
|
||
processError(res.msg);
|
||
beautifyLoading.value = false;
|
||
}
|
||
});
|
||
} catch (error) {
|
||
beautifyLoading.value = false;
|
||
console.error(error);
|
||
}
|
||
};
|
||
// 生成
|
||
const generate = async () => {
|
||
// 如果没登录,跳转登录
|
||
const token = LocalStorage.getItem("sd-token");
|
||
if (!token) {
|
||
router.push("/login");
|
||
return;
|
||
}
|
||
if (!prompt.value) {
|
||
createLoading.value = false;
|
||
processError("请输入描述内容");
|
||
return;
|
||
}
|
||
if (JSON.stringify(selectedSize.value) !== "{}") {
|
||
apiWidth.value = selectedSize.value.width;
|
||
apiHeight.value = selectedSize.value.height;
|
||
} else {
|
||
apiHeight.value = height.value;
|
||
apiWidth.value = width.value;
|
||
}
|
||
if (!apiWidth.value || !apiHeight.value) {
|
||
createLoading.value = false;
|
||
processError("请输入宽高");
|
||
return;
|
||
}
|
||
createLoading.value = true;
|
||
apiprompt.value = await getTranslatePrompt();
|
||
if (!apiprompt.value) {
|
||
processError("描述内容不合法");
|
||
createLoading.value = false;
|
||
return;
|
||
}
|
||
if (activeButton.value === 1) {
|
||
txt2img();
|
||
} else {
|
||
// 如果没有上传图片
|
||
if (!init_images.value.length) {
|
||
createLoading.value = false;
|
||
processError("请上传参考图");
|
||
return;
|
||
}
|
||
img2img();
|
||
}
|
||
if (plane.value) {
|
||
plane.value.classList.add("animate__fadeOutTopRight");
|
||
planeWord.value.classList.add("animate__zoomOut");
|
||
}
|
||
|
||
// 放入和生成数量相同的空字符串
|
||
historyList.value.unshift({
|
||
imgList: new Array(batch_size.value).fill(""),
|
||
prompt: prompt.value,
|
||
dateTime: moment().format("YYYY年MM月DD日 HH:mm:ss"),
|
||
});
|
||
// 滚动到顶部
|
||
if (scrollAreaRef.value) {
|
||
scrollAreaRef.value.setScrollPosition("vertical", 0, 300);
|
||
}
|
||
setTimeout(() => {
|
||
noImgData.value = false;
|
||
}, 1000);
|
||
};
|
||
// 翻译描述内容
|
||
const getTranslatePrompt = async () => {
|
||
return new Promise((resolve, reject) => {
|
||
const data = {
|
||
txt: prompt.value,
|
||
};
|
||
ModelApi.translate(data).then((res) => {
|
||
if (res.status === 0) {
|
||
resolve(res.data.content);
|
||
} else {
|
||
processError(res.msg);
|
||
createLoading.value = false;
|
||
reject();
|
||
}
|
||
});
|
||
});
|
||
};
|
||
// 文生图
|
||
const txt2img = async () => {
|
||
try {
|
||
let data = {
|
||
prompt: apiprompt.value,
|
||
real_prompt: prompt.value,
|
||
|
||
sd_model_hash: seletedModel.value.hash,
|
||
width: apiWidth.value,
|
||
height: apiHeight.value,
|
||
batch_size: batch_size.value, //每次张数
|
||
n_iter: 1, //生成批次
|
||
steps: 30, //生成步数
|
||
override_settings_restore_afterwards: true,
|
||
override_settings: {
|
||
sd_model_checkpoint: seletedModel.value.title,
|
||
},
|
||
};
|
||
await ModelApi.txt2img(data).then((res) => {
|
||
if (res.status === 0) {
|
||
createLoading.value = false;
|
||
historyList.value[0].imgList = res.data.images;
|
||
getUserInfo();
|
||
} else {
|
||
processError(res.msg);
|
||
createLoading.value = false;
|
||
historyList.value[0].imgList = new Array(batch_size.value).fill(
|
||
"https://cdns.fontree.cn/fonchain-main/prod/image/default/ai/wrong.png"
|
||
);
|
||
}
|
||
});
|
||
} catch (error) {
|
||
createLoading.value = false;
|
||
console.error(error);
|
||
}
|
||
};
|
||
// 图生图
|
||
const img2img = async () => {
|
||
try {
|
||
let data = {
|
||
prompt: apiprompt.value,
|
||
real_prompt: prompt.value,
|
||
init_images: init_images.value,
|
||
sd_model_hash: seletedModel.value.hash,
|
||
real_negative_prompt: negative_prompt.value,
|
||
negative_prompt: negative_prompt.value,
|
||
width: apiWidth.value,
|
||
height: apiHeight.value,
|
||
batch_size: batch_size.value, //每次张数
|
||
n_iter: 1, //生成批次
|
||
steps: 30, //生成步数
|
||
override_settings_restore_afterwards: true,
|
||
override_settings: {
|
||
sd_model_checkpoint: seletedModel.value.title,
|
||
},
|
||
};
|
||
await ModelApi.img2img(data).then((res) => {
|
||
if (res.status === 0) {
|
||
createLoading.value = false;
|
||
historyList.value[0].imgList = res.data.images;
|
||
getUserInfo();
|
||
} else {
|
||
processError(res.msg);
|
||
createLoading.value = false;
|
||
historyList.value[0].imgList = new Array(batch_size.value).fill(
|
||
"https://cdns.fontree.cn/fonchain-main/prod/image/default/ai/wrong.png"
|
||
);
|
||
}
|
||
});
|
||
} catch (error) {
|
||
createLoading.value = false;
|
||
console.error(error);
|
||
}
|
||
};
|
||
// 切换模式
|
||
const setActiveButton = (buttonNumber) => {
|
||
if (buttonNumber === 1) {
|
||
// 添加fade动画
|
||
fadeOut1.value.classList.add("animate__fadeOutLeft");
|
||
fadeOut2.value.classList.add("animate__fadeOutLeft");
|
||
fadeOut3.value.classList.add("animate__fadeOutLeft");
|
||
fadeOut4.value.classList.add("animate__fadeOutLeft");
|
||
init_images.value = [];
|
||
negative_prompt.value = "";
|
||
}
|
||
let timer = buttonNumber === 1 ? 500 : 0;
|
||
setTimeout(() => {
|
||
activeButton.value = buttonNumber;
|
||
}, timer);
|
||
// 背景menu-bg跟随点击的按钮移动
|
||
const menuBg = document.querySelector(".menu-bg");
|
||
const menuButton = document.querySelectorAll(".menu-button");
|
||
const button = menuButton[buttonNumber - 1];
|
||
const { top, left, width, height } = button.getBoundingClientRect();
|
||
menuBg.style.top = `${top - height + 10}px`;
|
||
menuBg.style.left = `${left}px`;
|
||
};
|
||
const chooseModel = (model) => {
|
||
// 如果点击的是已经选中的模型,不做任何操作
|
||
if (model.nowSelect) {
|
||
return;
|
||
}
|
||
seletedModel.value = model;
|
||
model.nowSelect = !model.nowSelect;
|
||
modelArr.value.forEach((item) => {
|
||
if (item !== model) {
|
||
item.nowSelect = false;
|
||
}
|
||
});
|
||
console.log(seletedModel.value);
|
||
};
|
||
const chooseSize = (size) => {
|
||
// 如果点击的是已经选中的尺寸,不做任何操作
|
||
if (size.nowSelect) {
|
||
return;
|
||
}
|
||
selectedSize.value = size;
|
||
size.nowSelect = !size.nowSelect;
|
||
sizeArr.value.forEach((item) => {
|
||
if (item !== size) {
|
||
item.nowSelect = false;
|
||
}
|
||
});
|
||
};
|
||
// 监听with和height的值,如果都有值,取消图片和尺寸的选中状态
|
||
watch([width, height], ([newWidth, newHeight]) => {
|
||
if (newWidth && newHeight) {
|
||
selectedSize.value = {};
|
||
sizeArr.value.forEach((item) => {
|
||
item.nowSelect = false;
|
||
});
|
||
}
|
||
});
|
||
|
||
onBeforeMount(() => {
|
||
getModelList();
|
||
getUserInfo();
|
||
});
|
||
</script>
|
||
<style scoped lang="scss">
|
||
.q-page {
|
||
background: #19191a;
|
||
display: flex;
|
||
height: 100%;
|
||
width: 100%;
|
||
}
|
||
.q-gutter-sm > * {
|
||
margin-left: 15px;
|
||
}
|
||
.silder {
|
||
width: 110px;
|
||
background: #212121;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
overflow: hidden;
|
||
.menu-box {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-top: 30px;
|
||
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
.menu-button {
|
||
z-index: 20;
|
||
height: 90px;
|
||
width: 90px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
flex-direction: column;
|
||
background-color: transparent;
|
||
padding: 20px 10px 20px 10px;
|
||
margin-bottom: 20px;
|
||
cursor: pointer;
|
||
transition: background-color 0.5s ease;
|
||
.act img {
|
||
width: 55px;
|
||
height: auto;
|
||
}
|
||
.no-act img {
|
||
width: 40px;
|
||
height: 40px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.act {
|
||
color: #fff;
|
||
font-weight: bold;
|
||
text-shadow: 0px 3px 4px #de53ab;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.no-act {
|
||
color: #fff;
|
||
font-weight: bold;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
.menu-bg {
|
||
position: absolute;
|
||
padding: 20px 10px 20px 10px;
|
||
margin-bottom: 20px;
|
||
background: linear-gradient(to right, #62d1ef, #5f33f3, #dc4cac);
|
||
z-index: 10;
|
||
height: 90px;
|
||
width: 90px;
|
||
border-radius: 10px;
|
||
transition: top 0.5s ease, left 0.5s ease;
|
||
top: 0;
|
||
left: 10px;
|
||
}
|
||
}
|
||
}
|
||
.img-content {
|
||
height: 100%;
|
||
padding: 15px;
|
||
background: #19191a;
|
||
flex: 1;
|
||
background-image: url("../../assets/image/ai/img-bg.png");
|
||
background-size: cover;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
.plane {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
.word {
|
||
color: #fff;
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
margin-top: 20px;
|
||
}
|
||
}
|
||
.created-img-box {
|
||
.img-page {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
span {
|
||
color: #7e7e7e;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
.img-list-box {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20px;
|
||
margin-top: 20px;
|
||
margin-bottom: 20px;
|
||
.img-detail-box {
|
||
width: 400px;
|
||
height: 400px;
|
||
background: #212121;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
:deep(.n-spin-content) {
|
||
height: 100%;
|
||
&:hover {
|
||
transform: scale(1.1);
|
||
transition: transform 0.5s ease-in-out;
|
||
}
|
||
&:not(:hover) {
|
||
transform: scale(1);
|
||
transition: transform 0.5s ease-in-out;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.setting-content {
|
||
width: 490px;
|
||
padding: 15px;
|
||
.setting {
|
||
width: 100%;
|
||
margin-bottom: 14px;
|
||
height: 87%;
|
||
background: #212121;
|
||
border-radius: 10px;
|
||
padding: 20px 20px 20px 20px;
|
||
.prompt-title {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
.cirl {
|
||
width: 17px;
|
||
height: 20px;
|
||
}
|
||
// 鼠标悬浮放大后在点击按钮上添加动画
|
||
.runse {
|
||
width: 22px;
|
||
height: 22px;
|
||
cursor: pointer;
|
||
transition: transform 0.5s ease;
|
||
&:hover {
|
||
transform: scale(1.2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.ms-content {
|
||
border: 2px solid transparent;
|
||
animation-play-state: running !important;
|
||
height: 125px;
|
||
width: 100%;
|
||
margin-bottom: 14px;
|
||
border-radius: 10px;
|
||
.content-input {
|
||
background: #212121;
|
||
height: 100%;
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
}
|
||
.model-box {
|
||
width: 100%;
|
||
height: 200px;
|
||
text-align: center;
|
||
.style-box {
|
||
width: 80px;
|
||
height: 80px;
|
||
animation-play-state: running !important;
|
||
border-radius: 6px;
|
||
display: inline-block;
|
||
}
|
||
.all-box {
|
||
width: 80px;
|
||
height: 80px;
|
||
// 文字上下左右居中
|
||
display: flex;
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
font-weight: bold;
|
||
justify-content: center;
|
||
margin-left: 32px;
|
||
align-items: center;
|
||
background: linear-gradient(260deg, #c448b8, #591df5);
|
||
border-radius: 6px;
|
||
}
|
||
.size-box {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #212121 !important;
|
||
width: 128px;
|
||
height: 65px;
|
||
animation-play-state: running !important;
|
||
border-radius: 6px;
|
||
.left-img {
|
||
margin-right: 10px;
|
||
}
|
||
div {
|
||
font-size: 11px;
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
}
|
||
.border-change {
|
||
border: 2px solid transparent;
|
||
animation-play-state: running;
|
||
}
|
||
.border-default {
|
||
border: 2px solid #7e7e7e;
|
||
}
|
||
.wh-box {
|
||
width: 100%;
|
||
height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
padding: 10px 30px 10px 20px;
|
||
margin-top: 20px;
|
||
border-radius: 6px;
|
||
border: 2px solid #7e7e7e;
|
||
background: #19191a;
|
||
:deep(.n-input) {
|
||
background-color: #19191a;
|
||
}
|
||
:deep(.n-input__suffix) {
|
||
display: none;
|
||
}
|
||
}
|
||
.bottom-box {
|
||
height: 13%;
|
||
margin-top: 10px;
|
||
background: #212121;
|
||
border-radius: 10px;
|
||
padding: 17px 17px 27px 27px;
|
||
display: flex;
|
||
.num-box {
|
||
width: 120px;
|
||
text-align: center;
|
||
|
||
.num-select {
|
||
height: 57px;
|
||
:deep(.n-base-selection-label) {
|
||
height: 57px;
|
||
background-color: #212121;
|
||
width: 110px;
|
||
color: #fff;
|
||
}
|
||
:deep(.n-base-selection-input__content) {
|
||
color: #fff;
|
||
}
|
||
margin-bottom: 5px;
|
||
}
|
||
div {
|
||
color: #7e7e7e;
|
||
}
|
||
}
|
||
.btn-box {
|
||
flex: 1;
|
||
text-align: center;
|
||
.create {
|
||
width: 260px;
|
||
height: 55px;
|
||
background: linear-gradient(260deg, #c448b8, #591df5);
|
||
border-radius: 6px;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
margin-left: 15px;
|
||
margin-bottom: 5px;
|
||
}
|
||
div {
|
||
color: #7e7e7e;
|
||
}
|
||
}
|
||
}
|
||
.popover {
|
||
background: red;
|
||
}
|
||
.popout {
|
||
background: #212121;
|
||
}
|
||
@property --bg-angle {
|
||
inherits: false;
|
||
initial-value: 0deg;
|
||
syntax: "<angle>";
|
||
}
|
||
|
||
@keyframes spin {
|
||
to {
|
||
--bg-angle: 360deg;
|
||
}
|
||
}
|
||
//
|
||
.gallery-track {
|
||
position: fixed;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 0.25rem;
|
||
padding: 0.25rem;
|
||
will-change: transform;
|
||
}
|
||
|
||
.card {
|
||
border-radius: 1rem;
|
||
color: white;
|
||
width: min(400px, 90vw);
|
||
height: 400px;
|
||
overflow: hidden;
|
||
animation: spin 2.5s infinite linear paused;
|
||
background: linear-gradient(
|
||
to bottom,
|
||
oklch(0.1 0 240 / 0.95),
|
||
oklch(0.1 0 240 / 0.95)
|
||
)
|
||
padding-box,
|
||
conic-gradient(
|
||
from var(--bg-angle) in oklch longer hue,
|
||
oklch(0.85 0.17 0) 0 0
|
||
)
|
||
border-box;
|
||
|
||
& .card-image-wrapper {
|
||
height: 135%;
|
||
will-change: transform;
|
||
|
||
& img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
}
|
||
@media (width < 800px) {
|
||
.gallery-track {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
|
||
@media (width < 550px) {
|
||
.gallery-track {
|
||
grid-template-columns: repeat(1, 1fr);
|
||
}
|
||
}
|
||
|
||
//
|
||
:deep(.n-input .n-input__border) {
|
||
border: 0;
|
||
}
|
||
// 更改placeholder的颜色
|
||
:deep(.n-input__placeholder) {
|
||
color: #7e7e7e;
|
||
}
|
||
:deep(.n-input__textarea-el) {
|
||
color: #7e7e7e;
|
||
}
|
||
:deep(.n-input__input-el) {
|
||
color: #7e7e7e;
|
||
}
|
||
:deep(.n-spin) {
|
||
color: #c348b8;
|
||
}
|
||
:deep(.n-spin-container) {
|
||
height: 100%;
|
||
}
|
||
:deep(.n-spin-content) {
|
||
height: 100%;
|
||
}
|
||
:deep(.n-upload-dragger) {
|
||
background: #212121;
|
||
height: 420px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
}
|
||
:deep(.n-upload-trigger.n-upload-trigger--image-card) {
|
||
width: 420px;
|
||
height: 400px;
|
||
margin-bottom: 10px;
|
||
}
|
||
:deep(.n-upload-file) {
|
||
width: 420px !important;
|
||
height: 400px !important;
|
||
}
|
||
</style>
|