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 ImageHotEnglishWords"
27         :key="hotWord"
28         @click="handleHotWordClick(hotWord)"
29       >
30         {{ hotWord }}
31       </el-button>
32     </el-space>
33   </div>
34   <div class="group-item">
35     <div>
36       <el-text tag="b">采样方法</el-text>
37     </div>
38     <el-space wrap class="group-item-body">
39       <el-select v-model="sampler" placeholder="Select" size="large" class="!w-350px">
40         <el-option
41           v-for="item in StableDiffusionSamplers"
42           :key="item.key"
43           :label="item.name"
44           :value="item.key"
45         />
46       </el-select>
47     </el-space>
48   </div>
49   <div class="group-item">
50     <div>
51       <el-text tag="b">CLIP</el-text>
52     </div>
53     <el-space wrap class="group-item-body">
54       <el-select v-model="clipGuidancePreset" placeholder="Select" size="large" class="!w-350px">
55         <el-option
56           v-for="item in StableDiffusionClipGuidancePresets"
57           :key="item.key"
58           :label="item.name"
59           :value="item.key"
60         />
61       </el-select>
62     </el-space>
63   </div>
64   <div class="group-item">
65     <div>
66       <el-text tag="b">风格</el-text>
67     </div>
68     <el-space wrap class="group-item-body">
69       <el-select v-model="stylePreset" placeholder="Select" size="large" class="!w-350px">
70         <el-option
71           v-for="item in StableDiffusionStylePresets"
72           :key="item.key"
73           :label="item.name"
74           :value="item.key"
75         />
76       </el-select>
77     </el-space>
78   </div>
79   <div class="group-item">
80     <div>
81       <el-text tag="b">图片尺寸</el-text>
82     </div>
83     <el-space wrap class="group-item-body">
84       <el-input v-model="width" class="w-170px" placeholder="图片宽度" />
85       <el-input v-model="height" class="w-170px" placeholder="图片高度" />
86     </el-space>
87   </div>
88   <div class="group-item">
89     <div>
90       <el-text tag="b">迭代步数</el-text>
91     </div>
92     <el-space wrap class="group-item-body">
93       <el-input
94         v-model="steps"
95         type="number"
96         size="large"
97         class="!w-350px"
98         placeholder="Please input"
99       />
100     </el-space>
101   </div>
102   <div class="group-item">
103     <div>
104       <el-text tag="b">引导系数</el-text>
105     </div>
106     <el-space wrap class="group-item-body">
107       <el-input
108         v-model="scale"
109         type="number"
110         size="large"
111         class="!w-350px"
112         placeholder="Please input"
113       />
114     </el-space>
115   </div>
116   <div class="group-item">
117     <div>
118       <el-text tag="b">随机因子</el-text>
119     </div>
120     <el-space wrap class="group-item-body">
121       <el-input
122         v-model="seed"
123         type="number"
124         size="large"
125         class="!w-350px"
126         placeholder="Please input"
127       />
128     </el-space>
129   </div>
130   <div class="btns">
131     <el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage">
132       {{ drawIn ? '生成中' : '生成内容' }}
133     </el-button>
134   </div>
135 </template>
136 <script setup lang="ts">
137 import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
138 import { hasChinese } from '@/views/ai/utils/utils'
139 import {
140   AiPlatformEnum,
141   ImageHotEnglishWords,
142   StableDiffusionClipGuidancePresets,
143   StableDiffusionSamplers,
144   StableDiffusionStylePresets
145 } from '@/views/ai/utils/constants'
146
147 const message = useMessage() // 消息弹窗
148
149 // 定义属性
150 const drawIn = ref<boolean>(false) // 生成中
151 const selectHotWord = ref<string>('') // 选中的热词
152 // 表单
153 const prompt = ref<string>('') // 提示词
154 const width = ref<number>(512) // 图片宽度
155 const height = ref<number>(512) // 图片高度
156 const sampler = ref<string>('DDIM') // 采样方法
157 const steps = ref<number>(20) // 迭代步数
158 const seed = ref<number>(42) // 控制生成图像的随机性
159 const scale = ref<number>(7.5) // 引导系数
160 const clipGuidancePreset = ref<string>('NONE') // 文本提示相匹配的图像(clip_guidance_preset) 简称 CLIP
161 const stylePreset = ref<string>('3d-model') // 风格
162
163 const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
164
165 /** 选择热词 */
166 const handleHotWordClick = async (hotWord: string) => {
167   // 情况一:取消选中
168   if (selectHotWord.value == hotWord) {
169     selectHotWord.value = ''
170     return
171   }
172
173   // 情况二:选中
174   selectHotWord.value = hotWord // 选中
175   prompt.value = hotWord // 替换提示词
176 }
177
178 /** 图片生成 */
179 const handleGenerateImage = async () => {
180   // 二次确认
181   if (hasChinese(prompt.value)) {
182     message.alert('暂不支持中文!')
183     return
184   }
185   await message.confirm(`确认生成内容?`)
186
187   try {
188     // 加载中
189     drawIn.value = true
190     // 回调
191     emits('onDrawStart', AiPlatformEnum.STABLE_DIFFUSION)
192     // 发送请求
193     const form = {
194       platform: AiPlatformEnum.STABLE_DIFFUSION,
195       model: 'stable-diffusion-v1-6',
196       prompt: prompt.value, // 提示词
197       width: width.value, // 图片宽度
198       height: height.value, // 图片高度
199       options: {
200         seed: seed.value, // 随机种子
201         steps: steps.value, // 图片生成步数
202         scale: scale.value, // 引导系数
203         sampler: sampler.value, // 采样算法
204         clipGuidancePreset: clipGuidancePreset.value, // 文本提示相匹配的图像 CLIP
205         stylePreset: stylePreset.value // 风格
206       }
207     } as ImageDrawReqVO
208     await ImageApi.drawImage(form)
209   } finally {
210     // 回调
211     emits('onDrawComplete', AiPlatformEnum.STABLE_DIFFUSION)
212     // 加载结束
213     drawIn.value = false
214   }
215 }
216
217 /** 填充值 */
218 const settingValues = async (detail: ImageVO) => {
219   prompt.value = detail.prompt
220   width.value = detail.width
221   height.value = detail.height
222   seed.value = detail.options?.seed
223   steps.value = detail.options?.steps
224   scale.value = detail.options?.scale
225   sampler.value = detail.options?.sampler
226   clipGuidancePreset.value = detail.options?.clipGuidancePreset
227   stylePreset.value = detail.options?.stylePreset
228 }
229
230 /** 暴露组件方法 */
231 defineExpose({ settingValues })
232 </script>
233 <style scoped lang="scss">
234 // 提示词
235 .prompt {
236 }
237
238 // 热词
239 .hot-words {
240   display: flex;
241   flex-direction: column;
242   margin-top: 30px;
243
244   .word-list {
245     display: flex;
246     flex-direction: row;
247     flex-wrap: wrap;
248     justify-content: start;
249     margin-top: 15px;
250
251     .btn {
252       margin: 0;
253     }
254   }
255 }
256
257 // 模型
258 .group-item {
259   margin-top: 30px;
260
261   .group-item-body {
262     margin-top: 15px;
263     width: 100%;
264   }
265 }
266
267 .btns {
268   display: flex;
269   justify-content: center;
270   margin-top: 50px;
271 }
272 </style>