index.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. style="width: 100%; margin-top: 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 round
  23. class="btn"
  24. :type="(selectHotWord === hotWord ? 'primary' : 'default')"
  25. v-for="hotWord in hotWords"
  26. :key="hotWord"
  27. @click="handlerHotWordClick(hotWord)"
  28. >
  29. {{ hotWord }}
  30. </el-button>
  31. </el-space>
  32. </div>
  33. <div class="image-size">
  34. <div>
  35. <el-text tag="b">尺寸</el-text>
  36. </div>
  37. <el-space wrap class="size-list">
  38. <div class="size-item"
  39. v-for="imageSize in imageSizeList"
  40. :key="imageSize.key"
  41. @click="handlerSizeClick(imageSize)">
  42. <div :class="selectImageSize === imageSize ? 'size-wrapper selectImageSize' : 'size-wrapper'">
  43. <div :style="imageSize.style"></div>
  44. </div>
  45. <div class="size-font">{{ imageSize.key }}</div>
  46. </div>
  47. </el-space>
  48. </div>
  49. <div class="version">
  50. <div>
  51. <el-text tag="b">版本</el-text>
  52. </div>
  53. <el-space wrap class="version-list">
  54. <el-select
  55. v-model="selectVersion"
  56. class="version-select"
  57. clearable
  58. placeholder="请选择版本"
  59. style="width: 350px"
  60. @change="handlerChangeVersion"
  61. >
  62. <el-option
  63. v-for="item in versionList"
  64. :key="item.value"
  65. :label="item.label"
  66. :value="item.value"
  67. />
  68. </el-select>
  69. </el-space>
  70. </div>
  71. <div class="model">
  72. <div>
  73. <el-text tag="b">模型</el-text>
  74. </div>
  75. <el-space wrap class="model-list">
  76. <div
  77. :class="selectModel === model ? 'modal-item selectModel' : 'modal-item'"
  78. v-for="model in models"
  79. :key="model.key"
  80. >
  81. <el-image
  82. :src="model.image"
  83. fit="contain"
  84. @click="handlerModelClick(model)"
  85. />
  86. <div class="model-font">{{model.name}}</div>
  87. </div>
  88. </el-space>
  89. </div>
  90. <div class="btns">
  91. <!-- <el-button size="large" round>重置内容</el-button>-->
  92. <el-button type="primary" size="large" round @click="handlerGenerateImage">生成内容</el-button>
  93. </div>
  94. </template>
  95. <script setup lang="ts">
  96. // image 模型
  97. import {ImageApi, ImageMidjourneyImagineReqVO} from "@/api/ai/image";
  98. // 定义 emits
  99. const emits = defineEmits(['onDrawStart', 'onDrawComplete'])
  100. interface ImageModelVO {
  101. key: string
  102. name: string
  103. image: string
  104. }
  105. // image 大小
  106. interface ImageSizeVO {
  107. key: string
  108. style: string,
  109. width: string,
  110. height: string,
  111. }
  112. // 定义属性
  113. const prompt = ref<string>('') // 提示词
  114. const selectHotWord = ref<string>('') // 选中的热词
  115. const hotWords = ref<string[]>(['中国旗袍', '古装美女', '卡通头像', '机甲战士', '童话小屋', '中国长城']) // 热词
  116. const selectModel = ref<any>() // 选中的热词
  117. const models = ref<ImageModelVO[]>([
  118. {
  119. key: 'midjourney',
  120. name: 'MJ',
  121. image: 'https://bigpt8.com/pc/_nuxt/mj.34a61377.png',
  122. },
  123. {
  124. key: 'niji',
  125. name: 'NIJI',
  126. image: 'https://bigpt8.com/pc/_nuxt/nj.ca79b143.png',
  127. },
  128. ]) // 模型
  129. selectModel.value = models.value[0] // 默认选中
  130. const selectImageSize = ref<ImageSizeVO>({} as ImageSizeVO) // 选中 size
  131. const imageSizeList = ref<ImageSizeVO[]>([
  132. {
  133. key: '1:1',
  134. width: "1",
  135. height: "1",
  136. style: 'width: 30px; height: 30px;background-color: #dcdcdc;',
  137. },
  138. {
  139. key: '3:4',
  140. width: "3",
  141. height: "4",
  142. style: 'width: 30px; height: 40px;background-color: #dcdcdc;',
  143. },
  144. {
  145. key: '4:3',
  146. width: "4",
  147. height: "3",
  148. style: 'width: 40px; height: 30px;background-color: #dcdcdc;',
  149. },
  150. {
  151. key: '9:16',
  152. width: "9",
  153. height: "16",
  154. style: 'width: 30px; height: 50px;background-color: #dcdcdc;',
  155. },
  156. {
  157. key: '16:9',
  158. width: "16",
  159. height: "9",
  160. style: 'width: 50px; height: 30px;background-color: #dcdcdc;',
  161. },
  162. ]) // size
  163. selectImageSize.value = imageSizeList.value[0]
  164. // version
  165. const versionList = ref<any>([
  166. {
  167. value: '6.0',
  168. label: 'v6.0',
  169. },
  170. {
  171. value: '5.2',
  172. label: 'v5.2',
  173. },
  174. {
  175. value: '5.1',
  176. label: 'v5.1',
  177. },
  178. {
  179. value: '5.0',
  180. label: 'v5.0',
  181. },
  182. {
  183. value: '4.0',
  184. label: 'v4.0',
  185. },
  186. ]) // version 列表
  187. const selectVersion = ref<any>('6.0') // 选中的 version
  188. // 定义 Props
  189. const props = defineProps({})
  190. /**
  191. * 热词 - click
  192. */
  193. const handlerHotWordClick = async (hotWord: string) => {
  194. // 取消
  195. if (selectHotWord.value == hotWord) {
  196. selectHotWord.value = ''
  197. return
  198. }
  199. // 选中
  200. selectHotWord.value = hotWord
  201. // 设置提示次
  202. prompt.value = hotWord
  203. }
  204. /**
  205. * size - click
  206. */
  207. const handlerSizeClick = async (imageSize: ImageSizeVO) => {
  208. if (selectImageSize.value === imageSize) {
  209. selectImageSize.value = {} as ImageSizeVO
  210. return
  211. }
  212. selectImageSize.value = imageSize
  213. }
  214. /**
  215. * 模型 - click
  216. */
  217. const handlerModelClick = async (model: ImageModelVO) => {
  218. selectModel.value = model
  219. }
  220. /**
  221. * version - click
  222. */
  223. const handlerChangeVersion = async (version) => {
  224. console.log('version', version)
  225. }
  226. /**
  227. * 图片生产
  228. */
  229. const handlerGenerateImage = async () => {
  230. // todo @范 图片生产逻辑
  231. try {
  232. // 回调
  233. emits('onDrawStart', selectModel.value.key)
  234. // 发送请求
  235. const req = {
  236. prompt: prompt.value,
  237. model: selectModel.value.key,
  238. width: selectImageSize.value.width,
  239. height: selectImageSize.value.height,
  240. version: selectVersion.value,
  241. base64Array: [],
  242. } as ImageMidjourneyImagineReqVO
  243. await ImageApi.midjourneyImagine(req)
  244. } finally {
  245. // 回调
  246. emits('onDrawComplete', selectModel.value.key)
  247. }
  248. }
  249. </script>
  250. <style scoped lang="scss">
  251. // 提示词
  252. .prompt {
  253. }
  254. // 热词
  255. .hot-words {
  256. display: flex;
  257. flex-direction: column;
  258. margin-top: 30px;
  259. .word-list {
  260. display: flex;
  261. flex-direction: row;
  262. flex-wrap: wrap;
  263. justify-content: start;
  264. margin-top: 15px;
  265. .btn {
  266. margin: 0;
  267. }
  268. }
  269. }
  270. // version
  271. .version {
  272. margin-top: 20px;
  273. .version-list {
  274. margin-top: 20px;
  275. width: 100%;
  276. }
  277. }
  278. // 模型
  279. .model {
  280. margin-top: 30px;
  281. .model-list {
  282. margin-top: 15px;
  283. .modal-item {
  284. display: flex;
  285. flex-direction: column;
  286. align-items: center;
  287. width: 150px;
  288. //outline: 1px solid blue;
  289. overflow: hidden;
  290. border: 3px solid transparent;
  291. cursor: pointer;
  292. .model-font {
  293. font-size: 14px;
  294. color: #3e3e3e;
  295. font-weight: bold;
  296. }
  297. }
  298. .selectModel {
  299. border: 3px solid #1293ff;
  300. border-radius: 5px;
  301. }
  302. }
  303. }
  304. // 尺寸
  305. .image-size {
  306. width: 100%;
  307. margin-top: 30px;
  308. .size-list {
  309. display: flex;
  310. flex-direction: row;
  311. justify-content: space-between;
  312. width: 100%;
  313. margin-top: 20px;
  314. .size-item {
  315. display: flex;
  316. flex-direction: column;
  317. align-items: center;
  318. cursor: pointer;
  319. .size-wrapper {
  320. display: flex;
  321. flex-direction: column;
  322. align-items: center;
  323. justify-content: center;
  324. border-radius: 7px;
  325. padding: 4px;
  326. width: 50px;
  327. height: 50px;
  328. background-color: #fff;
  329. border: 1px solid #fff;
  330. }
  331. .size-font {
  332. font-size: 14px;
  333. color: #3e3e3e;
  334. font-weight: bold;
  335. }
  336. }
  337. }
  338. .selectImageSize {
  339. border: 1px solid #1293ff !important;
  340. }
  341. }
  342. .btns {
  343. display: flex;
  344. justify-content: center;
  345. margin-top: 50px;
  346. }
  347. </style>