index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <!-- dall3 -->
  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. const message = useMessage() // 消息弹窗
  147. // 定义属性
  148. const drawIn = ref<boolean>(false) // 生成中
  149. const selectHotWord = ref<string>('') // 选中的热词
  150. // 表单
  151. const prompt = ref<string>('') // 提示词
  152. const width = ref<number>(512) // 图片宽度
  153. const height = ref<number>(512) // 图片高度
  154. const sampler = ref<string>('DDIM') // 采样方法
  155. const steps = ref<number>(20) // 迭代步数
  156. const seed = ref<number>(42) // 控制生成图像的随机性
  157. const scale = ref<number>(7.5) // 引导系数
  158. const clipGuidancePreset = ref<string>('NONE') // 文本提示相匹配的图像(clip_guidance_preset) 简称 CLIP
  159. const stylePreset = ref<string>('3d-model') // 风格
  160. const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
  161. /** 选择热词 */
  162. const handleHotWordClick = async (hotWord: string) => {
  163. // 情况一:取消选中
  164. if (selectHotWord.value == hotWord) {
  165. selectHotWord.value = ''
  166. return
  167. }
  168. // 情况二:选中
  169. selectHotWord.value = hotWord // 选中
  170. prompt.value = hotWord // 替换提示词
  171. }
  172. /** 图片生成 */
  173. const handleGenerateImage = async () => {
  174. // 二次确认
  175. if (hasChinese(prompt.value)) {
  176. message.alert('暂不支持中文!')
  177. return
  178. }
  179. await message.confirm(`确认生成内容?`)
  180. try {
  181. // 加载中
  182. drawIn.value = true
  183. // 回调
  184. emits('onDrawStart', AiPlatformEnum.STABLE_DIFFUSION)
  185. // 发送请求
  186. const form = {
  187. platform: AiPlatformEnum.STABLE_DIFFUSION,
  188. model: 'stable-diffusion-v1-6',
  189. prompt: prompt.value, // 提示词
  190. width: width.value, // 图片宽度
  191. height: height.value, // 图片高度
  192. options: {
  193. seed: seed.value, // 随机种子
  194. steps: steps.value, // 图片生成步数
  195. scale: scale.value, // 引导系数
  196. sampler: sampler.value, // 采样算法
  197. clipGuidancePreset: clipGuidancePreset.value, // 文本提示相匹配的图像 CLIP
  198. stylePreset: stylePreset.value // 风格
  199. }
  200. } as ImageDrawReqVO
  201. await ImageApi.drawImage(form)
  202. } finally {
  203. // 回调
  204. emits('onDrawComplete', AiPlatformEnum.STABLE_DIFFUSION)
  205. // 加载结束
  206. drawIn.value = false
  207. }
  208. }
  209. /** 填充值 */
  210. const settingValues = async (detail: ImageVO) => {
  211. prompt.value = detail.prompt
  212. width.value = detail.width
  213. height.value = detail.height
  214. seed.value = detail.options?.seed
  215. steps.value = detail.options?.steps
  216. scale.value = detail.options?.scale
  217. sampler.value = detail.options?.sampler
  218. clipGuidancePreset.value = detail.options?.clipGuidancePreset
  219. stylePreset.value = detail.options?.stylePreset
  220. }
  221. /** 暴露组件方法 */
  222. defineExpose({ settingValues })
  223. </script>
  224. <style scoped lang="scss">
  225. // 提示词
  226. .prompt {
  227. }
  228. // 热词
  229. .hot-words {
  230. display: flex;
  231. flex-direction: column;
  232. margin-top: 30px;
  233. .word-list {
  234. display: flex;
  235. flex-direction: row;
  236. flex-wrap: wrap;
  237. justify-content: start;
  238. margin-top: 15px;
  239. .btn {
  240. margin: 0;
  241. }
  242. }
  243. }
  244. // 模型
  245. .group-item {
  246. margin-top: 30px;
  247. .group-item-body {
  248. margin-top: 15px;
  249. width: 100%;
  250. }
  251. }
  252. .btns {
  253. display: flex;
  254. justify-content: center;
  255. margin-top: 50px;
  256. }
  257. </style>