Files
gpustack-ui/src/pages/llmodels/components/instance-cells/name-cell.tsx
T

140 lines
3.5 KiB
TypeScript

import { convertFileSize } from '@/utils';
import {
HddFilled,
InfoCircleOutlined,
PieChartFilled,
ThunderboltFilled
} from '@ant-design/icons';
import { AutoTooltip, IconFont } from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import { Tooltip } from 'antd';
import _ from 'lodash';
import React, { useEffect } from 'react';
import { ModelInstanceListItem } from '../../config/types';
import '../../style/instance-item.less';
export interface NameCellProps {
record: ModelInstanceListItem;
modelData: any;
defaultOpenId?: string;
showWorkerInfo?: boolean;
styles?: {
label?: React.CSSProperties;
};
}
const calcTotalVram = (vram: Record<string, number>) => {
return _.sum(_.values(vram));
};
const WorkerInfoContent: React.FC<NameCellProps> = ({ record, modelData }) => {
const intl = useIntl();
let workerIp = '-';
if (record.worker_ip) {
workerIp = record.port
? `${record.worker_ip}:${record.port}`
: record.worker_ip;
}
return (
<div>
<div>{record.worker_name}</div>
<div className="flex-center">
<HddFilled className="m-r-5" />
{workerIp}
</div>
<div className="flex-center">
<IconFont type="icon-filled-gpu" className="m-r-5" />
{intl.formatMessage({ id: 'models.table.gpuindex' })}: [
{_.join(
record.gpu_indexes?.sort?.((a, b) => a - b),
','
)}
]
</div>
<div className="flex-center">
<ThunderboltFilled className="m-r-5" />
{intl.formatMessage({ id: 'models.form.backend' })}:{' '}
{record?.backend || modelData?.backend || ''}
{record.backend_version || modelData?.backend_version
? `(${record.backend_version || modelData?.backend_version})`
: ''}
</div>
<div className="flex-center">
<PieChartFilled className="m-r-5" />
{intl.formatMessage({ id: 'models.table.vram.allocated' })}:{' '}
{convertFileSize(
record.computed_resource_claim?.vram
? calcTotalVram(record.computed_resource_claim?.vram)
: 0,
1
)}
</div>
</div>
);
};
const WorkerInfo = (props: {
title: React.ReactNode;
defaultOpen: boolean;
}) => {
const [open, setOpen] = React.useState(props.defaultOpen);
useEffect(() => {
if (props.defaultOpen) {
setTimeout(() => {
setOpen(false);
}, 1000);
}
}, [props.defaultOpen]);
return (
<span className="server-info-wrapper">
<Tooltip
open={open}
onOpenChange={setOpen}
title={props.title}
styles={{
container: {
width: 'max-content',
maxWidth: '400px'
}
}}
>
<span className="server-info">
<InfoCircleOutlined />
</span>
</Tooltip>
</span>
);
};
const NameCell: React.FC<NameCellProps> = ({
record,
modelData,
defaultOpenId,
showWorkerInfo = true,
styles
}) => {
return (
<span className="instance-name flex-center" style={{ gap: 4 }}>
<AutoTooltip title={record.name} ghost>
<span className="m-r-5" style={styles?.label}>
{record.name}
</span>
</AutoTooltip>
{!!record.worker_id && showWorkerInfo && (
<WorkerInfo
title={
<WorkerInfoContent
record={record}
modelData={modelData}
></WorkerInfoContent>
}
defaultOpen={defaultOpenId === record.name}
></WorkerInfo>
)}
</span>
);
};
export default NameCell;