Forráskód Böngészése

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

YunaiV 5 hónapja
szülő
commit
ae632ac23b

+ 2 - 3
src/api/ai/image/index.ts

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

+ 0 - 53
src/api/ai/model/chatModel/index.ts

@@ -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 })
-  }
-}

+ 54 - 0
src/api/ai/model/model/index.ts

@@ -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 })
+  }
+}

+ 1 - 0
src/utils/dict.ts

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

+ 4 - 4
src/views/ai/chat/index/components/conversation/ConversationUpdateForm.vue

@@ -58,9 +58,9 @@
   </Dialog>
 </template>
 <script setup lang="ts">
-import { CommonStatusEnum } from '@/utils/constants'
-import { ChatModelApi, ChatModelVO } from '@/api/ai/model/chatModel'
+import { ModelApi, ModelVO } from '@/api/ai/model/model'
 import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation'
+import { AiModelTypeEnum } from '@/views/ai/utils/constants'
 
 /** AI 聊天对话的更新表单 */
 defineOptions({ name: 'ChatConversationUpdateForm' })
@@ -85,7 +85,7 @@ const formRules = reactive({
   maxContexts: [{ required: true, message: '上下文数量不能为空', trigger: 'blur' }]
 })
 const formRef = ref() // 表单 Ref
-const chatModelList = ref([] as ChatModelVO[]) // 聊天模型列表
+const chatModelList = ref([] as ModelVO[]) // 聊天模型列表
 
 /** 打开弹窗 */
 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 方法,用于打开弹窗
 

+ 3 - 3
src/views/ai/chat/index/components/role/RoleList.vue

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

+ 48 - 40
src/views/ai/image/index/components/other/index.vue → src/views/ai/image/index/components/common/index.vue

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

+ 54 - 11
src/views/ai/image/index/components/dall3/index.vue

@@ -2,11 +2,11 @@
 <template>
   <div class="prompt">
     <el-text tag="b">画面描述</el-text>
-    <el-text tag="p">建议使用“形容词+动词+风格”的格式,使用“,”隔开</el-text>
+    <el-text tag="p">建议使用"形容词 + 动词 + 风格"的格式,使用","隔开</el-text>
     <el-input
       v-model="prompt"
       maxlength="1024"
-      rows="5"
+      :rows="5"
       class="w-100% mt-15px"
       input-style="border-radius: 7px;"
       placeholder="例如:童话里的小屋应该是什么样子?"
@@ -82,7 +82,14 @@
     </el-space>
   </div>
   <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 ? '生成中' : '生成内容' }}
     </el-button>
   </div>
@@ -95,11 +102,22 @@ import {
   ImageHotWords,
   Dall3SizeList,
   ImageModelVO,
-  AiPlatformEnum
+  AiPlatformEnum,
+  ImageSizeVO
 } from '@/views/ai/utils/constants'
+import { ModelVO } from '@/api/ai/model/model'
 
 const message = useMessage() // 消息弹窗
 
+// 接收父组件传入的模型列表
+const props = defineProps({
+  models: {
+    type: Array<ModelVO>,
+    default: () => [] as ModelVO[]
+  }
+})
+const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
+
 // 定义属性
 const prompt = ref<string>('') // 提示词
 const drawIn = ref<boolean>(false) // 生成中
@@ -108,8 +126,6 @@ const selectModel = ref<string>('dall-e-3') // 模型
 const selectSize = ref<string>('1024x1024') // 选中 size
 const style = ref<string>('vivid') // style 样式
 
