You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ModifyModelService.vue 14 kB

2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. * * Licensed under the Apache License,
  2. Version 2.0 (the "License"); * you may not use this file except in compliance with the License. *
  3. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless
  4. required by applicable law or agreed to in writing, software * distributed under the License is
  5. distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  6. implied. * See the License for the specific language governing permissions and * limitations under
  7. the License. * ============================================================= */
  8. <template>
  9. <BaseModal
  10. :visible="visible"
  11. :loading="loading"
  12. title="修改服务"
  13. @change="hide"
  14. @ok="handleModify"
  15. >
  16. <el-form ref="formRef" :model="modelDetail" :rules="rules" label-width="100px">
  17. <el-form-item label="服务名称" prop="name">
  18. <el-input v-model="modelDetail.name" placeholder="服务名称不能超过32字" maxlength="32" />
  19. </el-form-item>
  20. <el-form-item label="模型类型" prop="modelType" style="width: 66.7%;">
  21. <InfoSelect v-model="modelDetail.modelType" :dataSource="modelTypeList" />
  22. </el-form-item>
  23. <el-form-item label="算法" prop="algorithmId" style="width: 66.7%;">
  24. <InfoSelect
  25. v-model="modelDetail.algorithmId"
  26. :dataSource="algorithmList"
  27. filterable
  28. labelKey="algorithmName"
  29. valueKey="id"
  30. />
  31. </el-form-item>
  32. <el-form-item label="预加载模型" prop="modelParentId">
  33. <div class="flex">
  34. <div style="width: 40%;">
  35. <InfoSelect
  36. v-model="modelDetail.modelParentId"
  37. :dataSource="modelList"
  38. filterable
  39. labelKey="name"
  40. valueKey="id"
  41. style="width: 100%;"
  42. placeholder="请选择模型"
  43. @change="handleModelParentIdChange"
  44. />
  45. </div>
  46. <div style="width: 40%; margin-left: 10px;">
  47. <InfoSelect
  48. v-model="modelDetail.modelBranchId"
  49. :dataSource="modelBranchList"
  50. filterable
  51. labelKey="version"
  52. valueKey="id"
  53. style="width: 100%;"
  54. placeholder="请选择模型版本"
  55. />
  56. </div>
  57. </div>
  58. </el-form-item>
  59. <el-form-item label="镜像" prop="imageId">
  60. <div class="flex">
  61. <div style="width: 40%;">
  62. <InfoSelect
  63. v-model="modelDetail.imageName"
  64. :dataSource="imageList"
  65. filterable
  66. plain
  67. style="width: 100%;"
  68. placeholder="请选择镜像"
  69. @change="handleImageNameChange"
  70. />
  71. </div>
  72. <div style="width: 40%; margin-left: 10px;">
  73. <InfoSelect
  74. v-model="modelDetail.imageId"
  75. :dataSource="imageTagList"
  76. filterable
  77. labelKey="imageTag"
  78. valueKey="id"
  79. style="width: 100%;"
  80. placeholder="请选择镜像版本"
  81. />
  82. </div>
  83. </div>
  84. </el-form-item>
  85. <el-form-item label="节点类型" prop="resourcesPoolType">
  86. <InfoRadio
  87. v-model="modelDetail.resourcesPoolType"
  88. :dataSource="resourcesPoolTypeOptions"
  89. :radioProps="radioProps"
  90. @change="handleResourcesPoolTypeChange"
  91. />
  92. </el-form-item>
  93. <el-form-item label="节点规格" prop="resourcesPoolSpecs" style="width: 66.7%;">
  94. <InfoSelect
  95. v-model="modelDetail.resourcesPoolSpecs"
  96. :dataSource="resourcesPoolSpecList"
  97. filterable
  98. labelKey="specsName"
  99. valueKey="id"
  100. style="width: 100%;"
  101. placeholder="请选择节点规格"
  102. />
  103. </el-form-item>
  104. <el-form-item label="服务数量" prop="instanceCount" style="width: 66.7%;">
  105. <div class="flex">
  106. <el-input-number v-model="modelDetail.instanceNum" :min="1" :step="1" step-strictly />
  107. </div>
  108. </el-form-item>
  109. <el-form-item label="描述">
  110. <el-input
  111. v-model="modelDetail.remark"
  112. type="textarea"
  113. placeholder="服务描述"
  114. maxlength="100"
  115. rows="3"
  116. />
  117. </el-form-item>
  118. </el-form>
  119. </BaseModal>
  120. </template>
  121. <script>
  122. import { Message } from 'element-ui';
  123. import {
  124. watch,
  125. reactive,
  126. ref,
  127. watchEffect,
  128. nextTick,
  129. inject,
  130. onMounted,
  131. } from '@vue/composition-api';
  132. import { pick, omit } from 'lodash';
  133. import BaseModal from '@/components/BaseModal';
  134. import InfoSelect from '@/components/InfoSelect';
  135. import InfoRadio from '@/components/InfoRadio';
  136. import { modifyModelService, detail } from '@/api/preparation/model';
  137. import { listAll as listAlgorithms } from '@/api/algorithm/algorithm';
  138. import { getModelByResource } from '@/api/model/model';
  139. import { list as listBranchModel } from '@/api/model/modelVersion';
  140. import { getImageNameList, getImageTagList } from '@/api/trainingImage';
  141. import { list as listResourceSpec } from '@/api/system/resources';
  142. import { types } from '@/utils/validate';
  143. import {
  144. RESOURCES_POOL_TYPE_ENUM,
  145. RESOURCES_MODULE_ENUM,
  146. modelTypeSymbol,
  147. IMAGE_TYPE_ENUM,
  148. } from '@/utils/constant';
  149. const initialForm = {
  150. name: undefined,
  151. modelType: undefined,
  152. algorithmId: undefined,
  153. modelParentId: undefined,
  154. modelBranchId: undefined,
  155. imageName: undefined,
  156. imageId: undefined,
  157. resourcesPoolType: RESOURCES_POOL_TYPE_ENUM.CPU,
  158. resourcesPoolSpecs: undefined,
  159. instanceNum: 1,
  160. remark: undefined,
  161. };
  162. // 节点类型
  163. const resourcesPoolTypeOptions = Object.keys(RESOURCES_POOL_TYPE_ENUM).map((d) => ({
  164. label: d,
  165. value: RESOURCES_POOL_TYPE_ENUM[d],
  166. }));
  167. const radioProps = {
  168. border: true,
  169. };
  170. export default {
  171. name: 'ModifyModelService',
  172. components: {
  173. BaseModal,
  174. InfoSelect,
  175. InfoRadio,
  176. },
  177. props: {
  178. refresh: Function,
  179. },
  180. setup(props) {
  181. const visible = ref(false);
  182. const loading = ref(false);
  183. const formRef = ref(null);
  184. const algorithmList = ref([]);
  185. const modelList = ref([]);
  186. const modelBranchList = ref([]);
  187. const imageList = ref([]);
  188. const imageTagList = ref([]);
  189. const resourcesPoolSpecList = ref([]);
  190. const resourcesPoolSpecLists = ref({ CPU: [], GPU: [] });
  191. const modelTypeList = inject(modelTypeSymbol);
  192. const modelDetail = ref({ ...initialForm });
  193. const state = reactive({
  194. model: { ...initialForm },
  195. });
  196. const reset = () => {
  197. loading.value = false;
  198. modelDetail.value = { ...initialForm };
  199. algorithmList.value = [];
  200. modelList.value = [];
  201. modelBranchList.value = [];
  202. imageList.value = [];
  203. imageTagList.value = [];
  204. resourcesPoolSpecList.value = [];
  205. };
  206. const validateInstanceCount = (rule, value, callback) => {
  207. const { instanceNum } = modelDetail.value;
  208. if (!types.number(instanceNum)) {
  209. callback(new Error('节点数量必须为数字'));
  210. return;
  211. }
  212. if (Number(instanceNum) < 1) {
  213. callback(new Error('节点数量不能小于1'));
  214. return;
  215. }
  216. callback();
  217. };
  218. const rules = {
  219. name: [{ required: true, message: '请填写服务名称', trigger: ['change'] }],
  220. modelType: [{ required: true, message: '请选择模型类型', trigger: ['change'] }],
  221. algorithmId: [{ required: true, message: '请选择算法', trigger: ['change'] }],
  222. imageId: [{ required: true, message: '请选择镜像及版本', trigger: ['change'] }],
  223. resourcesPoolType: [{ required: true, message: '请选择节点类型', trigger: ['change'] }],
  224. resourcesPoolSpecs: [{ required: true, message: '请选择节点规格', trigger: ['change'] }],
  225. instanceCount: { required: true, validator: validateInstanceCount, trigger: 'blur' },
  226. };
  227. const getSpecsId = (rawSpecs) => {
  228. const targetSpecs = JSON.parse(rawSpecs);
  229. const specs = resourcesPoolSpecList.value.find(
  230. (d) =>
  231. d.cpuNum === targetSpecs.cpuNum &&
  232. d.gpuNum === targetSpecs.gpuNum &&
  233. d.memNum === targetSpecs.memNum
  234. );
  235. if (!specs) return null;
  236. return specs.id;
  237. };
  238. const show = async (serviceId) => {
  239. const res = await detail(serviceId);
  240. modelDetail.value = { ...res };
  241. nextTick(() => {
  242. modelDetail.value.resourcesPoolSpecs = getSpecsId(res.resourcesPoolSpecs);
  243. });
  244. visible.value = true;
  245. };
  246. const hide = () => {
  247. visible.value = false;
  248. nextTick(() => {
  249. reset();
  250. formRef.value.resetFields();
  251. });
  252. };
  253. // 查询算法列表
  254. const queryAlgorithms = (params = {}) => {
  255. return listAlgorithms({ algorithmUsage: params.modelType });
  256. };
  257. // 查询预加载模型列表
  258. const queryModelWeights = async () => {
  259. // 加载我的模型、预加载模型
  260. const [myModels, preTrainedModels] = await Promise.all([
  261. getModelByResource(0),
  262. getModelByResource(1),
  263. ]);
  264. return [...myModels, ...preTrainedModels];
  265. };
  266. // 查询预加载模型版本列表
  267. const queryModelVersions = async (parentId) => {
  268. modelBranchList.value = await listBranchModel({ parentId }).then((res) => res.result);
  269. };
  270. // 查询镜像列表
  271. const queryImages = () => {
  272. return getImageNameList({ imageTypes: [IMAGE_TYPE_ENUM.DATASETMARKED] });
  273. };
  274. // 查询镜像版本列表
  275. const queryImageTagList = async (imageName) => {
  276. imageTagList.value = await getImageTagList({ imageName });
  277. };
  278. // 预加载模型变化,版本清空
  279. const handleModelParentIdChange = () => {
  280. modelDetail.value.modelBranchId = undefined;
  281. };
  282. // 镜像名变化,版本清空
  283. const handleImageNameChange = () => {
  284. modelDetail.value.imageId = undefined;
  285. nextTick(() => {
  286. formRef.value.clearValidate('imageId');
  287. });
  288. };
  289. // 节点类型变化,节点规格清空
  290. const handleResourcesPoolTypeChange = () => {
  291. modelDetail.value.resourcesPoolSpecs = undefined;
  292. };
  293. const buildParams = async (params) => {
  294. try {
  295. const res = await Promise.all([
  296. queryAlgorithms(params),
  297. queryModelWeights(params),
  298. queryImages(),
  299. ]);
  300. // eslint-disable-next-line prefer-destructuring
  301. algorithmList.value = res[0];
  302. // eslint-disable-next-line prefer-destructuring
  303. modelList.value = res[1];
  304. // eslint-disable-next-line prefer-destructuring
  305. imageList.value = res[2];
  306. } catch (err) {
  307. console.error(err);
  308. Message.error(err.message || '参数获取失败');
  309. }
  310. };
  311. const normalizeResourceSpec = (specId) => {
  312. const selectedSpecItem = resourcesPoolSpecList.value.find((item) => item.id === specId);
  313. if (!selectedSpecItem) return null;
  314. return {
  315. resourcesPoolSpecs: JSON.stringify(pick(selectedSpecItem, ['cpuNum', 'gpuNum', 'memNum'])),
  316. };
  317. };
  318. // 确认修改
  319. const handleModify = () => {
  320. formRef.value.validate((valid) => {
  321. if (valid) {
  322. loading.value = true;
  323. const resourceSpec = normalizeResourceSpec(modelDetail.value.resourcesPoolSpecs);
  324. // 修改模型服务
  325. modifyModelService({
  326. ...omit(modelDetail.value, ['resourcesPoolSpecs']),
  327. ...resourceSpec,
  328. instanceNum: Number(modelDetail.value.instanceNum),
  329. })
  330. .then(() => {
  331. Message.success('模型服务修改成功');
  332. hide();
  333. props.refresh();
  334. })
  335. .finally(() => {
  336. loading.value = false;
  337. });
  338. }
  339. });
  340. };
  341. // 节点类型变化,节点规格列表变化
  342. watchEffect(() => {
  343. resourcesPoolSpecList.value =
  344. resourcesPoolSpecLists.value[modelDetail.value.resourcesPoolType];
  345. });
  346. // 模型类型变化,算法/预加载模型/镜像列表刷新
  347. watch(
  348. () => modelDetail.value.modelType,
  349. (next) => {
  350. if (next) {
  351. buildParams({ modelType: next });
  352. }
  353. }
  354. );
  355. // 预加载模型变化,预加载模型版本刷新
  356. watch(
  357. () => modelDetail.value.modelParentId,
  358. (next) => {
  359. next && queryModelVersions(next);
  360. }
  361. );
  362. // 镜像名称变化,镜像版本刷新
  363. watch(
  364. () => modelDetail.value.imageName,
  365. (next) => {
  366. next && queryImageTagList(next);
  367. }
  368. );
  369. onMounted(async () => {
  370. const params = {
  371. module: RESOURCES_MODULE_ENUM.DATA_ANNOTATION,
  372. curent: 1,
  373. size: 500,
  374. };
  375. const res = await Promise.all([
  376. listResourceSpec({ ...params, resourcesPoolType: RESOURCES_POOL_TYPE_ENUM.CPU }),
  377. listResourceSpec({ ...params, resourcesPoolType: RESOURCES_POOL_TYPE_ENUM.GPU }),
  378. ]);
  379. resourcesPoolSpecLists.value = {
  380. [RESOURCES_POOL_TYPE_ENUM.CPU]: res[0].result,
  381. [RESOURCES_POOL_TYPE_ENUM.GPU]: res[1].result,
  382. };
  383. });
  384. return {
  385. visible,
  386. loading,
  387. show,
  388. hide,
  389. rules,
  390. state,
  391. formRef,
  392. handleModify,
  393. modelDetail,
  394. modelTypeList,
  395. algorithmList,
  396. modelList,
  397. modelBranchList,
  398. imageList,
  399. imageTagList,
  400. radioProps,
  401. resourcesPoolTypeOptions,
  402. resourcesPoolSpecList,
  403. resourcesPoolSpecLists,
  404. handleModelParentIdChange,
  405. handleImageNameChange,
  406. handleResourcesPoolTypeChange,
  407. };
  408. },
  409. };
  410. </script>

一站式算法开发平台、高性能分布式深度学习框架、先进算法模型库、视觉模型炼知平台、数据可视化分析平台等一系列平台及工具,在模型高效分布式训练、数据处理和可视分析、模型炼知和轻量化等技术上形成独特优势,目前已在产学研等各领域近千家单位及个人提供AI应用赋能