fix: usage chart y axis ticks, add esc hint for drawer

This commit is contained in:
jialin
2025-06-16 19:28:02 +08:00
parent 81833c4938
commit 109906d083
21 changed files with 323 additions and 179 deletions
+15 -3
View File
@@ -18,6 +18,7 @@ const Chart: React.FC<{
const chart = useRef<echarts.EChartsType>(); const chart = useRef<echarts.EChartsType>();
const resizeable = useRef(false); const resizeable = useRef(false);
const resizeObserver = useRef<ResizeObserver>(); const resizeObserver = useRef<ResizeObserver>();
const finished = useRef(false);
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
@@ -49,7 +50,7 @@ const Chart: React.FC<{
useEffect(() => { useEffect(() => {
const handleOnFinished = () => { const handleOnFinished = () => {
if (!chart.current) return; if (!chart.current || finished.current) return;
const currentChart = chart.current; const currentChart = chart.current;
const optionsYAxis = currentChart.getOption()?.yAxis; const optionsYAxis = currentChart.getOption()?.yAxis;
@@ -75,22 +76,32 @@ const Chart: React.FC<{
const ticksList = axes.map((axis) => axis.scale.getTicks()); const ticksList = axes.map((axis) => axis.scale.getTicks());
const counts = ticksList.map((t) => t.length); const counts = ticksList.map((t) => t.length);
if (counts[0] === counts[1]) return;
const unifiedCount = Math.max(counts[0], counts[1]); const unifiedCount = Math.max(counts[0], counts[1]);
const newMax0 = intervals[0] * (unifiedCount - 1); const newMax0 = intervals[0] * (unifiedCount - 1);
const newMax1 = intervals[1] * (unifiedCount - 1); const newMax1 = intervals[1] * (unifiedCount - 1);
// get yaxis max value
const maxValue0 = Math.max();
const maxValue1 = yAxisModels[1].get('max');
// if newMax0 equal to maxValue0, and newMax1 equal to maxValue1, do not update yAxis
if (counts[0] === counts[1]) return;
const yAxis: any[] = [{}, {}]; const yAxis: any[] = [{}, {}];
if (counts[0] < unifiedCount) { if (counts[0] < unifiedCount) {
yAxis[0].max = newMax0; yAxis[0].max = newMax0;
yAxis[0].interval = intervals[0];
yAxis[0].splitNumber = unifiedCount;
} }
if (counts[1] < unifiedCount) { if (counts[1] < unifiedCount) {
yAxis[1].max = newMax1; yAxis[1].max = newMax1;
yAxis[1].interval = intervals[1];
yAxis[1].splitNumber = unifiedCount;
} }
finished.current = true;
setTimeout(() => { setTimeout(() => {
currentChart.setOption({ currentChart.setOption({
@@ -112,6 +123,7 @@ const Chart: React.FC<{
useEffect(() => { useEffect(() => {
resizeable.current = false; resizeable.current = false;
finished.current = false;
resize(); resize();
setOption(options); setOption(options);
resizeable.current = true; resizeable.current = true;
@@ -0,0 +1,19 @@
import { useEscHint } from '@/hooks/use-esc-hint';
import { Drawer, type DrawerProps } from 'antd';
const ScrollerModal = (props: DrawerProps) => {
const { EscHint } = useEscHint({
enabled: !props.keyboard && props.open
});
return (
<>
<Drawer {...props}>
{props.children}
{EscHint}
</Drawer>
</>
);
};
export default ScrollerModal;
+2 -1
View File
@@ -27,7 +27,8 @@ const KeybindingsMap = {
NEW3: ['Ctrl+3', 'Meta+3'], NEW3: ['Ctrl+3', 'Meta+3'],
NEW4: ['Ctrl+4', 'Meta+4'], NEW4: ['Ctrl+4', 'Meta+4'],
FOCUS: ['/', '/'], FOCUS: ['/', '/'],
ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter'] ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter'],
ESC: ['Esc', 'Esc']
}; };
type KeyBindingType = keyof typeof KeybindingsMap; type KeyBindingType = keyof typeof KeybindingsMap;
+3 -1
View File
@@ -24,7 +24,9 @@ export default {
}, },
Tabs: { Tabs: {
titleFontSizeLG: 14 titleFontSizeLG: 14
// cardBg: '#1D1E20' },
DatePicker: {
fontSizeLG: 14
}, },
Menu: { Menu: {
iconSize: 16, iconSize: 16,
+2
View File
@@ -84,6 +84,7 @@ html {
--ant-color-border: #d9d9d9; --ant-color-border: #d9d9d9;
--ant-line-type: solid; --ant-line-type: solid;
--ant-line-width: 1px; --ant-line-width: 1px;
--color-esc-hint-bg: rgba(0, 0, 0, 75%);
} }
html[data-theme='realDark'] { html[data-theme='realDark'] {
@@ -99,6 +100,7 @@ html[data-theme='realDark'] {
--color-modal-content-bg: #1f1f1f; --color-modal-content-bg: #1f1f1f;
--color-modal-box-shadow: none; --color-modal-box-shadow: none;
--color-spotlight-bg: #3e3e3e; --color-spotlight-bg: #3e3e3e;
--color-esc-hint-bg: rgba(150, 150, 150, 75%);
background: #141414; background: #141414;
+93
View File
@@ -0,0 +1,93 @@
import HotKeys from '@/config/hotkeys';
import { useIntl } from '@umijs/max';
import { createStyles } from 'antd-style';
import { throttle } from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
const useStyles = createStyles(({ css, token }) => ({
hintOverlay: css`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--color-esc-hint-bg);
color: ${token.colorTextLightSolid};
padding: 16px 24px;
border-radius: 4px;
z-index: 2000;
font-size: 14px;
pointer-events: none;
animation: fadeInOut 2s ease-in-out;
@keyframes fadeInOut {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
opacity: 0;
}
}
`
}));
export function useEscHint(options?: {
enabled?: boolean;
message?: string;
throttleDelay?: number;
}) {
const { enabled = true, message, throttleDelay = 3000 } = options || {};
const intl = useIntl();
const { styles } = useStyles();
const [visible, setVisible] = useState(false);
const timeoutRef = useRef<any>(null);
const showHintThrottled = useMemo(
() =>
throttle(
() => {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
setVisible(true);
timeoutRef.current = setTimeout(() => setVisible(false), 2000);
},
throttleDelay,
{
leading: true,
trailing: false
}
),
[throttleDelay]
);
useHotkeys(
HotKeys.ESC,
() => {
showHintThrottled();
},
{
enabled: enabled
}
);
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
showHintThrottled.cancel();
};
}, [showHintThrottled]);
const EscHint = visible ? (
<div className={styles.hintOverlay}>
{message || intl.formatMessage({ id: 'common.tips.escape.disable' })}
</div>
) : null;
return { EscHint };
}
+3 -1
View File
@@ -247,5 +247,7 @@ export default {
'common.appearance.theme': 'Theme', 'common.appearance.theme': 'Theme',
'common.page.wentwrong': 'Something went wrong.', 'common.page.wentwrong': 'Something went wrong.',
'common.page.refresh.tips': 'common.page.refresh.tips':
'Oops! Something went wrong. Try refreshing the page.' 'Oops! Something went wrong. Try refreshing the page.',
'common.tips.escape.disable':
'Click Cancel or the X at the top right to close.'
}; };
+4 -1
View File
@@ -247,7 +247,9 @@ export default {
'common.appearance.theme': 'Theme', 'common.appearance.theme': 'Theme',
'common.page.wentwrong': 'Something went wrong.', 'common.page.wentwrong': 'Something went wrong.',
'common.page.refresh.tips': 'common.page.refresh.tips':
'Oops! Something went wrong. Try refreshing the page.' 'Oops! Something went wrong. Try refreshing the page.',
'common.tips.escape.disable':
'Click Cancel or the X at the top right to close.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -263,4 +265,5 @@ export default {
// 10. 'common.appearance.theme': 'Theme', // 10. 'common.appearance.theme': 'Theme',
// 11. 'common.page.wentwrong': 'Something went wrong.', // 11. 'common.page.wentwrong': 'Something went wrong.',
// 12. 'common.page.refresh.tips': 'Oops! Something went wrong. Try refreshing the page.' // 12. 'common.page.refresh.tips': 'Oops! Something went wrong. Try refreshing the page.'
// 13. 'common.tips.escape.disable': 'Click Cancel or the X at the top right to close.'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+5 -2
View File
@@ -245,9 +245,12 @@ export default {
'common.button.forgotpassword': 'Забыли пароль?', 'common.button.forgotpassword': 'Забыли пароль?',
'common.appearance.theme': 'Тема', 'common.appearance.theme': 'Тема',
'common.page.wentwrong': 'Что-то пошло не так.', 'common.page.wentwrong': 'Что-то пошло не так.',
'common.page.refresh.tips': 'Упс! Что-то пошло не так. Попробуйте обновить страницу.' 'common.page.refresh.tips':
'Упс! Что-то пошло не так. Попробуйте обновить страницу.',
'common.tips.escape.disable':
'Click Cancel or the X at the top right to close.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'common.tips.escape.disable': 'Click Cancel or the X at the top right to close.'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+2 -1
View File
@@ -241,5 +241,6 @@ export default {
'common.button.forgotpassword': '忘记密码?', 'common.button.forgotpassword': '忘记密码?',
'common.appearance.theme': '主题', 'common.appearance.theme': '主题',
'common.page.wentwrong': '哎呀,出了点问题', 'common.page.wentwrong': '哎呀,出了点问题',
'common.page.refresh.tips': '出了点问题,试试刷新页面吧!' 'common.page.refresh.tips': '出了点问题,试试刷新页面吧!',
'common.tips.escape.disable': '请点击「取消」按钮或右上角 X 关闭窗口'
}; };
@@ -75,7 +75,6 @@ const ActiveTable = () => {
left={ left={
<span <span
style={{ style={{
padding: '9px 0',
fontWeight: 'var(--font-weight-bold)' fontWeight: 'var(--font-weight-bold)'
}} }}
> >
@@ -14,7 +14,7 @@ const FilterWrapper = styled.div`
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 16px; margin-bottom: 0px;
.selection { .selection {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -61,44 +61,48 @@ const UsageInner: FC<{ paddingRight: string }> = ({ paddingRight }) => {
xl={16} xl={16}
style={{ paddingRight: paddingRight }} style={{ paddingRight: paddingRight }}
> >
<TitleWrapper> <div
{intl.formatMessage({ id: 'dashboard.usage' })} style={{
</TitleWrapper> display: 'flex',
<FilterWrapper> justifyContent: 'space-between',
<div className="selection"> alignItems: 'center',
<DatePicker.RangePicker marginBottom: 0
style={{ width: 240 }} }}
></DatePicker.RangePicker> >
<Select <TitleWrapper>
mode="multiple" {intl.formatMessage({ id: 'dashboard.usage' })}
maxTagCount={1} </TitleWrapper>
placeholder={intl.formatMessage({ <FilterWrapper>
id: 'dashboard.usage.selectuser' <Button
})} type="text"
style={{ width: 160 }} icon={<ExportOutlined />}
></Select> onClick={handleExport}
<Select >
mode="multiple" {intl.formatMessage({ id: 'common.button.export' })}
maxTagCount={1} </Button>
placeholder={intl.formatMessage({ <div className="selection">
id: 'dashboard.usage.selectmodel' <DatePicker.RangePicker
})} style={{ width: 240 }}
style={{ width: 160 }} ></DatePicker.RangePicker>
></Select> <Select
</div> mode="multiple"
<Button maxTagCount={1}
type="text" placeholder={intl.formatMessage({
icon={<ExportOutlined />} id: 'dashboard.usage.selectuser'
onClick={handleExport} })}
> style={{ width: 160 }}
{intl.formatMessage({ id: 'common.button.export' })} ></Select>
</Button> <Select
</FilterWrapper> mode="multiple"
{/* <SimpleCard maxTagCount={1}
dataList={dataList} placeholder={intl.formatMessage({
height={80} id: 'dashboard.usage.selectmodel'
bordered={true} })}
></SimpleCard> */} style={{ width: 160 }}
></Select>
</div>
</FilterWrapper>
</div>
<RequestTokenInner <RequestTokenInner
requestData={requestTokenData.requestData} requestData={requestTokenData.requestData}
xAxisData={requestTokenData.xAxisData} xAxisData={requestTokenData.xAxisData}
@@ -13,7 +13,7 @@ const TopUser: React.FC<TopUserProps> = (props) => {
return ( return (
<CardWrapper> <CardWrapper>
<HBar seriesData={userData} xAxisData={topUserList} height={496}></HBar> <HBar seriesData={userData} xAxisData={topUserList} height={440}></HBar>
</CardWrapper> </CardWrapper>
); );
}; };
@@ -1,9 +1,10 @@
import ModalFooter from '@/components/modal-footer'; import ModalFooter from '@/components/modal-footer';
import GSDrawer from '@/components/scroller-modal/gs-drawer';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import { createAxiosToken } from '@/hooks/use-chunk-request'; import { createAxiosToken } from '@/hooks/use-chunk-request';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Drawer } from 'antd'; import { Button } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -500,7 +501,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
}, []); }, []);
return ( return (
<Drawer <GSDrawer
title={ title={
<div className="flex-between flex-center"> <div className="flex-between flex-center">
<span <span
@@ -613,7 +614,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
</ColumnWrapper> </ColumnWrapper>
</FormWrapper> </FormWrapper>
</FormContext.Provider> </FormContext.Provider>
</Drawer> </GSDrawer>
); );
}; };
+30 -17
View File
@@ -1,8 +1,9 @@
import ModalFooter from '@/components/modal-footer'; import ModalFooter from '@/components/modal-footer';
import GSDrawer from '@/components/scroller-modal/gs-drawer';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Drawer } from 'antd'; import { Button } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
@@ -14,6 +15,8 @@ import {
import { FormContext } from '../config/form-context'; import { FormContext } from '../config/form-context';
import { FormData, SourceType } from '../config/types'; import { FormData, SourceType } from '../config/types';
import { import {
MessageStatus,
WarningStausOptions,
checkOnlyAscendNPU, checkOnlyAscendNPU,
useCheckCompatibility, useCheckCompatibility,
useSelectModel useSelectModel
@@ -106,6 +109,7 @@ const AddModal: FC<AddModalProps> = (props) => {
setWarningStatus, setWarningStatus,
handleBackendChangeBefore, handleBackendChangeBefore,
cancelEvaluate, cancelEvaluate,
unlockWarningStatus,
handleOnValuesChange: handleOnValuesChangeBefore, handleOnValuesChange: handleOnValuesChangeBefore,
handleEvaluateOnChange, handleEvaluateOnChange,
warningStatus, warningStatus,
@@ -141,7 +145,8 @@ const AddModal: FC<AddModalProps> = (props) => {
/** /**
* *
* @param state target to distinguish the evaluate state * @param state target to distinguish the evaluate state, current evaluate state
* can be 'model', 'file' or 'form'.
*/ */
const setEvaluteState = (state: EvaluateProccessType) => { const setEvaluteState = (state: EvaluateProccessType) => {
evaluateStateRef.current.state = state; evaluateStateRef.current.state = state;
@@ -203,6 +208,7 @@ const AddModal: FC<AddModalProps> = (props) => {
}); });
if (item.fakeName) { if (item.fakeName) {
unlockWarningStatus();
const currentModelId = requestModelIdRef.current; const currentModelId = requestModelIdRef.current;
setEvaluteState(EvaluateProccess.file); setEvaluteState(EvaluateProccess.file);
const evaluateRes = await handleEvaluateOnChange?.({ const evaluateRes = await handleEvaluateOnChange?.({
@@ -245,7 +251,10 @@ const AddModal: FC<AddModalProps> = (props) => {
* evaluate: true means select a model file from the evaluate result * evaluate: true means select a model file from the evaluate result
*/ */
updateRequestModelId(); updateRequestModelId();
// If the evaluate is false, it means that the user selects a new model or the first time to open the modal.
if (!evaluate) { if (!evaluate) {
unlockWarningStatus();
setEvaluteState(EvaluateProccess.model); setEvaluteState(EvaluateProccess.model);
setSelectedModel(item); setSelectedModel(item);
form.current?.form?.resetFields(resetFieldsByModel); form.current?.form?.resetFields(resetFieldsByModel);
@@ -260,8 +269,8 @@ const AddModal: FC<AddModalProps> = (props) => {
setIsGGUF(false); setIsGGUF(false);
const modelInfo = onSelectModel(item, props.source); const modelInfo = onSelectModel(item, props.source);
if ( if (
!isHolderRef.current.model && evaluateStateRef.current.state === EvaluateProccess.model &&
evaluateStateRef.current.state === EvaluateProccess.model item.evaluateResult
) { ) {
handleShowCompatibleAlert(item.evaluateResult); handleShowCompatibleAlert(item.evaluateResult);
form.current?.setFieldsValue?.({ form.current?.setFieldsValue?.({
@@ -365,17 +374,20 @@ const AddModal: FC<AddModalProps> = (props) => {
return warningStatus.show && warningStatus.type !== 'success'; return warningStatus.show && warningStatus.type !== 'success';
}, [warningStatus.show, warningStatus.type]); }, [warningStatus.show, warningStatus.type]);
const displayEvaluateStatus = (data: { // This is only a placeholder for querying the model or file during the transition period.
show?: boolean; const displayEvaluateStatus = (
flag: Record<string, boolean>; params: MessageStatus,
}) => { options?: WarningStausOptions
setIsHolderRef(data.flag); ) => {
setWarningStatus({ setWarningStatus(
show: isHolderRef.current.model || isHolderRef.current.file, {
title: '', show: params.show,
type: 'transition', title: '',
message: intl.formatMessage({ id: 'models.form.evaluating' }) type: 'transition',
}); message: intl.formatMessage({ id: 'models.form.evaluating' })
},
options
);
}; };
useEffect(() => { useEffect(() => {
@@ -395,7 +407,7 @@ const AddModal: FC<AddModalProps> = (props) => {
}, [open, props.gpuOptions.length]); }, [open, props.gpuOptions.length]);
return ( return (
<Drawer <GSDrawer
title={ title={
<div className="flex-between flex-center"> <div className="flex-between flex-center">
<span>{title}</span> <span>{title}</span>
@@ -435,6 +447,7 @@ const AddModal: FC<AddModalProps> = (props) => {
modelSource={props.source} modelSource={props.source}
onSelectModel={handleOnSelectModel} onSelectModel={handleOnSelectModel}
displayEvaluateStatus={displayEvaluateStatus} displayEvaluateStatus={displayEvaluateStatus}
unlockWarningStatus={unlockWarningStatus}
gpuOptions={props.gpuOptions} gpuOptions={props.gpuOptions}
></SearchModel> ></SearchModel>
</ColumnWrapper> </ColumnWrapper>
@@ -535,7 +548,7 @@ const AddModal: FC<AddModalProps> = (props) => {
</FormWrapper> </FormWrapper>
</FormContext.Provider> </FormContext.Provider>
</div> </div>
</Drawer> </GSDrawer>
); );
}; };
+56 -60
View File
@@ -20,9 +20,9 @@ import React, {
useState useState
} from 'react'; } from 'react';
import 'simplebar-react/dist/simplebar.min.css'; import 'simplebar-react/dist/simplebar.min.css';
import styled from 'styled-components';
import { import {
downloadModelFile, downloadModelFile,
downloadModelScopeModelfile,
queryHuggingfaceModelDetail, queryHuggingfaceModelDetail,
queryModelScopeModelDetail queryModelScopeModelDetail
} from '../apis'; } from '../apis';
@@ -30,6 +30,41 @@ import { modelSourceMap } from '../config';
import '../style/model-card.less'; import '../style/model-card.less';
import TitleWrapper from './title-wrapper'; import TitleWrapper from './title-wrapper';
const MkdTitle = styled.span`
cursor: pointer;
background-color: var(--ant-color-fill-tertiary);
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
height: 36px;
`;
const MarkDownTitle: React.FC<{
collapsed: boolean;
loading: boolean;
onCollapse: () => void;
}> = ({ collapsed, loading, onCollapse }) => {
const intl = useIntl();
return (
<MkdTitle onClick={onCollapse}>
<span>
<FileTextOutlined className="m-r-2 text-tertiary" />{' '}
{intl.formatMessage({ id: 'models.readme' })}
</span>
<span>
{collapsed ? (
<DownOutlined />
) : loading ? (
<Spin spinning={true} size="small"></Spin>
) : (
<RightOutlined />
)}
</span>
</MkdTitle>
);
};
const ModelCard: React.FC<{ const ModelCard: React.FC<{
onCollapse: (flag: boolean) => void; onCollapse: (flag: boolean) => void;
setIsGGUF: (flag: boolean) => void; setIsGGUF: (flag: boolean) => void;
@@ -69,6 +104,7 @@ const ModelCard: React.FC<{
return modelData?.ModelType?.[0]; return modelData?.ModelType?.[0];
} }
}, [modelData, modelSource]); }, [modelData, modelSource]);
const loadFile = useCallback(async (repo: string, sha: string) => { const loadFile = useCallback(async (repo: string, sha: string) => {
try { try {
axiosTokenRef.current?.abort?.(); axiosTokenRef.current?.abort?.();
@@ -95,27 +131,6 @@ const ModelCard: React.FC<{
} }
}; };
const loadConfig = useCallback(async (repo: string, sha: string) => {
try {
loadConfigTokenRef.current?.abort?.();
loadConfigTokenRef.current = new AbortController();
const res = await downloadModelFile(
{
repo,
revision: sha,
path: 'config.json'
},
{
signal: loadConfigTokenRef.current.signal
}
);
return res || null;
} catch (error) {
console.log('error======', error);
return null;
}
}, []);
const removeMetadata = useCallback((str: string) => { const removeMetadata = useCallback((str: string) => {
let indexes = []; let indexes = [];
let index = str.indexOf('---'); let index = str.indexOf('---');
@@ -165,23 +180,6 @@ const ModelCard: React.FC<{
} }
}; };
const loadModelscopeModelConfig = useCallback(async (name: string) => {
try {
loadConfigJsonTokenRef.current?.abort?.();
loadConfigJsonTokenRef.current = new AbortController();
return await downloadModelScopeModelfile(
{
name: name
},
{
signal: loadConfigJsonTokenRef.current.token
}
);
} catch (error) {
return null;
}
}, []);
const getModelScopeModelDetail = async () => { const getModelScopeModelDetail = async () => {
try { try {
const data = await queryModelScopeModelDetail( const data = await queryModelScopeModelDetail(
@@ -352,27 +350,25 @@ const ModelCard: React.FC<{
overflow: 'hidden' overflow: 'hidden'
}} }}
> >
<span className="mkd-title" onClick={handleCollapse}> <MarkDownTitle
<span> onCollapse={handleCollapse}
<FileTextOutlined className="m-r-2 text-tertiary" />{' '} collapsed={collapsed}
README.md loading={loading}
</span> ></MarkDownTitle>
<span> <Spin spinning={loading && collapsed}>
{collapsed ? <DownOutlined /> : <RightOutlined />} <SimpleOverlay
</span> style={{
</span> paddingTop: collapsed ? 12 : 0,
<SimpleOverlay maxHeight: collapsed ? 300 : 0
style={{ }}
paddingTop: collapsed ? 12 : 0, >
maxHeight: collapsed ? 300 : 0 <MarkdownViewer
}} generateImgLink={generateModeScopeImgLink}
> content={readmeText}
<MarkdownViewer theme="light"
generateImgLink={generateModeScopeImgLink} ></MarkdownViewer>
content={readmeText} </SimpleOverlay>
theme="light" </Spin>
></MarkdownViewer>
</SimpleOverlay>
</div> </div>
)} )}
</div> </div>
+34 -32
View File
@@ -18,7 +18,11 @@ import {
modelSourceMap modelSourceMap
} from '../config'; } from '../config';
import { handleRecognizeAudioModel } from '../config/audio-catalog'; import { handleRecognizeAudioModel } from '../config/audio-catalog';
import { checkCurrentbackend } from '../hooks'; import {
MessageStatus,
WarningStausOptions,
checkCurrentbackend
} from '../hooks';
import SearchStyle from '../style/search-result.less'; import SearchStyle from '../style/search-result.less';
import SearchInput from './search-input'; import SearchInput from './search-input';
import SearchResult from './search-result'; import SearchResult from './search-result';
@@ -37,10 +41,11 @@ interface SearchInputProps {
setLoadingModel?: (flag: boolean) => void; setLoadingModel?: (flag: boolean) => void;
onSourceChange?: (source: string) => void; onSourceChange?: (source: string) => void;
onSelectModel: (model: any, evaluate?: boolean) => void; onSelectModel: (model: any, evaluate?: boolean) => void;
displayEvaluateStatus?: (data: { unlockWarningStatus?: () => void;
show?: boolean; displayEvaluateStatus?: (
flag: Record<string, boolean>; data: MessageStatus,
}) => void; options?: WarningStausOptions
) => void;
} }
const SearchModel: React.FC<SearchInputProps> = (props) => { const SearchModel: React.FC<SearchInputProps> = (props) => {
@@ -52,7 +57,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
gpuOptions, gpuOptions,
setLoadingModel, setLoadingModel,
onSelectModel, onSelectModel,
displayEvaluateStatus displayEvaluateStatus,
unlockWarningStatus
} = props; } = props;
const [dataSource, setDataSource] = useState<{ const [dataSource, setDataSource] = useState<{
repoOptions: any[]; repoOptions: any[];
@@ -296,19 +302,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
(item) => item.id === currentRef.current (item) => item.id === currentRef.current
); );
/**
* if item is GGUF, the evaluating would be do after selecting the model file, Or the evaluate status of model would be overrided the
* file evaluate status.
*/
if (currentItem && !currentItem.isGGUF) {
displayEvaluateStatus?.({
show: false,
flag: {
model: false
}
});
}
if (currentItem) { if (currentItem) {
handleOnSelectModel(currentItem, true); handleOnSelectModel(currentItem, true);
} }
@@ -372,12 +365,18 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
networkError: false, networkError: false,
sortType: sort sortType: sort
}); });
displayEvaluateStatus?.({
show: true, // It's a new request, so we need to reset the state
flag: { unlockWarningStatus?.();
model: list.length > 0 displayEvaluateStatus?.(
{
show: list.length > 0,
message: ''
},
{
override: true
} }
}); );
handleOnSelectModel(list[0]); handleOnSelectModel(list[0]);
setLoadingModel?.(false); setLoadingModel?.(false);
@@ -393,9 +392,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
setLoadingModel?.(false); setLoadingModel?.(false);
displayEvaluateStatus?.({ displayEvaluateStatus?.({
show: false, show: false,
flag: { message: ''
model: false
}
}); });
handleOnSelectModel({}); handleOnSelectModel({});
cacheRepoOptions.current = []; cacheRepoOptions.current = [];
@@ -460,12 +457,17 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
repoOptions: currentList repoOptions: currentList
}; };
}); });
displayEvaluateStatus?.({ unlockWarningStatus?.();
show: true, // reset evaluate status
flag: { displayEvaluateStatus?.(
model: true {
show: true,
message: ''
},
{
override: true
} }
}); );
console.log('isEvaluating:', isEvaluating); console.log('isEvaluating:', isEvaluating);
handleOnSelectModel(currentList[0]); handleOnSelectModel(currentList[0]);
handleEvaluate(currentList); handleEvaluate(currentList);
@@ -128,4 +128,4 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
); );
}; };
export default React.memo(SearchResult); export default SearchResult;
+4 -3
View File
@@ -1,7 +1,8 @@
import ModalFooter from '@/components/modal-footer'; import ModalFooter from '@/components/modal-footer';
import GSDrawer from '@/components/scroller-modal/gs-drawer';
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Drawer } from 'antd'; import { Button } from 'antd';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import ColumnWrapper from '../components/column-wrapper'; import ColumnWrapper from '../components/column-wrapper';
@@ -125,7 +126,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
}, [open, source]); }, [open, source]);
return ( return (
<Drawer <GSDrawer
title={ title={
<div className="flex-between flex-center"> <div className="flex-between flex-center">
<span <span
@@ -248,7 +249,7 @@ const DownloadModel: React.FC<AddModalProps> = (props) => {
</ColumnWrapper> </ColumnWrapper>
</div> </div>
</div> </div>
</Drawer> </GSDrawer>
); );
}; };
+2 -2
View File
@@ -26,7 +26,7 @@ import {
ListItem ListItem
} from '../config/types'; } from '../config/types';
type MessageStatus = { export type MessageStatus = {
show: boolean; show: boolean;
title?: string; title?: string;
type?: Global.MessageType; type?: Global.MessageType;
@@ -36,7 +36,7 @@ type MessageStatus = {
evaluateResult?: EvaluateResult; evaluateResult?: EvaluateResult;
}; };
type WarningStausOptions = { export type WarningStausOptions = {
lockAfterUpdate?: boolean; lockAfterUpdate?: boolean;
override?: boolean; override?: boolean;
}; };
-10
View File
@@ -24,16 +24,6 @@
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
.mkd-title {
cursor: pointer;
background-color: var(--ant-color-fill-tertiary);
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
height: 36px;
}
} }
.card-wrapper { .card-wrapper {