|
@@ -3,12 +3,11 @@
|
|
|
<div class="prompt">
|
|
|
<el-text tag="b">画面描述</el-text>
|
|
|
<el-text tag="p">建议使用“形容词+动词+风格”的格式,使用“,”隔开</el-text>
|
|
|
- <!-- TODO @fan:style 看看能不能哟 unocss 替代 @芋艿 尝试了下没效果,哪个地方有使用么,我看看 -->
|
|
|
<el-input
|
|
|
v-model="prompt"
|
|
|
maxlength="1024"
|
|
|
rows="5"
|
|
|
- style="width: 100%; margin-top: 15px;"
|
|
|
+ class="w-100% mt-15px"
|
|
|
input-style="border-radius: 7px;"
|
|
|
placeholder="例如:童话里的小屋应该是什么样子?"
|
|
|
show-word-limit
|
|
@@ -20,12 +19,13 @@
|
|
|
<el-text tag="b">随机热词</el-text>
|
|
|
</div>
|
|
|
<el-space wrap class="word-list">
|
|
|
- <el-button round
|
|
|
- class="btn"
|
|
|
- :type="(selectHotWord === hotWord ? 'primary' : 'default')"
|
|
|
- v-for="hotWord in hotWords"
|
|
|
- :key="hotWord"
|
|
|
- @click="handleHotWordClick(hotWord)"
|
|
|
+ <el-button
|
|
|
+ round
|
|
|
+ class="btn"
|
|
|
+ :type="selectHotWord === hotWord ? 'primary' : 'default'"
|
|
|
+ v-for="hotWord in ImageHotWords"
|
|
|
+ :key="hotWord"
|
|
|
+ @click="handleHotWordClick(hotWord)"
|
|
|
>
|
|
|
{{ hotWord }}
|
|
|
</el-button>
|
|
@@ -37,17 +37,12 @@
|
|
|
</div>
|
|
|
<el-space wrap class="model-list">
|
|
|
<div
|
|
|
- :class="selectModel === model.key ? 'modal-item selectModel' : 'modal-item'"
|
|
|
- v-for="model in models"
|
|
|
+ :class="model === model.key ? 'modal-item selectModel' : 'modal-item'"
|
|
|
+ v-for="model in Dall3Models"
|
|
|
:key="model.key"
|
|
|
-
|
|
|
>
|
|
|
- <el-image
|
|
|
- :src="model.image"
|
|
|
- fit="contain"
|
|
|
- @click="handleModelClick(model)"
|
|
|
- />
|
|
|
- <div class="model-font">{{model.name}}</div>
|
|
|
+ <el-image :src="model.image" fit="contain" @click="handleModelClick(model)" />
|
|
|
+ <div class="model-font">{{ model.name }}</div>
|
|
|
</div>
|
|
|
</el-space>
|
|
|
</div>
|
|
@@ -57,16 +52,16 @@
|
|
|
</div>
|
|
|
<el-space wrap class="image-style-list">
|
|
|
<div
|
|
|
- :class="selectImageStyle === imageStyle.key ? 'image-style-item selectImageStyle' : 'image-style-item'"
|
|
|
+ :class="
|
|
|
+ selectImageStyle === imageStyle.key
|
|
|
+ ? 'image-style-item selectImageStyle'
|
|
|
+ : 'image-style-item'
|
|
|
+ "
|
|
|
v-for="imageStyle in imageStyleList"
|
|
|
:key="imageStyle.key"
|
|
|
>
|
|
|
- <el-image
|
|
|
- :src="imageStyle.image"
|
|
|
- fit="contain"
|
|
|
- @click="handleStyleClick(imageStyle)"
|
|
|
- />
|
|
|
- <div class="style-font">{{imageStyle.name}}</div>
|
|
|
+ <el-image :src="imageStyle.image" fit="contain" @click="handleStyleClick(imageStyle)" />
|
|
|
+ <div class="style-font">{{ imageStyle.name }}</div>
|
|
|
</div>
|
|
|
</el-space>
|
|
|
</div>
|
|
@@ -75,11 +70,13 @@
|
|
|
<el-text tag="b">画面比例</el-text>
|
|
|
</div>
|
|
|
<el-space wrap class="size-list">
|
|
|
- <div class="size-item"
|
|
|
- v-for="imageSize in imageSizeList"
|
|
|
- :key="imageSize.key"
|
|
|
- @click="handleSizeClick(imageSize)">
|
|
|
- <div :class="selectImageSize === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'">
|
|
|
+ <div
|
|
|
+ class="size-item"
|
|
|
+ v-for="imageSize in imageSizeList"
|
|
|
+ :key="imageSize.key"
|
|
|
+ @click="handleSizeClick(imageSize)"
|
|
|
+ >
|
|
|
+ <div :class="size === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'">
|
|
|
<div :style="imageSize.style"></div>
|
|
|
</div>
|
|
|
<div class="size-font">{{ imageSize.name }}</div>
|
|
@@ -87,17 +84,16 @@
|
|
|
</el-space>
|
|
|
</div>
|
|
|
<div class="btns">
|
|
|
- <el-button type="primary"
|
|
|
- size="large"
|
|
|
- round
|
|
|
- :loading="drawIn"
|
|
|
- @click="handleGenerateImage">
|
|
|
- {{drawIn ? '生成中' : '生成内容'}}
|
|
|
+ <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage">
|
|
|
+ {{ drawIn ? '生成中' : '生成内容' }}
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
-import {ImageApi, ImageDrawReqVO, ImageVO} from '@/api/ai/image';
|
|
|
+import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
|
|
|
+import { Dall3Models, ImageHotWords } from '@/views/ai/utils/constants'
|
|
|
+
|
|
|
+const message = useMessage() // 消息弹窗
|
|
|
|
|
|
// image 模型
|
|
|
interface ImageModelVO {
|
|
@@ -109,32 +105,18 @@ interface ImageModelVO {
|
|
|
// image 大小
|
|
|
interface ImageSizeVO {
|
|
|
key: string
|
|
|
- name: string,
|
|
|
- style: string,
|
|
|
- width: string,
|
|
|
- height: string,
|
|
|
+ name: string
|
|
|
+ style: string
|
|
|
+ width: string
|
|
|
+ height: string
|
|
|
}
|
|
|
|
|
|
// 定义属性
|
|
|
-const prompt = ref<string>('') // 提示词
|
|
|
-const drawIn = ref<boolean>(false) // 生成中
|
|
|
+const prompt = ref<string>('') // 提示词
|
|
|
+const drawIn = ref<boolean>(false) // 生成中
|
|
|
const selectHotWord = ref<string>('') // 选中的热词
|
|
|
-const hotWords = ref<string[]>(['中国旗袍', '古装美女', '卡通头像', '机甲战士', '童话小屋', '中国长城']) // 热词
|
|
|
-const selectModel = ref<string>('dall-e-3') // 模型
|
|
|
-// message
|
|
|
-const message = useMessage()
|
|
|
-const models = ref<ImageModelVO[]>([
|
|
|
- {
|
|
|
- key: 'dall-e-3',
|
|
|
- name: 'DALL·E 3',
|
|
|
- image: `/src/assets/ai/dall2.jpg`,
|
|
|
- },
|
|
|
- {
|
|
|
- key: 'dall-e-2',
|
|
|
- name: 'DALL·E 2',
|
|
|
- image: `/src/assets/ai/dall3.jpg`,
|
|
|
- },
|
|
|
-]) // 模型
|
|
|
+const model = ref<string>('dall-e-3') // 模型
|
|
|
+const size = ref<string>('1024x1024') // 选中 size
|
|
|
|
|
|
const selectImageStyle = ref<string>('vivid') // style 样式
|
|
|
|
|
@@ -142,37 +124,36 @@ const imageStyleList = ref<ImageModelVO[]>([
|
|
|
{
|
|
|
key: 'vivid',
|
|
|
name: '清晰',
|
|
|
- image: `/src/assets/ai/qingxi.jpg`,
|
|
|
+ image: `/src/assets/ai/qingxi.jpg`
|
|
|
},
|
|
|
{
|
|
|
key: 'natural',
|
|
|
name: '自然',
|
|
|
- image: `/src/assets/ai/ziran.jpg`,
|
|
|
- },
|
|
|
-]) // style
|
|
|
+ image: `/src/assets/ai/ziran.jpg`
|
|
|
+ }
|
|
|
+]) // style
|
|
|
|
|
|
-const selectImageSize = ref<string>('1024x1024') // 选中 size
|
|
|
const imageSizeList = ref<ImageSizeVO[]>([
|
|
|
{
|
|
|
key: '1024x1024',
|
|
|
name: '1:1',
|
|
|
width: '1024',
|
|
|
height: '1024',
|
|
|
- style: 'width: 30px; height: 30px;background-color: #dcdcdc;',
|
|
|
+ style: 'width: 30px; height: 30px;background-color: #dcdcdc;'
|
|
|
},
|
|
|
{
|
|
|
key: '1024x1792',
|
|
|
name: '3:5',
|
|
|
width: '1024',
|
|
|
height: '1792',
|
|
|
- style: 'width: 30px; height: 50px;background-color: #dcdcdc;',
|
|
|
+ style: 'width: 30px; height: 50px;background-color: #dcdcdc;'
|
|
|
},
|
|
|
{
|
|
|
key: '1792x1024',
|
|
|
name: '5:3',
|
|
|
width: '1792',
|
|
|
height: '1024',
|
|
|
- style: 'width: 50px; height: 30px;background-color: #dcdcdc;',
|
|
|
+ style: 'width: 50px; height: 30px;background-color: #dcdcdc;'
|
|
|
}
|
|
|
]) // size
|
|
|
|
|
@@ -196,7 +177,7 @@ const handleHotWordClick = async (hotWord: string) => {
|
|
|
|
|
|
/** 模型 - click */
|
|
|
const handleModelClick = async (model: ImageModelVO) => {
|
|
|
- selectModel.value = model.key
|
|
|
+ model.value = model.key
|
|
|
}
|
|
|
|
|
|
/** 样式 - click */
|
|
@@ -206,7 +187,7 @@ const handleStyleClick = async (imageStyle: ImageModelVO) => {
|
|
|
|
|
|
/** size - click */
|
|
|
const handleSizeClick = async (imageSize: ImageSizeVO) => {
|
|
|
- selectImageSize.value = imageSize.key
|
|
|
+ size.value = imageSize.key
|
|
|
}
|
|
|
|
|
|
/** 图片生产 */
|
|
@@ -217,23 +198,23 @@ const handleGenerateImage = async () => {
|
|
|
// 加载中
|
|
|
drawIn.value = true
|
|
|
// 回调
|
|
|
- emits('onDrawStart', selectModel.value)
|
|
|
- const imageSize = imageSizeList.value.find(item => item.key === selectImageSize.value) as ImageSizeVO
|
|
|
+ emits('onDrawStart', model.value)
|
|
|
+ const imageSize = imageSizeList.value.find((item) => item.key === size.value) as ImageSizeVO
|
|
|
const form = {
|
|
|
platform: 'OpenAI',
|
|
|
prompt: prompt.value, // 提示词
|
|
|
- model: selectModel.value, // 模型
|
|
|
+ model: model.value, // 模型
|
|
|
width: imageSize.width, // size 不能为空
|
|
|
height: imageSize.height, // size 不能为空
|
|
|
options: {
|
|
|
- style: selectImageStyle.value, // 图像生成的风格
|
|
|
+ style: selectImageStyle.value // 图像生成的风格
|
|
|
}
|
|
|
} as ImageDrawReqVO
|
|
|
// 发送请求
|
|
|
await ImageApi.drawImage(form)
|
|
|
} finally {
|
|
|
// 回调
|
|
|
- emits('onDrawComplete', selectModel.value)
|
|
|
+ emits('onDrawComplete', model.value)
|
|
|
// 加载结束
|
|
|
drawIn.value = false
|
|
|
}
|
|
@@ -242,17 +223,18 @@ const handleGenerateImage = async () => {
|
|
|
/** 填充值 */
|
|
|
const settingValues = async (imageDetail: ImageVO) => {
|
|
|
prompt.value = imageDetail.prompt
|
|
|
- selectModel.value = imageDetail.model
|
|
|
+ model.value = imageDetail.model
|
|
|
//
|
|
|
selectImageStyle.value = imageDetail.options?.style
|
|
|
//
|
|
|
- const imageSize = imageSizeList.value.find(item => item.key === `${imageDetail.width}x${imageDetail.height}`) as ImageSizeVO
|
|
|
+ const imageSize = imageSizeList.value.find(
|
|
|
+ (item) => item.key === `${imageDetail.width}x${imageDetail.height}`
|
|
|
+ ) as ImageSizeVO
|
|
|
await handleSizeClick(imageSize)
|
|
|
}
|
|
|
|
|
|
/** 暴露组件方法 */
|
|
|
defineExpose({ settingValues })
|
|
|
-
|
|
|
</script>
|
|
|
<style scoped lang="scss">
|
|
|
// 提示词
|
|
@@ -309,7 +291,6 @@ defineExpose({ settingValues })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// 样式 style
|
|
|
.image-style {
|
|
|
margin-top: 30px;
|