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="model">
35     <div>
36       <el-text tag="b">模型选择</el-text>
37     </div>
38     <el-space wrap class="model-list">
39       <div
40         :class="selectModel === model.key ? 'modal-item selectModel' : 'modal-item'"
41         v-for="model in Dall3Models"
42         :key="model.key"
43       >
44         <el-image :src="model.image" fit="contain" @click="handleModelClick(model)" />
45         <div class="model-font">{{ model.name }}</div>
46       </div>
47     </el-space>
48   </div>
49   <div class="image-style">
50     <div>
51       <el-text tag="b">风格选择</el-text>
52     </div>
53     <el-space wrap class="image-style-list">
54       <div
55         :class="style === imageStyle.key ? 'image-style-item selectImageStyle' : 'image-style-item'"
56         v-for="imageStyle in Dall3StyleList"
57         :key="imageStyle.key"
58       >
59         <el-image :src="imageStyle.image" fit="contain" @click="handleStyleClick(imageStyle)" />
60         <div class="style-font">{{ imageStyle.name }}</div>
61       </div>
62     </el-space>
63   </div>
64   <div class="image-size">
65     <div>
66       <el-text tag="b">画面比例</el-text>
67     </div>
68     <el-space wrap class="size-list">
69       <div
70         class="size-item"
71         v-for="imageSize in Dall3SizeList"
72         :key="imageSize.key"
73         @click="handleSizeClick(imageSize)"
74       >
75         <div
76           :class="selectSize === imageSize.key ? 'size-wrapper selectImageSize' : 'size-wrapper'"
77         >
78           <div :style="imageSize.style"></div>
79         </div>
80         <div class="size-font">{{ imageSize.name }}</div>
81       </div>
82     </el-space>
83   </div>
84   <div class="btns">
85     <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage">
86       {{ drawIn ? '生成中' : '生成内容' }}
87     </el-button>
88   </div>
89 </template>
90 <script setup lang="ts">
91 import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
92 import {
93   Dall3Models,
94   Dall3StyleList,
95   ImageHotWords,
96   Dall3SizeList,
97   ImageModelVO,
98   AiPlatformEnum
99 } from '@/views/ai/utils/constants'
100
101 const message = useMessage() // 消息弹窗
102
103 // 定义属性
104 const prompt = ref<string>('') // 提示词
105 const drawIn = ref<boolean>(false) // 生成中
106 const selectHotWord = ref<string>('') // 选中的热词
107 const selectModel = ref<string>('dall-e-3') // 模型
108 const selectSize = ref<string>('1024x1024') // 选中 size
109 const style = ref<string>('vivid') // style 样式
110
111 const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
112
113 /** 选择热词 */
114 const handleHotWordClick = async (hotWord: string) => {
115   // 情况一:取消选中
116   if (selectHotWord.value == hotWord) {
117     selectHotWord.value = ''
118     return
119   }
120
121   // 情况二:选中
122   selectHotWord.value = hotWord
123   prompt.value = hotWord
124 }
125
126 /** 选择 model 模型 */
127 const handleModelClick = async (model: ImageModelVO) => {
128   selectModel.value = model.key
129 }
130
131 /** 选择 style 样式  */
132 const handleStyleClick = async (imageStyle: ImageModelVO) => {
133   style.value = imageStyle.key
134 }
135
136 /** 选择 size 大小  */
137 const handleSizeClick = async (imageSize: ImageSizeVO) => {
138   selectSize.value = imageSize.key
139 }
140
141 /**  图片生产  */
142 const handleGenerateImage = async () => {
143   // 二次确认
144   await message.confirm(`确认生成内容?`)
145   try {
146     // 加载中
147     drawIn.value = true
148     // 回调
149     emits('onDrawStart', AiPlatformEnum.OPENAI)
150     const imageSize = Dall3SizeList.find((item) => item.key === selectSize.value) as ImageSizeVO
151     const form = {
152       platform: AiPlatformEnum.OPENAI,
153       prompt: prompt.value, // 提示词
154       model: selectModel.value, // 模型
155       width: imageSize.width, // size 不能为空
156       height: imageSize.height, // size 不能为空
157       options: {
158         style: style.value // 图像生成的风格
159       }
160     } as ImageDrawReqVO
161     // 发送请求
162     await ImageApi.drawImage(form)
163   } finally {
164     // 回调
165     emits('onDrawComplete', AiPlatformEnum.OPENAI)
166     // 加载结束
167     drawIn.value = false
168   }
169 }
170
171 /** 填充值 */
172 const settingValues = async (detail: ImageVO) => {
173   prompt.value = detail.prompt
174   selectModel.value = detail.model
175   style.value = detail.options?.style
176   const imageSize = Dall3SizeList.find(
177     (item) => item.key === `${detail.width}x${detail.height}`
178   ) as ImageSizeVO
179   await handleSizeClick(imageSize)
180 }
181
182 /** 暴露组件方法 */
183 defineExpose({ settingValues })
184 </script>
185 <style scoped lang="scss">
186 // 提示词
187 .prompt {
188 }
189
190 // 热词
191 .hot-words {
192   display: flex;
193   flex-direction: column;
194   margin-top: 30px;
195
196   .word-list {
197     display: flex;
198     flex-direction: row;
199     flex-wrap: wrap;
200     justify-content: start;
201     margin-top: 15px;
202
203     .btn {
204       margin: 0;
205     }
206   }
207 }
208
209 // 模型
210 .model {
211   margin-top: 30px;
212
213   .model-list {
214     margin-top: 15px;
215
216     .modal-item {
217       width: 110px;
218       //outline: 1px solid blue;
219       overflow: hidden;
220       display: flex;
221       flex-direction: column;
222       align-items: center;
223       border: 3px solid transparent;
224       cursor: pointer;
225
226       .model-font {
227         font-size: 14px;
228         color: #3e3e3e;
229         font-weight: bold;
230       }
231     }
232
233     .selectModel {
234       border: 3px solid #1293ff;
235       border-radius: 5px;
236     }
237   }
238 }
239
240 // 样式 style
241 .image-style {
242   margin-top: 30px;
243
244   .image-style-list {
245     margin-top: 15px;
246
247     .image-style-item {
248       width: 110px;
249       //outline: 1px solid blue;
250       overflow: hidden;
251       display: flex;
252       flex-direction: column;
253       align-items: center;
254       border: 3px solid transparent;
255       cursor: pointer;
256
257       .style-font {
258         font-size: 14px;
259         color: #3e3e3e;
260         font-weight: bold;
261       }
262     }
263
264     .selectImageStyle {
265       border: 3px solid #1293ff;
266       border-radius: 5px;
267     }
268   }
269 }
270
271 // 尺寸
272 .image-size {
273   width: 100%;
274   margin-top: 30px;
275
276   .size-list {
277     display: flex;
278     flex-direction: row;
279     justify-content: space-between;
280     width: 100%;
281     margin-top: 20px;
282
283     .size-item {
284       display: flex;
285       flex-direction: column;
286       align-items: center;
287       cursor: pointer;
288
289       .size-wrapper {
290         display: flex;
291         flex-direction: column;
292         align-items: center;
293         justify-content: center;
294         border-radius: 7px;
295         padding: 4px;
296         width: 50px;
297         height: 50px;
298         background-color: #fff;
299         border: 1px solid #fff;
300       }
301
302       .size-font {
303         font-size: 14px;
304         color: #3e3e3e;
305         font-weight: bold;
306       }
307     }
308   }
309
310   .selectImageSize {
311     border: 1px solid #1293ff !important;
312   }
313 }
314
315 .btns {
316   display: flex;
317   justify-content: center;
318   margin-top: 50px;
319 }
320 </style>