index.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import { apiInterceptors, getModelList } from '@/client/api';
  2. import ModelForm from '@/components/model/model-form';
  3. import BlurredCard from '@/new-components/common/blurredCard';
  4. import ConstructLayout from '@/new-components/layout/Construct';
  5. import { IModelData } from '@/types/model';
  6. import { MODEL_ICON_DICT } from '@/utils/constants';
  7. import { PlusOutlined, SearchOutlined } from '@ant-design/icons';
  8. import { Avatar, Button, Input, Modal, Tag } from 'antd';
  9. import moment from 'moment';
  10. import { useEffect, useState } from 'react';
  11. import { useTranslation } from 'react-i18next';
  12. function Models() {
  13. const { t } = useTranslation();
  14. const [models, setModels] = useState<Array<IModelData>>([]);
  15. const [isModalOpen, setIsModalOpen] = useState(false);
  16. // const [loading, setLoading] = useState<boolean>(false);
  17. async function getModels() {
  18. const [, res] = await apiInterceptors(getModelList());
  19. if (res) {
  20. setModels([...res, ...res, ...res, ...res, ...res]);
  21. }
  22. }
  23. // TODO: delete unuesed function
  24. // async function stopTheModel(info: IModelData) {
  25. // if (loading) {
  26. // return;
  27. // }
  28. // setLoading(true);
  29. // const [, res] = await apiInterceptors(
  30. // stopModel({
  31. // host: info.host,
  32. // port: info.port,
  33. // model: info.model_name,
  34. // worker_type: info.model_type,
  35. // params: {},
  36. // }),
  37. // );
  38. // setLoading(false);
  39. // if (res === true) {
  40. // message.success(t('stop_model_success'));
  41. // }
  42. // }
  43. useEffect(() => {
  44. getModels();
  45. }, []);
  46. // TODO: unuesed function
  47. // const onSearch = useDebounceFn(
  48. // async (e: any) => {
  49. // const v = e.target.value;
  50. // await modelSearch({ model_name: v });
  51. // },
  52. // { wait: 500 },
  53. // ).run;
  54. const returnLogo = (name: string) => {
  55. const formatterModal = name?.replaceAll('-', '_').split('_')[0];
  56. const dict = Object.keys(MODEL_ICON_DICT);
  57. for (let i = 0; i < dict.length; i++) {
  58. const element = dict[i];
  59. if (formatterModal?.includes(element)) {
  60. return MODEL_ICON_DICT[element];
  61. }
  62. }
  63. return '/pictures/model.png';
  64. };
  65. return (
  66. <ConstructLayout>
  67. <div className='px-6 bg-[#fff]'>
  68. <div className='mt-2 rounded-[10px] flex h-16 justify-between items-center'>
  69. <Input
  70. variant='filled'
  71. prefix={<SearchOutlined />}
  72. placeholder={t('please_enter_the_keywords')}
  73. allowClear
  74. className='w-[400px] h-[40px]
  75. border-1 border-[#f1f1f1]
  76. backdrop-filter
  77. backdrop-blur-lg
  78. dark:border-[#6f7f95]
  79. dark:bg-[#6f7f95]
  80. dark:bg-opacity-60'
  81. />
  82. <span className='flex gap-2 items-center'>
  83. <Avatar className='bg-gradient-to-tr from-[#31afff] to-[#1677ff] cursor-pointer'>
  84. </Avatar>
  85. <span
  86. >
  87. admin
  88. </span>
  89. </span>
  90. </div>
  91. <div className='flex justify-between items-center mb-6'>
  92. <span></span>
  93. <div className='flex items-center gap-4 mt-4'>
  94. <Button
  95. className='border-none text-white bg-button-gradient'
  96. onClick={() => {
  97. setIsModalOpen(true);
  98. }}
  99. >
  100. 创建模型
  101. </Button>
  102. </div>
  103. </div>
  104. <div className='rounded-[10px] w-full h-full flex flex-wrap pb-12 mx-[-8px] bg-slate-200 p-4 border-1 mb-2 '>
  105. {models.map(item => (
  106. <BlurredCard
  107. logo={returnLogo(item.model_name)}
  108. description={
  109. <div className='flex flex-col gap-1 relative text-xs bottom-4'>
  110. <div className='flex overflow-hidden'>
  111. <p className='w-28 text-gray-500 mr-2'>Host:</p>
  112. <p className='flex-1 text-ellipsis'>{item.host}</p>
  113. </div>
  114. <div className='flex overflow-hidden'>
  115. <p className='w-28 text-gray-500 mr-2'>Manage Host:</p>
  116. <p className='flex-1 text-ellipsis'>
  117. {item.manager_host}:{item.manager_port}
  118. </p>
  119. </div>
  120. <div className='flex overflow-hidden'>
  121. <p className='w-28 text-gray-500 mr-2'>Last Heart Beat:</p>
  122. <p className='flex-1 text-ellipsis'>{moment(item.last_heartbeat).format('YYYY-MM-DD')}</p>
  123. </div>
  124. </div>
  125. }
  126. name={item.model_name}
  127. key={item.model_name}
  128. rightTopHover={false}
  129. Tags={
  130. <div>
  131. <Tag color={item.healthy ? 'green' : 'red'}>{item.healthy ? 'Healthy' : 'Unhealthy'}</Tag>
  132. <Tag>{item.model_type}</Tag>
  133. </div>
  134. }
  135. />
  136. ))}
  137. </div>
  138. <Modal
  139. width={800}
  140. open={isModalOpen}
  141. title={t('create_model')}
  142. onCancel={() => {
  143. setIsModalOpen(false);
  144. }}
  145. footer={null}
  146. >
  147. <ModelForm
  148. onCancel={() => {
  149. setIsModalOpen(false);
  150. }}
  151. onSuccess={() => {
  152. setIsModalOpen(false);
  153. getModels();
  154. }}
  155. />
  156. </Modal>
  157. </div>
  158. </ConstructLayout>
  159. );
  160. }
  161. export default Models;