【代码重构】AI:“聊天模型”重构为“模型”,支持 type 模型类型

This commit is contained in:
YunaiV 2025-03-03 21:26:24 +08:00
parent 0f4216f6f7
commit ae632ac23b
13 changed files with 276 additions and 184 deletions

View File

@ -20,9 +20,8 @@ export interface ImageVO {
} }
export interface ImageDrawReqVO { export interface ImageDrawReqVO {
platform: string // 平台
prompt: string // 提示词 prompt: string // 提示词
model: string // 模型 modelId: number // 模型
style: string // 图像生成的风格 style: string // 图像生成的风格
width: string // 图片宽度 width: string // 图片宽度
height: string // 图片高度 height: string // 图片高度
@ -31,7 +30,7 @@ export interface ImageDrawReqVO {
export interface ImageMidjourneyImagineReqVO { export interface ImageMidjourneyImagineReqVO {
prompt: string // 提示词 prompt: string // 提示词
model: string // 模型 mj nijj modelId: number // 模型
base64Array: string[] // size不能为空 base64Array: string[] // size不能为空
width: string // 图片宽度 width: string // 图片宽度
height: string // 图片高度 height: string // 图片高度

View File

@ -1,53 +0,0 @@
import request from '@/config/axios'
// AI 聊天模型 VO
export interface ChatModelVO {
id: number // 编号
keyId: number // API 秘钥编号
name: string // 模型名字
model: string // 模型标识
platform: string // 模型平台
sort: number // 排序
status: number // 状态
temperature: number // 温度参数
maxTokens: number // 单条回复的最大 Token 数量
maxContexts: number // 上下文的最大 Message 数量
}
// AI 聊天模型 API
export const ChatModelApi = {
// 查询聊天模型分页
getChatModelPage: async (params: any) => {
return await request.get({ url: `/ai/chat-model/page`, params })
},
// 获得聊天模型列表
getChatModelSimpleList: async (status?: number) => {
return await request.get({
url: `/ai/chat-model/simple-list`,
params: {
status
}
})
},
// 查询聊天模型详情
getChatModel: async (id: number) => {
return await request.get({ url: `/ai/chat-model/get?id=` + id })
},
// 新增聊天模型
createChatModel: async (data: ChatModelVO) => {
return await request.post({ url: `/ai/chat-model/create`, data })
},
// 修改聊天模型
updateChatModel: async (data: ChatModelVO) => {
return await request.put({ url: `/ai/chat-model/update`, data })
},
// 删除聊天模型
deleteChatModel: async (id: number) => {
return await request.delete({ url: `/ai/chat-model/delete?id=` + id })
}
}

View File

@ -0,0 +1,54 @@
import request from '@/config/axios'
// AI 聊天模型 VO
export interface ModelVO {
id: number // 编号
keyId: number // API 秘钥编号
name: string // 模型名字
model: string // 模型标识
platform: string // 模型平台
type: number // 模型类型
sort: number // 排序
status: number // 状态
temperature?: number // 温度参数
maxTokens?: number // 单条回复的最大 Token 数量
maxContexts?: number // 上下文的最大 Message 数量
}
// AI 模型 API
export const ModelApi = {
// 查询模型分页
getModelPage: async (params: any) => {
return await request.get({ url: `/ai/model/page`, params })
},
// 获得模型列表
getModelSimpleList: async (type?: number) => {
return await request.get({
url: `/ai/model/simple-list`,
params: {
type
}
})
},
// 查询模型详情
getModel: async (id: number) => {
return await request.get({ url: `/ai/model/get?id=` + id })
},
// 新增模型
createModel: async (data: ModelVO) => {
return await request.post({ url: `/ai/model/create`, data })
},
// 修改聊天模型
updateModel: async (data: ModelVO) => {
return await request.put({ url: `/ai/model/update`, data })
},
// 删除聊天模型
deleteModel: async (id: number) => {
return await request.delete({ url: `/ai/model/delete?id=` + id })
}
}

View File

@ -219,6 +219,7 @@ export enum DICT_TYPE {
// ========== AI - 人工智能模块 ========== // ========== AI - 人工智能模块 ==========
AI_PLATFORM = 'ai_platform', // AI 平台 AI_PLATFORM = 'ai_platform', // AI 平台
AI_MODEL_TYPE = 'ai_model_type', // AI 模型类型
AI_IMAGE_STATUS = 'ai_image_status', // AI 图片状态 AI_IMAGE_STATUS = 'ai_image_status', // AI 图片状态
AI_MUSIC_STATUS = 'ai_music_status', // AI 音乐状态 AI_MUSIC_STATUS = 'ai_music_status', // AI 音乐状态
AI_GENERATE_MODE = 'ai_generate_mode', // AI 生成模式 AI_GENERATE_MODE = 'ai_generate_mode', // AI 生成模式

View File

@ -58,9 +58,9 @@
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CommonStatusEnum } from '@/utils/constants' import { ModelApi, ModelVO } from '@/api/ai/model/model'
import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel'
import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation' import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation'
import { AiModelTypeEnum } from '@/views/ai/utils/constants'
/** AI 聊天对话的更新表单 */ /** AI 聊天对话的更新表单 */
defineOptions({ name: 'ChatConversationUpdateForm' }) defineOptions({ name: 'ChatConversationUpdateForm' })
@ -85,7 +85,7 @@ const formRules = reactive({
maxContexts: [{ required: true, message: '上下文数量不能为空', trigger: 'blur' }] maxContexts: [{ required: true, message: '上下文数量不能为空', trigger: 'blur' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
const chatModelList = ref([] as ChatModelVO[]) // const chatModelList = ref([] as ModelVO[]) //
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (id: number) => { const open = async (id: number) => {
@ -107,7 +107,7 @@ const open = async (id: number) => {
} }
} }
// //
chatModelList.value = await ChatModelApi.getChatModelSimpleList(CommonStatusEnum.ENABLE) chatModelList.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
} }
defineExpose({ open }) // open defineExpose({ open }) // open

View File

@ -41,9 +41,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ChatRoleVO} from '@/api/ai/model/chatRole' import { ChatRoleVO } from '@/api/ai/model/chatRole'
import {PropType, ref} from 'vue' import { PropType, ref } from 'vue'
import {More} from '@element-plus/icons-vue' import { More } from '@element-plus/icons-vue'
const tabsRef = ref<any>() // tabs ref const tabsRef = ref<any>() // tabs ref

View File

@ -2,11 +2,11 @@
<template> <template>
<div class="prompt"> <div class="prompt">
<el-text tag="b">画面描述</el-text> <el-text tag="b">画面描述</el-text>
<el-text tag="p">建议使用形容词+动词+风格的格式使用隔开</el-text> <el-text tag="p">建议使用形容词 + 动词 + 风格的格式使用隔开</el-text>
<el-input <el-input
v-model="prompt" v-model="prompt"
maxlength="1024" maxlength="1024"
rows="5" :rows="5"
class="w-100% mt-15px" class="w-100% mt-15px"
input-style="border-radius: 7px;" input-style="border-radius: 7px;"
placeholder="例如:童话里的小屋应该是什么样子?" placeholder="例如:童话里的小屋应该是什么样子?"
@ -57,8 +57,13 @@
<el-text tag="b">模型</el-text> <el-text tag="b">模型</el-text>
</div> </div>
<el-space wrap class="group-item-body"> <el-space wrap class="group-item-body">
<el-select v-model="model" placeholder="Select" size="large" class="!w-350px"> <el-select v-model="modelId" placeholder="Select" size="large" class="!w-350px">
<el-option v-for="item in models" :key="item.key" :label="item.name" :value="item.key" /> <el-option
v-for="item in platformModels"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select> </el-select>
</el-space> </el-space>
</div> </div>
@ -72,25 +77,34 @@
</el-space> </el-space>
</div> </div>
<div class="btns"> <div class="btns">
<el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage"> <el-button
type="primary"
size="large"
round
:loading="drawIn"
:disabled="prompt.length === 0"
@click="handleGenerateImage"
>
{{ drawIn ? '生成中' : '生成内容' }} {{ drawIn ? '生成中' : '生成内容' }}
</el-button> </el-button>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image' import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
import { import { AiPlatformEnum, ImageHotWords, OtherPlatformEnum } from '@/views/ai/utils/constants'
AiPlatformEnum, import { ModelVO } from '@/api/ai/model/model'
ChatGlmModels,
ImageHotWords,
ImageModelVO,
OtherPlatformEnum,
QianFanModels,
TongYiWanXiangModels
} from '@/views/ai/utils/constants'
const message = useMessage() // const message = useMessage() //
//
const props = defineProps({
models: {
type: Array<ModelVO>,
default: () => [] as ModelVO[]
}
})
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // emits
// //
const drawIn = ref<boolean>(false) // const drawIn = ref<boolean>(false) //
const selectHotWord = ref<string>('') // const selectHotWord = ref<string>('') //
@ -99,10 +113,8 @@ const prompt = ref<string>('') // 提示词
const width = ref<number>(512) // const width = ref<number>(512) //
const height = ref<number>(512) // const height = ref<number>(512) //
const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) // const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) //
const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // TongYiWanXiangModelsQianFanModels const platformModels = ref<ModelVO[]>([]) //
const model = ref<string>(models.value[0].key) // const modelId = ref<number>() //
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // emits
/** 选择热词 */ /** 选择热词 */
const handleHotWordClick = async (hotWord: string) => { const handleHotWordClick = async (hotWord: string) => {
@ -125,11 +137,11 @@ const handleGenerateImage = async () => {
// //
drawIn.value = true drawIn.value = true
// //
emits('onDrawStart', AiPlatformEnum.STABLE_DIFFUSION) emits('onDrawStart', otherPlatform.value)
// //
const form = { const form = {
platform: otherPlatform.value, platform: otherPlatform.value,
model: model.value, // modelId: modelId.value, //
prompt: prompt.value, // prompt: prompt.value, //
width: width.value, // width: width.value, //
height: height.value, // height: height.value, //
@ -138,7 +150,7 @@ const handleGenerateImage = async () => {
await ImageApi.drawImage(form) await ImageApi.drawImage(form)
} finally { } finally {
// //
emits('onDrawComplete', AiPlatformEnum.STABLE_DIFFUSION) emits('onDrawComplete', otherPlatform.value)
// //
drawIn.value = false drawIn.value = false
} }
@ -153,33 +165,29 @@ const settingValues = async (detail: ImageVO) => {
/** 平台切换 */ /** 平台切换 */
const handlerPlatformChange = async (platform: string) => { const handlerPlatformChange = async (platform: string) => {
// //
if (AiPlatformEnum.TONG_YI === platform) { platformModels.value = props.models.filter((item: ModelVO) => item.platform === platform)
models.value = TongYiWanXiangModels
} else if (AiPlatformEnum.YI_YAN === platform) { //
models.value = QianFanModels if (platformModels.value.length > 0) {
} else if (AiPlatformEnum.ZHI_PU === platform) { modelId.value = platformModels.value[0].id // 使 model
models.value = ChatGlmModels
} else { } else {
models.value = [] modelId.value = undefined
}
//
if (models.value.length > 0) {
model.value = models.value[0].key
} else {
model.value = ''
} }
} }
/** 监听 models 变化 */
watch(
() => props.models,
() => {
handlerPlatformChange(otherPlatform.value)
},
{ immediate: true, deep: true }
)
/** 暴露组件方法 */ /** 暴露组件方法 */
defineExpose({ settingValues }) defineExpose({ settingValues })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
//
.prompt {
}
//
.hot-words { .hot-words {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -2,11 +2,11 @@
<template> <template>
<div class="prompt"> <div class="prompt">
<el-text tag="b">画面描述</el-text> <el-text tag="b">画面描述</el-text>
<el-text tag="p">建议使用形容词+动词+风格的格式使用隔开</el-text> <el-text tag="p">建议使用"形容词 + 动词 + 风格"的格式使用""隔开</el-text>
<el-input <el-input
v-model="prompt" v-model="prompt"
maxlength="1024" maxlength="1024"
rows="5" :rows="5"
class="w-100% mt-15px" class="w-100% mt-15px"
input-style="border-radius: 7px;" input-style="border-radius: 7px;"
placeholder="例如:童话里的小屋应该是什么样子?" placeholder="例如:童话里的小屋应该是什么样子?"
@ -82,7 +82,14 @@
</el-space> </el-space>
</div> </div>
<div class="btns"> <div class="btns">
<el-button type="primary" size="large" round :loading="drawIn" @click="handleGenerateImage"> <el-button
type="primary"
size="large"
round
:loading="drawIn"
:disabled="prompt.length === 0"
@click="handleGenerateImage"
>
{{ drawIn ? '生成中' : '生成内容' }} {{ drawIn ? '生成中' : '生成内容' }}
</el-button> </el-button>
</div> </div>
@ -95,11 +102,22 @@ import {
ImageHotWords, ImageHotWords,
Dall3SizeList, Dall3SizeList,
ImageModelVO, ImageModelVO,
AiPlatformEnum AiPlatformEnum,
ImageSizeVO
} from '@/views/ai/utils/constants' } from '@/views/ai/utils/constants'
import { ModelVO } from '@/api/ai/model/model'
const message = useMessage() // const message = useMessage() //
//
const props = defineProps({
models: {
type: Array<ModelVO>,
default: () => [] as ModelVO[]
}
})
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // emits
// //
const prompt = ref<string>('') // const prompt = ref<string>('') //
const drawIn = ref<boolean>(false) // const drawIn = ref<boolean>(false) //
@ -108,8 +126,6 @@ const selectModel = ref<string>('dall-e-3') // 模型
const selectSize = ref<string>('1024x1024') // size const selectSize = ref<string>('1024x1024') // size
const style = ref<string>('vivid') // style const style = ref<string>('vivid') // style
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // emits
/** 选择热词 */ /** 选择热词 */
const handleHotWordClick = async (hotWord: string) => { const handleHotWordClick = async (hotWord: string) => {
// //
@ -126,6 +142,27 @@ const handleHotWordClick = async (hotWord: string) => {
/** 选择 model 模型 */ /** 选择 model 模型 */
const handleModelClick = async (model: ImageModelVO) => { const handleModelClick = async (model: ImageModelVO) => {
selectModel.value = model.key selectModel.value = model.key
//
//
if (model.key === 'dall-e-3') {
// DALL-E-3
style.value = 'vivid' // vivid
} else if (model.key === 'dall-e-2') {
// DALL-E-2
style.value = 'natural' // DALL-E-2
}
//
//
const recommendedSize = Dall3SizeList.find(
(size) =>
(model.key === 'dall-e-3' && size.key === '1024x1024') ||
(model.key === 'dall-e-2' && size.key === '512x512')
)
if (recommendedSize) {
selectSize.value = recommendedSize.key
}
} }
/** 选择 style 样式 */ /** 选择 style 样式 */
@ -140,6 +177,15 @@ const handleSizeClick = async (imageSize: ImageSizeVO) => {
/** 图片生产 */ /** 图片生产 */
const handleGenerateImage = async () => { const handleGenerateImage = async () => {
// models
const matchedModel = props.models.find(
(item) => item.model === selectModel.value && item.platform === AiPlatformEnum.OPENAI
)
if (!matchedModel) {
message.error('该模型不可用,请选择其它模型')
return
}
// //
await message.confirm(`确认生成内容?`) await message.confirm(`确认生成内容?`)
try { try {
@ -151,7 +197,8 @@ const handleGenerateImage = async () => {
const form = { const form = {
platform: AiPlatformEnum.OPENAI, platform: AiPlatformEnum.OPENAI,
prompt: prompt.value, // prompt: prompt.value, //
model: selectModel.value, // modelId: matchedModel.id, // 使
style: style.value, //
width: imageSize.width, // size width: imageSize.width, // size
height: imageSize.height, // size height: imageSize.height, // size
options: { options: {
@ -183,10 +230,6 @@ const settingValues = async (detail: ImageVO) => {
defineExpose({ settingValues }) defineExpose({ settingValues })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
//
.prompt {
}
// //
.hot-words { .hot-words {
display: flex; display: flex;

View File

@ -6,21 +6,28 @@
<el-segmented v-model="selectPlatform" :options="platformOptions" /> <el-segmented v-model="selectPlatform" :options="platformOptions" />
</div> </div>
<div class="modal-switch-container"> <div class="modal-switch-container">
<Common
v-if="selectPlatform === 'common'"
ref="commonRef"
:models="models"
@on-draw-complete="handleDrawComplete"
/>
<Dall3 <Dall3
v-if="selectPlatform === AiPlatformEnum.OPENAI" v-if="selectPlatform === AiPlatformEnum.OPENAI"
ref="dall3Ref" ref="dall3Ref"
:models="models"
@on-draw-start="handleDrawStart" @on-draw-start="handleDrawStart"
@on-draw-complete="handleDrawComplete" @on-draw-complete="handleDrawComplete"
/> />
<Midjourney v-if="selectPlatform === AiPlatformEnum.MIDJOURNEY" ref="midjourneyRef" /> <Midjourney
v-if="selectPlatform === AiPlatformEnum.MIDJOURNEY"
ref="midjourneyRef"
:models="models"
/>
<StableDiffusion <StableDiffusion
v-if="selectPlatform === AiPlatformEnum.STABLE_DIFFUSION" v-if="selectPlatform === AiPlatformEnum.STABLE_DIFFUSION"
ref="stableDiffusionRef" ref="stableDiffusionRef"
@on-draw-complete="handleDrawComplete" :models="models"
/>
<Other
v-if="selectPlatform === 'other'"
ref="otherRef"
@on-draw-complete="handleDrawComplete" @on-draw-complete="handleDrawComplete"
/> />
</div> </div>
@ -38,17 +45,23 @@ import { ImageVO } from '@/api/ai/image'
import Dall3 from './components/dall3/index.vue' import Dall3 from './components/dall3/index.vue'
import Midjourney from './components/midjourney/index.vue' import Midjourney from './components/midjourney/index.vue'
import StableDiffusion from './components/stableDiffusion/index.vue' import StableDiffusion from './components/stableDiffusion/index.vue'
import Other from './components/other/index.vue' import Common from './components/common/index.vue'
import { ModelApi, ModelVO } from '@/api/ai/model/model'
import { AiModelTypeEnum } from '@/views/ai/utils/constants'
const imageListRef = ref<any>() // image ref const imageListRef = ref<any>() // image ref
const dall3Ref = ref<any>() // dall3(openai) ref const dall3Ref = ref<any>() // dall3(openai) ref
const midjourneyRef = ref<any>() // midjourney ref const midjourneyRef = ref<any>() // midjourney ref
const stableDiffusionRef = ref<any>() // stable diffusion ref const stableDiffusionRef = ref<any>() // stable diffusion ref
const otherRef = ref<any>() // stable diffusion ref const commonRef = ref<any>() // stable diffusion ref
// //
const selectPlatform = ref(AiPlatformEnum.MIDJOURNEY) const selectPlatform = ref('common') //
const platformOptions = [ const platformOptions = [
{
label: '通用',
value: 'common'
},
{ {
label: 'DALL3 绘画', label: 'DALL3 绘画',
value: AiPlatformEnum.OPENAI value: AiPlatformEnum.OPENAI
@ -58,15 +71,13 @@ const platformOptions = [
value: AiPlatformEnum.MIDJOURNEY value: AiPlatformEnum.MIDJOURNEY
}, },
{ {
label: 'Stable Diffusion', label: 'SD 绘图',
value: AiPlatformEnum.STABLE_DIFFUSION value: AiPlatformEnum.STABLE_DIFFUSION
},
{
label: '其它',
value: 'other'
} }
] ]
const models = ref<ModelVO[]>([]) //
/** 绘画 start */ /** 绘画 start */
const handleDrawStart = async (platform: string) => {} const handleDrawStart = async (platform: string) => {}
@ -75,7 +86,7 @@ const handleDrawComplete = async (platform: string) => {
await imageListRef.value.getImageList() await imageListRef.value.getImageList()
} }
/** 重新生成:将画图详情填充到对应平台 */ /** 重新生成:将画图详情填充到对应平台 */
const handleRegeneration = async (image: ImageVO) => { const handleRegeneration = async (image: ImageVO) => {
// //
selectPlatform.value = image.platform selectPlatform.value = image.platform
@ -90,6 +101,12 @@ const handleRegeneration = async (image: ImageVO) => {
} }
// TODO @fan other // TODO @fan other
} }
/** 组件挂载的时候 */
onMounted(async () => {
//
models.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.IMAGE)
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -109,10 +126,7 @@ const handleRegeneration = async (image: ImageVO) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 20px; padding: 20px;
width: 350px; width: 390px;
.segmented {
}
.segmented .el-segmented { .segmented .el-segmented {
--el-border-radius-base: 16px; --el-border-radius-base: 16px;

View File

@ -68,8 +68,9 @@
import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { ChatRoleApi, ChatRoleVO } from '@/api/ai/model/chatRole' import { ChatRoleApi, ChatRoleVO } from '@/api/ai/model/chatRole'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' import { ModelApi, ModelVO } from '@/api/ai/model/model'
import { FormRules } from 'element-plus' import { FormRules } from 'element-plus'
import { AiModelTypeEnum } from '@/views/ai/utils/constants'
/** AI 聊天角色 表单 */ /** AI 聊天角色 表单 */
defineOptions({ name: 'ChatRoleForm' }) defineOptions({ name: 'ChatRoleForm' })
@ -94,7 +95,7 @@ const formData = ref({
status: CommonStatusEnum.ENABLE status: CommonStatusEnum.ENABLE
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
const chatModelList = ref([] as ChatModelVO[]) // const chatModelList = ref([] as ModelVO[]) //
/** 是否【我】自己创建,私有角色 */ /** 是否【我】自己创建,私有角色 */
const isUser = computed(() => { const isUser = computed(() => {
@ -128,7 +129,7 @@ const open = async (type: string, id?: number, title?: string) => {
} }
} }
// //
chatModelList.value = await ChatModelApi.getChatModelSimpleList(CommonStatusEnum.ENABLE) chatModelList.value = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
} }
defineExpose({ open }) // open defineExpose({ open }) // open

View File

@ -17,6 +17,21 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="模型类型" prop="type">
<el-select
v-model="formData.type"
placeholder="请输入模型类型"
clearable
:disabled="formData.id"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.AI_MODEL_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="API 秘钥" prop="keyId"> <el-form-item label="API 秘钥" prop="keyId">
<el-select v-model="formData.keyId" placeholder="请选择 API 秘钥" clearable> <el-select v-model="formData.keyId" placeholder="请选择 API 秘钥" clearable>
<el-option <el-option
@ -47,7 +62,11 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="温度参数" prop="temperature"> <el-form-item
label="温度参数"
prop="temperature"
v-if="formData.type === AiModelTypeEnum.CHAT"
>
<el-input-number <el-input-number
v-model="formData.temperature" v-model="formData.temperature"
placeholder="请输入温度参数" placeholder="请输入温度参数"
@ -56,7 +75,11 @@
:precision="2" :precision="2"
/> />
</el-form-item> </el-form-item>
<el-form-item label="回复数 Token 数" prop="maxTokens"> <el-form-item
label="回复数 Token 数"
prop="maxTokens"
v-if="formData.type === AiModelTypeEnum.CHAT"
>
<el-input-number <el-input-number
v-model="formData.maxTokens" v-model="formData.maxTokens"
placeholder="请输入回复数 Token 数" placeholder="请输入回复数 Token 数"
@ -64,7 +87,11 @@
:max="4096" :max="4096"
/> />
</el-form-item> </el-form-item>
<el-form-item label="上下文数量" prop="maxContexts"> <el-form-item
label="上下文数量"
prop="maxContexts"
v-if="formData.type === AiModelTypeEnum.CHAT"
>
<el-input-number <el-input-number
v-model="formData.maxContexts" v-model="formData.maxContexts"
placeholder="请输入上下文数量" placeholder="请输入上下文数量"
@ -80,13 +107,14 @@
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' import { ModelApi, ModelVO } from '@/api/ai/model/model'
import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import { AiModelTypeEnum } from '@/views/ai/utils/constants'
/** API 聊天模型 表单 */ /** API 模型的表单 */
defineOptions({ name: 'ChatModelForm' }) defineOptions({ name: 'ModelForm' })
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
@ -101,6 +129,7 @@ const formData = ref({
name: undefined, name: undefined,
model: undefined, model: undefined,
platform: undefined, platform: undefined,
type: undefined,
sort: undefined, sort: undefined,
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
temperature: undefined, temperature: undefined,
@ -112,6 +141,7 @@ const formRules = reactive({
name: [{ required: true, message: '模型名字不能为空', trigger: 'blur' }], name: [{ required: true, message: '模型名字不能为空', trigger: 'blur' }],
model: [{ required: true, message: '模型标识不能为空', trigger: 'blur' }], model: [{ required: true, message: '模型标识不能为空', trigger: 'blur' }],
platform: [{ required: true, message: '所属平台不能为空', trigger: 'blur' }], platform: [{ required: true, message: '所属平台不能为空', trigger: 'blur' }],
type: [{ required: true, message: '模型类型不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }], sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }] status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
}) })
@ -128,13 +158,13 @@ const open = async (type: string, id?: number) => {
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await ChatModelApi.getChatModel(id) formData.value = await ModelApi.getModel(id)
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
// //
apiKeyList.value = await ApiKeyApi.getApiKeySimpleList(CommonStatusEnum.ENABLE) apiKeyList.value = await ApiKeyApi.getApiKeySimpleList()
} }
defineExpose({ open }) // open defineExpose({ open }) // open
@ -146,12 +176,17 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
const data = formData.value as unknown as ChatModelVO const data = formData.value as unknown as ModelVO
if (data.type !== AiModelTypeEnum.CHAT) {
delete data.temperature
delete data.maxTokens
delete data.maxContexts
}
if (formType.value === 'create') { if (formType.value === 'create') {
await ChatModelApi.createChatModel(data) await ModelApi.createModel(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await ChatModelApi.updateChatModel(data) await ModelApi.updateModel(data)
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
dialogVisible.value = false dialogVisible.value = false
@ -170,6 +205,7 @@ const resetForm = () => {
name: undefined, name: undefined,
model: undefined, model: undefined,
platform: undefined, platform: undefined,
type: undefined,
sort: undefined, sort: undefined,
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
temperature: undefined, temperature: undefined,

View File

@ -42,7 +42,7 @@
type="primary" type="primary"
plain plain
@click="openForm('create')" @click="openForm('create')"
v-hasPermi="['ai:chat-model:create']" v-hasPermi="['ai:model:create']"
> >
<Icon icon="ep:plus" class="mr-5px" /> 新增 <Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button> </el-button>
@ -58,6 +58,11 @@
<dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" /> <dict-tag :type="DICT_TYPE.AI_PLATFORM" :value="scope.row.platform" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="模型类型" align="center" prop="platform">
<template #default="scope">
<dict-tag :type="DICT_TYPE.AI_MODEL_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="模型名字" align="center" prop="name" /> <el-table-column label="模型名字" align="center" prop="name" />
<el-table-column label="模型标识" align="center" prop="model" /> <el-table-column label="模型标识" align="center" prop="model" />
<el-table-column label="API 秘钥" align="center" prop="keyId" min-width="140"> <el-table-column label="API 秘钥" align="center" prop="keyId" min-width="140">
@ -80,7 +85,7 @@
link link
type="primary" type="primary"
@click="openForm('update', scope.row.id)" @click="openForm('update', scope.row.id)"
v-hasPermi="['ai:chat-model:update']" v-hasPermi="['ai:model:update']"
> >
编辑 编辑
</el-button> </el-button>
@ -88,7 +93,7 @@
link link
type="danger" type="danger"
@click="handleDelete(scope.row.id)" @click="handleDelete(scope.row.id)"
v-hasPermi="['ai:chat-model:delete']" v-hasPermi="['ai:model:delete']"
> >
删除 删除
</el-button> </el-button>
@ -105,23 +110,23 @@
</ContentWrap> </ContentWrap>
<!-- 表单弹窗添加/修改 --> <!-- 表单弹窗添加/修改 -->
<ChatModelForm ref="formRef" @success="getList" /> <ModelForm ref="formRef" @success="getList" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel' import { ModelApi, ModelVO } from '@/api/ai/model/model'
import ChatModelForm from './ChatModelForm.vue' import ModelForm from './ModelForm.vue'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey' import { ApiKeyApi, ApiKeyVO } from '@/api/ai/model/apiKey'
/** API 聊天模型 列表 */ /** API 模型列表 */
defineOptions({ name: 'AiChatModel' }) defineOptions({ name: 'AiModel' })
const message = useMessage() // const message = useMessage() //
const { t } = useI18n() // const { t } = useI18n() //
const loading = ref(true) // const loading = ref(true) //
const list = ref<ChatModelVO[]>([]) // const list = ref<ModelVO[]>([]) //
const total = ref(0) // const total = ref(0) //
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
@ -137,7 +142,7 @@ const apiKeyList = ref([] as ApiKeyVO[]) // API 密钥列表
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const data = await ChatModelApi.getChatModelPage(queryParams) const data = await ModelApi.getModelPage(queryParams)
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
} finally { } finally {
@ -169,7 +174,7 @@ const handleDelete = async (id: number) => {
// //
await message.delConfirm() await message.delConfirm()
// //
await ChatModelApi.deleteChatModel(id) await ModelApi.deleteModel(id)
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// //
await getList() await getList()
@ -178,7 +183,7 @@ const handleDelete = async (id: number) => {
/** 初始化 **/ /** 初始化 **/
onMounted(async () => { onMounted(async () => {
getList() await getList()
// //
apiKeyList.value = await ApiKeyApi.getApiKeySimpleList() apiKeyList.value = await ApiKeyApi.getApiKeySimpleList()
}) })

View File

@ -23,6 +23,15 @@ export const AiPlatformEnum = {
SUNO: 'Suno' // Suno AI SUNO: 'Suno' // Suno AI
} }
export const AiModelTypeEnum = {
CHAT: 1, // 聊天
IMAGE: 2, // 图像
VOICE: 3, // 音频
VIDEO: 4, // 视频
EMBEDDING: 5, // 向量
RERANK: 6 // 重排
}
export const OtherPlatformEnum: ImageModelVO[] = [ export const OtherPlatformEnum: ImageModelVO[] = [
{ {
key: AiPlatformEnum.TONG_YI, key: AiPlatformEnum.TONG_YI,
@ -211,31 +220,6 @@ export const StableDiffusionStylePresets: ImageModelVO[] = [
} }
] ]
export const TongYiWanXiangModels: ImageModelVO[] = [
{
key: 'wanx-v1',
name: 'wanx-v1'
},
{
key: 'wanx-sketch-to-image-v1',
name: 'wanx-sketch-to-image-v1'
}
]
export const QianFanModels: ImageModelVO[] = [
{
key: 'sd_xl',
name: 'sd_xl'
}
]
export const ChatGlmModels: ImageModelVO[] = [
{
key: 'cogview-3',
name: 'cogview-3'
}
]
export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [ export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [
{ {
key: 'NONE', key: 'NONE',