fix: image edit ux
This commit is contained in:
@@ -18,6 +18,7 @@ export default function createProxyTable(target?: string) {
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
ws: true,
|
ws: true,
|
||||||
|
log: 'debug',
|
||||||
pathRewrite: (pth: string) => pth.replace(`/^/${api}`, `/${api}`),
|
pathRewrite: (pth: string) => pth.replace(`/^/${api}`, `/${api}`),
|
||||||
// onProxyRes: (proxyRes: any, req: any, res: any) => {
|
// onProxyRes: (proxyRes: any, req: any, res: any) => {
|
||||||
// console.log('headers=========', {
|
// console.log('headers=========', {
|
||||||
|
|||||||
@@ -14,5 +14,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|||||||
import IconFont from '../icon-font';
|
import IconFont from '../icon-font';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
type Point = { x: number; y: number };
|
type Point = { x: number; y: number; lineWidth: number };
|
||||||
type Stroke = Point[];
|
type Stroke = Point[];
|
||||||
|
|
||||||
type CanvasImageEditorProps = {
|
type CanvasImageEditorProps = {
|
||||||
@@ -48,6 +48,13 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
const cursorRef = useRef<HTMLDivElement>(null);
|
const cursorRef = useRef<HTMLDivElement>(null);
|
||||||
const [imgLoaded, setImgLoaded] = useState(false);
|
const [imgLoaded, setImgLoaded] = useState(false);
|
||||||
|
|
||||||
|
let scale = 1;
|
||||||
|
let offsetX = 0;
|
||||||
|
let offsetY = 0;
|
||||||
|
|
||||||
|
const MIN_SCALE = 0.5;
|
||||||
|
const MAX_SCALE = 5;
|
||||||
|
|
||||||
const getTransformedPoint = (event: React.MouseEvent<HTMLCanvasElement>) => {
|
const getTransformedPoint = (event: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
const overlayCanvas = overlayCanvasRef.current!;
|
const overlayCanvas = overlayCanvasRef.current!;
|
||||||
const rect = overlayCanvas.getBoundingClientRect();
|
const rect = overlayCanvas.getBoundingClientRect();
|
||||||
@@ -187,13 +194,12 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
stroke: Stroke | Point[],
|
stroke: Stroke | Point[],
|
||||||
options: {
|
options: {
|
||||||
lineWidth: number;
|
lineWidth?: number;
|
||||||
color: string;
|
color: string;
|
||||||
compositeOperation: 'source-over' | 'destination-out';
|
compositeOperation: 'source-over' | 'destination-out';
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const { lineWidth, color, compositeOperation } = options;
|
const { color, compositeOperation } = options;
|
||||||
ctx.lineWidth = lineWidth;
|
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
ctx.globalCompositeOperation = compositeOperation;
|
ctx.globalCompositeOperation = compositeOperation;
|
||||||
@@ -201,6 +207,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
stroke.forEach((point, i) => {
|
stroke.forEach((point, i) => {
|
||||||
|
ctx.lineWidth = point.lineWidth;
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
ctx.moveTo(point.x, point.y);
|
ctx.moveTo(point.x, point.y);
|
||||||
} else {
|
} else {
|
||||||
@@ -248,7 +255,8 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
console.log('Drawing:', e.nativeEvent, { x, y });
|
console.log('Drawing:', e.nativeEvent, { x, y });
|
||||||
currentStroke.current.push({
|
currentStroke.current.push({
|
||||||
x,
|
x,
|
||||||
y
|
y,
|
||||||
|
lineWidth
|
||||||
});
|
});
|
||||||
|
|
||||||
const ctx = overlayCanvasRef.current!.getContext('2d');
|
const ctx = overlayCanvasRef.current!.getContext('2d');
|
||||||
@@ -257,12 +265,12 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
|
|
||||||
drawLine(
|
drawLine(
|
||||||
ctx!,
|
ctx!,
|
||||||
{ x, y },
|
{ x, y, lineWidth },
|
||||||
{ lineWidth, color: COLOR, compositeOperation: 'destination-out' }
|
{ lineWidth, color: COLOR, compositeOperation: 'destination-out' }
|
||||||
);
|
);
|
||||||
drawLine(
|
drawLine(
|
||||||
ctx!,
|
ctx!,
|
||||||
{ x, y },
|
{ x, y, lineWidth },
|
||||||
{ lineWidth, color: COLOR, compositeOperation: 'source-over' }
|
{ lineWidth, color: COLOR, compositeOperation: 'source-over' }
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -276,7 +284,8 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
const { x, y } = getTransformedPoint(e);
|
const { x, y } = getTransformedPoint(e);
|
||||||
currentStroke.current.push({
|
currentStroke.current.push({
|
||||||
x,
|
x,
|
||||||
y
|
y,
|
||||||
|
lineWidth
|
||||||
});
|
});
|
||||||
|
|
||||||
const ctx = overlayCanvasRef.current!.getContext('2d');
|
const ctx = overlayCanvasRef.current!.getContext('2d');
|
||||||
@@ -367,20 +376,18 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
strokes?.forEach((stroke: Point[], index) => {
|
strokes?.forEach((stroke: Point[], index) => {
|
||||||
overlayCtx.save();
|
overlayCtx.save();
|
||||||
drawStroke(overlayCtx, stroke, {
|
drawStroke(overlayCtx, stroke, {
|
||||||
lineWidth,
|
|
||||||
color: COLOR,
|
color: COLOR,
|
||||||
compositeOperation: 'destination-out'
|
compositeOperation: 'destination-out'
|
||||||
});
|
});
|
||||||
|
|
||||||
drawStroke(overlayCtx, stroke, {
|
drawStroke(overlayCtx, stroke, {
|
||||||
lineWidth,
|
|
||||||
color: COLOR,
|
color: COLOR,
|
||||||
compositeOperation: 'source-over'
|
compositeOperation: 'source-over'
|
||||||
});
|
});
|
||||||
overlayCtx.restore();
|
overlayCtx.restore();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[lineWidth, drawStroke]
|
[drawStroke]
|
||||||
);
|
);
|
||||||
|
|
||||||
const undo = () => {
|
const undo = () => {
|
||||||
@@ -408,7 +415,8 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
return stroke.map((point) => {
|
return stroke.map((point) => {
|
||||||
return {
|
return {
|
||||||
x: point.x * scale,
|
x: point.x * scale,
|
||||||
y: point.y * scale
|
y: point.y * scale,
|
||||||
|
lineWidth: point.lineWidth
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -466,7 +474,6 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
const contentRect = entries[0].contentRect;
|
const contentRect = entries[0].contentRect;
|
||||||
if (!contentRect.width || !contentRect.height || !imgLoaded) return;
|
if (!contentRect.width || !contentRect.height || !imgLoaded) return;
|
||||||
await drawImage();
|
await drawImage();
|
||||||
console.log('Image Loaded:', imageStatus, strokesRef.current);
|
|
||||||
if (imageStatus.isOriginal) {
|
if (imageStatus.isOriginal) {
|
||||||
redrawStrokes(strokesRef.current, 'resize');
|
redrawStrokes(strokesRef.current, 'resize');
|
||||||
}
|
}
|
||||||
@@ -486,24 +493,70 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
}
|
}
|
||||||
}, [drawImage, onReset, redrawStrokes, imageStatus]);
|
}, [drawImage, onReset, redrawStrokes, imageStatus]);
|
||||||
|
|
||||||
|
const calcTransformedPoint = (event: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
|
const overlayCanvas = overlayCanvasRef.current!;
|
||||||
|
const rect = overlayCanvas.getBoundingClientRect();
|
||||||
|
|
||||||
|
// 获取鼠标在画布上的原始坐标
|
||||||
|
const x = event.clientX - rect.left;
|
||||||
|
const y = event.clientY - rect.top;
|
||||||
|
|
||||||
|
// 考虑缩放比例和偏移量
|
||||||
|
const transformedX = (x - offsetX) / scale;
|
||||||
|
const transformedY = (y - offsetY) / scale;
|
||||||
|
|
||||||
|
return { x: transformedX, y: transformedY };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnWheel = (event: WheelEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const zoomFactor = event.deltaY < 0 ? 1.1 : 0.9;
|
||||||
|
const newScale = Math.min(
|
||||||
|
MAX_SCALE,
|
||||||
|
Math.max(MIN_SCALE, scale * zoomFactor)
|
||||||
|
);
|
||||||
|
|
||||||
|
const rect = canvasRef.current!.getBoundingClientRect();
|
||||||
|
const mouseX = event.clientX - rect.left;
|
||||||
|
const mouseY = event.clientY - rect.top;
|
||||||
|
|
||||||
|
// 计算新的偏移量
|
||||||
|
offsetX = mouseX - (mouseX - offsetX) * (newScale / scale);
|
||||||
|
offsetY = mouseY - (mouseY - offsetY) * (newScale / scale);
|
||||||
|
|
||||||
|
// 更新缩放比例
|
||||||
|
scale = newScale;
|
||||||
|
|
||||||
|
// 设置画布的变换
|
||||||
|
const overlayCtx = overlayCanvasRef.current!.getContext('2d')!;
|
||||||
|
overlayCtx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
const canvasCtx = canvasRef.current!.getContext('2d')!;
|
||||||
|
canvasCtx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
overlayCanvasRef.current!.style.transform = `scale(${scale})`;
|
||||||
|
canvasRef.current!.style.transform = `scale(${scale})`;
|
||||||
|
|
||||||
|
console.log('Zoom:', scale, offsetX, offsetY);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initializeImage();
|
initializeImage();
|
||||||
}, [initializeImage]);
|
}, [initializeImage]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const container = containerRef.current;
|
// const container = containerRef.current;
|
||||||
if (!container) return;
|
// if (!container) return;
|
||||||
if (container) {
|
// if (container) {
|
||||||
resizeObserver.current = new ResizeObserver(
|
// resizeObserver.current = new ResizeObserver(
|
||||||
_.throttle(handleResize, 100)
|
// _.throttle(handleResize, 100)
|
||||||
);
|
// );
|
||||||
resizeObserver.current.observe(container);
|
// resizeObserver.current.observe(container);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return () => {
|
// return () => {
|
||||||
resizeObserver.current?.disconnect();
|
// resizeObserver.current?.disconnect();
|
||||||
};
|
// };
|
||||||
}, [handleResize, containerRef.current]);
|
// }, [handleResize, containerRef.current]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
createOffscreenCanvas();
|
createOffscreenCanvas();
|
||||||
@@ -551,7 +604,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = ({
|
|||||||
style={{ marginBlock: '4px 6px', marginLeft: 0, flex: 1 }}
|
style={{ marginBlock: '4px 6px', marginLeft: 0, flex: 1 }}
|
||||||
vertical={false}
|
vertical={false}
|
||||||
defaultValue={lineWidth}
|
defaultValue={lineWidth}
|
||||||
min={1}
|
min={10}
|
||||||
max={60}
|
max={60}
|
||||||
onChange={(value) => setLineWidth(value)}
|
onChange={(value) => setLineWidth(value)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ interface ChunkedCollection {
|
|||||||
collection: any[];
|
collection: any[];
|
||||||
type: string | number;
|
type: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventsType = 'CREATE' | 'UPDATE' | 'DELETE' | 'INSERT';
|
||||||
|
|
||||||
// Only used to update lists without nested state
|
// Only used to update lists without nested state
|
||||||
export function useUpdateChunkedList(options: {
|
export function useUpdateChunkedList(options: {
|
||||||
|
events?: EventsType[];
|
||||||
dataList?: any[];
|
dataList?: any[];
|
||||||
limit?: number;
|
limit?: number;
|
||||||
setDataList: (args: any, opts?: any) => void;
|
setDataList: (args: any, opts?: any) => void;
|
||||||
@@ -17,10 +21,10 @@ export function useUpdateChunkedList(options: {
|
|||||||
mapFun?: (args: any) => any;
|
mapFun?: (args: any) => any;
|
||||||
computedID?: (d: object) => string;
|
computedID?: (d: object) => string;
|
||||||
}) {
|
}) {
|
||||||
|
const { events = ['CREATE', 'DELETE', 'UPDATE', 'INSERT'] } = options;
|
||||||
const deletedIdsRef = useRef<Set<number | string>>(new Set());
|
const deletedIdsRef = useRef<Set<number | string>>(new Set());
|
||||||
const cacheDataListRef = useRef<any[]>(options.dataList || []);
|
const cacheDataListRef = useRef<any[]>(options.dataList || []);
|
||||||
const timerRef = useRef<any>(null);
|
const timerRef = useRef<any>(null);
|
||||||
const countRef = useRef<number>(0);
|
|
||||||
const limit = options.limit || 10;
|
const limit = options.limit || 10;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -57,7 +61,7 @@ export function useUpdateChunkedList(options: {
|
|||||||
}
|
}
|
||||||
const ids: any[] = data?.ids || [];
|
const ids: any[] = data?.ids || [];
|
||||||
// CREATE
|
// CREATE
|
||||||
if (data?.type === WatchEventType.CREATE) {
|
if (data?.type === WatchEventType.CREATE && events.includes('CREATE')) {
|
||||||
const newDataList = collections.reduce((acc: any[], item: any) => {
|
const newDataList = collections.reduce((acc: any[], item: any) => {
|
||||||
const updateIndex = cacheDataListRef.current?.findIndex(
|
const updateIndex = cacheDataListRef.current?.findIndex(
|
||||||
(sItem: any) => sItem.id === item.id
|
(sItem: any) => sItem.id === item.id
|
||||||
@@ -77,7 +81,7 @@ export function useUpdateChunkedList(options: {
|
|||||||
].slice(0, limit);
|
].slice(0, limit);
|
||||||
}
|
}
|
||||||
// DELETE
|
// DELETE
|
||||||
if (data?.type === WatchEventType.DELETE) {
|
if (data?.type === WatchEventType.DELETE && events.includes('DELETE')) {
|
||||||
cacheDataListRef.current = cacheDataListRef.current?.filter(
|
cacheDataListRef.current = cacheDataListRef.current?.filter(
|
||||||
(item: any) => {
|
(item: any) => {
|
||||||
return !ids?.includes(item.id);
|
return !ids?.includes(item.id);
|
||||||
@@ -89,7 +93,7 @@ export function useUpdateChunkedList(options: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// UPDATE
|
// UPDATE
|
||||||
if (data?.type === WatchEventType.UPDATE) {
|
if (data?.type === WatchEventType.UPDATE && events.includes('UPDATE')) {
|
||||||
collections?.forEach((item: any) => {
|
collections?.forEach((item: any) => {
|
||||||
const updateIndex = cacheDataListRef.current?.findIndex(
|
const updateIndex = cacheDataListRef.current?.findIndex(
|
||||||
(sItem: any) => sItem.id === item.id
|
(sItem: any) => sItem.id === item.id
|
||||||
@@ -97,7 +101,7 @@ export function useUpdateChunkedList(options: {
|
|||||||
const updateItem = { ...item };
|
const updateItem = { ...item };
|
||||||
if (updateIndex > -1) {
|
if (updateIndex > -1) {
|
||||||
cacheDataListRef.current[updateIndex] = updateItem;
|
cacheDataListRef.current[updateIndex] = updateItem;
|
||||||
} else if (updateIndex === -1) {
|
} else if (updateIndex === -1 && events.includes('INSERT')) {
|
||||||
cacheDataListRef.current = [
|
cacheDataListRef.current = [
|
||||||
updateItem,
|
updateItem,
|
||||||
...cacheDataListRef.current.slice(0, limit - 1)
|
...cacheDataListRef.current.slice(0, limit - 1)
|
||||||
|
|||||||
@@ -88,5 +88,5 @@ export default {
|
|||||||
'models.form.search.gguftips':
|
'models.form.search.gguftips':
|
||||||
'If using macOS 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',
|
||||||
'models.filter.category': 'Filter by Category'
|
'models.filter.category': 'Filter by category'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { ListItem } from './config/types';
|
|||||||
const { Column } = Table;
|
const { Column } = Table;
|
||||||
|
|
||||||
const APIKeys: React.FC = () => {
|
const APIKeys: React.FC = () => {
|
||||||
console.log('APIKeys========');
|
|
||||||
const rowSelection = useTableRowSelection();
|
const rowSelection = useTableRowSelection();
|
||||||
const { sortOrder, setSortOrder } = useTableSort({
|
const { sortOrder, setSortOrder } = useTableSort({
|
||||||
defaultSortOrder: 'descend'
|
defaultSortOrder: 'descend'
|
||||||
@@ -47,7 +46,6 @@ const APIKeys: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handlePageChange = (page: number, pageSize: number) => {
|
const handlePageChange = (page: number, pageSize: number) => {
|
||||||
console.log('handlePageChange====', page, pageSize);
|
|
||||||
setQueryParams({
|
setQueryParams({
|
||||||
...queryParams,
|
...queryParams,
|
||||||
page: page,
|
page: page,
|
||||||
@@ -56,7 +54,6 @@ const APIKeys: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleTableChange = (pagination: any, filters: any, sorter: any) => {
|
const handleTableChange = (pagination: any, filters: any, sorter: any) => {
|
||||||
console.log('handleTableChange=======', pagination, filters, sorter);
|
|
||||||
setSortOrder(sorter.order);
|
setSortOrder(sorter.order);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const Catalog: React.FC = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [span, setSpan] = React.useState(8);
|
const [span, setSpan] = React.useState(8);
|
||||||
const [activeId, setActiveId] = React.useState(-1);
|
const [activeId, setActiveId] = React.useState(-1);
|
||||||
|
const [isFirst, setIsFirst] = React.useState(true);
|
||||||
const [dataSource, setDataSource] = useState<{
|
const [dataSource, setDataSource] = useState<{
|
||||||
dataList: CatalogItemType[];
|
dataList: CatalogItemType[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -102,6 +103,8 @@ const Catalog: React.FC = () => {
|
|||||||
total: dataSource.total
|
total: dataSource.total
|
||||||
});
|
});
|
||||||
console.log('error', error);
|
console.log('error', error);
|
||||||
|
} finally {
|
||||||
|
setIsFirst(false);
|
||||||
}
|
}
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
@@ -297,7 +300,7 @@ const Catalog: React.FC = () => {
|
|||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
wrapperClassName="skelton-wrapper"
|
wrapperClassName="skelton-wrapper"
|
||||||
>
|
>
|
||||||
<CatalogSkelton span={span}></CatalogSkelton>
|
{isFirst && <CatalogSkelton span={span}></CatalogSkelton>}
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ import { Button, Drawer } from 'antd';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { queryCatalogItemSpec } from '../apis';
|
import { queryCatalogItemSpec } from '../apis';
|
||||||
import { backendOptionsMap, modelSourceMap, sourceOptions } from '../config';
|
import {
|
||||||
|
backendOptionsMap,
|
||||||
|
modelCategoriesMap,
|
||||||
|
modelSourceMap,
|
||||||
|
sourceOptions
|
||||||
|
} from '../config';
|
||||||
import { CatalogSpec, FormData, ListItem } from '../config/types';
|
import { CatalogSpec, FormData, ListItem } from '../config/types';
|
||||||
import ColumnWrapper from './column-wrapper';
|
import ColumnWrapper from './column-wrapper';
|
||||||
import DataForm from './data-form';
|
import DataForm from './data-form';
|
||||||
@@ -40,6 +45,7 @@ const backendOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const defaultQuant = ['Q4_K_M'];
|
const defaultQuant = ['Q4_K_M'];
|
||||||
|
const EmbeddingRerankFirstQuant = ['FP16'];
|
||||||
const AddModal: React.FC<AddModalProps> = (props) => {
|
const AddModal: React.FC<AddModalProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
@@ -51,7 +57,6 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
current,
|
current,
|
||||||
width = 600
|
width = 600
|
||||||
} = props || {};
|
} = props || {};
|
||||||
const SEARCH_SOURCE = [];
|
|
||||||
|
|
||||||
const form = useRef<any>({});
|
const form = useRef<any>({});
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -69,6 +74,16 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
form.current?.submit?.();
|
form.current?.submit?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDefaultQuant = (data: { category: string; quantOption: string }) => {
|
||||||
|
if (
|
||||||
|
data.category === modelCategoriesMap.embedding ||
|
||||||
|
data.category === modelCategoriesMap.reranker
|
||||||
|
) {
|
||||||
|
return EmbeddingRerankFirstQuant.includes(data.quantOption);
|
||||||
|
}
|
||||||
|
return defaultQuant.includes(data.quantOption);
|
||||||
|
};
|
||||||
|
|
||||||
const getModelFile = (spec: CatalogSpec) => {
|
const getModelFile = (spec: CatalogSpec) => {
|
||||||
let modelInfo = {};
|
let modelInfo = {};
|
||||||
if (spec.source === modelSourceMap.huggingface_value) {
|
if (spec.source === modelSourceMap.huggingface_value) {
|
||||||
@@ -234,7 +249,10 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
size: _.get(sizeList, '0.value', 0),
|
size: _.get(sizeList, '0.value', 0),
|
||||||
quantization:
|
quantization:
|
||||||
_.find(quantizaList, (item: { label: string; value: string }) =>
|
_.find(quantizaList, (item: { label: string; value: string }) =>
|
||||||
defaultQuant.includes(item.value)
|
getDefaultQuant({
|
||||||
|
category: _.get(current, 'categories.0', ''),
|
||||||
|
quantOption: item.value
|
||||||
|
})
|
||||||
)?.value || _.get(quantizaList, '0.value', '')
|
)?.value || _.get(quantizaList, '0.value', '')
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -264,7 +282,10 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
const source = _.get(sources, '0.value', '');
|
const source = _.get(sources, '0.value', '');
|
||||||
const defaultSpec =
|
const defaultSpec =
|
||||||
_.find(groupList[source], (item: CatalogSpec) => {
|
_.find(groupList[source], (item: CatalogSpec) => {
|
||||||
return defaultQuant.includes(item.quantization);
|
return getDefaultQuant({
|
||||||
|
category: _.get(current, 'categories.0', ''),
|
||||||
|
quantOption: item.quantization
|
||||||
|
});
|
||||||
}) || _.get(groupList, `${source}.0`, {});
|
}) || _.get(groupList, `${source}.0`, {});
|
||||||
|
|
||||||
setSourceList(sources);
|
setSourceList(sources);
|
||||||
@@ -320,7 +341,10 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
size: val,
|
size: val,
|
||||||
quantization:
|
quantization:
|
||||||
_.find(list, (item: { label: string; value: string }) =>
|
_.find(list, (item: { label: string; value: string }) =>
|
||||||
defaultQuant.includes(item.value)
|
getDefaultQuant({
|
||||||
|
category: _.get(current, 'categories.0', ''),
|
||||||
|
quantOption: item.value
|
||||||
|
})
|
||||||
)?.value || _.get(list, '0.value', '')
|
)?.value || _.get(list, '0.value', '')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ import UpdateModel from './update-modal';
|
|||||||
import ViewLogsModal from './view-logs-modal';
|
import ViewLogsModal from './view-logs-modal';
|
||||||
|
|
||||||
interface ModelsProps {
|
interface ModelsProps {
|
||||||
handleSearch: (e: any) => void;
|
handleSearch: () => void;
|
||||||
handleNameChange: (e: any) => void;
|
handleNameChange: (e: any) => void;
|
||||||
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;
|
||||||
@@ -337,7 +337,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
const handleModalOk = useCallback(
|
const handleModalOk = useCallback(
|
||||||
async (data: FormData) => {
|
async (data: FormData) => {
|
||||||
try {
|
try {
|
||||||
console.log('data:', data, openDeployModal);
|
|
||||||
const result = getSourceRepoConfigValue(currentData?.source, data);
|
const result = getSourceRepoConfigValue(currentData?.source, data);
|
||||||
await updateModel({
|
await updateModel({
|
||||||
data: {
|
data: {
|
||||||
@@ -348,6 +347,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
});
|
});
|
||||||
setOpenAddModal(false);
|
setOpenAddModal(false);
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
handleSearch();
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
},
|
},
|
||||||
[currentData]
|
[currentData]
|
||||||
@@ -385,6 +385,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
updateExpandedRowKeys([modelData.id, ...expandedRowKeys]);
|
updateExpandedRowKeys([modelData.id, ...expandedRowKeys]);
|
||||||
}, 300);
|
}, 300);
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
|
handleSearch?.();
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
},
|
},
|
||||||
[openDeployModal]
|
[openDeployModal]
|
||||||
@@ -405,6 +406,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
removeExpandedRowKey([row.id]);
|
removeExpandedRowKey([row.id]);
|
||||||
rowSelection.removeSelectedKey(row.id);
|
rowSelection.removeSelectedKey(row.id);
|
||||||
handleDeleteSuccess();
|
handleDeleteSuccess();
|
||||||
|
handleSearch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -419,6 +421,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
rowSelection.clearSelections();
|
rowSelection.clearSelections();
|
||||||
removeExpandedRowKey(rowSelection.selectedRowKeys);
|
removeExpandedRowKey(rowSelection.selectedRowKeys);
|
||||||
handleDeleteSuccess();
|
handleDeleteSuccess();
|
||||||
|
handleSearch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ const Models: React.FC = () => {
|
|||||||
|
|
||||||
const { updateChunkedList, cacheDataListRef, deletedIdsRef } =
|
const { updateChunkedList, cacheDataListRef, deletedIdsRef } =
|
||||||
useUpdateChunkedList({
|
useUpdateChunkedList({
|
||||||
|
events: ['UPDATE'],
|
||||||
dataList: dataSource.dataList,
|
dataList: dataSource.dataList,
|
||||||
setDataList(list, opts?: any) {
|
setDataList(list, opts?: any) {
|
||||||
setDataSource((pre) => {
|
setDataSource((pre) => {
|
||||||
@@ -118,8 +119,6 @@ const Models: React.FC = () => {
|
|||||||
_.each(list, (data: any) => {
|
_.each(list, (data: any) => {
|
||||||
updateChunkedList(data);
|
updateChunkedList(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('deletedIdsRef=======', deletedIdsRef.current);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateInstanceHandler = (list: any) => {
|
const updateInstanceHandler = (list: any) => {
|
||||||
@@ -129,14 +128,19 @@ const Models: React.FC = () => {
|
|||||||
const createModelsChunkRequest = useCallback(async () => {
|
const createModelsChunkRequest = useCallback(async () => {
|
||||||
chunkRequedtRef.current?.current?.cancel?.();
|
chunkRequedtRef.current?.current?.cancel?.();
|
||||||
try {
|
try {
|
||||||
|
const query = {
|
||||||
|
search: queryParams.search,
|
||||||
|
categories: queryParams.categories
|
||||||
|
};
|
||||||
chunkRequedtRef.current = setChunkRequest({
|
chunkRequedtRef.current = setChunkRequest({
|
||||||
url: `${MODELS_API}?${qs.stringify(_.pickBy(queryParams, (val: any) => !!val))}`,
|
url: `${MODELS_API}?${qs.stringify(_.pickBy(query, (val: any) => !!val))}`,
|
||||||
handler: updateHandler
|
handler: updateHandler
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}, [queryParams]);
|
}, [queryParams.categories, queryParams.search]);
|
||||||
|
|
||||||
const createModelsInstanceChunkRequest = useCallback(async () => {
|
const createModelsInstanceChunkRequest = useCallback(async () => {
|
||||||
chunkInstanceRequedtRef.current?.current?.cancel?.();
|
chunkInstanceRequedtRef.current?.current?.cancel?.();
|
||||||
try {
|
try {
|
||||||
@@ -150,11 +154,6 @@ const Models: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getList = async () => {
|
|
||||||
await fetchData();
|
|
||||||
await createModelsChunkRequest();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnViewLogs = useCallback(() => {
|
const handleOnViewLogs = useCallback(() => {
|
||||||
isPageHidden.current = true;
|
isPageHidden.current = true;
|
||||||
chunkRequedtRef.current?.current?.cancel?.();
|
chunkRequedtRef.current?.current?.cancel?.();
|
||||||
@@ -173,12 +172,9 @@ const Models: React.FC = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]);
|
}, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]);
|
||||||
|
|
||||||
const handleSearch = useCallback(
|
const handleSearch = useCallback(async () => {
|
||||||
async (e: any) => {
|
await fetchData();
|
||||||
await fetchData();
|
}, [fetchData]);
|
||||||
},
|
|
||||||
[fetchData]
|
|
||||||
);
|
|
||||||
|
|
||||||
const debounceUpdateFilter = _.debounce((e: any) => {
|
const debounceUpdateFilter = _.debounce((e: any) => {
|
||||||
setQueryParams({
|
setQueryParams({
|
||||||
@@ -202,12 +198,16 @@ const Models: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getList();
|
fetchData();
|
||||||
return () => {
|
return () => {
|
||||||
axiosToken?.cancel?.();
|
axiosToken?.cancel?.();
|
||||||
};
|
};
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
createModelsChunkRequest();
|
||||||
|
}, [createModelsChunkRequest]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getWorkerList();
|
getWorkerList();
|
||||||
createModelsInstanceChunkRequest();
|
createModelsInstanceChunkRequest();
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const METAKEYS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const advancedFieldsDefaultValus = {
|
const advancedFieldsDefaultValus = {
|
||||||
seed: 1,
|
seed: null,
|
||||||
sample_method: 'euler_a',
|
sample_method: 'euler_a',
|
||||||
cfg_scale: 4.5,
|
cfg_scale: 4.5,
|
||||||
guidance: 3.5,
|
guidance: 3.5,
|
||||||
@@ -278,6 +278,14 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setMessageId();
|
setMessageId();
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
setCurrentPrompt(current?.content || '');
|
setCurrentPrompt(current?.content || '');
|
||||||
|
setUploadList((pre) => {
|
||||||
|
return pre.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
dataUrl: image
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
setRouteCache(routeCachekey['/playground/text-to-image'], true);
|
setRouteCache(routeCachekey['/playground/text-to-image'], true);
|
||||||
|
|
||||||
const imgSize = _.split(finalParameters.size, 'x').map((item: string) =>
|
const imgSize = _.split(finalParameters.size, 'x').map((item: string) =>
|
||||||
@@ -338,8 +346,8 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
const result: any = await fetchChunkedData({
|
const result: any = await fetchChunkedData({
|
||||||
data: params,
|
data: params,
|
||||||
// url: `http:///v1/images/edits?t=${Date.now()}`,
|
// url: 'http://192.168.50.174:40053/v1/images/edits',
|
||||||
url: `${EDIT_IMAGE_API}?t=${Date.now()}`,
|
url: EDIT_IMAGE_API,
|
||||||
signal: requestToken.current.signal
|
signal: requestToken.current.signal
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -372,6 +380,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
imgItem.dataUrl = `data:image/png;base64,${item.b64_json}`;
|
imgItem.dataUrl = `data:image/png;base64,${item.b64_json}`;
|
||||||
}
|
}
|
||||||
const progress = _.round(item.progress, 0);
|
const progress = _.round(item.progress, 0);
|
||||||
|
console.log('progress:', item, progress);
|
||||||
newImageList[item.index] = {
|
newImageList[item.index] = {
|
||||||
dataUrl: imgItem.dataUrl,
|
dataUrl: imgItem.dataUrl,
|
||||||
height: imgSize[1],
|
height: imgSize[1],
|
||||||
@@ -381,7 +390,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
uid: imgItem.uid,
|
uid: imgItem.uid,
|
||||||
span: imgItem.span,
|
span: imgItem.span,
|
||||||
loading: stream_options.chunk_results ? progress < 100 : false,
|
loading: stream_options.chunk_results ? progress < 100 : false,
|
||||||
preview: progress >= 100,
|
preview: false,
|
||||||
progress: progress
|
progress: progress
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -588,6 +597,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleUpdateImageList = useCallback((base64List: any) => {
|
const handleUpdateImageList = useCallback((base64List: any) => {
|
||||||
|
console.log('updateimagelist=========', base64List);
|
||||||
const img = _.get(base64List, '[0].dataUrl', '');
|
const img = _.get(base64List, '[0].dataUrl', '');
|
||||||
setUploadList(base64List);
|
setUploadList(base64List);
|
||||||
setImage(img);
|
setImage(img);
|
||||||
@@ -667,7 +677,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
{...uploadList[0]}
|
{...uploadList[0]}
|
||||||
height={125}
|
height={125}
|
||||||
maxHeight={125}
|
maxHeight={125}
|
||||||
preview={true}
|
preview={false}
|
||||||
loading={false}
|
loading={false}
|
||||||
autoSize={false}
|
autoSize={false}
|
||||||
editable={false}
|
editable={false}
|
||||||
@@ -728,11 +738,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
return (
|
return (
|
||||||
<div className="ground-left-wrapper">
|
<div className="ground-left-wrapper">
|
||||||
<div className="ground-left">
|
<div className="ground-left">
|
||||||
<div
|
<div className="message-list-wrap" style={{ paddingBottom: 16 }}>
|
||||||
className="message-list-wrap"
|
|
||||||
ref={scroller}
|
|
||||||
style={{ paddingBottom: 16 }}
|
|
||||||
>
|
|
||||||
<>
|
<>
|
||||||
<div className="content" style={{ height: '100%' }}>
|
<div className="content" style={{ height: '100%' }}>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ const createFormData = (data: any): FormData => {
|
|||||||
formData.append(key, value);
|
formData.append(key, value);
|
||||||
} else if (typeof value === 'object' && value !== null) {
|
} else if (typeof value === 'object' && value !== null) {
|
||||||
formData.append(key, JSON.stringify(value));
|
formData.append(key, JSON.stringify(value));
|
||||||
} else {
|
} else if (value !== undefined && value !== null) {
|
||||||
formData.append(key, String(value));
|
formData.append(key, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user