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.

index.tsx 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * @Author: 赵伟
  3. * @Date: 2024-04-16 13:58:08
  4. * @Description: 创建镜像
  5. */
  6. import KFIcon from '@/components/KFIcon';
  7. import KFRadio, { type KFRadioItem } from '@/components/KFRadio';
  8. import PageTitle from '@/components/PageTitle';
  9. import ParameterInput from '@/components/ParameterInput';
  10. import SubAreaTitle from '@/components/SubAreaTitle';
  11. import { useComputingResource } from '@/hooks/resource';
  12. import ResourceSelectorModal, {
  13. ResourceSelectorResponse,
  14. ResourceSelectorType,
  15. selectorTypeConfig,
  16. } from '@/pages/Pipeline/components/ResourceSelectorModal';
  17. import { createEditorReq } from '@/services/developmentEnvironment';
  18. import { openAntdModal } from '@/utils/modal';
  19. import { to } from '@/utils/promise';
  20. import { useNavigate } from '@umijs/max';
  21. import { App, Button, Col, Form, Input, Row, Select } from 'antd';
  22. import { pick } from 'lodash';
  23. import { useState } from 'react';
  24. import styles from './index.less';
  25. type FormData = {
  26. name: string;
  27. computing_resource: string;
  28. standard: string;
  29. image: string;
  30. model: ResourceSelectorResponse;
  31. dataset: ResourceSelectorResponse;
  32. };
  33. enum ComputingResourceType {
  34. GPU = 'GPU',
  35. NPU = 'NPU',
  36. }
  37. const EditorRadioItems: KFRadioItem[] = [
  38. {
  39. key: ComputingResourceType.GPU,
  40. title: '英伟达GPU',
  41. icon: <KFIcon type="icon-jiyugongwangjingxiang" />,
  42. },
  43. {
  44. key: ComputingResourceType.NPU,
  45. title: '昇腾NPU',
  46. icon: <KFIcon type="icon-bendishangchuan" />,
  47. },
  48. ];
  49. function EditorCreate() {
  50. const navgite = useNavigate();
  51. const [form] = Form.useForm();
  52. const { message } = App.useApp();
  53. const [resourceStandardList, filterResourceStandard] = useComputingResource();
  54. const [selectedModel, setSelectedModel] = useState<ResourceSelectorResponse | undefined>(
  55. undefined,
  56. ); // 选择的模型,为了再次打开时恢复原来的选择
  57. const [selectedDataset, setSelectedDataset] = useState<ResourceSelectorResponse | undefined>(
  58. undefined,
  59. ); // 选择的数据集,为了再次打开时恢复原来的选择
  60. const [selectedMirror, setSelectedMirror] = useState<ResourceSelectorResponse | undefined>(
  61. undefined,
  62. ); // 选择的镜像,为了再次打开时恢复原来的选择
  63. // 创建编辑器
  64. const createEditor = async (formData: FormData) => {
  65. // const { model, dataset } = formData;
  66. // const params = {
  67. // ...formData,
  68. // model: JSON.stringify(omit(model, ['showValue'])),
  69. // dataset: JSON.stringify(dataset, ['showValue']),
  70. // };
  71. const [res] = await to(createEditorReq(formData));
  72. if (res) {
  73. message.success('创建成功');
  74. navgite(-1);
  75. }
  76. };
  77. // 提交
  78. const handleSubmit = (values: FormData) => {
  79. createEditor(values);
  80. };
  81. // 取消
  82. const cancel = () => {
  83. navgite(-1);
  84. };
  85. // 获取选择数据集、模型后面按钮 icon
  86. const getSelectBtnIcon = (type: ResourceSelectorType) => {
  87. return <KFIcon type={selectorTypeConfig[type].buttonIcon} font={16} />;
  88. };
  89. // 选择模型、镜像、数据集
  90. const selectResource = (name: string, type: ResourceSelectorType) => {
  91. let resource: ResourceSelectorResponse | undefined;
  92. switch (type) {
  93. case ResourceSelectorType.Model:
  94. resource = selectedModel;
  95. break;
  96. case ResourceSelectorType.Dataset:
  97. resource = selectedDataset;
  98. break;
  99. default:
  100. resource = selectedMirror;
  101. break;
  102. }
  103. const { close } = openAntdModal(ResourceSelectorModal, {
  104. type,
  105. defaultExpandedKeys: resource ? [resource.id] : [],
  106. defaultCheckedKeys: resource ? [`${resource.id}-${resource.version}`] : [],
  107. defaultActiveTab: resource?.activeTab,
  108. onOk: (res) => {
  109. if (res) {
  110. if (type === ResourceSelectorType.Mirror) {
  111. form.setFieldValue(name, res.path);
  112. setSelectedMirror(res);
  113. } else {
  114. const showValue = `${res.name}:${res.version}`;
  115. form.setFieldValue(name, {
  116. ...pick(res, ['id', 'version', 'path']),
  117. showValue,
  118. });
  119. if (type === ResourceSelectorType.Model) {
  120. setSelectedModel(res);
  121. } else if (type === ResourceSelectorType.Dataset) {
  122. setSelectedDataset(res);
  123. }
  124. }
  125. } else {
  126. if (type === ResourceSelectorType.Model) {
  127. setSelectedModel(undefined);
  128. } else if (type === ResourceSelectorType.Dataset) {
  129. setSelectedDataset(undefined);
  130. } else if (type === ResourceSelectorType.Mirror) {
  131. setSelectedMirror(undefined);
  132. }
  133. form.setFieldValue(name, '');
  134. }
  135. close();
  136. },
  137. });
  138. };
  139. return (
  140. <div className={styles['editor-create']}>
  141. <PageTitle title="创建编辑器"></PageTitle>
  142. <div className={styles['editor-create__content']}>
  143. <div>
  144. <Form
  145. name="editor-create"
  146. labelCol={{ flex: '100px' }}
  147. wrapperCol={{ flex: 1 }}
  148. labelAlign="left"
  149. form={form}
  150. initialValues={{ computing_resource: ComputingResourceType.GPU }}
  151. onFinish={handleSubmit}
  152. size="large"
  153. >
  154. <SubAreaTitle
  155. title="基本信息"
  156. image={require('@/assets/img/mirror-basic.png')}
  157. style={{ marginBottom: '26px' }}
  158. ></SubAreaTitle>
  159. <Row gutter={10}>
  160. <Col span={10}>
  161. <Form.Item
  162. label="任务名称"
  163. name="name"
  164. rules={[
  165. {
  166. required: true,
  167. message: '请输入任务名称',
  168. },
  169. ]}
  170. >
  171. <Input placeholder="请输入任务名称" maxLength={64} showCount allowClear />
  172. </Form.Item>
  173. </Col>
  174. </Row>
  175. <Row gutter={10}>
  176. <Col span={10}>
  177. <Form.Item
  178. label="计算资源"
  179. name="computing_resource"
  180. rules={[
  181. {
  182. required: true,
  183. message: '请选择计算资源',
  184. },
  185. ]}
  186. >
  187. <KFRadio items={EditorRadioItems}></KFRadio>
  188. </Form.Item>
  189. </Col>
  190. </Row>
  191. <Row gutter={8}>
  192. <Col span={10}>
  193. <Form.Item
  194. label="资源规格"
  195. name="standard"
  196. rules={[
  197. {
  198. required: true,
  199. message: '请选择资源规格',
  200. },
  201. ]}
  202. >
  203. <Select
  204. showSearch
  205. placeholder="请选择资源规格"
  206. filterOption={filterResourceStandard}
  207. options={resourceStandardList}
  208. fieldNames={{
  209. label: 'description',
  210. value: 'standard',
  211. }}
  212. />
  213. </Form.Item>
  214. </Col>
  215. </Row>
  216. <SubAreaTitle
  217. title="参数设置"
  218. image={require('@/assets/img/editor-parameter.png')}
  219. style={{ marginTop: '20px', marginBottom: '24px' }}
  220. ></SubAreaTitle>
  221. <Row gutter={8}>
  222. <Col span={10}>
  223. <Form.Item
  224. label="镜像"
  225. name="image"
  226. rules={[
  227. {
  228. required: true,
  229. message: '请输入镜像',
  230. },
  231. ]}
  232. >
  233. <ParameterInput
  234. placeholder="请选择镜像"
  235. canInput={false}
  236. size="large"
  237. onClick={() => selectResource('image', ResourceSelectorType.Mirror)}
  238. />
  239. </Form.Item>
  240. </Col>
  241. <Col span={10}>
  242. <Button
  243. size="large"
  244. type="link"
  245. icon={getSelectBtnIcon(ResourceSelectorType.Mirror)}
  246. onClick={() => selectResource('image', ResourceSelectorType.Mirror)}
  247. >
  248. 选择镜像
  249. </Button>
  250. </Col>
  251. </Row>
  252. <Row gutter={8}>
  253. <Col span={10}>
  254. <Form.Item
  255. label="模型"
  256. name="model"
  257. rules={[
  258. {
  259. required: true,
  260. message: '请选择模型',
  261. },
  262. ]}
  263. >
  264. <ParameterInput
  265. placeholder="请选择模型"
  266. canInput={false}
  267. size="large"
  268. onClick={() => selectResource('model', ResourceSelectorType.Model)}
  269. />
  270. </Form.Item>
  271. </Col>
  272. <Col span={10}>
  273. <Button
  274. size="large"
  275. type="link"
  276. icon={getSelectBtnIcon(ResourceSelectorType.Model)}
  277. onClick={() => selectResource('model', ResourceSelectorType.Model)}
  278. >
  279. 选择模型
  280. </Button>
  281. </Col>
  282. </Row>
  283. <Row gutter={8}>
  284. <Col span={10}>
  285. <Form.Item
  286. label="数据集"
  287. name="dataset"
  288. rules={[
  289. {
  290. required: true,
  291. message: '请选择数据集',
  292. },
  293. ]}
  294. >
  295. <ParameterInput
  296. placeholder="请选择数据集"
  297. canInput={false}
  298. size="large"
  299. onClick={() => selectResource('dataset', ResourceSelectorType.Dataset)}
  300. />
  301. </Form.Item>
  302. </Col>
  303. <Col span={10}>
  304. <Button
  305. size="large"
  306. type="link"
  307. icon={getSelectBtnIcon(ResourceSelectorType.Dataset)}
  308. onClick={() => selectResource('dataset', ResourceSelectorType.Dataset)}
  309. >
  310. 选择数据集
  311. </Button>
  312. </Col>
  313. </Row>
  314. <Form.Item wrapperCol={{ offset: 0, span: 16 }}>
  315. <Button type="primary" htmlType="submit">
  316. 确定
  317. </Button>
  318. <Button
  319. type="default"
  320. htmlType="button"
  321. onClick={cancel}
  322. style={{ marginLeft: '20px' }}
  323. >
  324. 取消
  325. </Button>
  326. </Form.Item>
  327. </Form>
  328. </div>
  329. </div>
  330. </div>
  331. );
  332. }
  333. export default EditorCreate;