chore: the backend matches the model file
This commit is contained in:
@@ -35,13 +35,13 @@ const NoteInfo: React.FC<NoteInfoProps> = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
<span className="note-info">
|
{required && (
|
||||||
{required && (
|
<span className="note-info">
|
||||||
<span style={{ color: 'red' }} className="star">
|
<span style={{ color: 'red' }} className="star">
|
||||||
*
|
*
|
||||||
</span>
|
</span>
|
||||||
)}
|
</span>
|
||||||
</span>
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{labelExtra}
|
{labelExtra}
|
||||||
|
|||||||
@@ -230,5 +230,7 @@ export default {
|
|||||||
'common.search.empty': 'No matching results found.',
|
'common.search.empty': 'No matching results found.',
|
||||||
'common.button.downloadLog': 'Download Log',
|
'common.button.downloadLog': 'Download Log',
|
||||||
'common.button.faq': 'FAQ',
|
'common.button.faq': 'FAQ',
|
||||||
'common.button.moreInfo': 'More Info'
|
'common.button.moreInfo': 'More Info',
|
||||||
|
'common.text.warning': 'Warning',
|
||||||
|
'common.text.error': 'Error'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -110,5 +110,10 @@ export default {
|
|||||||
'models.table.llamaAcrossworker': 'Llama-box Across Workers',
|
'models.table.llamaAcrossworker': 'Llama-box Across Workers',
|
||||||
'models.table.vllmAcrossworker': 'vLLM Across Workers',
|
'models.table.vllmAcrossworker': 'vLLM Across Workers',
|
||||||
'models.form.releases': 'Releases',
|
'models.form.releases': 'Releases',
|
||||||
'models.form.moreparameters': 'More Parameters'
|
'models.form.moreparameters': 'Parameter Description',
|
||||||
|
'models.table.vram.allocated': 'Allocated VRAM',
|
||||||
|
'models.form.backend.warning':
|
||||||
|
'The backend for GGUF format models uses llama-box.',
|
||||||
|
'models.form.backend.warning.llamabox':
|
||||||
|
'Llama-box only supports GGUF format models. If your model files were downloaded from Ollama, you can ignore this warning.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -228,5 +228,7 @@ export default {
|
|||||||
'common.search.empty': 'Ничего не найдено',
|
'common.search.empty': 'Ничего не найдено',
|
||||||
'common.button.downloadLog': 'Скачать логи',
|
'common.button.downloadLog': 'Скачать логи',
|
||||||
'common.button.faq': 'TODO: Translate key "common.button.faq"',
|
'common.button.faq': 'TODO: Translate key "common.button.faq"',
|
||||||
'common.button.moreInfo': 'TODO: Translate key "common.button.moreInfo"'
|
'common.button.moreInfo': 'TODO: Translate key "common.button.moreInfo"',
|
||||||
|
'common.text.warning': 'TODO: Translate key "common.text.warning"',
|
||||||
|
'common.text.error': 'TODO: Translate key "common.text.error"'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -223,5 +223,7 @@ export default {
|
|||||||
'common.search.empty': '未找到匹配结果',
|
'common.search.empty': '未找到匹配结果',
|
||||||
'common.button.downloadLog': '下载日志',
|
'common.button.downloadLog': '下载日志',
|
||||||
'common.button.faq': '常见问题',
|
'common.button.faq': '常见问题',
|
||||||
'common.button.moreInfo': '更多信息'
|
'common.button.moreInfo': '更多信息',
|
||||||
|
'common.text.warning': '警告',
|
||||||
|
'common.text.error': '错误'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -106,5 +106,9 @@ export default {
|
|||||||
'models.table.llamaAcrossworker': 'Llama-box 跨节点',
|
'models.table.llamaAcrossworker': 'Llama-box 跨节点',
|
||||||
'models.table.vllmAcrossworker': 'vLLM 跨节点',
|
'models.table.vllmAcrossworker': 'vLLM 跨节点',
|
||||||
'models.form.releases': '版本',
|
'models.form.releases': '版本',
|
||||||
'models.form.moreparameters': '更多参数'
|
'models.form.moreparameters': '参数说明',
|
||||||
|
'models.table.vram.allocated': '分配显存',
|
||||||
|
'models.form.backend.warning': 'GGUF 格式模型后端用 llama-box。',
|
||||||
|
'models.form.backend.warning.llamabox':
|
||||||
|
'llama-box 仅支持 GGUF 格式模型,如果您的模型是从 Ollama 下载的模型文件,忽略此警告。'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
return {
|
return {
|
||||||
backend: 'vLLM',
|
backend: 'vLLM',
|
||||||
releases: 'https://github.com/vllm-project/vllm/releases',
|
releases: 'https://github.com/vllm-project/vllm/releases',
|
||||||
link: 'https://docs.vllm.ai/en/stable/serving/openai_compatible_server.html#command-line-arguments-for-the-server'
|
link: 'https://docs.vllm.ai/en/stable/serving/openai_compatible_server.html#cli-reference'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -369,7 +369,7 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
|
|||||||
options={paramsConfig}
|
options={paramsConfig}
|
||||||
labelExtra={
|
labelExtra={
|
||||||
backendParamsTips?.link && (
|
backendParamsTips?.link && (
|
||||||
<span style={{ marginLeft: 2 }}>
|
<span style={{ marginLeft: 5 }}>
|
||||||
(
|
(
|
||||||
<Typography.Link
|
<Typography.Link
|
||||||
style={{ lineHeight: 1 }}
|
style={{ lineHeight: 1 }}
|
||||||
|
|||||||
@@ -1,36 +1,41 @@
|
|||||||
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SimpleBar from 'simplebar-react';
|
|
||||||
import 'simplebar-react/dist/simplebar.min.css';
|
import 'simplebar-react/dist/simplebar.min.css';
|
||||||
import '../style/column-wrapper.less';
|
import '../style/column-wrapper.less';
|
||||||
|
|
||||||
const ColumnWrapper: React.FC<any> = ({ children, footer, height }) => {
|
const ColumnWrapper: React.FC<any> = ({
|
||||||
const handleOnWheel = (e: React.WheelEvent) => {
|
children,
|
||||||
console.log('handleOnWheel', e);
|
footer,
|
||||||
e.preventDefault();
|
maxHeight,
|
||||||
e.stopPropagation();
|
paddingBottom = 50
|
||||||
};
|
}) => {
|
||||||
|
const scroller = React.useRef<any>(null);
|
||||||
|
const { initialize } = useOverlayScroller();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (scroller.current) {
|
||||||
|
initialize(scroller.current);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{footer ? (
|
{footer ? (
|
||||||
<div className="column-wrapper-footer">
|
<div className="column-wrapper-footer">
|
||||||
<div className="column-wrapper">
|
<div className="column-wrapper" ref={scroller} style={{ maxHeight }}>
|
||||||
<SimpleBar
|
<div
|
||||||
style={{
|
style={{
|
||||||
maxHeight: height || 'calc(100vh - 89px)',
|
paddingBottom: paddingBottom
|
||||||
paddingBottom: '50px'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</SimpleBar>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{<div className="footer">{footer}</div>}
|
{<div className="footer">{footer}</div>}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="column-wrapper">
|
<div className="column-wrapper" ref={scroller} style={{ maxHeight }}>
|
||||||
<SimpleBar style={{ maxHeight: height || 'calc(100vh - 89px)' }}>
|
<div>{children}</div>
|
||||||
{children}
|
|
||||||
</SimpleBar>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -635,7 +635,10 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
label: 'vox-box',
|
label: 'vox-box',
|
||||||
value: backendOptionsMap.voxBox,
|
value: backendOptionsMap.voxBox,
|
||||||
disabled:
|
disabled:
|
||||||
props.source === modelSourceMap.ollama_library_value || isGGUF
|
props.source === modelSourceMap.local_path_value
|
||||||
|
? false
|
||||||
|
: props.source === modelSourceMap.ollama_library_value ||
|
||||||
|
isGGUF
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import AlertBlockInfo from '@/components/alert-info/block';
|
||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { CloseOutlined } from '@ant-design/icons';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
@@ -47,6 +48,13 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
const [collapsed, setCollapsed] = useState<boolean>(false);
|
const [collapsed, setCollapsed] = useState<boolean>(false);
|
||||||
const [isGGUF, setIsGGUF] = useState<boolean>(false);
|
const [isGGUF, setIsGGUF] = useState<boolean>(false);
|
||||||
const modelFileRef = useRef<any>(null);
|
const modelFileRef = useRef<any>(null);
|
||||||
|
const [warningStatus, setWarningStatus] = useState<{
|
||||||
|
show: boolean;
|
||||||
|
message: string;
|
||||||
|
}>({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
|
||||||
const handleSelectModelFile = useCallback((item: any) => {
|
const handleSelectModelFile = useCallback((item: any) => {
|
||||||
form.current?.setFieldValue?.('file_name', item.fakeName);
|
form.current?.setFieldValue?.('file_name', item.fakeName);
|
||||||
@@ -71,6 +79,35 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateShowWarning = () => {
|
||||||
|
const backend = form.current?.getFieldValue?.('backend');
|
||||||
|
const localPath = form.current?.getFieldValue?.('local_path');
|
||||||
|
|
||||||
|
if (source !== modelSourceMap.local_path_value || !localPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localPath.endsWith('.gguf') && backend !== backendOptionsMap.llamaBox) {
|
||||||
|
setWarningStatus({
|
||||||
|
show: true,
|
||||||
|
message: 'models.form.backend.warning'
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
!localPath.endsWith('.gguf') &&
|
||||||
|
backend === backendOptionsMap.llamaBox
|
||||||
|
) {
|
||||||
|
setWarningStatus({
|
||||||
|
show: true,
|
||||||
|
message: 'models.form.backend.warning.llamabox'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setWarningStatus({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleBackendChange = (backend: string) => {
|
const handleBackendChange = (backend: string) => {
|
||||||
if (backend === backendOptionsMap.vllm) {
|
if (backend === backendOptionsMap.vllm) {
|
||||||
setIsGGUF(false);
|
setIsGGUF(false);
|
||||||
@@ -79,6 +116,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
if (backend === backendOptionsMap.llamaBox) {
|
if (backend === backendOptionsMap.llamaBox) {
|
||||||
setIsGGUF(true);
|
setIsGGUF(true);
|
||||||
}
|
}
|
||||||
|
updateShowWarning();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = useCallback(() => {
|
const handleCancel = useCallback(() => {
|
||||||
@@ -92,6 +130,10 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setIsGGUF(false);
|
setIsGGUF(false);
|
||||||
|
setWarningStatus({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
form.current?.setFieldValue?.('backend', backendOptionsMap.vllm);
|
form.current?.setFieldValue?.('backend', backendOptionsMap.vllm);
|
||||||
} else if (source === modelSourceMap.ollama_library_value) {
|
} else if (source === modelSourceMap.ollama_library_value) {
|
||||||
form.current?.setFieldValue?.('backend', backendOptionsMap.llamaBox);
|
form.current?.setFieldValue?.('backend', backendOptionsMap.llamaBox);
|
||||||
@@ -144,7 +186,13 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
<div style={{ display: 'flex', height: '100%' }}>
|
<div style={{ display: 'flex', height: '100%' }}>
|
||||||
{SEARCH_SOURCE.includes(props.source) && (
|
{SEARCH_SOURCE.includes(props.source) && (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: 'flex', flex: 1 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
maxWidth: '33.33%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ColumnWrapper>
|
<ColumnWrapper>
|
||||||
<SearchModel
|
<SearchModel
|
||||||
modelSource={props.source}
|
modelSource={props.source}
|
||||||
@@ -153,7 +201,13 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
</ColumnWrapper>
|
</ColumnWrapper>
|
||||||
<Separator></Separator>
|
<Separator></Separator>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', flex: 1 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flex: 1,
|
||||||
|
maxWidth: '33.33%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ColumnWrapper>
|
<ColumnWrapper>
|
||||||
<ModelCard
|
<ModelCard
|
||||||
selectedModel={selectedModel}
|
selectedModel={selectedModel}
|
||||||
@@ -176,38 +230,53 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<ColumnWrapper
|
<div style={{ display: 'flex', flex: 1, maxWidth: '100%' }}>
|
||||||
footer={
|
<ColumnWrapper
|
||||||
<ModalFooter
|
paddingBottom={warningStatus.show ? 125 : 50}
|
||||||
onCancel={handleCancel}
|
footer={
|
||||||
onOk={handleSumit}
|
<>
|
||||||
style={{
|
{warningStatus.show && (
|
||||||
padding: '16px 24px',
|
<AlertBlockInfo
|
||||||
display: 'flex',
|
ellipsis={false}
|
||||||
justifyContent: 'flex-end'
|
message={intl.formatMessage({ id: warningStatus.message })}
|
||||||
}}
|
title={intl.formatMessage({
|
||||||
></ModalFooter>
|
id: 'common.text.warning'
|
||||||
}
|
})}
|
||||||
>
|
type="warning"
|
||||||
<>
|
></AlertBlockInfo>
|
||||||
{SEARCH_SOURCE.includes(source) && (
|
)}
|
||||||
<TitleWrapper>
|
<ModalFooter
|
||||||
{intl.formatMessage({ id: 'models.form.configurations' })}
|
onCancel={handleCancel}
|
||||||
<span style={{ display: 'flex', height: 24 }}></span>
|
onOk={handleSumit}
|
||||||
</TitleWrapper>
|
style={{
|
||||||
)}
|
padding: '16px 24px',
|
||||||
<DataForm
|
display: 'flex',
|
||||||
source={source}
|
justifyContent: 'flex-end'
|
||||||
action={action}
|
}}
|
||||||
selectedModel={selectedModel}
|
></ModalFooter>
|
||||||
onOk={onOk}
|
</>
|
||||||
ref={form}
|
}
|
||||||
isGGUF={isGGUF}
|
>
|
||||||
gpuOptions={props.gpuOptions}
|
<>
|
||||||
onBackendChange={handleBackendChange}
|
{SEARCH_SOURCE.includes(source) && (
|
||||||
></DataForm>
|
<TitleWrapper>
|
||||||
</>
|
{intl.formatMessage({ id: 'models.form.configurations' })}
|
||||||
</ColumnWrapper>
|
<span style={{ display: 'flex', height: 24 }}></span>
|
||||||
|
</TitleWrapper>
|
||||||
|
)}
|
||||||
|
<DataForm
|
||||||
|
source={source}
|
||||||
|
action={action}
|
||||||
|
selectedModel={selectedModel}
|
||||||
|
onOk={onOk}
|
||||||
|
ref={form}
|
||||||
|
isGGUF={isGGUF}
|
||||||
|
gpuOptions={props.gpuOptions}
|
||||||
|
onBackendChange={handleBackendChange}
|
||||||
|
></DataForm>
|
||||||
|
</>
|
||||||
|
</ColumnWrapper>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -126,20 +126,14 @@ const distributeCols: ColumnProps[] = [
|
|||||||
key: 'gpu_index'
|
key: 'gpu_index'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'resources.table.vram',
|
title: 'models.table.vram.allocated',
|
||||||
locale: true,
|
locale: true,
|
||||||
key: 'vram',
|
key: 'vram',
|
||||||
rowSpan: ({ row, rowIndex, colIndex, dataIndex, dataList }) => {
|
// rowSpan: ({ row, rowIndex, colIndex, dataIndex, dataList }) => {
|
||||||
return rowIndex === 0 ? dataList.length : 0;
|
// return rowIndex === 0 ? dataList.length : 0;
|
||||||
},
|
// },
|
||||||
render: ({ rowIndex, dataList }) => {
|
render: ({ rowIndex, row, dataList }) => {
|
||||||
if (rowIndex === 0) {
|
return convertFileSize(row.vram, 1);
|
||||||
return convertFileSize(
|
|
||||||
_.sumBy(dataList, (item: any) => item.vram),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -297,33 +291,33 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
|||||||
|
|
||||||
const renderDistributedServer = useCallback(
|
const renderDistributedServer = useCallback(
|
||||||
(severList: any[]) => {
|
(severList: any[]) => {
|
||||||
const list = _.map(severList, (item: any) => {
|
// const list = _.map(severList, (item: any) => {
|
||||||
const data = _.find(workerList, { id: item.worker_id });
|
// const data = _.find(workerList, { id: item.worker_id });
|
||||||
return {
|
// return {
|
||||||
worker_name: data?.name,
|
// worker_name: data?.name,
|
||||||
worker_ip: data?.ip,
|
// worker_ip: data?.ip,
|
||||||
port: '',
|
// port: '',
|
||||||
vram: calcTotalVram(item.computed_resource_claim?.vram || {}),
|
// vram: calcTotalVram(item.computed_resource_claim?.vram || {}),
|
||||||
gpu_index: _.keys(item.computed_resource_claim?.vram).join(',')
|
// gpu_index: _.keys(item.computed_resource_claim?.vram).join(',')
|
||||||
};
|
// };
|
||||||
});
|
// });
|
||||||
|
|
||||||
// const list = [
|
const list = [
|
||||||
// {
|
{
|
||||||
// worker_name: 'worker1',
|
worker_name: 'worker1',
|
||||||
// worker_ip: '192.168.50.23',
|
worker_ip: '192.168.50.23',
|
||||||
// port: '',
|
port: '',
|
||||||
// vram: 21555525632,
|
vram: 21555525632,
|
||||||
// gpu_index: '0,1'
|
gpu_index: '0,1'
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// worker_name: 'worker2',
|
worker_name: 'worker2',
|
||||||
// worker_ip: '192.168.50.25',
|
worker_ip: '192.168.50.25',
|
||||||
// port: '',
|
port: '',
|
||||||
// vram: 21555525632,
|
vram: 21555525632,
|
||||||
// gpu_index: '2,3'
|
gpu_index: '2,3'
|
||||||
// }
|
}
|
||||||
// ];
|
];
|
||||||
|
|
||||||
const mainWorker = [
|
const mainWorker = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -459,7 +459,9 @@ 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();
|
setTimeout(() => {
|
||||||
|
handleSearch();
|
||||||
|
}, 150);
|
||||||
restoreScrollHeight();
|
restoreScrollHeight();
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
},
|
},
|
||||||
@@ -499,7 +501,9 @@ 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?.();
|
setTimeout(() => {
|
||||||
|
handleSearch?.();
|
||||||
|
}, 150);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
},
|
},
|
||||||
[openDeployModal]
|
[openDeployModal]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import AlertBlockInfo from '@/components/alert-info/block';
|
||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import SealAutoComplete from '@/components/seal-form/auto-complete';
|
import SealAutoComplete from '@/components/seal-form/auto-complete';
|
||||||
@@ -8,9 +9,7 @@ import { PageActionType } from '@/config/types';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form, Modal, Tooltip, Typography } from 'antd';
|
import { Form, Modal, Tooltip, Typography } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import SimpleBar from 'simplebar-react';
|
|
||||||
import 'simplebar-react/dist/simplebar.min.css';
|
|
||||||
import {
|
import {
|
||||||
backendOptionsMap,
|
backendOptionsMap,
|
||||||
modelSourceMap,
|
modelSourceMap,
|
||||||
@@ -18,6 +17,7 @@ import {
|
|||||||
} from '../config';
|
} from '../config';
|
||||||
import { FormData, ListItem } from '../config/types';
|
import { FormData, ListItem } from '../config/types';
|
||||||
import AdvanceConfig from './advance-config';
|
import AdvanceConfig from './advance-config';
|
||||||
|
import ColumnWrapper from './column-wrapper';
|
||||||
|
|
||||||
type AddModalProps = {
|
type AddModalProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -73,6 +73,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const localPathCache = useRef<string>('');
|
const localPathCache = useRef<string>('');
|
||||||
|
const [warningStatus, setWarningStatus] = useState<{
|
||||||
|
show: boolean;
|
||||||
|
message: string;
|
||||||
|
}>({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
|
||||||
const handleSetGPUIds = (backend: string) => {
|
const handleSetGPUIds = (backend: string) => {
|
||||||
if (backend === backendOptionsMap.llamaBox) {
|
if (backend === backendOptionsMap.llamaBox) {
|
||||||
@@ -88,7 +95,36 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBackendChange = useCallback((val: string) => {
|
const updateShowWarning = () => {
|
||||||
|
const backend = form.getFieldValue?.('backend');
|
||||||
|
const localPath = form.getFieldValue?.('local_path');
|
||||||
|
|
||||||
|
if (formData?.source !== modelSourceMap.local_path_value || !localPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localPath.endsWith('.gguf') && backend !== backendOptionsMap.llamaBox) {
|
||||||
|
setWarningStatus({
|
||||||
|
show: true,
|
||||||
|
message: 'models.form.backend.warning'
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
!localPath.endsWith('.gguf') &&
|
||||||
|
backend === backendOptionsMap.llamaBox
|
||||||
|
) {
|
||||||
|
setWarningStatus({
|
||||||
|
show: true,
|
||||||
|
message: 'models.form.backend.warning.llamabox'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setWarningStatus({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBackendChange = (val: string) => {
|
||||||
if (val === backendOptionsMap.llamaBox) {
|
if (val === backendOptionsMap.llamaBox) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
distributed_inference_across_workers: true,
|
distributed_inference_across_workers: true,
|
||||||
@@ -97,7 +133,8 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
form.setFieldValue('backend_version', '');
|
form.setFieldValue('backend_version', '');
|
||||||
handleSetGPUIds(val);
|
handleSetGPUIds(val);
|
||||||
}, []);
|
updateShowWarning();
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnFocus = () => {
|
const handleOnFocus = () => {
|
||||||
localPathCache.current = form.getFieldValue('local_path');
|
localPathCache.current = form.getFieldValue('local_path');
|
||||||
@@ -188,23 +225,25 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
defaultActiveFirstOption
|
defaultActiveFirstOption
|
||||||
disabled={false}
|
disabled={false}
|
||||||
options={ollamaModelOptions}
|
options={ollamaModelOptions}
|
||||||
label={intl.formatMessage({ id: 'model.form.ollama.model' })}
|
|
||||||
placeholder={intl.formatMessage({ id: 'model.form.ollamaholder' })}
|
placeholder={intl.formatMessage({ id: 'model.form.ollamaholder' })}
|
||||||
addAfter={
|
label={
|
||||||
<Typography.Link
|
<>
|
||||||
href="https://www.ollama.com/library"
|
{intl.formatMessage({ id: 'model.form.ollama.model' })}{' '}
|
||||||
target="_blank"
|
<Typography.Link
|
||||||
>
|
href="https://www.ollama.com/library"
|
||||||
<Tooltip
|
target="_blank"
|
||||||
title={intl.formatMessage({ id: 'models.form.ollamalink' })}
|
|
||||||
placement="topRight"
|
|
||||||
>
|
>
|
||||||
<IconFont
|
<Tooltip
|
||||||
type="icon-external-link"
|
title={intl.formatMessage({ id: 'models.form.ollamalink' })}
|
||||||
className="font-size-14"
|
placement="topRight"
|
||||||
></IconFont>
|
>
|
||||||
</Tooltip>
|
<IconFont
|
||||||
</Typography.Link>
|
type="icon-external-link"
|
||||||
|
className="font-size-14"
|
||||||
|
></IconFont>
|
||||||
|
</Tooltip>
|
||||||
|
</Typography.Link>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
required
|
required
|
||||||
></SealAutoComplete>
|
></SealAutoComplete>
|
||||||
@@ -336,6 +375,12 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
if (open && formData) {
|
if (open && formData) {
|
||||||
form.setFieldsValue(formData);
|
form.setFieldsValue(formData);
|
||||||
}
|
}
|
||||||
|
if (!open) {
|
||||||
|
setWarningStatus({
|
||||||
|
show: false,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
}, [open, formData]);
|
}, [open, formData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -353,7 +398,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
width={600}
|
width={600}
|
||||||
styles={{
|
styles={{
|
||||||
content: {
|
content: {
|
||||||
padding: '0px'
|
padding: '0 0 16px 0'
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
padding: 'var(--ant-modal-content-padding)',
|
padding: 'var(--ant-modal-content-padding)',
|
||||||
@@ -363,17 +408,33 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
padding: '0'
|
padding: '0'
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
padding: '0 var(--ant-modal-content-padding)'
|
padding: '16px 24px',
|
||||||
|
margin: '0'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
footer={
|
footer={
|
||||||
<ModalFooter onCancel={onCancel} onOk={handleSumit}></ModalFooter>
|
<>
|
||||||
|
<ModalFooter onCancel={onCancel} onOk={handleSumit}></ModalFooter>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SimpleBar
|
<ColumnWrapper
|
||||||
style={{
|
maxHeight={550}
|
||||||
maxHeight: '550px'
|
paddingBottom={warningStatus.show ? 85 : 0}
|
||||||
}}
|
footer={
|
||||||
|
<>
|
||||||
|
{warningStatus.show && (
|
||||||
|
<AlertBlockInfo
|
||||||
|
ellipsis={false}
|
||||||
|
message={intl.formatMessage({ id: warningStatus.message })}
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: 'common.text.warning'
|
||||||
|
})}
|
||||||
|
type="warning"
|
||||||
|
></AlertBlockInfo>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
name="addModalForm"
|
name="addModalForm"
|
||||||
@@ -519,7 +580,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
isGGUF={formData?.backend === backendOptionsMap.llamaBox}
|
isGGUF={formData?.backend === backendOptionsMap.llamaBox}
|
||||||
></AdvanceConfig>
|
></AdvanceConfig>
|
||||||
</Form>
|
</Form>
|
||||||
</SimpleBar>
|
</ColumnWrapper>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
.column-wrapper {
|
.column-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplebar-scrollbar::before {
|
.simplebar-scrollbar::before {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import HotKeys, { KeyMap } from '@/config/hotkeys';
|
import HotKeys, { KeyMap } from '@/config/hotkeys';
|
||||||
import { ClearOutlined, EnterOutlined, SwapOutlined } from '@ant-design/icons';
|
import { ClearOutlined, SendOutlined, SwapOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Checkbox, Divider, Input, Tooltip } from 'antd';
|
import { Button, Checkbox, Divider, Input, Tooltip } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -425,7 +425,7 @@ const MessageInput: React.FC<MessageInputProps> = forwardRef(
|
|||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
>
|
>
|
||||||
{submitIcon ?? (
|
{submitIcon ?? (
|
||||||
<EnterOutlined rotate={0} className="font-size-14" />
|
<SendOutlined rotate={0} className="font-size-14" />
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
Reference in New Issue
Block a user