Skip to content

Commit 33366ef

Browse files
committed
【增加】StableDiffusion
1 parent 918f35f commit 33366ef

File tree

2 files changed

+301
-2
lines changed

2 files changed

+301
-2
lines changed

src/views/ai/image/index.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@on-draw-start="handlerDrawStart"
1212
@on-draw-complete="handlerDrawComplete" />
1313
<Midjourney v-if="selectModel === 'MJ绘画'" />
14+
<StableDiffusion v-if="selectModel === 'Stable Diffusion'" />
1415
</div>
1516
</div>
1617
<div class="main">
@@ -23,14 +24,15 @@
2324
// TODO @fan:在整个挪到 /views/ai/image/index 目录。因为我想在 /views/ai/image/manager 做管理的功能,进行下区分!
2425
import Dall3 from './dall3/index.vue'
2526
import Midjourney from './midjourney/index.vue'
27+
import StableDiffusion from './stable-diffusion/index.vue'
2628
import ImageTask from './ImageTask.vue'
2729
2830
// ref
2931
const imageTaskRef = ref<any>() // image task ref
3032
3133
// 定义属性
32-
const selectModel = ref('DALL3绘画')
33-
const modelOptions = ['DALL3绘画', 'MJ绘画']
34+
const selectModel = ref('Stable Diffusion')
35+
const modelOptions = ['DALL3绘画', 'MJ绘画', 'Stable Diffusion']
3436
const drawIn = ref<boolean>(false) // 生成中
3537
3638
/** 绘画 - start */
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
<!-- dall3 -->
2+
<template>
3+
<div class="prompt">
4+
<el-text tag="b">画面描述</el-text>
5+
<el-text tag="p">建议使用“形容词+动词+风格”的格式,使用“,”隔开</el-text>
6+
<!-- TODO @fan:style 看看能不能哟 unocss 替代 -->
7+
<el-input
8+
v-model="prompt"
9+
maxlength="1024"
10+
rows="5"
11+
style="width: 100%; margin-top: 15px;"
12+
input-style="border-radius: 7px;"
13+
placeholder="例如:童话里的小屋应该是什么样子?"
14+
show-word-limit
15+
type="textarea"
16+
/>
17+
</div>
18+
<div class="hot-words">
19+
<div>
20+
<el-text tag="b">随机热词</el-text>
21+
</div>
22+
<el-space wrap class="word-list">
23+
<el-button round
24+
class="btn"
25+
:type="(selectHotWord === hotWord ? 'primary' : 'default')"
26+
v-for="hotWord in hotWords"
27+
:key="hotWord"
28+
@click="handlerHotWordClick(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
40+
v-model="selectSampler"
41+
placeholder="Select"
42+
size="large"
43+
style="width: 350px;"
44+
>
45+
<el-option
46+
v-for="item in sampler"
47+
:key="item.key"
48+
:label="item.name"
49+
:value="item.key"
50+
/>
51+
</el-select>
52+
</el-space>
53+
</div>
54+
55+
<div class="group-item">
56+
<div>
57+
<el-text tag="b">图片尺寸</el-text>
58+
</div>
59+
<el-space wrap class="group-item-body">
60+
<el-select
61+
v-model="selectImageSize"
62+
placeholder="Select"
63+
size="large"
64+
style="width: 350px;"
65+
>
66+
<el-option
67+
v-for="item in imageSizeList"
68+
:key="item.key"
69+
:label="item.key"
70+
:value="item.key"
71+
/>
72+
</el-select>
73+
</el-space>
74+
</div>
75+
<div class="group-item">
76+
<div>
77+
<el-text tag="b">迭代步数</el-text>
78+
</div>
79+
<el-space wrap class="group-item-body">
80+
<el-input v-model="steps" type="number" size="large" style="width: 350px" placeholder="Please input" />
81+
</el-space>
82+
</div>
83+
<div class="group-item">
84+
<div>
85+
<el-text tag="b">随机性</el-text>
86+
</div>
87+
<el-space wrap class="group-item-body">
88+
<el-input v-model="seed" type="number" size="large" style="width: 350px" placeholder="Please input" />
89+
</el-space>
90+
</div>
91+
<div class="btns">
92+
<el-button type="primary"
93+
size="large"
94+
round
95+
:loading="drawIn"
96+
@click="handlerGenerateImage">
97+
{{drawIn ? '生成中' : '生成内容'}}
98+
</el-button>
99+
</div>
100+
</template>
101+
<script setup lang="ts">
102+
import {ImageApi, ImageDrawReqVO} from '@/api/ai/image';
103+
104+
// image 模型
105+
interface ImageModelVO {
106+
key: string
107+
name: string
108+
}
109+
110+
// image 大小
111+
interface ImageSizeVO {
112+
key: string
113+
width: string,
114+
height: string,
115+
}
116+
117+
// 定义属性
118+
const prompt = ref<string>('') // 提示词
119+
const drawIn = ref<boolean>(false) // 生成中
120+
const selectHotWord = ref<string>('') // 选中的热词
121+
const hotWords = ref<string[]>(['中国旗袍', '古装美女', '卡通头像', '机甲战士', '童话小屋', '中国长城']) // 热词
122+
const selectSampler = ref<any>({}) // 模型
123+
// message
124+
const message = useMessage()
125+
// 模型
126+
const sampler = ref<ImageModelVO[]>([
127+
{
128+
key: 'Euler a',
129+
name: 'Euler a',
130+
},
131+
{
132+
key: 'DPM++ 2S a Karras',
133+
name: 'DPM++ 2S a Karras',
134+
},
135+
{
136+
key: 'DPM++ 2M Karras',
137+
name: 'DPM++ 2M Karras',
138+
},
139+
{
140+
key: 'DPM++ SDE Karras',
141+
name: 'DPM++ SDE Karras',
142+
},
143+
{
144+
key: 'DPM++ 2M SDE Karras',
145+
name: 'DPM++ 2M SDE Karras',
146+
},
147+
]) // 模型
148+
selectSampler.value = sampler.value[0]
149+
150+
151+
const selectImageSize = ref<ImageSizeVO>({} as ImageSizeVO) // 选中 size
152+
const imageSizeList = ref<ImageSizeVO[]>([
153+
{
154+
key: '512x512',
155+
width: '512',
156+
height: '512',
157+
},
158+
{
159+
key: '1024x1024',
160+
width: '1024',
161+
height: '1024',
162+
},
163+
{
164+
key: '1024x1792',
165+
width: '1024',
166+
height: '1792',
167+
},
168+
{
169+
key: '1792x1024',
170+
width: '1792',
171+
height: '1024',
172+
},
173+
{
174+
key: '2048x2048',
175+
width: '2048',
176+
height: '2048',
177+
},
178+
{
179+
key: '720x1280',
180+
width: '720',
181+
height: '1280',
182+
},
183+
{
184+
key: '1080x1920',
185+
width: '1080',
186+
height: '1920',
187+
},
188+
{
189+
key: '1440x2560',
190+
width: '1440',
191+
height: '2560',
192+
},
193+
{
194+
key: '2160x3840',
195+
width: '2160',
196+
height: '3840',
197+
},
198+
]) // size
199+
selectImageSize.value = imageSizeList.value[0]
200+
201+
const steps = ref<number>(20) // 迭代步数
202+
const seed = ref<number>(-1) // 控制生成图像的随机性
203+
204+
// 定义 Props
205+
const props = defineProps({})
206+
// 定义 emits
207+
const emits = defineEmits(['onDrawStart', 'onDrawComplete'])
208+
209+
// TODO @fan:如果是简单注释,建议用 /** */,主要是现在项目里是这种风格哈,保持一致好点~
210+
// TODO @fan:handler 应该改成 handle 哈
211+
/** 热词 - click */
212+
const handlerHotWordClick = async (hotWord: string) => {
213+
// 取消选中
214+
if (selectHotWord.value == hotWord) {
215+
selectHotWord.value = ''
216+
return
217+
}
218+
// 选中
219+
selectHotWord.value = hotWord
220+
// 替换提示词
221+
prompt.value = hotWord
222+
}
223+
224+
/** 图片生产 */
225+
const handlerGenerateImage = async () => {
226+
// 二次确认
227+
await message.confirm(`确认生成内容?`)
228+
try {
229+
// 加载中
230+
drawIn.value = true
231+
// 回调
232+
emits('onDrawStart', 'StableDiffusion')
233+
const form = {
234+
platform: 'StableDiffusion',
235+
model: 'stable-diffusion-v1-6',
236+
prompt: prompt.value, // 提示词
237+
width: selectImageSize.value.width, // 图片宽度
238+
height: selectImageSize.value.height, // 图片高度
239+
options: {
240+
sampler: selectSampler.value.key, // 采样算法
241+
seed: seed.value, // 随机种子
242+
steps: steps.value, // 图片生成步数
243+
},
244+
} as ImageDrawReqVO
245+
// 发送请求
246+
await ImageApi.drawImage(form)
247+
} finally {
248+
// 回调
249+
emits('onDrawComplete', 'StableDiffusion')
250+
// 加载结束
251+
drawIn.value = false
252+
}
253+
}
254+
255+
</script>
256+
<style scoped lang="scss">
257+
258+
// 提示词
259+
.prompt {
260+
}
261+
262+
// 热词
263+
.hot-words {
264+
display: flex;
265+
flex-direction: column;
266+
margin-top: 30px;
267+
268+
.word-list {
269+
display: flex;
270+
flex-direction: row;
271+
flex-wrap: wrap;
272+
justify-content: start;
273+
margin-top: 15px;
274+
275+
.btn {
276+
margin: 0;
277+
}
278+
}
279+
}
280+
281+
// 模型
282+
.group-item {
283+
margin-top: 30px;
284+
285+
.group-item-body {
286+
margin-top: 15px;
287+
width: 100%;
288+
}
289+
}
290+
291+
292+
.btns {
293+
display: flex;
294+
justify-content: center;
295+
margin-top: 50px;
296+
}
297+
</style>

0 commit comments

Comments
 (0)