diff --git a/src/api/new-ai/docs.ts b/src/api/new-ai/docs.ts new file mode 100644 index 0000000..d42e777 --- /dev/null +++ b/src/api/new-ai/docs.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 文档 VO +export interface DocsVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 文档 API +export const DocsApi = { + // 获得文档分页 + async getDocsPage(params: any) { + return await request.get({ url: '/aigc/docs/page', params }) + }, + + // 获得文档列表 + async getDocsList(params: any) { + return await request.get({ url: '/aigc/docs/list', params }) + }, + + // 获得文档详情 + async getDocsById(id: string) { + return await request.get({ url: `/aigc/docs/${id}` }) + }, + + // 创建文档 + async addDocs(data: any) { + return await request.post({ url: '/aigc/docs', data }) + }, + + // 更新文档 + async updateDocs(data: any) { + return await request.put({ url: '/aigc/docs', data }) + }, + + // 删除文档 + async deleteDocs(id: string) { + return await request.delete({ url: `/aigc/docs/${id}` }) + }, + + // 重新向量化 + async reEmbedDocs(id: string) { + return await request.get({ url: `/aigc/embedding/re-embed/${id}` }) + } +} diff --git a/src/api/new-ai/embed-store.ts b/src/api/new-ai/embed-store.ts new file mode 100644 index 0000000..a67e929 --- /dev/null +++ b/src/api/new-ai/embed-store.ts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 嵌入存储 VO +export interface EmbedStoreVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 嵌入存储 API +export const EmbedStoreApi = { + // 获得嵌入存储列表 + getEmbedStoreList: async (params: any) => { + return await request.get({ url: '/aigc/embed-store/list', params }) + }, + + // 获得嵌入存储分页 + getEmbedStorePage: async (params: any) => { + return await request.get({ url: '/aigc/embed-store/page', params }) + }, + + // 获得嵌入存储详情 + getEmbedStore: async (id: string) => { + return await request.get({ url: `/aigc/embed-store/${id}` }) + }, + + // 创建嵌入存储 + createEmbedStore: async (data: any) => { + return await request.post({ url: '/aigc/embed-store', data }) + }, + + // 更新嵌入存储 + updateEmbedStore: async (data: any) => { + return await request.put({ url: '/aigc/embed-store', data }) + }, + + // 删除嵌入存储 + deleteEmbedStore: async (id: string) => { + return await request.delete({ url: `/aigc/embed-store/${id}` }) + } +} +// export function list(params: any) { +// return http.request({ +// url: '/aigc/embed-store/list', +// method: 'get', +// params, +// }); +// } + +// export function page(params: any) { +// return http.request({ +// url: '/aigc/embed-store/page', +// method: 'get', +// params, +// }); +// } + +// export function getById(id: string) { +// return http.request({ +// url: `/aigc/embed-store/${id}`, +// method: 'get', +// }); +// } + +// export function add(params: any) { +// return http.request({ +// url: '/aigc/embed-store', +// method: 'post', +// params, +// }); +// } + +// export function update(params: any) { +// return http.request({ +// url: '/aigc/embed-store', +// method: 'put', +// params, +// }); +// } + +// export function del(id?: string) { +// return http.request({ +// url: `/aigc/embed-store/${id}`, +// method: 'delete', +// }); +// } diff --git a/src/api/new-ai/embedding.ts b/src/api/new-ai/embedding.ts new file mode 100644 index 0000000..4a8326a --- /dev/null +++ b/src/api/new-ai/embedding.ts @@ -0,0 +1,81 @@ +import request from '@/config/axios' +import { AxiosProgressEvent } from 'axios' + +// AI 嵌入 API +export const EmbeddingApi = { + // 文本嵌入 + embeddingText: async (params: any) => { + return await request.post({ url: '/aigc/embedding/text', params }) + }, + + // 嵌入搜索 + embeddingSearch: async (data: any) => { + return await request.post({ url: '/aigc/embedding/search', data }) + }, + + // 文档嵌入 + embeddingDocs: async ( + knowledgeId: string, + data: any, + onUploadProgress?: (progressEvent: AxiosProgressEvent) => void + ) => { + return await request.post({ + url: `/aigc/embedding/docs/${knowledgeId}`, + data, + headers: { + 'Content-Type': 'multipart/form-data' + }, + onUploadProgress + }) + } +} +// /* +// * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. +// * +// * Licensed under the GNU Affero General Public License, Version 3 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * https://www.gnu.org/licenses/agpl-3.0.html +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ + +// import { http } from '@/utils/http/axios'; +// import { AxiosProgressEvent } from 'axios'; + +// export function embeddingText(params: any) { +// return http.request({ +// url: '/aigc/embedding/text', +// method: 'post', +// params, +// }); +// } + +// export function embeddingSearch(data: any) { +// return http.request({ +// url: '/aigc/embedding/search', +// method: 'post', +// data, +// }); +// } + +// export function embeddingDocs( +// knowledgeId: string, +// data: any, +// onUploadProgress?: (progressEvent: AxiosProgressEvent) => void +// ) { +// return http.request({ +// url: `/aigc/embedding/docs/${knowledgeId}`, +// method: 'post', +// data, +// headers: { +// 'Content-Type': 'multipart/form-data', +// }, +// onUploadProgress, +// }); +// } diff --git a/src/api/new-ai/knowledge.ts b/src/api/new-ai/knowledge.ts new file mode 100644 index 0000000..755f834 --- /dev/null +++ b/src/api/new-ai/knowledge.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +// AI 知识库 VO +export interface KnowledgeVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 知识库 API +export const KnowledgeApi = { + // 获得知识库列表 + getKnowledgeList: async (params: any) => { + return await request.get({ url: '/aigc/knowledge/list', params }) + }, + + // 获得知识库分页 + getKnowledgePage: async (params: any) => { + return await request.get({ url: '/aigc/knowledge/page', params }) + }, + + // 获得知识库详情 + getKnowledge: async (id: string) => { + return await request.get({ url: `/aigc/knowledge/${id}` }) + }, + + // 创建知识库 + createKnowledge: async (data: any) => { + return await request.post({ url: '/aigc/knowledge', data }) + }, + + // 更新知识库 + updateKnowledge: async (data: any) => { + return await request.put({ url: '/aigc/knowledge', data }) + }, + + // 删除知识库 + deleteKnowledge: async (id: string) => { + return await request.delete({ url: `/aigc/knowledge/${id}` }) + } +} \ No newline at end of file diff --git a/src/api/new-ai/model.ts b/src/api/new-ai/model.ts new file mode 100644 index 0000000..2aefc33 --- /dev/null +++ b/src/api/new-ai/model.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +// AI 模型 VO +export interface ModelVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 模型 API +export const ModelApi = { + // 获得模型分页 + getModelPage: async (params: any) => { + return await request.get({ url: '/chat/aigc/model/page', params }) + }, + + // 获得模型列表 + getModelList: async (params: any) => { + return await request.get({ url: '/chat/aigc/model/list', params }) + }, + + // 获得模型详情 + getModel: async (id: string) => { + return await request.get({ url: `/chat/aigc/model/${id}` }) + }, + + // 创建模型 + createModel: async (data: any) => { + return await request.post({ url: '/chat/aigc/model', data }) + }, + + // 更新模型 + updateModel: async (data: any) => { + return await request.put({ url: '/chat/aigc/model', data }) + }, + + // 删除模型 + deleteModel: async (id: string) => { + return await request.delete({ url: `/chat/aigc/model/${id}` }) + } +} \ No newline at end of file diff --git a/src/api/new-ai/slice.ts b/src/api/new-ai/slice.ts new file mode 100644 index 0000000..bd7947e --- /dev/null +++ b/src/api/new-ai/slice.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved. + * + * Licensed under the GNU Affero General Public License, Version 3 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.gnu.org/licenses/agpl-3.0.html + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import request from '@/config/axios' + +// AI 文档切片 VO +export interface SliceVO { + id: string + // TODO: Add other fields based on your data model +} + +// AI 文档切片 API +export const SliceApi = { + // 获得切片分页 + getSlicePage: async (params: any) => { + return await request.get({ url: '/aigc/docs/slice/page', params }) + }, + + // 获得切片列表 + getSliceList: async (params: any) => { + return await request.get({ url: '/aigc/docs/slice/list', params }) + }, + + // 获得切片详情 + getSlice: async (id: string) => { + return await request.get({ url: `/aigc/docs/slice/${id}` }) + }, + + // 创建切片 + createSlice: async (data: any) => { + return await request.post({ url: '/aigc/docs/slice', data }) + }, + + // 更新切片 + updateSlice: async (data: any) => { + return await request.put({ url: '/aigc/docs/slice', data }) + }, + + // 删除切片 + deleteSlice: async (id: string) => { + return await request.delete({ url: `/aigc/docs/slice/${id}` }) + } +} diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue index c7d22dc..4d59f03 100644 --- a/src/components/Form/src/Form.vue +++ b/src/components/Form/src/Form.vue @@ -191,7 +191,7 @@ export default defineComponent({ ) { slotsMap.default = () => renderOptions(item) } - + const formItemSlots: Recordable = setFormItemSlots(slots, item.field) // 如果有 labelMessage,自动使用插槽渲染 if (item?.labelMessage) { @@ -230,6 +230,7 @@ export default defineComponent({ return slots[item.field] ? ( getSlot(slots, item.field, formModel.value) ) : ( + <> {{ ...slotsMap }} + + ) } }} diff --git a/src/views/ai/model/chatModel/composables/columns.ts b/src/views/ai/model/chatModel/composables/columns.ts index 5a8f68f..d6d18f4 100644 --- a/src/views/ai/model/chatModel/composables/columns.ts +++ b/src/views/ai/model/chatModel/composables/columns.ts @@ -81,5 +81,9 @@ export function getColumns(provider: string) { return zhipuColumns; } } - return openaiColumns; + return [...openaiColumns, { + label: '操作', + field: 'action', + width: '150', + }]; } diff --git a/src/views/ai/model/chatModel/composables/consts.ts b/src/views/ai/model/chatModel/composables/consts.ts index 0b003f5..3b11bc0 100644 --- a/src/views/ai/model/chatModel/composables/consts.ts +++ b/src/views/ai/model/chatModel/composables/consts.ts @@ -196,3 +196,9 @@ export const LLMProviders: any[] = [ models: ['claude-3-opus', 'claude-3-opus-20240229', 'claude-3-sonnet', 'claude-3-haiku'], }, ]; +export enum ModelTypeEnum { + CHAT = 'CHAT', + EMBEDDING = 'EMBEDDING', + TEXT_IMAGE = 'TEXT_IMAGE', + WEB_SEARCH = 'WEB_SEARCH', +} \ No newline at end of file diff --git a/src/views/ai/model/chatModel/edit.vue b/src/views/ai/model/chatModel/edit.vue index 603c534..6a74c4f 100644 --- a/src/views/ai/model/chatModel/edit.vue +++ b/src/views/ai/model/chatModel/edit.vue @@ -1,25 +1,55 @@ diff --git a/src/views/ai/model/chatModel/index.vue b/src/views/ai/model/chatModel/index.vue index dacbec3..aac7055 100644 --- a/src/views/ai/model/chatModel/index.vue +++ b/src/views/ai/model/chatModel/index.vue @@ -3,14 +3,12 @@ import {Table} from '@/components/Table'; import {Delete, Edit, Plus} from '@element-plus/icons-vue'; import editCom from './edit.vue'; -import {computed, h, nextTick, reactive, ref} from 'vue'; -import {getColumns} from './composables/columns.ts'; -import {LLMProviders} from './composables/consts.ts'; -// import { del, list as getModels } from '@/api/aigc/model'; +import {computed, h, nextTick, reactive, ref, watch, onMounted} from 'vue'; +import {getColumns} from './composables/columns'; +import {LLMProviders, ModelTypeEnum} from './composables/consts'; +import {ModelApi} from '@/api/new-ai/model'; import {ElMessage, ElMessageBox} from 'element-plus'; -import {FormSchema} from "@/types/form"; -// import { ModelTypeEnum } from '@/api/models'; -import {getModels, ProviderEnum} from './composables/provider.ts'; +import {getModels, ProviderEnum} from './composables/provider'; const formData = ref({ provider: ProviderEnum.OPENAI @@ -19,129 +17,101 @@ const message = ElMessage; const dialog = ElMessageBox; const actionRef = ref(); const editRef = ref(); -const tableData = ref([ - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, - { - name: '1111' - }, { - name: '1111' - }, - { - name: '1111' +const tableData = ref([]); +const loading = ref(false); +// 获取模型列表 +const loadData = async () => { + loading.value = true; + try { + const res = await ModelApi.getModelList({ + provider: formData.value.provider, + type: ModelTypeEnum.CHAT + }).finally(() => { + loading.value = false; + }); + console.log(res) + tableData.value = res; + } catch (error) { + console.error('Failed to load models:', error); + message.error('获取模型列表失败'); } -]) -// const actionColumn = reactive({ -// width: 100, -// title: '操作', -// key: 'action', -// fixed: 'right', -// align: 'center', -// render(record: any) { -// return h(TableAction as any, { -// style: 'text', -// actions: [ -// { -// type: 'info', -// icon: Edit, -// onClick: handleEdit.bind(null, record), -// }, -// { -// type: 'error', -// icon: Delete, -// onClick: handleDel.bind(null, record), -// }, -// ], -// }); -// }, -// }); +}; + +// 监听 provider 变化重新加载数据 +watch(() => formData.value.provider, () => { + loadData(); +}); + +// 初始加载 +onMounted(() => { + loadData(); +}); const columns = computed(() => { nextTick(); return getColumns(formData.value.provider); }); -// const loadDataTable = async (params: any) => { -// if (formData.value.provider === '') { -// formData.value.provider = LLMProviders[0].model; -// } -// return await getModels({ ...params, provider: formData.value.provider, type: ModelTypeEnum.CHAT }); -// }; async function addModel() { console.log(formData.value.provider); - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.CHAT }); } function handleEdit(record: any) { editRef.value.show(record); } -function reloadTable() { - actionRef.value.reload(); +async function reloadTable() { + await loadData(); } -function handleDel(record: any) { - dialog.warning({ - title: '警告', - message: `你确定删除 [${record.name}] 模型吗?删除之后不可再用该模型对话`, +async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { confirmButtonText: '确定', - cancelButtonText: '不确定', + cancelButtonText: '取消', type: 'warning', }).then(async () => { - await del(record.id); - reloadTable(); - message.success('模型删除成功'); + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } }).catch(() => { - // 取消删除 }); } diff --git a/src/views/ai/model/embedStore/composables/index.ts b/src/views/ai/model/embedStore/composables/index.ts index 1d5a2eb..90c66f8 100644 --- a/src/views/ai/model/embedStore/composables/index.ts +++ b/src/views/ai/model/embedStore/composables/index.ts @@ -1,20 +1,25 @@ import {ref} from "vue"; import {FormSchema} from "@/types/form"; import {ElTag} from "element-plus"; +import {EmbedStoreApi} from "@/api/new-ai/embed-store"; export enum ProviderEnum { Redis = 'REDIS', PgVector = 'PGVECTOR', Milvus = 'MILVUS', } - - +export const ProviderConst = [ + { label: 'Redis', value: ProviderEnum.Redis }, + { label: 'PgVector', value: ProviderEnum.PgVector }, + { label: 'Milvus', value: ProviderEnum.Milvus }, +]; export default function () { const ProviderConst = [ { label: 'Redis', value: ProviderEnum.Redis }, { label: 'PgVector', value: ProviderEnum.PgVector }, { label: 'Milvus', value: ProviderEnum.Milvus }, ]; + function getProviderLabel(value: any) { const arr = ProviderConst.filter((i) => i.value === value); if (arr === undefined || arr.length === 0) { @@ -22,6 +27,7 @@ export default function () { } return arr[0].label; } + const shema = ref([ { label: '模型名称', @@ -32,6 +38,7 @@ export default function () { }, } ]) + const columns = ref([ { label: '数据库别名', @@ -59,7 +66,7 @@ export default function () { label: '向量纬度', field: 'dimension', align: 'center', - width: '80', + width: '100', render(row) { return h( ElTag, @@ -76,7 +83,6 @@ export default function () { label: '数据库地址', field: 'host', align: 'center', - width: '110', }, { label: '数据库端口', @@ -85,32 +91,46 @@ export default function () { width: '100', }, { - label: '数据库用户名', - field: 'username', + label: '数据库名称', + field: 'database', align: 'center', }, - { - label: '数据库密码', - field: 'password', - align: 'center', - }, - { - label: '数据库名', - field: 'databaseName', - align: 'center', - }, - { - label: '表名称', - field: 'tableName', - align: 'center', - }, - ]) + ]); + const tableData = ref([]) + const editRef = ref() + const searchParams = ref({}) + + // 加载数据 + const loadData = async () => { + try { + const res = await EmbedStoreApi.getEmbedStorePage(searchParams.value); + tableData.value = res.data.list; + } catch (error) { + console.error('Failed to load embed stores:', error); + } + } + + // 打开编辑对话框 + const open = () => { + editRef.value.show({}); + } + + // 处理搜索 + const handleSearch = (values: any) => { + searchParams.value = values; + loadData(); + } + return { - ProviderConst, - getProviderLabel, shema, columns, - tableData + tableData, + editRef, + open, + loadData, + handleSearch, + ProviderConst, + getProviderLabel } } diff --git a/src/views/ai/model/embedStore/edit.vue b/src/views/ai/model/embedStore/edit.vue new file mode 100644 index 0000000..e0abcc8 --- /dev/null +++ b/src/views/ai/model/embedStore/edit.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/src/views/ai/model/embedStore/index.vue b/src/views/ai/model/embedStore/index.vue index aedef94..1cb17e9 100644 --- a/src/views/ai/model/embedStore/index.vue +++ b/src/views/ai/model/embedStore/index.vue @@ -1,13 +1,21 @@ diff --git a/src/views/ai/model/embedding/composables/index.ts b/src/views/ai/model/embedding/composables/index.ts index 23a9d75..a6b14dd 100644 --- a/src/views/ai/model/embedding/composables/index.ts +++ b/src/views/ai/model/embedding/composables/index.ts @@ -1,12 +1,18 @@ -import {ElTag} from "element-plus"; -import {ref} from "vue"; +import {ref, watch} from "vue"; import {ProviderEnum} from "@/views/ai/model/chatModel/composables/provider"; +import {ModelApi} from "@/api/new-ai/model"; +import {ElTag, ElMessageBox as dialog, ElMessage as message} from "element-plus"; +import { ModelTypeEnum } from "../../chatModel/composables/consts"; + export default function () { - const formData = ref({ - provider: ProviderEnum.OPENAI - }) const editRef = ref() + const formData = ref({ + provider: ProviderEnum.OPENAI, + type: ModelTypeEnum.EMBEDDING + }); + const tableData = ref([]) + const baseColumns = [ { label: '模型别名', @@ -19,7 +25,7 @@ export default function () { }, { label: '向量纬度', - field: 'dimension', + field: 'dimension', align: 'center', width: '100', render(row) { @@ -41,17 +47,60 @@ export default function () { { label: 'Base Url', field: 'baseUrl', - }, + }, {label: '操作', field: 'action', width: 150} ]; - const tableData = ref([]) + + // 加载数据 + const loadData = async () => { + try { + const res = await ModelApi.getModelList({ provider: formData.value.provider, type: ModelTypeEnum.EMBEDDING }); + tableData.value = res; + } catch (error) { + console.error('Failed to load embedding models:', error); + } + } + + // 监听供应商变化 + watch(() => formData.value.provider, () => { + loadData(); + }, { immediate: true }); + const open = () => { - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.EMBEDDING}); + } + function handleEdit(record: any) { + editRef.value.show(record); + } + + async function reloadTable() { + await loadData(); + } + + async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }).then(async () => { + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } + }).catch(() => { + }); } return { baseColumns, tableData, formData, editRef, - open + open, + loadData, + handleDel, + handleEdit } } diff --git a/src/views/ai/model/embedding/edit.vue b/src/views/ai/model/embedding/edit.vue index c9c3be4..853b827 100644 --- a/src/views/ai/model/embedding/edit.vue +++ b/src/views/ai/model/embedding/edit.vue @@ -1,25 +1,59 @@ diff --git a/src/views/ai/model/embedding/index.vue b/src/views/ai/model/embedding/index.vue index f510bca..aaed469 100644 --- a/src/views/ai/model/embedding/index.vue +++ b/src/views/ai/model/embedding/index.vue @@ -1,11 +1,15 @@ diff --git a/src/views/ai/model/image/composables/index.ts b/src/views/ai/model/image/composables/index.ts index 4d4689e..d7550e1 100644 --- a/src/views/ai/model/image/composables/index.ts +++ b/src/views/ai/model/image/composables/index.ts @@ -1,51 +1,55 @@ +import {computed, nextTick, ref, watch} from "vue"; import {ProviderEnum} from "@/views/ai/model/image/composables/consts"; +import {ModelApi} from "@/api/new-ai/model"; +import { ModelTypeEnum } from "../../chatModel/composables/consts"; +import {ElTag, ElMessageBox as dialog, ElMessage as message} from "element-plus"; export default function () { - - const editRef= ref() + const editRef = ref() const formData = ref({ provider: ProviderEnum.OPENAI, + type: ModelTypeEnum.TEXT_IMAGE }); const tableData = ref([]) - const baseColumns = [ + const baseColumns = [ { - label: '模型别名', - field: 'name', + label: '模型别名', + field: 'name', }, { - label: '模型版本', - field: 'model', + label: '模型版本', + field: 'model', }, ]; - const openaiColumns = [ + const openaiColumns = [ ...baseColumns, { - label: 'Api Key', - field: 'apiKey', + label: 'Api Key', + field: 'apiKey', }, ]; - const azureOpenaiColumns = [ + const azureOpenaiColumns = [ ...baseColumns, { - label: 'Api Key', - field: 'apiKey', + label: 'Api Key', + field: 'apiKey', }, { - label: 'Endpoint', - field: 'endpoint', + label: 'Endpoint', + field: 'endpoint', }, { - label: 'Deployment Name', - field: 'azureDeploymentName', + label: 'Deployment Name', + field: 'azureDeploymentName', }, ]; - const zhipuColumns = [...baseColumns]; + const zhipuColumns = [...baseColumns]; + function getColumns(provider: string) { - console.log(provider); switch (provider) { case ProviderEnum.OPENAI: { return openaiColumns; @@ -56,21 +60,68 @@ export default function () { case ProviderEnum.ZHIPU: { return zhipuColumns; } + default: { + return baseColumns; + } } - return []; } + const columns = computed(() => { nextTick(); - return getColumns(formData.value.provider) + return [...getColumns(formData.value.provider), {label: '操作', field: 'action', width: 150}] }); + + // 加载数据 + const loadData = async () => { + try { + const res = await ModelApi.getModelList({ provider: formData.value.provider, type: ModelTypeEnum.TEXT_IMAGE }); + tableData.value = res; + } catch (error) { + console.error('Failed to load image models:', error); + } + } + + // 监听供应商变化 + watch(() => formData.value.provider, () => { + loadData(); + }, { immediate: true }); + const open = () => { - editRef.value.show({provider: formData.value.provider}); + editRef.value.show({provider: formData.value.provider, type: ModelTypeEnum.TEXT_IMAGE}); + } + function handleEdit(record: any) { + editRef.value.show(record); + } + + async function reloadTable() { + await loadData(); + } + + async function handleDel(record: any) { + dialog.confirm('确定要删除该模型吗?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }).then(async () => { + try { + await ModelApi.deleteModel(record.id); + await reloadTable(); + message.success('模型删除成功'); + } catch (error) { + console.error('Failed to delete model:', error); + message.error('删除模型失败'); + } + }).catch(() => { + }); } return { columns, tableData, formData, editRef, - open + open, + loadData, + handleDel, + handleEdit } } diff --git a/src/views/ai/model/image/edit.vue b/src/views/ai/model/image/edit.vue index d3b9744..ee9a6ab 100644 --- a/src/views/ai/model/image/edit.vue +++ b/src/views/ai/model/image/edit.vue @@ -1,25 +1,55 @@ - diff --git a/src/views/ai/model/image/index.vue b/src/views/ai/model/image/index.vue index f402948..c55649e 100644 --- a/src/views/ai/model/image/index.vue +++ b/src/views/ai/model/image/index.vue @@ -1,11 +1,16 @@ @@ -51,21 +62,18 @@ const {columns, tableData, formData, editRef, open} = usePage() } .menu { - transition: all .15s; + padding: 10px; + margin-bottom: 10px; + border-radius: 6px; cursor: pointer; - padding: 12px 10px; - border-radius: 5px; - margin-bottom: 20px; - - &.active { - color: #ffffff; - background-color: var(--el-color-primary); - } &:hover { - &:not(&.active) { - background-color: var(--el-color-info-light-7); - } + background: var(--el-fill-color-light); + } + + &.active { + background: var(--el-color-primary-light-9); + color: var(--el-color-primary); } } diff --git a/src/views/knowledge/dataset-form/components/data-cut.vue b/src/views/knowledge/dataset-form/components/data-cut.vue index 6dc7be6..c4c4957 100644 --- a/src/views/knowledge/dataset-form/components/data-cut.vue +++ b/src/views/knowledge/dataset-form/components/data-cut.vue @@ -1,6 +1,17 @@ diff --git a/src/views/knowledge/dataset-form/index.vue b/src/views/knowledge/dataset-form/index.vue index 3938fc3..9bfb21b 100644 --- a/src/views/knowledge/dataset-form/index.vue +++ b/src/views/knowledge/dataset-form/index.vue @@ -1,13 +1,19 @@ - diff --git a/src/views/knowledge/dataset.vue b/src/views/knowledge/dataset.vue index 4614cf3..5cf915a 100644 --- a/src/views/knowledge/dataset.vue +++ b/src/views/knowledge/dataset.vue @@ -1,7 +1,7 @@ -