fix: clear instances when page hidden

This commit is contained in:
jialin
2025-01-19 20:51:06 +08:00
parent 4643dbce17
commit c49bfb97dd
12 changed files with 83 additions and 82 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
// import './iconfont/iconfont.js'; // import './iconfont/iconfont.js';
const IconFont = createFromIconfontCN({ const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4613488_pz4284jx1rq.js' scriptUrl: '//at.alicdn.com/t/c/font_4613488_6x6w1c4c2c.js'
}); });
export default IconFont; export default IconFont;
+56 -8
View File
@@ -62,6 +62,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
const strokeCache = useRef<any>({}); const strokeCache = useRef<any>({});
const preImguid = useRef<string | number>(''); const preImguid = useRef<string | number>('');
const [activeScale, setActiveScale] = useState<number>(1); const [activeScale, setActiveScale] = useState<number>(1);
const negativeMaskRef = useRef<boolean>(false);
const getTransformedPoint = useCallback( const getTransformedPoint = useCallback(
(offsetX: number, offsetY: number) => { (offsetX: number, offsetY: number) => {
@@ -159,6 +160,41 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
strokesRef.current = strokes; strokesRef.current = strokes;
}; };
const inpaintArea = useCallback(
(data: Uint8ClampedArray<ArrayBufferLike>) => {
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i + 3];
if (alpha > 0) {
data[i] = 255; // Red
data[i + 1] = 255; // Green
data[i + 2] = 255; // Blue
data[i + 3] = 255; // Alpha
}
}
},
[]
);
const inpaintBackground = useCallback(
(data: Uint8ClampedArray<ArrayBufferLike>) => {
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i + 3];
if (alpha > 0) {
data[i] = 0; // Red
data[i + 1] = 0; // Green
data[i + 2] = 0; // Blue
data[i + 3] = 255; // Alpha
} else {
data[i] = 255;
data[i + 1] = 255;
data[i + 2] = 255;
data[i + 3] = 255;
}
}
},
[]
);
const generateMask = useCallback(() => { const generateMask = useCallback(() => {
if (strokesRef.current.length === 0) { if (strokesRef.current.length === 0) {
return null; return null;
@@ -178,15 +214,12 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
); );
const data = imageData.data; const data = imageData.data;
for (let i = 0; i < data.length; i += 4) { if (negativeMaskRef.current) {
const alpha = data[i + 3]; inpaintBackground(data);
if (alpha > 0) { } else {
data[i] = 255; // Red inpaintArea(data);
data[i + 1] = 255; // Green
data[i + 2] = 255; // Blue
data[i + 3] = 255; // Alpha
}
} }
maskCtx.putImageData(imageData, 0, 0); maskCtx.putImageData(imageData, 0, 0);
maskCtx.globalCompositeOperation = 'destination-over'; maskCtx.globalCompositeOperation = 'destination-over';
@@ -620,6 +653,12 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
cursorRef.current!.style.width = `${value}px`; cursorRef.current!.style.width = `${value}px`;
cursorRef.current!.style.height = `${value}px`; cursorRef.current!.style.height = `${value}px`;
}; };
const handleOnChangeMask = (e: any) => {
negativeMaskRef.current = e.target.checked;
saveImage();
};
useEffect(() => { useEffect(() => {
initializeImage(); initializeImage();
}, [initializeImage]); }, [initializeImage]);
@@ -719,6 +758,15 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
</Tooltip> </Tooltip>
</div> </div>
<div className="tools"> <div className="tools">
{/* <Checkbox
onChange={handleOnChangeMask}
className="flex-center"
value={negativeMaskRef.current}
>
<span className="font-size-12">
{intl.formatMessage({ id: 'playground.image.negativeMask' })}
</span>
</Checkbox> */}
<Tooltip <Tooltip
title={intl.formatMessage({ id: 'playground.image.saveMask' })} title={intl.formatMessage({ id: 'playground.image.saveMask' })}
> >
@@ -197,6 +197,7 @@ const TableRow: React.FC<
const handleVisibilityChange = async () => { const handleVisibilityChange = async () => {
if (document.visibilityState === 'hidden') { if (document.visibilityState === 'hidden') {
cacheDataListRef.current = []; cacheDataListRef.current = [];
setChildrenData([]);
} }
}; };
@@ -218,10 +219,6 @@ const TableRow: React.FC<
}; };
}, [firstLoad, expanded, tableContext.allChildren]); }, [firstLoad, expanded, tableContext.allChildren]);
useEffect(() => {
console.log('allSubChildren===', tableContext.allSubChildren);
}, [tableContext.allSubChildren]);
const renderRowPrefix = () => { const renderRowPrefix = () => {
if (expandable && rowSelection) { if (expandable && rowSelection) {
return ( return (
+1
View File
@@ -133,6 +133,7 @@ export default {
'The higher the value, the greater the modification to the original image.', 'The higher the value, the greater the modification to the original image.',
'playground.image.edit.tips': 'Click or drag image to this area to upload', 'playground.image.edit.tips': 'Click or drag image to this area to upload',
'playground.image.saveMask': 'Save Mask', 'playground.image.saveMask': 'Save Mask',
'playground.image.negativeMask': 'Negative Mask',
'playground.image.brushSize': 'Brush Size', 'playground.image.brushSize': 'Brush Size',
'playground.image.download': 'Download Image', 'playground.image.download': 'Download Image',
'playground.image.generate': 'Generate', 'playground.image.generate': 'Generate',
+1
View File
@@ -128,6 +128,7 @@ export default {
'playground.image.strength.tip': '值越高,它对原图的修改越大', 'playground.image.strength.tip': '值越高,它对原图的修改越大',
'playground.image.edit.tips': '点击或拖动图片到此区域上传', 'playground.image.edit.tips': '点击或拖动图片到此区域上传',
'playground.image.saveMask': '保存遮罩', 'playground.image.saveMask': '保存遮罩',
'playground.image.negativeMask': '反向遮罩',
'playground.image.brushSize': '画笔大小', 'playground.image.brushSize': '画笔大小',
'playground.image.download': '下载图片', 'playground.image.download': '下载图片',
'playground.image.generate': '生成图片', 'playground.image.generate': '生成图片',
+3 -27
View File
@@ -66,7 +66,6 @@ interface ModelsProps {
handleCategoryChange: (val: any) => void; handleCategoryChange: (val: any) => void;
onViewLogs: () => void; onViewLogs: () => void;
onCancelViewLogs: () => void; onCancelViewLogs: () => void;
allInstances: ModelInstanceListItem[];
queryParams: { queryParams: {
page: number; page: number;
perPage: number; perPage: number;
@@ -120,7 +119,6 @@ const Models: React.FC<ModelsProps> = ({
onViewLogs, onViewLogs,
onCancelViewLogs, onCancelViewLogs,
handleCategoryChange, handleCategoryChange,
allInstances,
deleteIds, deleteIds,
dataSource, dataSource,
gpuDeviceList, gpuDeviceList,
@@ -144,7 +142,6 @@ const Models: React.FC<ModelsProps> = ({
defaultSortOrder: 'descend' defaultSortOrder: 'descend'
}); });
const updateRef = useRef(false);
const [openLogModal, setOpenLogModal] = useState(false); const [openLogModal, setOpenLogModal] = useState(false);
const [openAddModal, setOpenAddModal] = useState(false); const [openAddModal, setOpenAddModal] = useState(false);
const [openDeployModal, setOpenDeployModal] = useState<any>({ const [openDeployModal, setOpenDeployModal] = useState<any>({
@@ -673,24 +670,17 @@ const Models: React.FC<ModelsProps> = ({
const renderChildren = useCallback( const renderChildren = useCallback(
(list: any, parent?: any) => { (list: any, parent?: any) => {
let childList = list;
if (allInstances.length && !updateRef.current) {
childList = list.filter((item: any) => {
return allInstances.some((instance) => instance.id === item.id);
});
updateRef.current = true;
}
return ( return (
<InstanceItem <InstanceItem
list={childList} list={list}
modelData={parent} modelData={parent}
gpuDeviceList={gpuDeviceList} gpuDeviceList={[]}
workerList={workerList} workerList={workerList}
handleChildSelect={handleChildSelect} handleChildSelect={handleChildSelect}
></InstanceItem> ></InstanceItem>
); );
}, },
[workerList, allInstances] [workerList]
); );
const generateSource = useCallback((record: ListItem) => { const generateSource = useCallback((record: ListItem) => {
@@ -746,20 +736,6 @@ const Models: React.FC<ModelsProps> = ({
} }
}; };
useEffect(() => {
const handleVisibilityChange = async () => {
if (document.visibilityState === 'hidden') {
updateRef.current = false;
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
return ( return (
<> <>
<PageContainer <PageContainer
@@ -61,6 +61,7 @@ const sourceOptions = [
{ {
label: 'models.form.localPath', label: 'models.form.localPath',
value: modelSourceMap.local_path_value, value: modelSourceMap.local_path_value,
locale: true,
key: 'local_path' key: 'local_path'
} }
]; ];
+3 -32
View File
@@ -1,7 +1,5 @@
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 as generateAxiosToken
} from '@/hooks/use-chunk-request';
import useUpdateChunkedList from '@/hooks/use-update-chunk-list'; import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
import { queryWorkersList } from '@/pages/resources/apis'; import { queryWorkersList } from '@/pages/resources/apis';
import { import {
@@ -11,17 +9,10 @@ import {
import _ from 'lodash'; import _ from 'lodash';
import qs from 'query-string'; import qs from 'query-string';
import { memo, useCallback, useEffect, useRef, useState } from 'react'; import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { import { MODELS_API, MODEL_INSTANCE_API, queryModelsList } from './apis';
MODELS_API,
MODEL_INSTANCE_API,
queryModelsInstances,
queryModelsList
} from './apis';
import TableList from './components/table-list'; import TableList from './components/table-list';
import { ListItem } from './config/types'; import { ListItem } from './config/types';
const INSTANCE_SYNC = 'instance_sync';
const Models: React.FC = () => { const Models: React.FC = () => {
const { setChunkRequest, createAxiosToken } = useSetChunkRequest(); const { setChunkRequest, createAxiosToken } = useSetChunkRequest();
const { setChunkRequest: setModelInstanceChunkRequest } = const { setChunkRequest: setModelInstanceChunkRequest } =
@@ -39,7 +30,6 @@ const Models: React.FC = () => {
total: 0 total: 0
}); });
const [allInstances, setAllInstances] = useState<any[]>([]);
const [gpuDeviceList, setGpuDeviceList] = useState<GPUDeviceItem[]>([]); const [gpuDeviceList, setGpuDeviceList] = useState<GPUDeviceItem[]>([]);
const [workerList, setWorkerList] = useState<WokerListItem[]>([]); const [workerList, setWorkerList] = useState<WokerListItem[]>([]);
const chunkRequedtRef = useRef<any>(); const chunkRequedtRef = useRef<any>();
@@ -69,24 +59,6 @@ const Models: React.FC = () => {
} }
}); });
const fetchModelsInstances = async () => {
try {
instancesToken.current?.cancel?.();
instancesToken.current = generateAxiosToken();
const params = {
page: 1,
perPage: 100
};
const data: any = await queryModelsInstances(params, {
token: instancesToken.current?.token
});
setAllInstances(data.items || []);
} catch (error) {
// ignore
setAllInstances([]);
}
};
const getWorkerList = async () => { const getWorkerList = async () => {
try { try {
const data = await queryWorkersList({ page: 1, perPage: 100 }); const data = await queryWorkersList({ page: 1, perPage: 100 });
@@ -249,7 +221,7 @@ const Models: React.FC = () => {
const handleVisibilityChange = async () => { const handleVisibilityChange = async () => {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
isPageHidden.current = false; isPageHidden.current = false;
await fetchModelsInstances(); // await fetchModelsInstances();
await Promise.all([ await Promise.all([
createModelsChunkRequest(), createModelsChunkRequest(),
createModelsInstanceChunkRequest() createModelsInstanceChunkRequest()
@@ -284,7 +256,6 @@ const Models: React.FC = () => {
handlePageChange={handlePageChange} handlePageChange={handlePageChange}
handleDeleteSuccess={fetchData} handleDeleteSuccess={fetchData}
onViewLogs={handleOnViewLogs} onViewLogs={handleOnViewLogs}
allInstances={allInstances}
onCancelViewLogs={handleOnCancelViewLogs} onCancelViewLogs={handleOnCancelViewLogs}
queryParams={queryParams} queryParams={queryParams}
loading={dataSource.loading} loading={dataSource.loading}
@@ -28,7 +28,7 @@ import React, {
useState useState
} from 'react'; } from 'react';
import { CREAT_IMAGE_API } from '../apis'; import { CREAT_IMAGE_API } from '../apis';
import { promptList } from '../config'; import { extractErrorMessage, promptList } from '../config';
import { import {
ImageAdvancedParamsConfig, ImageAdvancedParamsConfig,
ImageCustomSizeConfig, ImageCustomSizeConfig,
@@ -336,8 +336,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
if (result.error) { if (result.error) {
setTokenResult({ setTokenResult({
error: true, error: true,
errorMessage: errorMessage: extractErrorMessage(result)
result?.data?.error?.message || result?.data?.error || ''
}); });
setImageList([]); setImageList([]);
return; return;
@@ -30,6 +30,7 @@ import React, {
useState useState
} from 'react'; } from 'react';
import { EDIT_IMAGE_API } from '../apis'; import { EDIT_IMAGE_API } from '../apis';
import { extractErrorMessage } from '../config';
import { import {
ImageAdvancedParamsConfig, ImageAdvancedParamsConfig,
ImageCustomSizeConfig, ImageCustomSizeConfig,
@@ -369,11 +370,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
if (result.error) { if (result.error) {
setTokenResult({ setTokenResult({
error: true, error: true,
errorMessage: errorMessage: extractErrorMessage(result)
result?.data?.data?.detail ||
result?.data?.error?.message ||
result?.data?.error ||
''
}); });
setImageList([]); setImageList([]);
return; return;
+10
View File
@@ -156,3 +156,13 @@ export const promptList = [
'A full shot of two people jogging at sunset, featuring a vibrant, warm color palette shifting from twilight blues to peachy-orange tones, with visible sun rays and lens flares, conveying a sense of leisure and athleticism.', 'A full shot of two people jogging at sunset, featuring a vibrant, warm color palette shifting from twilight blues to peachy-orange tones, with visible sun rays and lens flares, conveying a sense of leisure and athleticism.',
'A close-up portrait of a golden retriever wearing black-framed glasses, exhibiting a rich golden-brown coat with a fluffy texture, and a neutral, light gray background.' 'A close-up portrait of a golden retriever wearing black-framed glasses, exhibiting a rich golden-brown coat with a fluffy texture, and a neutral, light gray background.'
]; ];
export const extractErrorMessage = (result: any) => {
return (
result?.data?.data?.detail ||
result?.data?.data?.message ||
result?.data?.error?.message ||
result?.data?.error ||
''
);
};
+2 -2
View File
@@ -451,7 +451,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [
min: 256, min: 256,
max: 3200, max: 3200,
step: 64, step: 64,
inputnumber: true inputnumber: false
}, },
rules: [ rules: [
{ {
@@ -471,7 +471,7 @@ export const ImageCustomSizeConfig: ParamsSchema[] = [
min: 256, min: 256,
max: 3200, max: 3200,
step: 64, step: 64,
inputnumber: true inputnumber: false
}, },
rules: [ rules: [
{ {