feat(ai): 新增 AI 绘图功能
- 添加 AI 绘图相关的 API 接口和路由 - 实现 AI 绘图页面,支持不同平台的绘图功能 - 添加绘图作品列表和重新生成功能 - 优化绘图页面样式和布局
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
<!-- dall3 -->
|
||||
<script setup lang="ts">
|
||||
import type { AiImageApi } from '#/api/ai/image';
|
||||
import type { AiModelModelApi } from '#/api/ai/model/model';
|
||||
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { confirm } from '@vben/common-ui';
|
||||
|
||||
import { Button, InputNumber, Select, Space, Textarea } from 'ant-design-vue';
|
||||
|
||||
import { drawImage } from '#/api/ai/image';
|
||||
import {
|
||||
AiPlatformEnum,
|
||||
ImageHotWords,
|
||||
OtherPlatformEnum,
|
||||
} from '#/utils/constants';
|
||||
|
||||
// 消息弹窗
|
||||
|
||||
// 接收父组件传入的模型列表
|
||||
const props = defineProps({
|
||||
models: {
|
||||
type: Array<AiModelModelApi.ModelVO>,
|
||||
default: () => [] as AiModelModelApi.ModelVO[],
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(['onDrawStart', 'onDrawComplete']);
|
||||
|
||||
// 定义属性
|
||||
const drawIn = ref<boolean>(false); // 生成中
|
||||
const selectHotWord = ref<string>(''); // 选中的热词
|
||||
// 表单
|
||||
const prompt = ref<string>(''); // 提示词
|
||||
const width = ref<number>(512); // 图片宽度
|
||||
const height = ref<number>(512); // 图片高度
|
||||
const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI); // 平台
|
||||
const platformModels = ref<AiModelModelApi.ModelVO[]>([]); // 模型列表
|
||||
const modelId = ref<number>(); // 选中的模型
|
||||
|
||||
/** 选择热词 */
|
||||
const handleHotWordClick = async (hotWord: string) => {
|
||||
// 情况一:取消选中
|
||||
if (selectHotWord.value === hotWord) {
|
||||
selectHotWord.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 情况二:选中
|
||||
selectHotWord.value = hotWord; // 选中
|
||||
prompt.value = hotWord; // 替换提示词
|
||||
};
|
||||
|
||||
/** 图片生成 */
|
||||
const handleGenerateImage = async () => {
|
||||
// 二次确认
|
||||
await confirm(`确认生成内容?`);
|
||||
try {
|
||||
// 加载中
|
||||
drawIn.value = true;
|
||||
// 回调
|
||||
emits('onDrawStart', otherPlatform.value);
|
||||
// 发送请求
|
||||
const form = {
|
||||
platform: otherPlatform.value,
|
||||
modelId: modelId.value, // 模型
|
||||
prompt: prompt.value, // 提示词
|
||||
width: width.value, // 图片宽度
|
||||
height: height.value, // 图片高度
|
||||
options: {},
|
||||
} as unknown as AiImageApi.ImageDrawReqVO;
|
||||
await drawImage(form);
|
||||
} finally {
|
||||
// 回调
|
||||
emits('onDrawComplete', otherPlatform.value);
|
||||
// 加载结束
|
||||
drawIn.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 填充值 */
|
||||
const settingValues = async (detail: AiImageApi.ImageVO) => {
|
||||
prompt.value = detail.prompt;
|
||||
width.value = detail.width;
|
||||
height.value = detail.height;
|
||||
};
|
||||
|
||||
/** 平台切换 */
|
||||
const handlerPlatformChange = async (platform: any) => {
|
||||
// 根据选择的平台筛选模型
|
||||
platformModels.value = props.models.filter(
|
||||
(item: AiModelModelApi.ModelVO) => item.platform === platform,
|
||||
);
|
||||
modelId.value =
|
||||
platformModels.value.length > 0 && platformModels.value[0]
|
||||
? platformModels.value[0].id
|
||||
: undefined;
|
||||
// 切换平台,默认选择一个模型
|
||||
};
|
||||
|
||||
/** 监听 models 变化 */
|
||||
watch(
|
||||
() => props.models,
|
||||
() => {
|
||||
handlerPlatformChange(otherPlatform.value);
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
/** 暴露组件方法 */
|
||||
defineExpose({ settingValues });
|
||||
</script>
|
||||
<template>
|
||||
<div class="prompt">
|
||||
<b>画面描述</b>
|
||||
<p>建议使用“形容词 + 动词 + 风格”的格式,使用“,”隔开</p>
|
||||
<Textarea
|
||||
v-model:value="prompt"
|
||||
:maxlength="1024"
|
||||
:rows="5"
|
||||
class="w-100% mt-[15px]"
|
||||
placeholder="例如:童话里的小屋应该是什么样子?"
|
||||
show-count
|
||||
/>
|
||||
</div>
|
||||
<div class="hot-words">
|
||||
<div>
|
||||
<b>随机热词</b>
|
||||
</div>
|
||||
<Space wrap class="word-list">
|
||||
<Button
|
||||
shape="round"
|
||||
class="btn"
|
||||
:type="selectHotWord === hotWord ? 'primary' : 'default'"
|
||||
v-for="hotWord in ImageHotWords"
|
||||
:key="hotWord"
|
||||
@click="handleHotWordClick(hotWord)"
|
||||
>
|
||||
{{ hotWord }}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="group-item">
|
||||
<div>
|
||||
<b>平台</b>
|
||||
</div>
|
||||
<Space wrap class="group-item-body">
|
||||
<Select
|
||||
v-model:value="otherPlatform"
|
||||
placeholder="Select"
|
||||
size="large"
|
||||
class="!w-[330px]"
|
||||
@change="handlerPlatformChange"
|
||||
>
|
||||
<Select.Option
|
||||
v-for="item in OtherPlatformEnum"
|
||||
:key="item.key"
|
||||
:value="item.key"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="group-item">
|
||||
<div>
|
||||
<b>模型</b>
|
||||
</div>
|
||||
<Space wrap class="group-item-body">
|
||||
<Select
|
||||
v-model:value="modelId"
|
||||
placeholder="Select"
|
||||
size="large"
|
||||
class="!w-[330px]"
|
||||
>
|
||||
<Select.Option
|
||||
v-for="item in platformModels"
|
||||
:key="item.id"
|
||||
:value="item.id"
|
||||
>
|
||||
{{ item.name }}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="group-item">
|
||||
<div>
|
||||
<b>图片尺寸</b>
|
||||
</div>
|
||||
<Space wrap class="group-item-body">
|
||||
<InputNumber
|
||||
v-model:value="width"
|
||||
class="mt-[10px] w-[170px]"
|
||||
placeholder="图片宽度"
|
||||
/>
|
||||
<InputNumber
|
||||
v-model:value="height"
|
||||
class="w-[170px]"
|
||||
placeholder="图片高度"
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
shape="round"
|
||||
:loading="drawIn"
|
||||
:disabled="prompt.length === 0"
|
||||
@click="handleGenerateImage"
|
||||
>
|
||||
{{ drawIn ? '生成中' : '生成内容' }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.hot-words {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 30px;
|
||||
|
||||
.word-list {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: start;
|
||||
margin-top: 15px;
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模型
|
||||
.group-item {
|
||||
margin-top: 30px;
|
||||
|
||||
.group-item-body {
|
||||
width: 100%;
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user