-const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
-
 /** 选择热词 */
 const handleHotWordClick = async (hotWord: string) => {
   // 情况一:取消选中
@@ -126,6 +142,27 @@ const handleHotWordClick = async (hotWord: string) => {
 /** 选择 model 模型 */
 const handleModelClick = async (model: ImageModelVO) => {
   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 样式  */
@@ -140,6 +177,15 @@ const handleSizeClick = async (imageSize: ImageSizeVO) => {
 
 /**  图片生产  */
 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(`确认生成内容?`)
   try {
@@ -151,7 +197,8 @@ const handleGenerateImage = async () => {
     const form = {
       platform: AiPlatformEnum.OPENAI,
       prompt: prompt.value, // 提示词
-      model: selectModel.value, // 模型
+      modelId: matchedModel.id, // 使用匹配到的模型
+      style: style.value, // 图像生成的风格
       width: imageSize.width, // size 不能为空
       height: imageSize.height, // size 不能为空
       options: {
@@ -183,10 +230,6 @@ const settingValues = async (detail: ImageVO) => {
 defineExpose({ settingValues })
 </script>
 <style scoped lang="scss">
-// 提示词
-.prompt {
-}
-
 // 热词
 .hot-words {
   display: flex;

+ 33 - 19
src/views/ai/image/index/index.vue

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

+ 4 - 3
src/views/ai/model/chatRole/ChatRoleForm.vue

@@ -68,8 +68,9 @@
 import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
 import { ChatRoleApi, ChatRoleVO } from '@/api/ai/model/chatRole'
 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 { AiModelTypeEnum } from '@/views/ai/utils/constants'
 
 /** AI 聊天角色 表单 */
 defineOptions({ name: 'ChatRoleForm' })
@@ -94,7 +95,7 @@ const formData = ref({
   status: CommonStatusEnum.ENABLE
 })
 const formRef = ref() // 表单 Ref
-const chatModelList = ref([] as ChatModelVO[]) // 聊天模型列表
+const chatModelList = ref([] as ModelVO[]) // 聊天模型列表
 
 /** 是否【我】自己创建,私有角色 */
 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 方法,用于打开弹窗
 

+ 47 - 11
src/views/ai/model/chatModel/ChatModelForm.vue → src/views/ai/model/model/ModelForm.vue

@@ -17,6 +17,21 @@
           />
         </el-select>
       </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-select v-model="formData.keyId" placeholder="请选择 API 秘钥" clearable>
           <el-option
@@ -47,7 +62,11 @@
           </el-radio>
         </el-radio-group>
       </el-form-item>
-      <el-form-item label="温度参数" prop="temperature">
+      <el-form-item
+        label="温度参数"
+        prop="temperature"
+        v-if="formData.type === AiModelTypeEnum.CHAT"
+      >
         <el-input-number
           v-model="formData.temperature"
           placeholder="请输入温度参数"
@@ -56,7 +75,11 @@
           :precision="2"
         />
       </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
           v-model="formData.maxTokens"
           placeholder="请输入回复数 Token 数"
@@ -64,7 +87,11 @@
           :max="4096"
         />
       </el-form-item>
-      <el-form-item label="上下文数量" prop="maxContexts">
+      <el-form-item
+        label="上下文数量"
+        prop="maxContexts"
+        v-if="formData.type === AiModelTypeEnum.CHAT"
+      >
         <el-input-number
           v-model="formData.maxContexts"
           placeholder="请输入上下文数量"
@@ -80,13 +107,14 @@
   </Dialog>
 </template>
 <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 { CommonStatusEnum } from '@/utils/constants'
 import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
+import { AiModelTypeEnum } from '@/views/ai/utils/constants'
 
-/** API 聊天模型 表单 */
-defineOptions({ name: 'ChatModelForm' })
+/** API 模型的表单 */
+defineOptions({ name: 'ModelForm' })
 
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
@@ -101,6 +129,7 @@ const formData = ref({
   name: undefined,
   model: undefined,
   platform: undefined,
+  type: undefined,
   sort: undefined,
   status: CommonStatusEnum.ENABLE,
   temperature: undefined,
@@ -112,6 +141,7 @@ const formRules = reactive({
   name: [{ required: true, message: '模型名字不能为空', trigger: 'blur' }],
   model: [{ required: true, message: '模型标识不能为空', trigger: 'blur' }],
   platform: [{ required: true, message: '所属平台不能为空', trigger: 'blur' }],
+  type: [{ required: true, message: '模型类型不能为空', trigger: 'blur' }],
   sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
   status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
 })
@@ -128,13 +158,13 @@ const open = async (type: string, id?: number) => {
   if (id) {
     formLoading.value = true
     try {
-      formData.value = await ChatModelApi.getChatModel(id)
+      formData.value = await ModelApi.getModel(id)
     } finally {
       formLoading.value = false
     }
   }
   // 获得下拉数据
-  apiKeyList.value = await ApiKeyApi.getApiKeySimpleList(CommonStatusEnum.ENABLE)
+  apiKeyList.value = await ApiKeyApi.getApiKeySimpleList()
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
@@ -146,12 +176,17 @@ const submitForm = async () => {
   // 提交请求
   formLoading.value = true
   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') {
-      await ChatModelApi.createChatModel(data)
+      await ModelApi.createModel(data)
       message.success(t('common.createSuccess'))
     } else {
-      await ChatModelApi.updateChatModel(data)
+      await ModelApi.updateModel(data)
       message.success(t('common.updateSuccess'))
     }
     dialogVisible.value = false
@@ -170,6 +205,7 @@ const resetForm = () => {
     name: undefined,
     model: undefined,
     platform: undefined,
+    type: undefined,
     sort: undefined,
     status: CommonStatusEnum.ENABLE,
     temperature: undefined,

+ 17 - 12
src/views/ai/model/chatModel/index.vue → src/views/ai/model/model/index.vue

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

+ 9 - 25
src/views/ai/utils/constants.ts

@@ -23,6 +23,15 @@ export const AiPlatformEnum = {
   SUNO: 'Suno' // Suno AI
 }
 
+export const AiModelTypeEnum = {
+  CHAT: 1, // 聊天
+  IMAGE: 2, // 图像
+  VOICE: 3, // 音频
+  VIDEO: 4, // 视频
+  EMBEDDING: 5, // 向量
+  RERANK: 6 // 重排
+}
+
 export const OtherPlatformEnum: ImageModelVO[] = [
   {
     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[] = [
   {
     key: 'NONE',