chore: watch request counts

This commit is contained in:
jialin
2024-12-27 14:56:06 +08:00
parent fb0a2798e7
commit 9f40e2c71e
14 changed files with 218 additions and 82 deletions
+1
View File
@@ -90,6 +90,7 @@ export default defineConfig({
model: {}, model: {},
initialState: {}, initialState: {},
request: {}, request: {},
keepalive: ['/playground/text-to-image'],
locale: { locale: {
antd: true, antd: true,
baseNavigator: true, baseNavigator: true,
+17
View File
@@ -0,0 +1,17 @@
import { atom, getDefaultStore } from 'jotai';
export const routeCacheAtom = atom<any>(new Map());
export const setRouteCache = (key: string, value: any) => {
const store = getDefaultStore();
const cache = store.get(routeCacheAtom);
cache.set(key, value);
store.set(routeCacheAtom, cache);
};
export const deleteRouteCache = (key: string) => {
const store = getDefaultStore();
const cache = store.get(routeCacheAtom);
cache.delete(key);
store.set(routeCacheAtom, cache);
};
+45
View File
@@ -0,0 +1,45 @@
interface WatchRequest {
id: number;
token: any;
cancel: () => void;
}
declare global {
interface Window {
__GPUSTACK_WATCH_REQUEST_CLEAR__: {
watchIDValue: number;
requestList: WatchRequest[];
};
}
}
window.__GPUSTACK_WATCH_REQUEST_CLEAR__ = {
watchIDValue: 0,
requestList: []
};
export const updateWatchIDValue = () => {
window.__GPUSTACK_WATCH_REQUEST_CLEAR__.watchIDValue =
window.__GPUSTACK_WATCH_REQUEST_CLEAR__.watchIDValue + 1;
return window.__GPUSTACK_WATCH_REQUEST_CLEAR__.watchIDValue;
};
export const updateWatchRequest = (watchToken: WatchRequest) => {
window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList.push(watchToken);
};
export const cancelWatchRequest = (n: number) => {
// cancel the before n requests
const requestList = window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList;
for (let i = 0; i < n; i++) {
requestList[i]?.cancel?.();
}
window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList = requestList.slice(n);
};
export const clearWatchRequestId = (id: number) => {
const requestList = window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList;
const newRequestList = requestList.filter((item) => item.id !== id);
window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList = newRequestList;
};
+3
View File
@@ -0,0 +1,3 @@
export default {
playgroundTextToImage: '/playground/text-to-image'
};
+29 -11
View File
@@ -1,3 +1,9 @@
import {
cancelWatchRequest,
clearWatchRequestId,
updateWatchIDValue,
updateWatchRequest
} from '@/atoms/watch-request';
import { WatchEventType } from '@/config'; import { WatchEventType } from '@/config';
import { request } from '@umijs/max'; import { request } from '@umijs/max';
import axios from 'axios'; import axios from 'axios';
@@ -106,6 +112,7 @@ export const sliceData = (data: string, loaded: number, loadedSize: any) => {
}; };
const useSetChunkRequest = () => { const useSetChunkRequest = () => {
const watchRequestList = window.__GPUSTACK_WATCH_REQUEST_CLEAR__.requestList;
const [requestReadyState, setRequestReadyState] = useState(3); const [requestReadyState, setRequestReadyState] = useState(3);
const axiosToken = useRef<any>(null); const axiosToken = useRef<any>(null);
const requestConfig = useRef<any>({}); const requestConfig = useRef<any>({});
@@ -124,17 +131,21 @@ const useSetChunkRequest = () => {
setRequestReadyState(3); setRequestReadyState(3);
}; };
const resetResultSchema = (result: any[]) => { const createAxiosToken = () => {
// ============ handle list data ============ const { CancelToken } = axios;
// return _.map(result, (data: any) => { const source = CancelToken.source();
// if (data.type === WatchEventType.DELETE) { const watchID = updateWatchIDValue();
// data.ids = _.map(data.items, (item: any) => item.id); return {
// } id: watchID,
// data.collection = data.items || []; token: source.token,
// return data; cancel() {
// }); source.cancel();
// ============ handle list data ============ clearWatchRequestId(watchID);
}
};
};
const resetResultSchema = (result: any[]) => {
return _.map(result, (data: any) => { return _.map(result, (data: any) => {
if (data.type === WatchEventType.DELETE) { if (data.type === WatchEventType.DELETE) {
data.ids = data.data?.id ? [data.data.id] : []; data.ids = data.data?.id ? [data.data.id] : [];
@@ -154,6 +165,12 @@ const useSetChunkRequest = () => {
reset(); reset();
axiosToken.current?.cancel?.(); axiosToken.current?.cancel?.();
axiosToken.current = createAxiosToken(); axiosToken.current = createAxiosToken();
updateWatchRequest(axiosToken.current);
if (watchRequestList.length >= 4) {
cancelWatchRequest(watchRequestList.length - 4 || 1);
}
try { try {
const { request: requestData } = await request(url, { const { request: requestData } = await request(url, {
params: { params: {
@@ -243,7 +260,8 @@ const useSetChunkRequest = () => {
}, [requestReadyState]); }, [requestReadyState]);
return { return {
setChunkRequest setChunkRequest,
createAxiosToken
}; };
}; };
+16 -1
View File
@@ -1,5 +1,6 @@
// @ts-nocheck // @ts-nocheck
import { routeCacheAtom } from '@/atoms/route-cache';
import { GPUStackVersionAtom, UpdateCheckAtom, userAtom } from '@/atoms/user'; import { GPUStackVersionAtom, UpdateCheckAtom, userAtom } from '@/atoms/user';
import ShortCuts, { import ShortCuts, {
modalConfig as ShortCutsConfig modalConfig as ShortCutsConfig
@@ -14,6 +15,7 @@ import { ProLayout } from '@ant-design/pro-components';
import { import {
Link, Link,
Outlet, Outlet,
dropByCacheKey,
history, history,
matchRoutes, matchRoutes,
useAppData, useAppData,
@@ -94,6 +96,7 @@ export default (props: any) => {
const { initialize: initialize } = useOverlayScroller(); const { initialize: initialize } = useOverlayScroller();
const { initialize: initializeMenu } = useOverlayScroller(); const { initialize: initializeMenu } = useOverlayScroller();
const [userInfo] = useAtom(userAtom); const [userInfo] = useAtom(userAtom);
const [routeCache] = useAtom(routeCacheAtom);
const [version] = useAtom(GPUStackVersionAtom); const [version] = useAtom(GPUStackVersionAtom);
const [updateCheck] = useAtom(UpdateCheckAtom); const [updateCheck] = useAtom(UpdateCheckAtom);
const location = useLocation(); const location = useLocation();
@@ -103,6 +106,8 @@ export default (props: any) => {
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
const [collapseValue, setCollapseValue] = useState(false); const [collapseValue, setCollapseValue] = useState(false);
console.log('routeCache========', routeCache);
const initialInfo = (useModel && useModel('@@initialState')) || { const initialInfo = (useModel && useModel('@@initialState')) || {
initialState: undefined, initialState: undefined,
loading: false, loading: false,
@@ -135,6 +140,15 @@ export default (props: any) => {
}); });
}; };
const dropRouteCache = (pathname) => {
console.log('routeCache.keys()========', routeCache.keys());
for (let key of routeCache.keys()) {
if (key !== pathname && !routeCache.get(key)) {
dropByCacheKey(key);
routeCache.delete(key);
}
}
};
const runtimeConfig = { const runtimeConfig = {
...initialInfo, ...initialInfo,
logout: async (userInfo) => { logout: async (userInfo) => {
@@ -156,7 +170,7 @@ export default (props: any) => {
}; };
const newRoutes = filterRoutes( const newRoutes = filterRoutes(
clientRoutes.filter((route) => route.id === '@@/global-layout'), clientRoutes.filter((route) => route.id === 'max-tabs'),
(route) => { (route) => {
return ( return (
(!!route.isLayout && route.id !== '@@/global-layout') || (!!route.isLayout && route.id !== '@@/global-layout') ||
@@ -307,6 +321,7 @@ export default (props: any) => {
: '/playground'; : '/playground';
history.push(pathname); history.push(pathname);
} }
dropRouteCache(pathname);
}} }}
formatMessage={formatMessage} formatMessage={formatMessage}
menu={{ menu={{
+1 -1
View File
@@ -85,6 +85,6 @@ export default {
'vLLM: For non-GGUF format models, supports x86 Linux only.', 'vLLM: For non-GGUF format models, supports x86 Linux only.',
'models.form.backend.voxbox': 'vox-box: For non-GGUF format audio models.', 'models.form.backend.voxbox': 'vox-box: For non-GGUF format audio models.',
'models.form.search.gguftips': 'models.form.search.gguftips':
'If using Mac or Windows as a worker, check GGUF (uncheck for audio models).', 'If using macOS or Windows as a worker, check GGUF (uncheck for audio models).',
'models.form.button.addlabel': 'Add Label' 'models.form.button.addlabel': 'Add Label'
}; };
+1 -1
View File
@@ -81,6 +81,6 @@ export default {
'models.form.backend.vllm': 'vLLM: 用于非 GGUF 格式模型,仅支持 x86 Linux', 'models.form.backend.vllm': 'vLLM: 用于非 GGUF 格式模型,仅支持 x86 Linux',
'models.form.backend.voxbox': 'vox-box: 用于非 GGUF 格式的音频模型', 'models.form.backend.voxbox': 'vox-box: 用于非 GGUF 格式的音频模型',
'models.form.search.gguftips': 'models.form.search.gguftips':
'当 Mac 或 Windows 作 worker 时勾选 GGUF(搜索音频模型时取消勾选)', '当 macOS 或 Windows 作 worker 时勾选 GGUF(搜索音频模型时取消勾选)',
'models.form.button.addlabel': '添加标签' 'models.form.button.addlabel': '添加标签'
}; };
+37 -25
View File
@@ -58,6 +58,8 @@ interface ModelsProps {
handleShowSizeChange?: (page: number, size: number) => void; handleShowSizeChange?: (page: number, size: number) => void;
handlePageChange: (page: number, pageSize: number | undefined) => void; handlePageChange: (page: number, pageSize: number | undefined) => void;
handleDeleteSuccess: () => void; handleDeleteSuccess: () => void;
onViewLogs: () => void;
onCancelViewLogs: () => void;
queryParams: { queryParams: {
page: number; page: number;
perPage: number; perPage: number;
@@ -106,6 +108,8 @@ const Models: React.FC<ModelsProps> = ({
handleSearch, handleSearch,
handlePageChange, handlePageChange,
handleDeleteSuccess, handleDeleteSuccess,
onViewLogs,
onCancelViewLogs,
dataSource, dataSource,
gpuDeviceList, gpuDeviceList,
workerList, workerList,
@@ -400,6 +404,7 @@ const Models: React.FC<ModelsProps> = ({
const handleLogModalCancel = useCallback(() => { const handleLogModalCancel = useCallback(() => {
setOpenLogModal(false); setOpenLogModal(false);
onCancelViewLogs();
}, []); }, []);
const handleDelete = async (row: any) => { const handleDelete = async (row: any) => {
@@ -454,31 +459,38 @@ const Models: React.FC<ModelsProps> = ({
navigate(`/playground/chat?model=${row.name}`); navigate(`/playground/chat?model=${row.name}`);
}; };
const handleViewLogs = async (row: any) => { const handleViewLogs = useCallback(
try { async (row: any) => {
setCurrentInstance({ try {
url: `${MODEL_INSTANCE_API}/${row.id}/logs`, setCurrentInstance({
status: row.state, url: `${MODEL_INSTANCE_API}/${row.id}/logs`,
id: row.id, status: row.state,
modelId: row.model_id, id: row.id,
tail: InstanceRealLogStatus.includes(row.state) ? undefined : PageSize modelId: row.model_id,
}); tail: InstanceRealLogStatus.includes(row.state) ? undefined : PageSize
setOpenLogModal(true); });
} catch (error) { setOpenLogModal(true);
console.log('error:', error); onViewLogs();
} } catch (error) {
}; console.log('error:', error);
const handleDeleteInstace = (row: any, list: ModelInstanceListItem[]) => {
modalRef.current.show({
content: 'models.instances',
okText: 'common.button.delrecreate',
operation: 'common.delete.single.confirm',
name: row.name,
async onOk() {
await deleteModelInstance(row.id);
} }
}); },
}; [onViewLogs]
);
const handleDeleteInstace = useCallback(
(row: any, list: ModelInstanceListItem[]) => {
modalRef.current.show({
content: 'models.instances',
okText: 'common.button.delrecreate',
operation: 'common.delete.single.confirm',
name: row.name,
async onOk() {
await deleteModelInstance(row.id);
}
});
},
[deleteModelInstance]
);
const getModelInstances = async (row: any) => { const getModelInstances = async (row: any) => {
const params = { const params = {
@@ -539,7 +551,7 @@ const Models: React.FC<ModelsProps> = ({
handleViewLogs(row); handleViewLogs(row);
} }
}, },
[] [handleViewLogs, handleDeleteInstace]
); );
const renderModelTags = useCallback( const renderModelTags = useCallback(
+51 -34
View File
@@ -1,9 +1,7 @@
import TableContext from '@/components/seal-table/table-context'; import TableContext from '@/components/seal-table/table-context';
import useSetChunkRequest, { import useSetChunkRequest from '@/hooks/use-chunk-request';
createAxiosToken
} from '@/hooks/use-chunk-request';
import useUpdateChunkedList from '@/hooks/use-update-chunk-list'; import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
import { queryGpuDevicesList, queryWorkersList } from '@/pages/resources/apis'; import { queryWorkersList } from '@/pages/resources/apis';
import { import {
GPUDeviceItem, GPUDeviceItem,
ListItem as WokerListItem ListItem as WokerListItem
@@ -17,7 +15,7 @@ import { ListItem } from './config/types';
const Models: React.FC = () => { const Models: React.FC = () => {
console.log('model list====1'); console.log('model list====1');
const { setChunkRequest } = useSetChunkRequest(); const { setChunkRequest, createAxiosToken } = useSetChunkRequest();
const { setChunkRequest: setModelInstanceChunkRequest } = const { setChunkRequest: setModelInstanceChunkRequest } =
useSetChunkRequest(); useSetChunkRequest();
const [modelInstances, setModelInstances] = useState<any[]>([]); const [modelInstances, setModelInstances] = useState<any[]>([]);
@@ -45,24 +43,16 @@ const Models: React.FC = () => {
const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({ const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
dataList: dataSource.dataList, dataList: dataSource.dataList,
setDataList(list) { setDataList(list) {
setDataSource({ setDataSource((pre) => {
total: dataSource.total, return {
loading: false, total: pre.total,
dataList: list loading: false,
dataList: list
};
}); });
} }
}); });
const getDeviceList = async () => {
try {
const data = await queryGpuDevicesList({ page: 1, perPage: 100 });
const gpuDeviceMap = _.groupBy(data.items, 'worker_name');
setGpuDeviceList(data.items || []);
} catch (error) {
// ingore
}
};
const getWorkerList = async () => { const getWorkerList = async () => {
try { try {
const data = await queryWorkersList({ page: 1, perPage: 100 }); const data = await queryWorkersList({ page: 1, perPage: 100 });
@@ -98,7 +88,7 @@ const Models: React.FC = () => {
loading: false, loading: false,
total: dataSource.total total: dataSource.total
}); });
console.log('error', error); console.log('error+++', error);
} finally { } finally {
setFirstLoad(false); setFirstLoad(false);
} }
@@ -122,7 +112,6 @@ const Models: React.FC = () => {
}; };
const updateInstanceHandler = (list: any) => { const updateInstanceHandler = (list: any) => {
console.log('updateInstanceHandler=====', list);
setModelInstances(list); setModelInstances(list);
}; };
@@ -170,19 +159,16 @@ const Models: React.FC = () => {
[queryParams] [queryParams]
); );
useEffect(() => { const handleOnViewLogs = useCallback(() => {
if (!firstLoad) { chunkRequedtRef.current?.current?.cancel?.();
setTimeout(() => { cacheDataListRef.current = [];
createModelsChunkRequest(); chunkInstanceRequedtRef.current?.current?.cancel?.();
createModelsInstanceChunkRequest(); }, []);
}, 100);
} const handleOnCancelViewLogs = useCallback(() => {
return () => { createModelsChunkRequest();
chunkRequedtRef.current?.current?.cancel?.(); createModelsInstanceChunkRequest();
cacheDataListRef.current = []; }, []);
chunkInstanceRequedtRef.current?.current?.cancel?.();
};
}, [firstLoad]);
useEffect(() => { useEffect(() => {
fetchData(); fetchData();
@@ -193,8 +179,37 @@ const Models: React.FC = () => {
useEffect(() => { useEffect(() => {
getWorkerList(); getWorkerList();
return () => {
chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
chunkInstanceRequedtRef.current?.current?.cancel?.();
};
}, []); }, []);
useEffect(() => {
if (!firstLoad) {
setTimeout(() => {
createModelsChunkRequest();
createModelsInstanceChunkRequest();
}, 100);
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
createModelsChunkRequest();
createModelsInstanceChunkRequest();
} else {
chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
chunkInstanceRequedtRef.current?.current?.cancel?.();
}
});
}
return () => {
document.removeEventListener('visibilitychange', () => {});
};
}, [firstLoad]);
return ( return (
<TableContext.Provider <TableContext.Provider
value={{ value={{
@@ -207,6 +222,8 @@ const Models: React.FC = () => {
handleSearch={handleSearch} handleSearch={handleSearch}
handlePageChange={handlePageChange} handlePageChange={handlePageChange}
handleDeleteSuccess={fetchData} handleDeleteSuccess={fetchData}
onViewLogs={handleOnViewLogs}
onCancelViewLogs={handleOnCancelViewLogs}
queryParams={queryParams} queryParams={queryParams}
loading={dataSource.loading} loading={dataSource.loading}
total={dataSource.total} total={dataSource.total}
@@ -114,9 +114,9 @@ const AudioInput: React.FC<AudioInputProps> = (props) => {
audioStream.current?.getTracks().forEach((track: any) => { audioStream.current?.getTracks().forEach((track: any) => {
track.stop(); track.stop();
}); });
scriptProcessor.current.disconnect(); scriptProcessor.current?.disconnect();
mediaStreamSource.current.disconnect(); mediaStreamSource.current?.disconnect();
audioContext.current.close(); audioContext.current?.close();
}; };
const handleStopRecording = () => { const handleStopRecording = () => {
@@ -1,7 +1,9 @@
import { setRouteCache } from '@/atoms/route-cache';
import AlertInfo from '@/components/alert-info'; import AlertInfo from '@/components/alert-info';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import FieldComponent from '@/components/seal-form/field-component'; import FieldComponent from '@/components/seal-form/field-component';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import routeCachekey from '@/config/route-cachekey';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import ThumbImg from '@/pages/playground/components/thumb-img'; import ThumbImg from '@/pages/playground/components/thumb-img';
import { generateRandomNumber } from '@/utils'; import { generateRandomNumber } from '@/utils';
@@ -208,6 +210,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
setMessageId(); setMessageId();
setTokenResult(null); setTokenResult(null);
setCurrentPrompt(current?.content || ''); setCurrentPrompt(current?.content || '');
setRouteCache(routeCachekey.playgroundTextToImage, true);
const imgSize = _.split(finalParameters.size, 'x'); const imgSize = _.split(finalParameters.size, 'x');
// preview // preview
@@ -237,7 +240,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
height: imgSize[1], height: imgSize[1],
width: imgSize[0], width: imgSize[0],
loading: true, loading: true,
progressType: stream_options.chunk_results ? 'dashboard' : 'line', progressType: 'dashboard',
preview: false, preview: false,
uid: setMessageId() uid: setMessageId()
}; };
@@ -316,6 +319,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
setImageList([]); setImageList([]);
} finally { } finally {
setLoading(false); setLoading(false);
setRouteCache(routeCachekey.playgroundTextToImage, false);
} }
}; };
const handleClear = () => { const handleClear = () => {
@@ -1,9 +1,11 @@
import { setRouteCache } from '@/atoms/route-cache';
import AlertInfo from '@/components/alert-info'; import AlertInfo from '@/components/alert-info';
import SingleImage from '@/components/auto-image/single-image'; import SingleImage from '@/components/auto-image/single-image';
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import CanvasImageEditor from '@/components/image-editor'; import CanvasImageEditor from '@/components/image-editor';
import FieldComponent from '@/components/seal-form/field-component'; import FieldComponent from '@/components/seal-form/field-component';
import SealSelect from '@/components/seal-form/seal-select'; import SealSelect from '@/components/seal-form/seal-select';
import routeCachekey from '@/config/route-cachekey';
import useOverlayScroller from '@/hooks/use-overlay-scroller'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import UploadImg from '@/pages/playground/components/upload-img'; import UploadImg from '@/pages/playground/components/upload-img';
import { base64ToFile, generateRandomNumber } from '@/utils'; import { base64ToFile, generateRandomNumber } from '@/utils';
@@ -218,6 +220,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
setMessageId(); setMessageId();
setTokenResult(null); setTokenResult(null);
setCurrentPrompt(current?.content || ''); setCurrentPrompt(current?.content || '');
setRouteCache(routeCachekey.playgroundTextToImage, true);
const imgSize = _.split(finalParameters.size, 'x'); const imgSize = _.split(finalParameters.size, 'x');
@@ -248,7 +251,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
height: imgSize[1], height: imgSize[1],
width: imgSize[0], width: imgSize[0],
loading: true, loading: true,
progressType: stream_options.chunk_results ? 'dashboard' : 'line', progressType: 'dashboard',
preview: false, preview: false,
uid: setMessageId() uid: setMessageId()
}; };
@@ -275,7 +278,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
const result: any = await fetchChunkedData({ const result: any = await fetchChunkedData({
data: params, data: params,
url: `http://192.168.50.4:40325/v1/images/edits?t=${Date.now()}`, url: `${EDIT_IMAGE_API}?t=${Date.now()}`,
signal: requestToken.current.signal signal: requestToken.current.signal
}); });
if (result.error) { if (result.error) {
@@ -327,6 +330,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
setImageList([]); setImageList([]);
} finally { } finally {
setLoading(false); setLoading(false);
setRouteCache(routeCachekey.playgroundTextToImage, false);
} }
}; };
const handleClear = () => { const handleClear = () => {
+3 -3
View File
@@ -5,7 +5,7 @@ import useWindowResize from '@/hooks/use-window-resize';
import { DiffOutlined, HighlightOutlined } from '@ant-design/icons'; import { DiffOutlined, HighlightOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components'; import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Segmented, Space, Tabs, TabsProps } from 'antd'; import { Button, Space, Tabs, TabsProps } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
@@ -155,14 +155,14 @@ const TextToImages: React.FC = () => {
<span className="font-600"> <span className="font-600">
{intl.formatMessage({ id: 'menu.playground.text2images' })} {intl.formatMessage({ id: 'menu.playground.text2images' })}
</span> </span>
{ {/* {
<Segmented <Segmented
options={optionsList} options={optionsList}
size="middle" size="middle"
className="m-l-40" className="m-l-40"
onChange={(key) => setActiveKey(key)} onChange={(key) => setActiveKey(key)}
></Segmented> ></Segmented>
} } */}
</div> </div>
), ),
breadcrumb: {} breadcrumb: {}