houzhongjian
2024-08-08 820397e43a0b64d35c6d31d2a55475061438593b
提交 | 用户 | 时间
820397 1 <!-- dall3 -->
H 2 <template>
3   <div class="prompt">
4     <el-text tag="b">画面描述</el-text>
5     <el-text tag="p">建议使用“形容词+动词+风格”的格式,使用“,”隔开.</el-text>
6     <el-input
7       v-model="prompt"
8       maxlength="1024"
9       rows="5"
10       class="w-100% mt-15px"
11       input-style="border-radius: 7px;"
12       placeholder="例如:童话里的小屋应该是什么样子?"
13       show-word-limit
14       type="textarea"
15     />
16   </div>
17   <div class="hot-words">
18     <div>
19       <el-text tag="b">随机热词</el-text>
20     </div>
21     <el-space wrap class="word-list">
22       <el-button
23         round
24         class="btn"
25         :type="selectHotWord === hotWord ? 'primary' : 'default'"
26         v-for="hotWord in ImageHotWords"
27         :key="hotWord"
28         @click="handleHotWordClick(hotWord)"
29       >
30         {{ hotWord }}
31       </el-button>
32     </el-space>
33   </div>
34   <div class="image-size">
35     <div>
36       <el-text tag="b">尺寸</el-text>
37     </div>
38     <el-space wrap class="size-list">
39       <div
40         class="size-item"
41         v-for="imageSize in MidjourneySizeList"
42         :key="imageSize.key"
43         @click="handleSizeClick(imageSize)"
44       >
45         <div
46           :class="selectSize === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'"
47         >
48           <div :style="imageSize.style"></div>
49         </div>
50         <div class="size-font">{{ imageSize.key }}</div>
51       </div>
52     </el-space>
53   </div>
54   <div class="model">
55     <div>
56       <el-text tag="b">模型</el-text>
57     </div>
58     <el-space wrap class="model-list">
59       <div
60         :class="selectModel === model.key ? 'modal-item selectModel' : 'modal-item'"
61         v-for="model in MidjourneyModels"
62         :key="model.key"
63       >
64         <el-image :src="model.image" fit="contain" @click="handleModelClick(model)" />
65         <div class="model-font">{{ model.name }}</div>
66       </div>
67     </el-space>
68   </div>
69   <div class="version">
70     <div>
71       <el-text tag="b">版本</el-text>
72     </div>
73     <el-space wrap class="version-list">
74       <el-select
75         v-model="selectVersion"
76         class="version-select !w-350px"
77         clearable
78         placeholder="请选择版本"
79       >
80         <el-option
81           v-for="item in versionList"
82           :key="item.value"
83           :label="item.label"
84           :value="item.value"
85         />
86       </el-select>
87     </el-space>
88   </div>
89   <div class="model">
90     <div>
91       <el-text tag="b">参考图</el-text>
92     </div>
93     <el-space wrap class="model-list">
94       <UploadImg v-model="referImageUrl" height="120px" width="120px" />
95     </el-space>
96   </div>
97   <div class="btns">
98     <el-button type="primary" size="large" round @click="handleGenerateImage">
99       {{ drawIn ? '生成中' : '生成内容' }}
100     </el-button>
101   </div>
102 </template>
103 <script setup lang="ts">
104 import { ImageApi, ImageMidjourneyImagineReqVO, ImageVO } from '@/api/ai/image'
105 import {
106   AiPlatformEnum,
107   ImageHotWords,
108   ImageSizeVO,
109   ImageModelVO,
110   MidjourneyModels,
111   MidjourneySizeList,
112   MidjourneyVersions,
113   NijiVersionList
114 } from '@/views/ai/utils/constants'
115
116 const message = useMessage() // 消息弹窗
117
118 // 定义属性
119 const drawIn = ref<boolean>(false) // 生成中
120 const selectHotWord = ref<string>('') // 选中的热词
121 // 表单
122 const prompt = ref<string>('') // 提示词
123 const referImageUrl = ref<any>() // 参考图
124 const selectModel = ref<string>('midjourney') // 选中的模型
125 const selectSize = ref<string>('1:1') // 选中 size
126 const selectVersion = ref<any>('6.0') // 选中的 version
127 const versionList = ref<any>(MidjourneyVersions) // version 列表
128 const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
129
130 /** 选择热词 */
131 const handleHotWordClick = async (hotWord: string) => {
132   // 情况一:取消选中
133   if (selectHotWord.value == hotWord) {
134     selectHotWord.value = ''
135     return
136   }
137
138   // 情况二:选中
139   selectHotWord.value = hotWord // 选中
140   prompt.value = hotWord // 设置提示次
141 }
142
143 /** 点击 size 尺寸 */
144 const handleSizeClick = async (imageSize: ImageSizeVO) => {
145   selectSize.value = imageSize.key
146 }
147
148 /** 点击 model 模型 */
149 const handleModelClick = async (model: ImageModelVO) => {
150   selectModel.value = model.key
151   if (model.key === 'niji') {
152     versionList.value = NijiVersionList // 默认选择 niji
153   } else {
154     versionList.value = MidjourneyVersions // 默认选择 midjourney
155   }
156   selectVersion.value = versionList.value[0].value
157 }
158
159 /** 图片生成 */
160 const handleGenerateImage = async () => {
161   // 二次确认
162   await message.confirm(`确认生成内容?`)
163   try {
164     // 加载中
165     drawIn.value = true
166     // 回调
167     emits('onDrawStart', AiPlatformEnum.MIDJOURNEY)
168     // 发送请求
169     const imageSize = MidjourneySizeList.find(
170       (item) => selectSize.value === item.key
171     ) as ImageSizeVO
172     const req = {
173       prompt: prompt.value,
174       model: selectModel.value,
175       width: imageSize.width,
176       height: imageSize.height,
177       version: selectVersion.value,
178       referImageUrl: referImageUrl.value
179     } as ImageMidjourneyImagineReqVO
180     await ImageApi.midjourneyImagine(req)
181   } finally {
182     // 回调
183     emits('onDrawComplete', AiPlatformEnum.MIDJOURNEY)
184     // 加载结束
185     drawIn.value = false
186   }
187 }
188
189 /** 填充值 */
190 const settingValues = async (detail: ImageVO) => {
191   // 提示词
192   prompt.value = detail.prompt
193   // image size
194   const imageSize = MidjourneySizeList.find(
195     (item) => item.key === `${detail.width}:${detail.height}`
196   ) as ImageSizeVO
197   selectSize.value = imageSize.key
198   // 选中模型
199   const model = MidjourneyModels.find((item) => item.key === detail.options?.model) as ImageModelVO
200   await handleModelClick(model)
201   // 版本
202   selectVersion.value = versionList.value.find(
203     (item) => item.value === detail.options?.version
204   ).value
205   // image
206   referImageUrl.value = detail.options.referImageUrl
207 }
208
209 /** 暴露组件方法 */
210 defineExpose({ settingValues })
211 </script>
212 <style scoped lang="scss">
213 // 提示词
214 .prompt {
215 }
216
217 // 热词
218 .hot-words {
219   display: flex;
220   flex-direction: column;
221   margin-top: 30px;
222
223   .word-list {
224     display: flex;
225     flex-direction: row;
226     flex-wrap: wrap;
227     justify-content: start;
228     margin-top: 15px;
229
230     .btn {
231       margin: 0;
232     }
233   }
234 }
235
236 // version
237 .version {
238   margin-top: 20px;
239
240   .version-list {
241     margin-top: 20px;
242     width: 100%;
243   }
244 }
245
246 // 模型
247 .model {
248   margin-top: 30px;
249
250   .model-list {
251     margin-top: 15px;
252
253     .modal-item {
254       display: flex;
255       flex-direction: column;
256       align-items: center;
257       width: 150px;
258       //outline: 1px solid blue;
259       overflow: hidden;
260       border: 3px solid transparent;
261       cursor: pointer;
262
263       .model-font {
264         font-size: 14px;
265         color: #3e3e3e;
266         font-weight: bold;
267       }
268     }
269
270     .selectModel {
271       border: 3px solid #1293ff;
272       border-radius: 5px;
273     }
274   }
275 }
276
277 // 尺寸
278 .image-size {
279   width: 100%;
280   margin-top: 30px;
281
282   .size-list {
283     display: flex;
284     flex-direction: row;
285     justify-content: space-between;
286     width: 100%;
287     margin-top: 20px;
288
289     .size-item {
290       display: flex;
291       flex-direction: column;
292       align-items: center;
293       cursor: pointer;
294
295       .size-wrapper {
296         display: flex;
297         flex-direction: column;
298         align-items: center;
299         justify-content: center;
300         border-radius: 7px;
301         padding: 4px;
302         width: 50px;
303         height: 50px;
304         background-color: #fff;
305         border: 1px solid #fff;
306       }
307
308       .size-font {
309         font-size: 14px;
310         color: #3e3e3e;
311         font-weight: bold;
312       }
313     }
314   }
315
316   .selectImageSize {
317     border: 1px solid #1293ff !important;
318   }
319 }
320
321 .btns {
322   display: flex;
323   justify-content: center;
324   margin-top: 50px;
325 }
326 </style>