fix: edit mask for undo

main
jialin 11 months ago
parent 08b3c9d1ac
commit 00ef7ab6ca

@ -43,6 +43,7 @@
padding-inline: 12px 12px;
border-radius: 0 0 var(--border-radius-mini) var(--border-radius-mini);
position: relative;
white-space: pre-wrap;
code {
line-height: 1.5;

@ -24,6 +24,7 @@ export default function useDrawing(props: {
const mouseDownState = useRef<boolean>(false);
const canvasRef = useRef<HTMLCanvasElement>(null);
const overlayCanvasRef = useRef<HTMLCanvasElement>(null);
const offscreenCanvasRef = useRef<any>(null);
const currentStroke = useRef<Point[]>([]);
const strokesRef = useRef<Stroke[]>([]);
const isDrawing = useRef<boolean>(false);
@ -101,20 +102,29 @@ export default function useDrawing(props: {
onSave({ mask, img });
};
const creatOffscreenCanvas = useCallback(() => {
if (!offscreenCanvasRef.current) {
offscreenCanvasRef.current = document.createElement('canvas');
}
}, []);
const setTransform = useCallback(() => {
creatOffscreenCanvas();
const ctx = canvasRef.current?.getContext('2d');
const overlayCtx = overlayCanvasRef.current?.getContext('2d');
const offCtx = offscreenCanvasRef.current?.getContext('2d');
if (!ctx || !overlayCtx) return;
ctx!.resetTransform();
overlayCtx!.resetTransform();
offCtx!.resetTransform();
const { current: scale } = autoScale;
const { x: translateX, y: translateY } = translatePos.current;
ctx!.setTransform(scale, 0, 0, scale, translateX, translateY);
overlayCtx!.setTransform(scale, 0, 0, scale, translateX, translateY);
offCtx!.setTransform(scale, 0, 0, scale, translateX, translateY);
}, []);
const getTransformedPoint = useCallback(
@ -134,9 +144,13 @@ export default function useDrawing(props: {
[]
);
const getTransformLineWidth = useCallback((lineWidth = 1) => {
return lineWidth / autoScale.current;
}, []);
const getTransformLineWidth = useCallback(
(w = 1) => {
const width = w || lineWidth;
return width / autoScale.current;
},
[lineWidth]
);
const drawLine = useCallback(
(
@ -180,6 +194,7 @@ export default function useDrawing(props: {
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.globalCompositeOperation = compositeOperation;
ctx.save();
ctx.beginPath();
@ -196,6 +211,7 @@ export default function useDrawing(props: {
ctx.strokeStyle = color;
}
ctx.stroke();
ctx.restore();
},
[getTransformLineWidth, getTransformedPoint]
);
@ -323,6 +339,9 @@ export default function useDrawing(props: {
const clearOverlayCanvas = useCallback(() => {
const ctx = overlayCanvasRef.current!.getContext('2d');
const offCtx = offscreenCanvasRef.current?.getContext('2d');
offCtx!.resetTransform();
ctx!.resetTransform();
ctx!.clearRect(
0,
@ -330,33 +349,48 @@ export default function useDrawing(props: {
overlayCanvasRef.current!.width,
overlayCanvasRef.current!.height
);
offCtx!.clearRect(
0,
0,
overlayCanvasRef.current!.width,
overlayCanvasRef.current!.height
);
}, []);
const clearCanvas = useCallback(() => {
const canvas = canvasRef.current!;
const ctx = canvasRef.current!.getContext('2d');
const offCtx = offscreenCanvasRef.current?.getContext('2d');
ctx!.resetTransform();
ctx!.clearRect(0, 0, canvas.width, canvas.height);
offCtx!.resetTransform();
offCtx!.clearRect(0, 0, canvas.width, canvas.height);
}, []);
const resetCanvas = useCallback(() => {
const canvas = canvasRef.current!;
const overlayCanvas = overlayCanvasRef.current!;
const offscreenCanvas = offscreenCanvasRef.current!;
const ctx = canvas.getContext('2d');
const overlayCtx = overlayCanvas.getContext('2d');
const offCtx = offscreenCanvasRef.current?.getContext('2d');
autoScale.current = 1;
baseScale.current = 1;
translatePos.current = { x: 0, y: 0 };
contentPos.current = { x: 0, y: 0 };
canvas.style.transform = 'scale(1)';
overlayCanvas.style.transform = 'scale(1)';
offscreenCanvas.style.transform = 'scale(1)';
cursorRef.current!.style.width = `${lineWidth}px`;
cursorRef.current!.style.height = `${lineWidth}px`;
ctx!.resetTransform();
overlayCtx!.resetTransform();
offCtx!.resetTransform();
}, []);
const fitView = () => {
@ -366,11 +400,13 @@ export default function useDrawing(props: {
setTransform();
overlayCanvasRef.current!.style.transform = `scale(${autoScale.current})`;
canvasRef.current!.style.transform = `scale(${autoScale.current})`;
offscreenCanvasRef.current!.style.transform = `scale(${autoScale.current})`;
};
return {
canvasRef,
overlayCanvasRef,
offscreenCanvasRef,
cursorRef,
strokesRef,
currentStroke,
@ -379,6 +415,7 @@ export default function useDrawing(props: {
autoScale,
baseScale,
maskStorkeRef,
creatOffscreenCanvas,
setMaskStrokes,
fitView,
setStrokes,

@ -4,6 +4,7 @@ import { MutableRefObject, useState } from 'react';
export default function useZoom(props: {
overlayCanvasRef: any;
canvasRef: any;
offscreenCanvasRef: any;
cursorRef: any;
lineWidth: number;
autoScale: MutableRefObject<number>;
@ -16,6 +17,7 @@ export default function useZoom(props: {
const {
overlayCanvasRef,
canvasRef,
offscreenCanvasRef,
cursorRef,
lineWidth,
translatePos,
@ -34,7 +36,6 @@ export default function useZoom(props: {
return;
}
console.log('Setting transform origin:', autoScale.current);
const rect = overlayCanvasRef.current!.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
@ -44,6 +45,7 @@ export default function useZoom(props: {
overlayCanvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`;
canvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`;
offscreenCanvasRef.current!.style.transformOrigin = `${originX * 100}% ${originY * 100}%`;
};
const updateZoom = (scaleChange: number, mouseX: number, mouseY: number) => {
@ -77,6 +79,8 @@ export default function useZoom(props: {
overlayCanvasRef.current!.style.transform = `scale(${autoScale.current})`;
canvasRef.current!.style.transform = `scale(${autoScale.current})`;
offscreenCanvasRef.current!.style.transform = `scale(${autoScale.current})`;
setCanvasTransformOrigin(event);
updateZoom(scaleChange, mouseX, mouseY);
};

@ -62,6 +62,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
const {
canvasRef,
overlayCanvasRef,
offscreenCanvasRef,
cursorRef,
strokesRef,
currentStroke,
@ -79,6 +80,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
handleMouseEnter,
saveImage,
resetCanvas,
creatOffscreenCanvas,
generateMask,
getTransformLineWidth,
getTransformedPoint,
@ -99,6 +101,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
const { handleOnWheel, setActiveScale, activeScale } = useZoom({
overlayCanvasRef,
canvasRef,
offscreenCanvasRef,
cursorRef,
lineWidth,
translatePos,
@ -114,9 +117,12 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
const updateCanvasSize = useCallback(() => {
const canvas = canvasRef.current!;
const overlayCanvas = overlayCanvasRef.current!;
const offscreenCanvas = offscreenCanvasRef.current!;
overlayCanvas.width = canvas.width;
overlayCanvas.height = canvas.height;
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
}, []);
const downloadMask = useCallback(() => {
@ -135,26 +141,26 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
options: {
lineWidth?: number;
color: string;
isInitial?: boolean;
}
) => {
const { color } = options;
const { color, isInitial } = options;
stroke.forEach((point) => {
const { x, y } = getTransformedPoint(point.x, point.y);
const width = getTransformLineWidth(point.lineWidth);
ctx.save();
// erase the previous stroke
ctx.globalCompositeOperation = 'destination-out';
ctx.fillRect(x - width / 2, y - width / 2, width, width);
if (isInitial) {
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillRect(x - width / 2, y - width / 2, width, width);
ctx.restore();
}
// draw the new stroke
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = color;
ctx.fillRect(x - width / 2, y - width / 2, width, width);
ctx.restore();
});
},
[getTransformLineWidth, getTransformedPoint]
@ -168,27 +174,31 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
console.log('Resetting strokes', currentStroke.current);
}, []);
const loadMaskPixs = (strokes: Stroke[]) => {
clearOverlayCanvas();
const loadMaskPixs = (strokes: Stroke[], isInitial?: boolean) => {
if (!strokes.length) {
return;
}
console.log('loadin mask pixs:');
const overlayCanvas = overlayCanvasRef.current!;
const overlayCtx = overlayCanvas!.getContext('2d')!;
setTransform();
const overlayCanvas = overlayCanvasRef.current!;
const overlayCtx = overlayCanvas.getContext('2d')!;
strokes?.forEach((stroke: Point[], index) => {
strokes.forEach((stroke: Point[]) => {
drawFillRect(overlayCtx, stroke, {
color: COLOR
color: COLOR,
isInitial: isInitial
});
});
};
const redrawStrokes = (strokes: Stroke[], type?: string) => {
console.log('Redrawing strokes:', strokes, type);
const redrawStrokes = (strokes: Stroke[]) => {
clearOverlayCanvas();
if (!strokes.length) {
setTransform();
console.log(
'Redrawing strokes:',
strokes.length,
maskStorkeRef.current.length
);
if (!strokes.length && !maskStorkeRef.current.length) {
return;
}
@ -198,8 +208,6 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
// clear offscreen canvas
setTransform();
overlayCtx.save();
loadMaskPixs(maskStorkeRef.current);
strokes?.forEach((stroke: Point[], index) => {
@ -213,10 +221,9 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
compositeOperation: 'source-over'
});
});
overlayCtx.restore();
};
const undo = () => {
const undo = useCallback(() => {
if (
strokesRef.current.length === 0 &&
maskStorkeRef.current.length === 0
@ -225,25 +232,23 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
return;
}
const lastlength = strokesRef.current.length;
const newStrokes = strokesRef.current.slice(0, -1);
setStrokes(newStrokes);
console.log(
'newstrokes=======',
newStrokes.length,
if (
!newStrokes.length &&
lastlength === 0 &&
maskStorkeRef.current.length
);
if (strokesRef.current.length) {
clearTimeout(timer.current);
timer.current = setTimeout(() => {
redrawStrokes(strokesRef.current);
}, 100);
} else if (maskStorkeRef.current.length) {
loadMaskPixs(maskStorkeRef.current);
) {
setMaskStrokes([]);
}
};
clearTimeout(timer.current);
timer.current = setTimeout(() => {
redrawStrokes(newStrokes);
}, 100);
}, []);
const downloadOriginImage = () => {
const canvas = canvasRef.current!;
@ -308,7 +313,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
// fit the image to the container
autoScale.current = 1;
creatOffscreenCanvas();
updateCanvasSize();
clearCanvas();
@ -335,7 +340,7 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
setTransform();
ctx.globalCompositeOperation = 'destination-out';
strokesRef.current.forEach((stroke) => {
[...strokesRef.current, ...maskStorkeRef.current].forEach((stroke) => {
stroke.forEach((point: Point) => {
const { x, y } = getTransformedPoint(point.x, point.y);
const lineWidth = getTransformLineWidth(point.lineWidth);
@ -369,14 +374,14 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
onReset();
resetCanvas();
} else if (
strokesRef.current.length &&
(strokesRef.current.length || maskStorkeRef.current.length) &&
imageStatus.isOriginal &&
!invertMask
) {
redrawStrokes(strokesRef.current);
saveImage();
} else if (
strokesRef.current.length &&
(strokesRef.current.length || maskStorkeRef.current.length) &&
imageStatus.isOriginal &&
invertMask
) {
@ -456,7 +461,9 @@ const CanvasImageEditor: React.FC<CanvasImageEditorProps> = forwardRef(
loadMaskPixs(strokes: Stroke[]) {
setMaskStrokes(strokes);
setStrokes([]);
loadMaskPixs(strokes);
setTransform();
clearOverlayCanvas();
loadMaskPixs(strokes, true);
}
}));

@ -1,11 +1,13 @@
import { useIntl } from '@umijs/max';
import { Typography } from 'antd';
import React from 'react';
interface TooltipListProps {
list: { title: React.ReactNode; tips: React.ReactNode }[];
list: { title: any; tips: string }[];
}
const TooltipList: React.FC<TooltipListProps> = (props) => {
const intl = useIntl();
const { list } = props;
return (
<ul className="tips-desc-list">
@ -20,7 +22,10 @@ const TooltipList: React.FC<TooltipListProps> = (props) => {
marginBottom: 0
}}
>
{item.title}:
{item.title?.locale
? intl.formatMessage({ id: item.title?.text || '' })
: item.title}
:
</Typography.Title>
<Typography.Text
style={{
@ -29,7 +34,7 @@ const TooltipList: React.FC<TooltipListProps> = (props) => {
lineHeight: 1.5
}}
>
{item.tips}
{intl.formatMessage({ id: item.tips })}
</Typography.Text>
</li>
);

@ -81,7 +81,7 @@ export default {
'models.form.filePath': 'Model Path',
'models.form.backendVersion': 'Backend Version',
'models.form.backendVersion.tips':
'To use the desired version of vLLM/llama-box/vox-box, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}',
'To use the desired version of {backend}, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}',
'models.form.gpuselector': 'GPU Selector',
'models.form.backend.llamabox':
'For GGUF format models, supports Linux, macOS, and Windows.',
@ -114,6 +114,8 @@ export default {
'models.table.vram.allocated': 'Allocated VRAM',
'models.form.backend.warning':
'The backend for GGUF format models uses llama-box.',
'models.form.ollama.warning':
'Deploy the Ollama model backend using llama-box.',
'models.form.backend.warning.llamabox':
'To use the llama-box backend, specify the full path to the model file (e.g.,<span style="font-weight: 700">/data/models/model.gguf</span>). For sharded models, provide the path to the first shard (e.g.,<span style="font-weight: 700">/data/models/model-00001-of-00004.gguf</span>).'
};

@ -81,7 +81,7 @@ export default {
'models.form.filePath': 'Путь к модели',
'models.form.backendVersion': 'Версия бэкенда',
'models.form.backendVersion.tips':
'To use the desired version of vLLM/llama-box/vox-box, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}',
'To use the desired version of {backend}, the system will automatically create a virtual environment in the online environment to install the corresponding version. After a GPUStack upgrade, the backend version will remain fixed. {link}',
'models.form.gpuselector': 'Селектор GPU',
'models.form.backend.llamabox':
'Для моделей формата GGUF. Поддержка Linux, macOS и Windows.',
@ -113,6 +113,8 @@ export default {
'models.table.vram.allocated': 'Allocated VRAM',
'models.form.backend.warning':
'The backend for GGUF format models uses llama-box.',
'models.form.ollama.warning':
'Deploy the Ollama model backend using llama-box.',
'models.form.backend.warning.llamabox': `To use the llama-box backend, specify the full path to the model file (e.g.,<span style="font-weight: 700">/data/models/model.gguf</span>). For sharded models, provide the path to the first shard (e.g.,<span style="font-weight: 700">/data/models/model-00001-of-00004.gguf</span>).`
};
@ -122,5 +124,6 @@ export default {
// 2. models.form.backend.warning
// 3. models.form.backend.warning.llamabox
// 4. models.table.vram.allocated
// 5. models.form.ollama.warning
// ========== End of To-Do List ==========

@ -78,7 +78,7 @@ export default {
'models.form.filePath': '模型路径',
'models.form.backendVersion': '后端版本',
'models.form.backendVersion.tips':
'固定以使用期望的 vLLM/llama-box/vox-box 版本在线环境会自动创建虚拟环境安装对应版本的vLLM/llama-box/vox-box。在 GPUStack 升级后也将保持固定的后端版本。{link}',
'固定以使用期望的 {backend} 版本,在线环境会自动创建虚拟环境安装对应版本的 {backend}。在 GPUStack 升级后也将保持固定的后端版本。{link}',
'models.form.gpuselector': 'GPU 选择器',
'models.form.backend.llamabox':
'用于 GGUF 格式模型,支持 Linux, macOS 和 Windows',
@ -108,6 +108,7 @@ export default {
'models.form.moreparameters': '参数说明',
'models.table.vram.allocated': '分配显存',
'models.form.backend.warning': 'GGUF 格式模型后端用 llama-box。',
'models.form.ollama.warning': '部署 Ollama 模型后端使用 llama-box。',
'models.form.backend.warning.llamabox':
'要使用 llama-box 后端,请指定模型文件的完整路径(例如:<span style="font-weight: 700">/data/models/model.gguf</span>)。对于分片模型,请提供第一个分片的路径(例如:<span style="font-weight: 700">/data/models/model-00001-of-00004.gguf</span>)。'
};

@ -340,6 +340,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
id: 'models.form.backendVersion.tips'
},
{
backend: backend,
link: backendParamsTips?.releases && (
<span
style={{

@ -21,6 +21,7 @@ import {
HuggingFaceTaskMap,
ModelscopeTaskMap,
backendOptionsMap,
backendTipsList,
modelSourceMap,
modelTaskMap,
ollamaModelOptions,
@ -89,36 +90,6 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
const localPathCache = useRef<string>('');
const backendTipsList = [
{
title: 'llama-box',
tips: intl.formatMessage({ id: 'models.form.backend.llamabox' })
},
{
title: 'vLLM',
tips: intl.formatMessage({ id: 'models.form.backend.vllm' })
},
{
title: 'vox-box',
tips: intl.formatMessage({ id: 'models.form.backend.voxbox' })
}
];
const localPathTipsList = [
{
title: intl.formatMessage({ id: 'models.localpath.gguf.tips.title' }),
tips: intl.formatMessage({ id: 'models.localpath.gguf.tips' })
},
{
title: intl.formatMessage({ id: 'models.localpath.shared.tips.title' }),
tips: intl.formatMessage({ id: 'models.localpath.chunks.tips' })
},
{
title: intl.formatMessage({ id: 'models.localpat.safe.tips.title' }),
tips: intl.formatMessage({ id: 'models.localpath.safe.tips' })
}
];
const handleSumit = () => {
form.submit();
};

@ -81,39 +81,34 @@ const AddModal: React.FC<AddModalProps> = (props) => {
const updateShowWarning = (backend: string) => {
const localPath = form.current?.getFieldValue?.('local_path');
const isBlobFile = localPath?.split('/').pop()?.includes('sha256');
if (isBlobFile) {
setWarningStatus({
show: false,
message: ''
});
return;
}
if (source !== modelSourceMap.local_path_value || !localPath) {
return;
}
if (localPath.endsWith('.gguf') && backend !== backendOptionsMap.llamaBox) {
setWarningStatus({
show: true,
message: 'models.form.backend.warning'
});
const isBlobFile = localPath?.split('/').pop()?.includes('sha256');
const isOllamaModel = localPath?.includes('ollama');
const isGGUFFile = localPath.endsWith('.gguf');
let warningMessage = '';
if (isBlobFile && isOllamaModel && backend === backendOptionsMap.llamaBox) {
warningMessage = '';
} else if (
!localPath.endsWith('.gguf') &&
backend === backendOptionsMap.llamaBox
isBlobFile &&
isOllamaModel &&
backend !== backendOptionsMap.llamaBox
) {
setWarningStatus({
show: true,
message: 'models.form.backend.warning.llamabox'
});
} else {
setWarningStatus({
show: false,
message: ''
});
warningMessage = 'models.form.ollama.warning';
} else if (isGGUFFile && backend !== backendOptionsMap.llamaBox) {
warningMessage = 'models.form.backend.warning';
} else if (!isGGUFFile && backend === backendOptionsMap.llamaBox) {
warningMessage = 'models.form.backend.warning.llamabox';
}
setWarningStatus({
show: !!warningMessage,
message: warningMessage
});
};
const handleBackendChange = (backend: string) => {

@ -4,6 +4,7 @@ import ModalFooter from '@/components/modal-footer';
import SealAutoComplete from '@/components/seal-form/auto-complete';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import TooltipList from '@/components/tooltip-list';
import { PageAction } from '@/config';
import { PageActionType } from '@/config/types';
import { useIntl } from '@umijs/max';
@ -12,6 +13,8 @@ import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import {
backendOptionsMap,
backendTipsList,
localPathTipsList,
modelSourceMap,
ollamaModelOptions
} from '../config';
@ -98,39 +101,34 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
const updateShowWarning = (backend: string) => {
const localPath = form.getFieldValue?.('local_path');
const isBlobFile = localPath?.split('/').pop()?.includes('sha256');
if (isBlobFile) {
setWarningStatus({
show: false,
message: ''
});
return;
}
if (formData?.source !== modelSourceMap.local_path_value || !localPath) {
return;
}
if (localPath.endsWith('.gguf') && backend !== backendOptionsMap.llamaBox) {
setWarningStatus({
show: true,
message: 'models.form.backend.warning'
});
const isBlobFile = localPath?.split('/').pop()?.includes('sha256');
const isOllamaModel = localPath?.includes('ollama');
const isGGUFFile = localPath.endsWith('.gguf');
let warningMessage = '';
if (isBlobFile && isOllamaModel && backend === backendOptionsMap.llamaBox) {
warningMessage = '';
} else if (
!localPath.endsWith('.gguf') &&
backend === backendOptionsMap.llamaBox
isBlobFile &&
isOllamaModel &&
backend !== backendOptionsMap.llamaBox
) {
setWarningStatus({
show: true,
message: 'models.form.backend.warning.llamabox'
});
} else {
setWarningStatus({
show: false,
message: ''
});
warningMessage = 'models.form.ollama.warning';
} else if (isGGUFFile && backend !== backendOptionsMap.llamaBox) {
warningMessage = 'models.form.backend.warning';
} else if (!isGGUFFile && backend === backendOptionsMap.llamaBox) {
warningMessage = 'models.form.backend.warning.llamabox';
}
setWarningStatus({
show: !!warningMessage,
message: warningMessage
});
};
const handleBackendChange = (val: string) => {
@ -284,6 +282,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
onFocus={handleOnFocus}
disabled={false}
label={intl.formatMessage({ id: 'models.form.filePath' })}
description={<TooltipList list={localPathTipsList}></TooltipList>}
required
></SealInput.Input>
</Form.Item>
@ -519,6 +518,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
required
onChange={handleBackendChange}
label={intl.formatMessage({ id: 'models.form.backend' })}
description={<TooltipList list={backendTipsList}></TooltipList>}
options={[
{
label: `llama-box`,

@ -88,6 +88,45 @@ export const ollamaModelOptions = [
}
];
export const backendTipsList = [
{
title: 'llama-box',
tips: 'models.form.backend.llamabox'
},
{
title: 'vLLM',
tips: 'models.form.backend.vllm'
},
{
title: 'vox-box',
tips: 'models.form.backend.voxbox'
}
];
export const localPathTipsList = [
{
title: {
text: 'models.localpath.gguf.tips.title',
locale: true
},
tips: 'models.localpath.gguf.tips'
},
{
title: {
text: 'models.localpath.shared.tips.title',
locale: true
},
tips: 'models.localpath.chunks.tips'
},
{
title: {
text: 'models.localpat.safe.tips.title',
locale: true
},
tips: 'models.localpath.safe.tips'
}
];
export const backendOptionsMap = {
llamaBox: 'llama-box',
vllm: 'vllm',

Loading…
Cancel
Save