diff --git a/charts/deployment.yaml b/charts/deployment.yaml index 77b8c73..d7c9ba2 100644 --- a/charts/deployment.yaml +++ b/charts/deployment.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: datatunerx-ui - image: release.daocloud.io/datatunerx/datatunerx-ui:v0.0.1-dev-abf7e99 + image: release.daocloud.io/datatunerx/datatunerx-ui:v0.0.1-dev-fbada94 env: - name: 'API_URL' value: "https://10.33.1.10:6443" diff --git a/doc/dak.md b/doc/dak.md deleted file mode 100644 index ce3c23a..0000000 --- a/doc/dak.md +++ /dev/null @@ -1,17 +0,0 @@ -# TODO - -## useQueryTable - -## Docker Image - -## Github Check - -## CI - -## unplugin-auto-import - -## I18n - -## 文件上传组件 - -## tailwind CSS diff --git a/samples/rayservice.yaml b/samples/rayservice.yaml index 36ccfde..ec8718c 100644 --- a/samples/rayservice.yaml +++ b/samples/rayservice.yaml @@ -1,7 +1,7 @@ apiVersion: ray.io/v1 kind: RayService metadata: - name: finetune-sample5 + name: finetune-sampleasdf namespace: datatunerx-dev labels: createdByFrontend: "true" diff --git a/src/App.vue b/src/App.vue index a14d0c3..f822d54 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,8 @@ + + diff --git a/src/api/ray-service.ts b/src/api/ray-service.ts index e48e00a..7419d97 100644 --- a/src/api/ray-service.ts +++ b/src/api/ray-service.ts @@ -176,3 +176,8 @@ const apiVersion = 'ray.io/v1'; const kind = 'RayService'; export const rayServiceClient = new K8sClient(apiVersion, kind); + +export interface InferenceApplication { + name: string, + llmCheckpoint: string, +} diff --git a/src/components/AnakinHeader.vue b/src/components/AnakinHeader.vue index 758641c..417ab71 100644 --- a/src/components/AnakinHeader.vue +++ b/src/components/AnakinHeader.vue @@ -1,33 +1,21 @@ @@ -138,16 +141,6 @@ $datatunerx-header-color: var(--dao-navigation-090); color: $datatunerx-header-color; background-color: $datatunerx-header-background; - &__product { - width: 210px; - /* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */ - font-family: PingFang SC-Bold, PingFang SC; - font-size: 26px; - font-weight: bold; - color: #fff; - text-align: center; - } - &__namespace { margin-left: 30px; font-size: 16px; diff --git a/src/components/AnakinNav.vue b/src/components/AnakinNav.vue index 697edd3..5fb1797 100644 --- a/src/components/AnakinNav.vue +++ b/src/components/AnakinNav.vue @@ -1,32 +1,50 @@ diff --git a/src/locales/en-US/views/InferenceApplication.json b/src/locales/en-US/views/InferenceApplication.json index a6ea144..2aa0d45 100644 --- a/src/locales/en-US/views/InferenceApplication.json +++ b/src/locales/en-US/views/InferenceApplication.json @@ -36,5 +36,13 @@ "delete":{ "header": "Delete Inference Application", "content": "Are you sure you want to delete this inference application?" + }, + + "create":{ + "header": "Create Inference Application", + "name": "Name", + "llmCheckpoint": "Model", + "createSuccess": "Inference application created successfully", + "createFailed": "Failed to create inference application" } } diff --git a/src/locales/zh-CN/views/InferenceApplication.json b/src/locales/zh-CN/views/InferenceApplication.json index b29efcb..64d6dfc 100644 --- a/src/locales/zh-CN/views/InferenceApplication.json +++ b/src/locales/zh-CN/views/InferenceApplication.json @@ -36,5 +36,12 @@ "delete": { "header": "删除推理应用", "content": "确定要删除推理应用吗?" + }, + "create": { + "header": "创建推理应用", + "name": "名称", + "llmCheckpoint": "模型", + "createSuccess": "推理应用创建成功", + "createFailed": "推理应用创建失败" } } diff --git a/src/plugins/axios/client.ts b/src/plugins/axios/client.ts index 41e8c9b..c06495e 100644 --- a/src/plugins/axios/client.ts +++ b/src/plugins/axios/client.ts @@ -1,5 +1,5 @@ import { DeleteOptions, ListMeta } from 'kubernetes-types/meta/v1'; -import { AxiosRequestConfig } from 'axios'; +import { AxiosRequestConfig, AxiosResponse } from 'axios'; import { OpPatch } from 'json-patch'; import httpClient from './index'; @@ -29,7 +29,7 @@ export class K8sClient { list(namespace: string, config?: AxiosRequestConfig) { const path = this.getPath(namespace); - return this.httpClient.get>(path, config); + return this.httpClient.get, AxiosResponse>, D>(path, config); } create(namespace: string, data: T) { diff --git a/src/router/index.ts b/src/router/index.ts index df31119..c647b77 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -3,11 +3,11 @@ import { createRouter, type RouteRecordRaw, type RouterHistory, type Router, createWebHistory, } from 'vue-router'; import Guards from '@/router/guards/index'; +import RouterContent from '@/layout/RouterContent.vue'; +import ConsoleContainer from '@/layout/console-container.vue'; import Login from '@/views/login/Login.vue'; -import RouterContent from '@/views/RouterContent.vue'; - import DatasetList from '@/views/dataset/DatasetList.vue'; import DatasetCreate from '@/views/dataset/DatasetCreate.vue'; import DatasetDetail from '@/views/dataset/DatasetDetail.vue'; @@ -31,108 +31,125 @@ const routes: Array = [ redirect: { name: 'Login', }, + }, + { + path: '/login', + name: 'Login', + component: Login, + }, + { + path: '/ns', + name: 'ConsoleContainer', + component: ConsoleContainer, children: [ { - path: 'login', - name: 'Login', - component: Login, - }, - { - path: 'fine-tune', + path: ':ns', component: RouterContent, children: [ { - path: '', - name: 'FinetuneExperimentList', - component: FinetuneExperimentList, - }, - { - path: 'create', - name: 'FinetuneExperimentCreate', - component: FinetuneExperimentCreate, - }, - { - path: ':name', - name: 'FinetuneExperimentDetail', - component: FinetuneExperimentDetail, - }, - { - path: ':name/job/:jobName', - name: 'FinetuneExperimentJobDetail', - component: FinetuneExperimentJobDetail, - }, - ], + path: 'fine-tune', + component: RouterContent, + children: [ + { + path: '', + name: 'FinetuneExperimentList', + component: FinetuneExperimentList, + }, + { + path: 'create', + name: 'FinetuneExperimentCreate', + component: FinetuneExperimentCreate, + }, + { + path: ':name', + name: 'FinetuneExperimentDetail', + component: FinetuneExperimentDetail, + }, + { + path: ':name/job/:jobName', + name: 'FinetuneExperimentJobDetail', + component: FinetuneExperimentJobDetail, + }, + ], - }, - { - path: 'finetune-registry', - component: RouterContent, - children: [ - { - path: '', - name: 'ModelRegistryList', - component: ModelRegistryList, - }, - ], - }, - { - path: 'datasets', - component: RouterContent, - children: [ - { - path: '', - name: 'DatasetList', - component: DatasetList, }, { - path: 'create', - name: 'DatasetCreate', - component: DatasetCreate, + path: 'finetune-registry', + component: RouterContent, + children: [ + { + path: '', + name: 'ModelRegistryList', + component: ModelRegistryList, + }, + ], }, { - path: ':name', - name: 'DatasetDetail', - component: DatasetDetail, + path: 'datasets', + component: RouterContent, + children: [ + { + path: '', + name: 'DatasetList', + component: DatasetList, + }, + { + path: 'create', + name: 'DatasetCreate', + component: DatasetCreate, + }, + { + path: ':name', + name: 'DatasetDetail', + component: DatasetDetail, + }, + ], }, - ], - }, - { - path: 'hyperparameter', - component: RouterContent, - children: [ { - path: '', - name: 'HyperparameterList', - component: HyperparameterList, - }, - { - path: 'create', - name: 'HyperparameterCreate', - component: HyperparameterCreate, - }, - { - path: ':name', - name: 'HyperparameterDetail', - component: HyperparameterDetail, - }, - ], + path: 'hyperparameter', + component: RouterContent, + children: [ + { + path: '', + name: 'HyperparameterList', + component: HyperparameterList, + }, + { + path: 'create', + name: 'HyperparameterCreate', + component: HyperparameterCreate, + }, + { + path: ':name', + name: 'HyperparameterDetail', + component: HyperparameterDetail, + }, + ], - }, + }, - { - path: 'inference-application', - component: RouterContent, - children: [ { - path: '', - name: 'InferenceApplicationList', - component: InferenceApplicationList, + path: 'inference-application', + component: RouterContent, + children: [ + { + path: '', + name: 'InferenceApplicationList', + component: InferenceApplicationList, + }, + ], }, + ], }, - ], }, + { + path: '/:pathMatch(.*)', + redirect: { + name: 'Login', + }, + }, ]; let router: Router | null = null; diff --git a/src/stores/experiment.ts b/src/stores/experiment.ts index 2cfa703..20b766e 100644 --- a/src/stores/experiment.ts +++ b/src/stores/experiment.ts @@ -90,6 +90,7 @@ export const useExperimentStore = defineStore('experiment', { return stream?.read().then((result) => this.processText(result, buffer, utf8Decoder, stream)); }) .catch(() => { + /* eslint-disable no-console */ console.log('Error! Retrying in 5 seconds...'); setTimeout(() => this.streamUpdates(namespace, lastResourceVersion), 5000); }); @@ -124,9 +125,10 @@ export const useExperimentStore = defineStore('experiment', { (experiment) => experiment.metadata?.name !== event.object.metadata.name, ); } - + /* eslint-disable no-console */ console.log(event.type, event.object.metadata.name); } catch (error) { + /* eslint-disable no-console */ console.log('Error while parsing', chunk, '\n', error); } }); diff --git a/src/stores/namespace.ts b/src/stores/namespace.ts index 6b365e7..aa9da4a 100644 --- a/src/stores/namespace.ts +++ b/src/stores/namespace.ts @@ -27,6 +27,7 @@ export const useNamespaceStore = defineStore('namespace', { nError(i18n.t('common.fetchFailed'), error); } }, + setNamespace(val: string) { localStorage.setItem(NAMESPACE, val); this.namespace = val; diff --git a/src/stores/user.ts b/src/stores/user.ts index 6e72fd0..3f0d90b 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -1,8 +1,5 @@ import { defineStore } from 'pinia'; import { TOKEN } from '@/utils/constant'; -import { useNamespaceStore } from '@/stores/namespace'; -import { i18n } from '@/plugins/vue-i18n'; -import { nError } from '@/utils/useNoty'; import isEmpty from 'lodash/isEmpty'; export const useUserStore = defineStore('user', { @@ -19,16 +16,6 @@ export const useUserStore = defineStore('user', { return !isEmpty(this.token); }, - async initView() { - const namespaceStore = useNamespaceStore(); - - try { - await namespaceStore.fetchNamespace(); - } catch (error) { - nError(i18n.t('common.fetchFailed'), error); - } - }, - async login(val: string) { this.setToken(val); }, diff --git a/src/views/dataset/DatasetCreate.vue b/src/views/dataset/DatasetCreate.vue index 910bb81..c9babea 100644 --- a/src/views/dataset/DatasetCreate.vue +++ b/src/views/dataset/DatasetCreate.vue @@ -22,7 +22,7 @@ import { useDataset } from './composition/dataset'; const { t } = useI18n(); -const namespaceStore = useNamespaceStore(); +const { namespace } = storeToRefs(useNamespaceStore()); const router = useRouter(); const { query } = useRoute(); @@ -34,7 +34,7 @@ const state = reactive({ }); const fetchPlugins = () => { - dataPluginClient.list(namespaceStore.namespace).then(({ data }) => { + dataPluginClient.list(namespace.value).then(({ data }) => { state.plugins = data.items; }); }; @@ -133,7 +133,7 @@ const duplicateSubset = useFieldError('spec.datasetMetadata.datasetInfo.subsets' onMounted(() => { if (isUpdate.value) { - fetchDataset(namespaceStore.namespace, query.name as string).then(() => { + fetchDataset(namespace.value, query.name as string).then(() => { resetForm({ values: dataset.value }); }); } @@ -203,25 +203,24 @@ const hasMarginBottom = computed(() => { const toList = () => { router.push({ name: 'DatasetList', + params: { + ns: namespace.value, + }, }); }; -// const onSubmit = () => { -// validate().then((valid) => { -// console.log('valid', valid); -// }); -// }; +watch(namespace, toList); const onSubmit = handleSubmit(async (values) => { try { if (isUpdate.value && values.metadata?.name) { await datasetClient.update( - namespaceStore.namespace, + namespace.value, values.metadata?.name, convertDatasetForPost(values), ); } else { - await datasetClient.create(namespaceStore.namespace, convertDatasetForPost(values)); + await datasetClient.create(namespace.value, convertDatasetForPost(values)); } nSuccess( t('common.notySuccess', { diff --git a/src/views/dataset/DatasetDetail.vue b/src/views/dataset/DatasetDetail.vue index 15f961f..3343b7c 100644 --- a/src/views/dataset/DatasetDetail.vue +++ b/src/views/dataset/DatasetDetail.vue @@ -104,7 +104,10 @@ const onEdit = () => { }; const toList = () => { - router.push({ name: 'DatasetList' }); + router.push({ + name: 'DatasetList', + params: { ns: namespace.value }, + }); }; watch(namespace, toList); diff --git a/src/views/dataset/DatasetList.vue b/src/views/dataset/DatasetList.vue index fbc8085..2963865 100644 --- a/src/views/dataset/DatasetList.vue +++ b/src/views/dataset/DatasetList.vue @@ -1,6 +1,6 @@ diff --git a/src/views/hyperparameter/HyperparameterList.vue b/src/views/hyperparameter/HyperparameterList.vue index 5d8ab31..2565792 100644 --- a/src/views/hyperparameter/HyperparameterList.vue +++ b/src/views/hyperparameter/HyperparameterList.vue @@ -17,6 +17,19 @@ const { t } = useI18n(); const router = useRouter(); const { namespace } = storeToRefs(useNamespaceStore()); +const searchOptions = [ + { + key: 'metadata.name', + label: t('views.Hyperparameter.name'), + single: true, + }, + { + key: 'spec.objective.type', + label: t('views.Hyperparameter.fineTuningType'), + single: true, + }, +]; + const columns = defineColumns([ { id: 'name', @@ -34,6 +47,7 @@ const columns = defineColumns([ { id: 'createAt', header: t('common.createTime'), + sortable: true, }, { id: 'action', @@ -43,12 +57,11 @@ const columns = defineColumns([ ]); const { - isLoading, pagedData, page, pageSize, total, handleRefresh, search, -} = useQueryTable(async () => hyperparameterClient.list(namespace.value)); + isLoading, pagedData, page, pageSize, total, handleRefresh, search, sort, +} = useQueryTable(() => hyperparameterClient.list(namespace.value)); const { onConfirmDelete } = useDeleteHyperparameter(namespace, handleRefresh); -// 监听命名空间变化,重新加载数据集 watch(namespace, handleRefresh); const regroupParameters = (parameters: Parameters) => { @@ -86,12 +99,14 @@ const onCreate = () => { diff --git a/src/views/inference-application/composition/inference-application.ts b/src/views/inference-application/composition/inference-application.ts index acfa41f..b180f54 100644 --- a/src/views/inference-application/composition/inference-application.ts +++ b/src/views/inference-application/composition/inference-application.ts @@ -1,6 +1,7 @@ -import { rayServiceClient, RayService } from '@/api/ray-service'; +import { rayServiceClient, RayService, InferenceApplication } from '@/api/ray-service'; import { createDialog } from '@dao-style/extend'; import ConfirmDeleteDialog from '@/components/ConfirmDeleteDialog.vue'; +import InferenceApplicationCreate from '../InferenceApplicationCreate.vue'; export function useDeleteInferenceApplication(namespace: Ref, handleRefresh: () => void) { const { t } = useI18n(); @@ -22,3 +23,19 @@ export function useDeleteInferenceApplication(namespace: Ref, handleRefr onConfirmDelete, }; } + +export function useCreateInferenceApplication(handleRefresh: () => void) { + const onCreate = async (model:InferenceApplication) => { + const dialog = createDialog(InferenceApplicationCreate); + + await dialog.show({ + modelValue: model, + }); + + handleRefresh(); + }; + + return { + onCreate, + }; +} diff --git a/src/views/login/Login.vue b/src/views/login/Login.vue index 089d82d..54056c0 100644 --- a/src/views/login/Login.vue +++ b/src/views/login/Login.vue @@ -23,14 +23,14 @@ const { handleSubmit } = useForm({ const onSubmit = handleSubmit(async (values) => { await userStore.login(values.token); router.push({ - name: 'FinetuneExperimentList', + name: 'ConsoleContainer', }); }); onMounted(async () => { if (loginSuccess.value) { router.push({ - name: 'FinetuneExperimentList', + name: 'ConsoleContainer', }); } }); diff --git a/src/views/model-registry/ModelRegistryList.vue b/src/views/model-registry/ModelRegistryList.vue index e967ef5..21acb8f 100644 --- a/src/views/model-registry/ModelRegistryList.vue +++ b/src/views/model-registry/ModelRegistryList.vue @@ -8,18 +8,19 @@ import ConfirmDeleteDialog from '@/components/ConfirmDeleteDialog.vue'; import CardLayoutContainer from '@/components/CardLayoutContainer.vue'; import ModelCard from './components/ModelCard.vue'; +import { useCreateInferenceApplication } from '../inference-application/composition/inference-application'; const { namespace } = storeToRefs(useNamespaceStore()); const { t } = useI18n(); const { isLoading, pagedData, page, pageSize, total, handleRefresh, search, -} = useQueryTable( - async () => llmCheckpointClient.list(namespace.value), -); +} = useQueryTable(() => llmCheckpointClient.list(namespace.value)); watch(namespace, handleRefresh); +const { onCreate } = useCreateInferenceApplication(handleRefresh); + const deleteFn = (name: string) => llmCheckpointClient.delete(namespace.value, name).then(() => { handleRefresh(); }); @@ -43,7 +44,7 @@ const onConfirmDelete = (name: string) => { :title="$t('views.ModelRegistry.modelRegistry')" /> @@ -55,6 +56,7 @@ const onConfirmDelete = (name: string) => { :key="registry.metadata?.name" :data="registry" @on-delete="onConfirmDelete" + @on-create="onCreate" /> diff --git a/src/views/model-registry/components/ModelCard.vue b/src/views/model-registry/components/ModelCard.vue index 861d376..a72d7c9 100644 --- a/src/views/model-registry/components/ModelCard.vue +++ b/src/views/model-registry/components/ModelCard.vue @@ -1,7 +1,5 @@