chore: ollama deprecated tips

This commit is contained in:
jialin
2025-05-08 11:09:05 +08:00
parent 1c87fef28d
commit 7f198b64f1
9 changed files with 315 additions and 84 deletions
+4 -2
View File
@@ -14,6 +14,7 @@ interface AlertInfoProps {
style?: React.CSSProperties;
contentStyle?: React.CSSProperties;
title?: React.ReactNode;
maxHeight?: number;
}
const TitleWrapper = styled.div`
@@ -39,7 +40,8 @@ const AlertInfo: React.FC<AlertInfoProps> = (props) => {
style,
title,
contentStyle,
icon
icon,
maxHeight = 86
} = props;
return (
@@ -65,7 +67,7 @@ const AlertInfo: React.FC<AlertInfoProps> = (props) => {
{title && (
<TitleWrapper className="title-text">{title}</TitleWrapper>
)}
<OverlayScroller maxHeight={86} style={{ ...contentStyle }}>
<OverlayScroller maxHeight={maxHeight} style={{ ...contentStyle }}>
<ContentWrapper
$hasTitle={!!title}
className={classNames('content', type)}
+11 -2
View File
@@ -102,7 +102,7 @@ export default {
'models.localpath.gguf.tips':
' Specify the model file, e.g., /data/models/model.gguf.',
'models.localpath.safe.tips':
'Specify the model directory that contains .safetensors and config.json files, e.g., /data/models/model/.',
'Specify the model directory that contains .safetensors and config.json files, e.g., /data/models/model.',
'models.localpath.chunks.tips': `Specify the first shard file of the model, e.g., /data/models/model-00001-of-00004.gguf.`,
'models.form.replicas.tips':
'Multiple replicas enable load balancing for { api } inference requests.',
@@ -148,5 +148,14 @@ export default {
'models.table.apiAccessInfo.jinaCompatible': 'Jina Compatible',
'models.table.apiAccessInfo.gotoCreate': 'Go to Create',
'models.search.parts': '{n} parts',
'models.search.evaluate.error': 'An error occurred during evaluation: '
'models.search.evaluate.error': 'An error occurred during evaluation: ',
'models.ollama.deprecated.title': 'Ollama Model Source Will Be Removed',
'models.ollama.deprecated.current':
'<span class="bold-text">Current Version (v0.6.1): </span>Ollama models are currently available for use.',
'models.ollama.deprecated.upcoming':
'<span class="bold-text">Upcoming Version (v0.7.0): </span>The Ollama model source will be removed from the UI.',
'models.ollama.deprecated.following':
'<span class="bold-text">Following the v0.7.0 update,</span> all previously deployed models will continue to work as expected.',
'models.ollama.deprecated.issue':
'See the related issue: <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979 on GitHub</a>.'
};
+19 -2
View File
@@ -101,7 +101,7 @@ export default {
'models.localpath.gguf.tips':
'モデルファイルを指定してください。例: /data/models/model.gguf。',
'models.localpath.safe.tips':
'config.jsonファイルを含む.safetensorsディレクトリを指定してください。例: /data/models/model/。',
'config.jsonファイルを含む.safetensorsディレクトリを指定してください。例: /data/models/model。',
'models.localpath.chunks.tips': `モデルの最初のシャードファイルを指定してください。例: /data/models/model-00001-of-00004.gguf。`,
'models.form.replicas.tips':
'複数のレプリカにより、{api} 推論リクエストの負荷分散が可能になります。',
@@ -148,5 +148,22 @@ export default {
'models.table.apiAccessInfo.jinaCompatible': 'Jina互換',
'models.table.apiAccessInfo.gotoCreate': '作成に移動',
'models.search.parts': '{n} 部分',
'models.search.evaluate.error': '評価中にエラーが発生しました: '
'models.search.evaluate.error': '評価中にエラーが発生しました: ',
'models.ollama.deprecated.title': 'Ollama Model Source Will Be Removed',
'models.ollama.deprecated.current':
'<span class="bold-text">Current Version (v0.6.1): </span>Ollama models are currently available for use.',
'models.ollama.deprecated.upcoming':
'<span class="bold-text">Upcoming Version (v0.7.0): </span>The Ollama model source will be removed from the UI.',
'models.ollama.deprecated.following':
'<span class="bold-text">Following the v0.7.0 update,</span> all previously deployed models will continue to work as expected.',
'models.ollama.deprecated.issue':
'See the related issue: <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979 on GitHub</a>.'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'models.ollama.deprecated.title': 'Ollama Model Source Will Be Removed',
// 2. 'models.ollama.deprecated.current':'<span class="bold-text">Current Version (v0.6.1): </span>Ollama models are currently available for use.',
// 3. 'models.ollama.deprecated.upcoming': '<span class="bold-text">Upcoming Version (v0.7.0): </span>The Ollama model source will be removed from the UI.',
// 4. 'models.ollama.deprecated.following': '<span class="bold-text">Following the v0.7.0 update,</span> all previously deployed models will continue to work as expected.',
// 5. 'models.ollama.deprecated.issue': 'See the related issue: <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979 on GitHub</a>.'
// ========== End of To-Do List ==========
+15 -2
View File
@@ -149,9 +149,22 @@ export default {
'models.table.apiAccessInfo.jinaCompatible': 'Совместимо с Jina',
'models.table.apiAccessInfo.gotoCreate': 'Перейти к созданию',
'models.search.parts': '{n} частей',
'models.search.evaluate.error': 'Возникла ошибка при вычислении: '
'models.search.evaluate.error': 'Возникла ошибка при вычислении: ',
'models.ollama.deprecated.title': 'Ollama Model Source Will Be Removed',
'models.ollama.deprecated.current':
'<span class="bold-text">Current Version (v0.6.1): </span>Ollama models are currently available for use.',
'models.ollama.deprecated.upcoming':
'<span class="bold-text">Upcoming Version (v0.7.0): </span>The Ollama model source will be removed from the UI.',
'models.ollama.deprecated.following':
'<span class="bold-text">Following the v0.7.0 update,</span> all previously deployed models will continue to work as expected.',
'models.ollama.deprecated.issue':
'See the related issue: <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979 on GitHub</a>.'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
// 1. 'models.ollama.deprecated.title': 'Ollama Model Source Will Be Removed',
// 2. 'models.ollama.deprecated.current':'<span class="bold-text">Current Version (v0.6.1): </span>Ollama models are currently available for use.',
// 3. 'models.ollama.deprecated.upcoming': '<span class="bold-text">Upcoming Version (v0.7.0): </span>The Ollama model source will be removed from the UI.',
// 4. 'models.ollama.deprecated.following': '<span class="bold-text">Following the v0.7.0 update,</span> all previously deployed models will continue to work as expected.',
// 5. 'models.ollama.deprecated.issue': 'See the related issue: <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979 on GitHub</a>.'
// ========== End of To-Do List ==========
+11 -2
View File
@@ -100,7 +100,7 @@ export default {
'models.localpath.shared.tips.title': '分片的 GGUF 格式模型',
'models.localpath.gguf.tips': '指向模型文件,例如 /data/models/model.gguf',
'models.localpath.safe.tips':
'指向包含 .safetensors, config.json 文件的模型目录,例如 /data/models/model/',
'指向包含 .safetensors, config.json 文件的模型目录,例如 /data/models/model',
'models.localpath.chunks.tips':
'指向模型第一个分片文件,例如 /data/models/model-00001-of-00004.gguf',
'models.form.replicas.tips': '多副本数实现 { api } 接口推理请求的负载均衡',
@@ -141,5 +141,14 @@ export default {
'models.table.apiAccessInfo.jinaCompatible': 'Jina 兼容',
'models.table.apiAccessInfo.gotoCreate': '去创建',
'models.search.parts': '{n} 个文件',
'models.search.evaluate.error': '评估过程中发生了错误:'
'models.search.evaluate.error': '评估过程中发生了错误:',
'models.ollama.deprecated.title': 'Ollama 模型源即将被移除',
'models.ollama.deprecated.current':
'<span class="bold-text">当前版本(v0.6.1):</span>Ollama 模型目前仍可使用。',
'models.ollama.deprecated.upcoming':
'<span class="bold-text">即将发布的版本(v0.7.0):</span>Ollama 模型源将在 UI 中被移除。',
'models.ollama.deprecated.following':
'<span class="bold-text">在 v0.7.0 更新后:</span> 所有先前部署的模型仍将正常运行。',
'models.ollama.deprecated.issue':
'参见 GitHub 上的问题 <a href="https://github.com/gpustack/gpustack/issues/1979" target="_blank">#1979</a>。'
};
+33 -4
View File
@@ -3,7 +3,7 @@ import PageTools from '@/components/page-tools';
import { PageAction } from '@/config';
import useBodyScroll from '@/hooks/use-body-scroll';
import { IS_FIRST_LOGIN, writeState } from '@/utils/localstore/index';
import { SyncOutlined } from '@ant-design/icons';
import { DoubleRightOutlined, SyncOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl, useNavigate } from '@umijs/max';
import { Button, Input, Pagination, Select, Space, message } from 'antd';
@@ -22,6 +22,18 @@ const PageWrapper = styled.div`
margin-block: 32px 16px;
`;
const MoreWrapper = styled.div`
display: flex;
justify-content: center;
margin-block: 16px;
opacity: 1;
transition: opacity 0.3s;
&.loading {
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
`;
const Catalog: React.FC = () => {
const intl = useIntl();
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
@@ -41,7 +53,7 @@ const Catalog: React.FC = () => {
});
const [queryParams, setQueryParams] = useState({
page: 1,
perPage: 12,
perPage: 30,
search: '',
categories: ''
});
@@ -159,8 +171,6 @@ const Catalog: React.FC = () => {
const handleCreateModel = useCallback(
async (data: FormData) => {
try {
console.log('data:', data, openDeployModal);
const modelData = await createModel({
data: {
..._.omit(data, ['size', 'quantization'])
@@ -213,6 +223,13 @@ const Catalog: React.FC = () => {
});
};
const loadMore = () => {
fetchData({
...queryParams,
page: queryParams.page + 1
});
};
useEffect(() => {
fetchData();
}, []);
@@ -298,6 +315,18 @@ const Catalog: React.FC = () => {
activeId={-1}
isFirst={isFirst}
></CatalogList>
{queryParams.page < dataSource.totalPage && (
<MoreWrapper className={dataSource.loading ? 'loading' : ''}>
<Button
onClick={loadMore}
size="middle"
type="text"
icon={<DoubleRightOutlined rotate={90} />}
>
{intl.formatMessage({ id: 'common.button.more' })}
</Button>
</MoreWrapper>
)}
<PageWrapper>
<Pagination
hideOnSinglePage={queryParams.perPage === 100}
@@ -23,6 +23,7 @@ import CompatibilityAlert from './compatible-alert';
import DataForm from './data-form';
import HFModelFile from './hf-model-file';
import ModelCard from './model-card';
import OllamaTips from './ollama-tips';
import SearchModel from './search-model';
import Separator from './separator';
import TitleWrapper from './title-wrapper';
@@ -360,6 +361,7 @@ const AddModal: FC<AddModalProps> = (props) => {
</ColWrapper>
</>
)}
<FormContext.Provider
value={{
isGGUF: isGGUF,
@@ -402,6 +404,9 @@ const AddModal: FC<AddModalProps> = (props) => {
}
>
<>
{source === modelSourceMap.ollama_library_value && (
<OllamaTips></OllamaTips>
)}
{SEARCH_SOURCE.includes(source) &&
deploymentType === 'modelList' && (
<TitleWrapper>
@@ -0,0 +1,128 @@
import AlertBlockInfo from '@/components/alert-info/block';
import IconFont from '@/components/icon-font';
import { useIntl } from '@umijs/max';
import { Button } from 'antd';
import { useState } from 'react';
import styled from 'styled-components';
const Wrapper = styled.div`
padding-inline: 24px;
`;
const Tips = styled.div`
margin-top: 8px !important;
ul {
margin: 0 !important;
padding: 0 !important;
margin-top: 8px !important;
li {
position: relative;
list-style: none;
line-height: 24px;
margin: 0 !important;
padding-inline: 16px 0 !important;
&::before {
content: '';
position: absolute;
left: 0px;
top: 0;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: var(--ant-color-text-secondary);
margin-top: 8px;
}
}
}
.bold {
font-weight: 700;
color: var(--ant-color-text);
}
.notice {
margin-top: 8px !important;
}
`;
const TitleWrapper = styled.div`
display: flex;
align-items: center;
font-weight: 700;
color: var(--ant-color-text);
justify-content: space-between;
`;
const RenderMessage = () => {
const intl = useIntl();
return (
<Tips>
<ul>
<li>
<span
dangerouslySetInnerHTML={{
__html: intl.formatMessage({
id: 'models.ollama.deprecated.current'
})
}}
></span>
</li>
<li>
<span
dangerouslySetInnerHTML={{
__html: intl.formatMessage({
id: 'models.ollama.deprecated.upcoming'
})
}}
></span>
</li>
</ul>
<div className="notice">
<span
dangerouslySetInnerHTML={{
__html: intl.formatMessage({
id: 'models.ollama.deprecated.following'
})
}}
></span>
<div
dangerouslySetInnerHTML={{
__html: intl.formatMessage({ id: 'models.ollama.deprecated.issue' })
}}
></div>
</div>
</Tips>
);
};
const OllamaTips = () => {
const intl = useIntl();
const [maxHeight, setMaxHeight] = useState(1);
const handleShowMore = () => {
setMaxHeight(maxHeight === 1 ? 600 : 1);
};
return (
<Wrapper>
<AlertBlockInfo
contentStyle={{ paddingInline: 0 }}
maxHeight={maxHeight}
ellipsis={false}
message={<RenderMessage></RenderMessage>}
title={
<TitleWrapper>
<div>
{intl.formatMessage({ id: 'models.ollama.deprecated.title' })}
</div>
<Button
onClick={handleShowMore}
size="small"
type="text"
icon={<IconFont type="icon-down"></IconFont>}
></Button>
</TitleWrapper>
}
type={'warning'}
></AlertBlockInfo>
</Wrapper>
);
};
export default OllamaTips;
+89 -70
View File
@@ -9,6 +9,7 @@ import { useIntl } from '@umijs/max';
import { Form, Typography } from 'antd';
import _ from 'lodash';
import React, { forwardRef, useImperativeHandle, useMemo } from 'react';
import OllamaTips from '../components/ollama-tips';
import {
localPathTipsList,
modelSourceMap,
@@ -38,6 +39,18 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
onOk(data);
};
const handleOnLocalPathBlur = (e: any) => {
let { value } = e.target;
// remove the last slash: windows or linux
const lastChar = value.slice(-1);
if (lastChar === '/' || lastChar === '\\') {
value = value.slice(0, -1);
}
form.setFieldsValue({
local_path: value
});
};
const renderLocalPathFields = () => {
return (
<>
@@ -54,6 +67,7 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
<SealInput.Input
required
label={intl.formatMessage({ id: 'models.form.filePath' })}
onBlur={handleOnLocalPathBlur}
description={<TooltipList list={localPathTipsList}></TooltipList>}
></SealInput.Input>
</Form.Item>
@@ -119,84 +133,89 @@ const TargetForm: React.FC<TargetFormProps> = forwardRef((props, ref) => {
}, [props.source, intl]);
return (
<Form
form={form}
onFinish={handleOk}
preserve={false}
style={{ padding: '16px 24px' }}
clearOnDestroy={true}
initialValues={{
source: source
}}
>
<Form.Item<FormData>
name="source"
rules={[
{
required: true,
message: getRuleMessage('select', 'models.form.source')
}
]}
<div>
{source === modelSourceMap.ollama_library_value && (
<OllamaTips></OllamaTips>
)}
<Form
form={form}
onFinish={handleOk}
preserve={false}
style={{ padding: '16px 24px' }}
clearOnDestroy={true}
initialValues={{
source: source
}}
>
{
<SealSelect
disabled
label={intl.formatMessage({
id: 'models.form.source'
})}
options={sourceOptions}
required
></SealSelect>
}
</Form.Item>
{renderFieldsBySource}
<Form.Item
name="worker_id"
rules={[
{
required: true,
message: getRuleMessage('select', 'worker', false)
}
]}
>
{
<SealSelect
label="Worker"
options={workersList}
required
></SealSelect>
}
</Form.Item>
{source !== modelSourceMap.local_path_value && (
<Form.Item<FormData>
name="local_dir"
name="source"
rules={[
{
required: false,
message: getRuleMessage(
'input',
'resources.modelfiles.form.localdir'
)
required: true,
message: getRuleMessage('select', 'models.form.source')
}
]}
>
<SealInput.Input
description={
<span
dangerouslySetInnerHTML={{
__html: intl.formatMessage({
id: 'resources.modelfiles.form.localdir.tips'
})
}}
></span>
}
label={intl.formatMessage({
id: 'resources.modelfiles.form.localdir'
})}
></SealInput.Input>
{
<SealSelect
disabled
label={intl.formatMessage({
id: 'models.form.source'
})}
options={sourceOptions}
required
></SealSelect>
}
</Form.Item>
)}
</Form>
{renderFieldsBySource}
<Form.Item
name="worker_id"
rules={[
{
required: true,
message: getRuleMessage('select', 'worker', false)
}
]}
>
{
<SealSelect
label="Worker"
options={workersList}
required
></SealSelect>
}
</Form.Item>
{source !== modelSourceMap.local_path_value && (
<Form.Item<FormData>
name="local_dir"
rules={[
{
required: false,
message: getRuleMessage(
'input',
'resources.modelfiles.form.localdir'
)
}
]}
>
<SealInput.Input
description={
<span
dangerouslySetInnerHTML={{
__html: intl.formatMessage({
id: 'resources.modelfiles.form.localdir.tips'
})
}}
></span>
}
label={intl.formatMessage({
id: 'resources.modelfiles.form.localdir'
})}
></SealInput.Input>
</Form.Item>
)}
</Form>
</div>
);
});