chore: display instance resource claim

main
jialin 12 months ago
parent 106ee43171
commit a2ef9d781d

@ -6,6 +6,10 @@
margin-bottom: 8px;
}
.m-b-6 {
margin-bottom: 6px;
}
.m-b-5 {
margin-bottom: 5px;
}

@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
// import './iconfont/iconfont.js';
const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4613488_y6wf3nguxjl.js'
scriptUrl: '//at.alicdn.com/t/c/font_4613488_d7ffxju7lc6.js'
});
export default IconFont;

@ -915,48 +915,42 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
</Tooltip>
</div>
<div className="tools">
{maskUpload?.length ? (
<span className="flex-center upload-mask">
<span className="font-size-12">
{intl.formatMessage({ id: 'playground.image.mask.uploaded' })}
</span>
</span>
) : (
{imageStatus.isOriginal && (
<>
{imageStatus.isOriginal && (
<>
<Tooltip
title={intl.formatMessage({
<Tooltip
title={
<span style={{ whiteSpace: 'pre-wrap' }}>
{intl.formatMessage({
id: 'playground.image.negativeMask.tips'
})}
>
<Checkbox
onChange={handleOnChangeMask}
className="flex-center"
checked={invertMask}
disabled={isDisabled || !!maskUpload?.length}
>
<span className="font-size-12">
{intl.formatMessage({
id: 'playground.image.negativeMask'
})}
</span>
</Checkbox>
</Tooltip>
<Tooltip
title={intl.formatMessage({
id: 'playground.image.saveMask'
</span>
}
>
<Checkbox
onChange={handleOnChangeMask}
className="flex-center"
checked={invertMask}
disabled={isDisabled || !!maskUpload?.length}
>
<span className="font-size-12">
{intl.formatMessage({
id: 'playground.image.negativeMask'
})}
>
<Button onClick={downloadMask} size="middle" type="text">
<IconFont
className="font-size-14"
type="icon-save2"
></IconFont>
</Button>
</Tooltip>
</>
)}
</span>
</Checkbox>
</Tooltip>
<Tooltip
title={intl.formatMessage({
id: 'playground.image.saveMask'
})}
>
<Button onClick={downloadMask} size="middle" type="text">
<IconFont
className="font-size-14"
type="icon-save2"
></IconFont>
</Button>
</Tooltip>
</>
)}
{!imageStatus.isOriginal && (

@ -1,6 +1,6 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import classNames from 'classnames';
import React from 'react';
import SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css';
import TableHeader from './header';
import './index.less';
@ -21,8 +21,14 @@ interface SimpleTableProps {
}
const SimpleTabel: React.FC<SimpleTableProps> = (props) => {
const { columns, dataSource, rowKey, bordered = true } = props;
const scroller = React.useRef<any>(null);
const { initialize } = useOverlayScroller();
React.useEffect(() => {
initialize(scroller.current);
}, [initialize]);
return (
<SimpleBar style={{ maxHeight: 200 }}>
<div style={{ maxHeight: 200 }} ref={scroller}>
<table
className={classNames('simple-table', {
'simple-table-bordered': bordered
@ -43,7 +49,7 @@ const SimpleTabel: React.FC<SimpleTableProps> = (props) => {
})}
</tbody>
</table>
</SimpleBar>
</div>
);
};

@ -1,26 +1,39 @@
import React from 'react';
import { convertFileSize } from '@/utils';
import { useIntl } from '@umijs/max';
import { Divider } from 'antd';
interface InfoColumnProps {
fieldList: { label: string; key: string }[];
fieldList: {
label: string;
key: string;
locale?: boolean;
render?: (val: any, data: any) => any;
}[];
style?: React.CSSProperties;
data: Record<string, any>;
}
const InfoColumn: React.FC<InfoColumnProps> = (props) => {
const { data, fieldList } = props;
const { data, fieldList, style } = props;
const intl = useIntl();
return (
<span className="flex">
<span className="flex" style={style}>
{fieldList.map((item, index) => {
return (
<>
<span className="flex-column flex-center">
<span> {intl.formatMessage({ id: item.label })}</span>
<span> {convertFileSize(data[item.key], 0)}</span>
<span>
{' '}
{item.locale
? intl.formatMessage({ id: item.label })
: item.label}
</span>
<span style={{ color: 'var(--color-white-quaternary)' }}>
{' '}
{item.render?.(data[item.key], data) ?? data[item.key]}
</span>
</span>
{index < fieldList.length - 1 ? (
<Divider

@ -53,6 +53,8 @@ html {
--color-white-light-2: rgba(255, 255, 255, 25%);
--color-white-light-3: rgba(255, 255, 255, 35%);
--color-white-light-4: rgba(255, 255, 255, 45%);
--color-gray-fill-4: rgba(92, 92, 92, 45%);
--color-gray-fill-3: rgba(92, 92, 92, 35%);
--color-text-1: var(--ant-color-text);
--color-text-3: rgba(0, 0, 0, 45%);
--color-text-2: rgba(0, 0, 0, 65%);

@ -148,5 +148,5 @@ export default {
'playground.image.origin': 'Original',
'playground.image.mask': 'Mask',
'playground.image.negativeMask.tips':
'After selection, no further masking can be drawn; therefore, you should draw the mask first and then check the option.'
'1. After selection, no further masking can be drawn; therefore, you should draw the mask first and then check the option.\n 2. Once a mask image is uploaded, no further masks can be generated.'
};

@ -142,5 +142,5 @@ export default {
'playground.image.origin': '原图',
'playground.image.mask': '遮罩',
'playground.image.negativeMask.tips':
'选择后,将不可再绘制遮罩;因此,你应该先绘制遮罩然后再勾选'
'1. 选择后,将不可再绘制遮罩;因此,你应该先绘制遮罩然后再勾选.\n 2. 当上传了遮罩图片,将不可再生成遮罩'
};

@ -7,12 +7,12 @@ import StatusTag from '@/components/status-tag';
import { HandlerOptions } from '@/hooks/use-chunk-fetch';
import useDownloadStream from '@/hooks/use-download-stream';
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
import { convertFileSize } from '@/utils';
import {
DeleteOutlined,
DownloadOutlined,
HddFilled,
InfoCircleOutlined,
ThunderboltFilled
InfoCircleOutlined
} from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import {
@ -28,6 +28,7 @@ import {
import dayjs from 'dayjs';
import _ from 'lodash';
import React, { useCallback, useMemo } from 'react';
import styled from 'styled-components';
import { MODEL_INSTANCE_API } from '../apis';
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
import { ModelInstanceListItem } from '../config/types';
@ -87,10 +88,20 @@ const distributeCols = [
return row.port ? `${row.worker_ip}:${row.port}` : row.worker_ip;
}
},
{
title: 'models.form.backend',
locale: true,
key: 'backend'
},
{
title: 'models.table.gpuindex',
locale: true,
key: 'gpu_index'
},
{
title: 'resources.table.memory',
locale: true,
key: 'ram'
}
];
@ -109,6 +120,40 @@ const renderMessage = (title: string) => {
);
};
const InfoItem = (props: { label: string; value: any; width?: number }) => {
const { label, value, width } = props;
const Wrapper = styled.div`
.info-item {
width: ${width ? `${width}px` : '100%'};
height: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 4px 8px;
background-color: var(--color-gray-fill-3);
border-radius: 4px;
.value {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
color: var(--color-white-quaternary);
.index {
color: var(--ant-color-text-light-solid);
}
}
}
`;
return (
<Wrapper>
<div className="info-item">
<span className="label">{label}</span>
<span className="value">{value}</span>
</div>
</Wrapper>
);
};
const InstanceItem: React.FC<InstanceItemProps> = ({
instanceData,
workerList,
@ -160,6 +205,23 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
[]
);
const displayGPUs = (vrams: Record<string, number>) => {
return (
<span className="flex-column">
{Object.keys(vrams)
?.sort?.()
.map((index) => {
return (
<span key={index}>
[{index}] {''}
{convertFileSize(vrams?.[index], 0)}
</span>
);
})}
</span>
);
};
const renderWorkerInfo = useMemo(() => {
let workerIp = '-';
if (instanceData.worker_ip) {
@ -167,23 +229,50 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
? `${instanceData.worker_ip}:${instanceData.port}`
: instanceData.worker_ip;
}
let backend = modelData?.backend || '';
if (modelData.backend_version) {
backend += ` (${modelData.backend_version})`;
}
const vrams = instanceData.computed_resource_claim?.vram || {};
return (
<div>
<div>{instanceData.worker_name}</div>
<div className="flex-center">
<div style={{ marginBottom: 5 }}>
<HddFilled className="m-r-5" />
{workerIp}
{instanceData.worker_name}
</div>
<div className="flex-center">
<IconFont type="icon-filled-gpu" className="m-r-5" />
{intl.formatMessage({ id: 'models.table.gpuindex' })}: [
{_.join(instanceData.gpu_indexes?.sort?.(), ',')}]
<div className="flex m-b-6 gap-6">
<InfoItem label="IP" value={workerIp} width={180}></InfoItem>
<InfoItem
width={90}
label={intl.formatMessage({ id: 'models.form.backend' })}
value={backend}
></InfoItem>
</div>
<div className="flex-center">
<ThunderboltFilled className="m-r-5" />
{intl.formatMessage({ id: 'models.form.backend' })}:{' '}
{modelData?.backend || ''}
{modelData.backend_version ? `(${modelData.backend_version})` : ''}
<div className="flex gap-6">
<InfoItem
width={180}
label={intl.formatMessage({ id: 'models.table.gpuindex' })}
value={Object.keys(vrams)
?.sort?.()
.map((index) => {
return (
<span className="flex-1" key={index}>
<span className="index">
[{index}] {''}
</span>
{convertFileSize(vrams?.[index], 0)}
</span>
);
})}
></InfoItem>
<InfoItem
width={90}
label={intl.formatMessage({ id: 'resources.table.memory' })}
value={convertFileSize(
instanceData.computed_resource_claim?.ram,
0
)}
></InfoItem>
</div>
</div>
);
@ -197,24 +286,23 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
worker_name: data?.name,
worker_ip: data?.ip,
port: '',
gpu_index: item.gpu_index
ram: convertFileSize(item.computed_resource_claim?.ram, 0),
gpu_index: displayGPUs(item.computed_resource_claim?.vram || {})
};
});
const mainWorker = [
{
worker_name: `${instanceData.worker_name}`,
worker_name: `${instanceData.worker_name} (main)`,
worker_ip: `${instanceData.worker_ip}`,
port: '',
gpu_index: `${instanceData.gpu_indexes?.sort?.()} (main)`
ram: convertFileSize(instanceData.computed_resource_claim?.ram, 0),
gpu_index: displayGPUs(instanceData.computed_resource_claim?.vram || {})
}
];
return (
<div>
<h3 style={{ margin: 0 }}>
{intl.formatMessage({ id: 'models.table.backend' })}
</h3>
<SimpleTabel
columns={distributeCols}
dataSource={[...mainWorker, ...list]}
@ -255,7 +343,13 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
<AutoTooltip title={instanceData.name} ghost>
<span className="m-r-5">{instanceData.name}</span>
</AutoTooltip>
<Tooltip title={renderWorkerInfo}>
<Tooltip
title={renderWorkerInfo}
overlayInnerStyle={{
width: 'max-content',
maxWidth: '400px'
}}
>
<span className="server-info">
<InfoCircleOutlined />
</span>
@ -327,7 +421,9 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
{instanceData?.distributed_servers?.rpc_servers?.length && (
<Tooltip
overlayInnerStyle={{
width: '400px'
width: 'max-content',
maxWidth: '500px',
minWidth: '400px'
}}
title={renderDistributionInfo}
>

@ -60,6 +60,12 @@ export interface FormData {
description: string;
}
interface ComputedResourceClaim {
offload_layers: number;
total_layers: number;
ram: number;
vram: Record<string, number>;
}
export interface ModelInstanceListItem {
backend?: string;
backend_version?: string;
@ -68,12 +74,14 @@ export interface ModelInstanceListItem {
huggingface_filename: string;
ollama_library_model_name: string;
distributed_servers?: {
rpc_servers: any[];
};
computed_resource_claim?: {
offload_layers: number;
total_layers: number;
rpc_servers: {
pid: number;
port: number;
worker_id: string;
computed_resource_claim: ComputedResourceClaim;
}[];
};
computed_resource_claim?: ComputedResourceClaim;
s3_address: string;
worker_id: number;
gpu_indexes?: number[];

@ -239,23 +239,23 @@ export const ImageEidtParamsConfig: ParamsSchema[] = [
];
export const ImageconstExtraConfig: ParamsSchema[] = [
{
type: 'Select',
name: 'quality',
options: [
{ label: 'playground.params.standard', value: 'standard', locale: true },
{ label: 'playground.params.hd', value: 'hd', locale: true }
],
label: {
text: 'playground.params.quality',
isLocalized: true
},
rules: [
{
required: false
}
]
},
// {
// type: 'Select',
// name: 'quality',
// options: [
// { label: 'playground.params.standard', value: 'standard', locale: true },
// { label: 'playground.params.hd', value: 'hd', locale: true }
// ],
// label: {
// text: 'playground.params.quality',
// isLocalized: true
// },
// rules: [
// {
// required: false
// }
// ]
// },
{
type: 'Select',
name: 'style',

@ -24,7 +24,8 @@ export const IMG_METAKEYS = [
'cfg_scale',
'guidance',
'negative_prompt',
'seed'
'seed',
'strength'
];
export const llmInitialValues = {
@ -44,12 +45,13 @@ export const advancedFieldsDefaultValus = {
guidance: 3.5,
sampling_steps: 10,
negative_prompt: null,
strength: null,
schedule_method: 'discrete',
preview: 'preview_faster'
};
export const openaiCompatibleFieldsDefaultValus = {
quality: 'standard',
// quality: 'standard',
style: null
};

@ -8,7 +8,7 @@ import StatusTag from '@/components/status-tag';
import Hotkeys from '@/config/hotkeys';
import useTableRowSelection from '@/hooks/use-table-row-selection';
import useTableSort from '@/hooks/use-table-sort';
import { handleBatchRequest } from '@/utils';
import { convertFileSize, handleBatchRequest } from '@/utils';
import {
DeleteOutlined,
EditOutlined,
@ -41,15 +41,27 @@ const { Column } = Table;
const fieldList = [
{
label: 'resources.table.total',
key: 'total'
key: 'total',
locale: true,
render: (val: any) => {
return convertFileSize(val, 0);
}
},
{
label: 'resources.table.used',
key: 'used'
key: 'used',
locale: true,
render: (val: any) => {
return convertFileSize(val, 0);
}
},
{
label: 'resources.table.allocated',
key: 'allocated'
key: 'allocated',
locale: true,
render: (val: any) => {
return convertFileSize(val, 0);
}
}
];

Loading…
Cancel
Save