| | |
| | | <template> |
| | | <div class="container"> |
| | | <Breadcrumb :items="['大模型', '大模型管理']" /> |
| | | <Breadcrumb :items="['大模型', '模型管理']" /> |
| | | |
| | | <a-row :gutter="20" align="stretch"> |
| | | <a-col :span="24"> |
| | | <a-card class="general-card" :title="$t('大模型管理')"> |
| | | <a-card |
| | | class="general-card" |
| | | style="min-height: 130px" |
| | | :title="$t('大模型管理')" |
| | | > |
| | | <a-row justify="space-between"> |
| | | <a-col :span="24"> |
| | | <a-col :span="24" class="table_add_clore" v-if="loading"> |
| | | <a-tabs |
| | | :active-key="activeKey" |
| | | :default-active-key="tabKey" |
| | | type="line" |
| | | :editable="true" |
| | | show-add-button |
| | | @tab-click="changeTabs" |
| | | @add="handleAdd" |
| | | @delete="handleDelete" |
| | | show-add-button |
| | | auto-switch |
| | | > |
| | | <!-- <a-tab-pane key="1" :title="$t('cardList.tab.title.all')">--> |
| | | <!-- <QualityInspection />--> |
| | | <!-- <TheService />--> |
| | | <!-- <RulesPreset />--> |
| | | <!-- </a-tab-pane>--> |
| | | <!-- <a-tab-pane key="2" :title="$t('cardList.tab.title.content')">--> |
| | | <!-- <QualityInspection />--> |
| | | <!-- </a-tab-pane>--> |
| | | <!-- <a-tab-pane key="3" :title="$t('cardList.tab.title.service')">--> |
| | | <!-- <TheService />--> |
| | | <!-- </a-tab-pane>--> |
| | | <!-- <a-tab-pane key="4" :title="$t('cardList.tab.title.preset')">--> |
| | | <!-- <RulesPreset />--> |
| | | <!-- </a-tab-pane>--> |
| | | |
| | | <a-tab-pane |
| | | v-for="(item, index) of data" |
| | | :key="item.key" |
| | | :title="item.title" |
| | | :closable="index >= 4" |
| | | v-for="(item, index) in tabData" |
| | | :key="index" |
| | | :title="index" |
| | | :closable="Object.keys(tabData).length >= 4" |
| | | > |
| | | <QualityInspection v-if="activeKey === 1" /> |
| | | <TheService v-if="activeKey === 1" /> |
| | | <RulesPreset v-if="activeKey === 1" /> |
| | | <a-scrollbar |
| | | style="height: calc(100vh - 320px); overflow: auto" |
| | | > |
| | | <div class="card_content"> |
| | | <div class="card-wrap content_top"> |
| | | <div class="card_wrap_box"> |
| | | <div class="card_wrap_box_img"> |
| | | <img |
| | | :style="{ |
| | | width: '100%', |
| | | }" |
| | | alt="暂无图片" |
| | | :src="item.logo ? httpUrl + item.logo : pdfImg" |
| | | /> |
| | | </div> |
| | | <a-card :bordered="false" hoverable> |
| | | <div class="arco-card-body-content"> |
| | | <div |
| | | class="arco-card-body-content-title" |
| | | style="word-wrap: break-word" |
| | | > |
| | | {{ item.tags }} |
| | | </div> |
| | | <!-- <div class="arco-card-body-content-dec">{{ |
| | | list.type |
| | | }}</div> --> |
| | | </div> |
| | | </a-card> |
| | | <div class="arco-btn-group"> |
| | | <a-space class="btn-group"> |
| | | <div class="create_time"> |
| | | 创建时间: |
| | | <span> {{ item.create_date }} </span> |
| | | </div> |
| | | |
| | | <QualityInspection v-if="activeKey === 2" /> |
| | | <!-- <editModel></editModel> --> |
| | | <a-button @click="handleDeleteModel(item, 1)"> |
| | | 删除 |
| | | </a-button> |
| | | <a-button |
| | | type="primary" |
| | | @click="handleEditModel(item, 1)" |
| | | > |
| | | 编辑 |
| | | </a-button> |
| | | </a-space> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="subset_list"> |
| | | <div |
| | | class="card-wrap" |
| | | v-for="(list, index) of item.llm" |
| | | :key="index" |
| | | > |
| | | <div class="card_wrap_box"> |
| | | <div class="card_wrap_box_img"> |
| | | <img |
| | | :style="{ |
| | | width: '100%', |
| | | }" |
| | | alt="暂无图片" |
| | | :src="list.logo ? httpUrl + list.logo : pdfImg" |
| | | /> |
| | | </div> |
| | | <a-card :bordered="false" hoverable> |
| | | <div class="arco-card-body-content"> |
| | | <div class="arco-card-body-content-title"> |
| | | {{ list.name }} |
| | | </div> |
| | | <div class="arco-card-body-content-dec">{{ |
| | | list.type |
| | | }}</div> |
| | | </div> |
| | | </a-card> |
| | | <div class="arco-btn-group"> |
| | | <a-space class="btn-group"> |
| | | <div class="create_time_list"> |
| | | 创建时间: |
| | | <span> {{ list.create_date }} </span> |
| | | </div> |
| | | <a-button @click="handleDeleteModel(list)"> |
| | | 删除 |
| | | </a-button> |
| | | <!-- <a-button |
| | | type="primary" |
| | | @click="handleEditModel(list)" |
| | | > |
| | | 编辑 |
| | | </a-button> --> |
| | | |
| | | <TheService v-if="activeKey === 3" /> |
| | | <RulesPreset v-if="activeKey === 4" /> |
| | | <CustomSettings v-if="activeKey > 4" /> |
| | | <!-- <editModel></editModel> --> |
| | | </a-space> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </a-scrollbar> |
| | | </a-tab-pane> |
| | | </a-tabs> |
| | | </a-col> |
| | | <div> </div> |
| | | <a-input-search |
| | | :placeholder="$t('cardList.searchInput.placeholder')" |
| | | style="width: 240px; position: absolute; top: 60px; right: 20px" |
| | | /> |
| | | <div class="box_right" v-if="Object.keys(tabData).length > 0"> |
| | | <!-- <div class="search_input"> |
| | | <a-input-search |
| | | :placeholder="$t('cardList.searchInput.placeholder')" |
| | | style="width: 240px" |
| | | /> |
| | | </div> --> |
| | | <div> |
| | | <a-button |
| | | type="primary" |
| | | @click="handleAddModel" |
| | | :disabled="addBtn" |
| | | > |
| | | <template #icon> |
| | | <icon-plus /> |
| | | </template> |
| | | 添加 |
| | | </a-button> |
| | | </div> |
| | | </div> |
| | | </a-row> |
| | | </a-card> |
| | | </a-col> |
| | | </a-row> |
| | | |
| | | <a-modal v-model:visible="visible" @Ok="handleOk" @cancel="handleCancel"> |
| | | <template #title> 添加框架 </template> |
| | | <a-form |
| | | ref="formRef" |
| | | :size="form.size" |
| | | :model="form" |
| | | @submit="handleSubmit" |
| | | > |
| | | <a-form-item |
| | | field="name" |
| | | label="标签名" |
| | | :rules="[ |
| | | { required: true, message: '不能为空' }, |
| | | { minLength: 1, message: '至少一个字符' }, |
| | | ]" |
| | | :validate-trigger="['change', 'input']" |
| | | > |
| | | <a-input v-model="form.name" placeholder="请输入标签名" /> |
| | | </a-form-item> |
| | | </a-form> |
| | | </a-modal> |
| | | <!-- 添加模型 --> |
| | | <addPageModel |
| | | v-model:show="show" |
| | | :task_id="task_id" |
| | | :type="modelType" |
| | | :title="title" |
| | | :editList="editList" |
| | | @refresh-parent="refreshParentMethod" |
| | | v-if="show" |
| | | ></addPageModel> |
| | | <!-- 添加tab模式 --> |
| | | <addTableName |
| | | v-model:tabShow="tabShow" |
| | | :nameList="editList" |
| | | :title="title" |
| | | @refresh-parent="refreshParentMethod" |
| | | v-if="tabShow" |
| | | ></addTableName> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, reactive, nextTick } from 'vue'; |
| | | import editModel from '@/views/dmx/model/components/editModel.vue'; |
| | | import addPageModel from './components/addPageModel.vue'; |
| | | import addTableName from './components/addTableName.vue'; |
| | | import { |
| | | modelList, |
| | | modelmyLlms, |
| | | deleteLlm, |
| | | deleteLlmFactory, |
| | | getFactoryDetail, |
| | | } from '@/api/model'; |
| | | import { Modal, Message } from '@arco-design/web-vue'; |
| | | import { userModelState } from '@/store'; |
| | | |
| | | import QualityInspection from './components/quality-inspection.vue'; |
| | | import TheService from './components/the-service.vue'; |
| | | import RulesPreset from './components/rules-preset.vue'; |
| | | import CustomSettings from './components/custom-settings.vue'; |
| | | import pdfImg from '@/assets/images/icon-chart.png'; |
| | | |
| | | const modelStore = userModelState(); |
| | | let count = 5; |
| | | const addBtn = ref(false); |
| | | const activeKey = ref(1); |
| | | const data = ref([ |
| | | { |
| | | key: 1, |
| | | title: '全部', |
| | | title: 'key', |
| | | content: 'Content of Tab Panel 1', |
| | | }, |
| | | { |
| | | key: 2, |
| | | title: '内容质检', |
| | | title: 'Ollama', |
| | | content: 'Content of Tab Panel 2', |
| | | }, |
| | | { |
| | | key: 3, |
| | | title: '开通服务', |
| | | title: 'Xinference', |
| | | content: 'Content of Tab Panel 3', |
| | | }, |
| | | { |
| | | key: 4, |
| | | title: '规则预置', |
| | | content: 'Content of Tab Panel 4', |
| | | }, |
| | | ]); |
| | | const changeTabs = (val) => { |
| | | activeKey.value = val; |
| | | } |
| | | const handleAdd = () => { |
| | | visible.value = true; |
| | | const tabData = ref({ |
| | | key: { |
| | | tags: '添加key', |
| | | id: 1, |
| | | live: 1, |
| | | }, |
| | | }); |
| | | |
| | | const isDeleteDialogVisible = ref(false); //删除提醒 |
| | | |
| | | const modalList = ref({}); |
| | | const tabKey = ref('key'); |
| | | const changeTabs = async (val) => { |
| | | tabKey.value = val; |
| | | await getFactory(); |
| | | }; |
| | | const handleDelete = (key: any) => { |
| | | data.value = data.value.filter((item) => item.key !== key); |
| | | |
| | | const httpUrl = modelStore.hrefUrl; |
| | | const show = ref(false); |
| | | const tabShow = ref(false); |
| | | const title = ref('添加模式'); |
| | | const task_id = ref(1); |
| | | const modelType = ref(1); |
| | | const handleAdd = () => { |
| | | tabShow.value = true; |
| | | title.value = '添加模型'; |
| | | editList.value.llm_factory = tabKey.value; |
| | | }; |
| | | const editList = ref<any>({ llm_factory: '' }); |
| | | //增加模型子类 |
| | | const handleAddModel = () => { |
| | | modelType.value = 2; |
| | | editList.value = [{ llm_factory: '' }]; |
| | | editList.value.llm_factory = tabKey.value; |
| | | show.value = true; |
| | | title.value = '添加模式'; |
| | | }; |
| | | //编辑模型子类 |
| | | const handleEditModel = (val, type) => { |
| | | if (type == 1) { |
| | | tabShow.value = true; |
| | | editList.value = val; |
| | | title.value = '编辑模型'; |
| | | editList.value.llm_factory = tabKey.value; |
| | | } else { |
| | | modelType.value = 2; |
| | | task_id.value = val.id; |
| | | show.value = true; |
| | | title.value = '编辑'; |
| | | editList.value = val; |
| | | editList.value.llm_factory = tabKey.value; |
| | | } |
| | | }; |
| | | |
| | | //删除模型 |
| | | const handleDeleteModel = (val, type) => { |
| | | const factory = tabKey.value; |
| | | if (type == 1) { |
| | | handleDelete(val); |
| | | } else { |
| | | Modal.confirm({ |
| | | title: '警告', |
| | | content: '确认删除吗', |
| | | okText: '确定', |
| | | cancelText: '取消', |
| | | onOk: async () => { |
| | | const res = await deleteLlm({ |
| | | llm_factory: tabKey.value, |
| | | llm_name: val.name, |
| | | }); |
| | | |
| | | if ((res as any).code == 0) { |
| | | queryModel(); |
| | | tabKey.value = factory; |
| | | } else { |
| | | } |
| | | }, |
| | | onCancel: () => {}, |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | //父级模型 |
| | | const handleDelete = async (key: any) => { |
| | | if (tabData.value[key] && tabData.value[key].llm.length > 0) { |
| | | Message.error('请先删除子模型'); |
| | | return; |
| | | } |
| | | |
| | | const res = await deleteLlmFactory(tabKey.value); |
| | | if ((res as any).code == 200) { |
| | | // Reflect.deleteProperty(tabData.value, tabKey.value); |
| | | queryModel(); |
| | | } |
| | | }; |
| | | |
| | | const visible = ref(false); |
| | | const formRef = ref(null); |
| | | const formRef = ref(); |
| | | |
| | | const form = reactive({ |
| | | size: 'medium', |
| | | name: '', |
| | | }); |
| | | const handleOk = () => { |
| | | count += 1; |
| | | formRef.value.validate().then((res) => { |
| | | formRef.value?.validate().then((res) => { |
| | | if (res) { |
| | | return; |
| | | } |
| | |
| | | }); |
| | | nextTick(() => { |
| | | visible.value = true; |
| | | |
| | | }) |
| | | }); |
| | | return false; |
| | | }; |
| | | const handleCancel = () => { |
| | | formRef.value.resetFields(); |
| | | visible.value = false; |
| | | |
| | | //获取模型列表 |
| | | const loading = ref(false); |
| | | const queryModel = async () => { |
| | | const res = await modelmyLlms(); |
| | | modalList.value = res.data; |
| | | loading.value = true; |
| | | tabData.value = Object.assign({}, tabData.value, res.data); |
| | | tabData.value = filterObject(tabData.value, 1); |
| | | |
| | | tabKey.value = Object.keys(tabData.value)[0]; |
| | | await getFactory(); |
| | | }; |
| | | const handleSubmit = ({ values, errors }) => { |
| | | this.$refs.formRef.validate().then((res, a, b) => { |
| | | debugger; |
| | | console.log('values', values); |
| | | queryModel(); |
| | | //返回满足条件的对象 |
| | | const filterObject = (obj, threshold) => { |
| | | return Object.keys(obj) |
| | | .filter((key) => obj[key].added == 1) |
| | | .reduce((result, key) => { |
| | | result[key] = obj[key]; |
| | | return result; |
| | | }, {}); |
| | | }; |
| | | |
| | | const refreshParentMethod = () => { |
| | | queryModel(); |
| | | // 这里执行需要的操作 |
| | | }; |
| | | |
| | | const getFactory = async () => { |
| | | const { data } = await getFactoryDetail({ |
| | | factory_name: tabKey.value, |
| | | }); |
| | | |
| | | if (data.set_type == 2) { |
| | | addBtn.value = true; |
| | | } else { |
| | | addBtn.value = false; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | :deep(.arco-list-col) { |
| | | display: flex; |
| | | flex-direction: row; |
| | |
| | | } |
| | | } |
| | | } |
| | | :deep(.arco-tabs-nav-tab) { |
| | | flex: none; |
| | | width: 60%; |
| | | } |
| | | .table_add_clore { |
| | | :deep(.arco-tabs-nav-add-btn .arco-icon-hover::before) { |
| | | top: 50%; |
| | | left: 50%; |
| | | width: 20px; |
| | | height: 20px; |
| | | transform: translate(-50%, -50%); |
| | | border-radius: 0; |
| | | background-color: #165dff; |
| | | } |
| | | |
| | | :deep(.arco-tabs-nav-add-btn .arco-icon-hover .arco-icon) { |
| | | color: #fff; |
| | | } |
| | | // :deep(.arco-tabs-nav) { |
| | | // max-width: 60%; |
| | | // } |
| | | |
| | | :deep(.arco-icon-hover::before) { |
| | | top: 50%; |
| | | left: 50%; |
| | | width: 20px; |
| | | height: 20px; |
| | | transform: translate(-50%, -50%); |
| | | // border-radius: 0; |
| | | // background-color: #eee; |
| | | } |
| | | :deep(.arco-tabs-tab-close-btn) { |
| | | display: none; |
| | | } |
| | | :deep(.arco-tabs-tab-close-btn .arco-icon) { |
| | | color: #666; |
| | | } |
| | | } |
| | | .box_right { |
| | | position: absolute; |
| | | top: 60px; |
| | | right: 20px; |
| | | display: flex; |
| | | .search_input { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | .arco-card-body-content { |
| | | .arco-card-body-content-title { |
| | | font-size: 16px; |
| | | color: #333; |
| | | margin-bottom: 10px; |
| | | font-weight: 400; |
| | | } |
| | | } |
| | | .content_top { |
| | | border-bottom: 1px solid #f0f0f0 !important; |
| | | } |
| | | .card_content { |
| | | .card_wrap_box_img { |
| | | // min-height: 200px; |
| | | height: 200px; |
| | | width: 100%; |
| | | img { |
| | | width: 100%; /* 或者其他固定宽度 */ |
| | | height: 100%; /* 或者其他固定高度 */ |
| | | object-fit: cover; /* 不会变形,但可能裁剪图片 */ |
| | | } |
| | | } |
| | | .subset_list { |
| | | display: flex; |
| | | flex-direction: row; |
| | | flex-wrap: wrap; |
| | | } |
| | | .card_wrap_box { |
| | | // position: relative; |
| | | .arco-btn-group { |
| | | position: absolute; |
| | | right: 10px; |
| | | top: 87%; |
| | | .create_time { |
| | | text-align: left; |
| | | width: 155px; |
| | | } |
| | | .create_time_list { |
| | | text-align: left; |
| | | width: 223px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .card-wrap { |
| | | width: 320px; |
| | | height: 350px; |
| | | margin: 20px 30px; |
| | | transition: all 0.3s; |
| | | border: 1px solid var(--color-neutral-3); |
| | | border-radius: 4px; |
| | | position: relative; |
| | | &:hover { |
| | | transform: translateY(-4px); |
| | | // box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | :deep(.arco-card) { |
| | | height: 100%; |
| | | border-radius: 4px; |
| | | .arco-card-body { |
| | | height: 100%; |
| | | .arco-space { |
| | | width: 100%; |
| | | height: 100%; |
| | | .arco-space-item { |
| | | height: 100%; |
| | | &:last-child { |
| | | flex: 1; |
| | | } |
| | | .arco-card-meta { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-flow: column; |
| | | .arco-card-meta-content { |
| | | flex: 1; |
| | | .arco-card-meta-description { |
| | | margin-top: 8px; |
| | | color: rgb(var(--gray-6)); |
| | | line-height: 20px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | .arco-card-meta-footer { |
| | | margin-top: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | :deep(.arco-card-meta-title) { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | // To prevent the shaking |
| | | line-height: 28px; |
| | | } |
| | | :deep(.arco-skeleton-line) { |
| | | &:last-child { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | } |
| | | } |
| | | </style> |