chore: version info modal
This commit is contained in:
+20
-1
@@ -1,6 +1,11 @@
|
||||
import { GPUStackVersionAtom } from '@/atoms/user';
|
||||
import { setAtomStorage } from '@/atoms/utils';
|
||||
import { RequestConfig, history } from '@umijs/max';
|
||||
import { requestConfig } from './request-config';
|
||||
import { queryCurrentUserState } from './services/profile/apis';
|
||||
import {
|
||||
queryCurrentUserState,
|
||||
queryVersionInfo
|
||||
} from './services/profile/apis';
|
||||
|
||||
const loginPath = '/login';
|
||||
let currentUserInfo: any = {};
|
||||
@@ -28,6 +33,18 @@ export async function getInitialState(): Promise<{
|
||||
return {} as Global.UserInfo;
|
||||
};
|
||||
|
||||
const getAppVersionInfo = async () => {
|
||||
try {
|
||||
const data = await queryVersionInfo();
|
||||
console.log('versioninfo=========', data);
|
||||
setAtomStorage(GPUStackVersionAtom, data);
|
||||
} catch (error) {
|
||||
console.error('queryVersionInfo error', error);
|
||||
}
|
||||
};
|
||||
|
||||
getAppVersionInfo();
|
||||
|
||||
if (![loginPath].includes(location.pathname)) {
|
||||
const userInfo = await fetchUserInfo();
|
||||
currentUserInfo = {
|
||||
@@ -43,6 +60,8 @@ export async function getInitialState(): Promise<{
|
||||
};
|
||||
}
|
||||
|
||||
console.log('app.tsx');
|
||||
|
||||
export const request: RequestConfig = {
|
||||
baseURL: ' /v1',
|
||||
...requestConfig
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { atom } from 'jotai';
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
|
||||
export const userAtom = atomWithStorage<any>('userInfo', null);
|
||||
|
||||
export const GPUStackVersionAtom = atom<{
|
||||
version: string;
|
||||
git_commit: string;
|
||||
}>({
|
||||
version: '',
|
||||
git_commit: ''
|
||||
});
|
||||
|
||||
export const initialPasswordAtom = atomWithStorage<string>(
|
||||
'initialPassword',
|
||||
''
|
||||
|
||||
@@ -8,7 +8,14 @@ export const clearAtomStorage = (atom: any) => {
|
||||
store.set(atom, null);
|
||||
};
|
||||
|
||||
export const getAtomStorage = (atom: any) => {
|
||||
export const setAtomStorage = (atom: any, value: any) => {
|
||||
if (!atom) {
|
||||
return;
|
||||
}
|
||||
const store = getDefaultStore();
|
||||
store.set(atom, value);
|
||||
};
|
||||
export const getAtomStorage = (atom: any): any => {
|
||||
if (!atom) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,20 @@ import { Button } from 'antd';
|
||||
type CopyButtonProps = {
|
||||
text: string;
|
||||
disabled?: boolean;
|
||||
fontSize?: string;
|
||||
type?: 'text' | 'primary' | 'dashed' | 'link' | 'default';
|
||||
size?: 'small' | 'middle' | 'large';
|
||||
shape?: 'circle' | 'round' | 'default';
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
|
||||
const CopyButton: React.FC<CopyButtonProps> = ({
|
||||
text,
|
||||
disabled,
|
||||
type = 'text',
|
||||
shape = 'circle',
|
||||
fontSize = '14px',
|
||||
style,
|
||||
size = 'middle'
|
||||
}) => {
|
||||
const { copied, copyToClipboard } = useCopyToClipboard();
|
||||
@@ -24,21 +30,20 @@ const CopyButton: React.FC<CopyButtonProps> = ({
|
||||
return (
|
||||
<Button
|
||||
type={type}
|
||||
shape="circle"
|
||||
shape={shape}
|
||||
size={size}
|
||||
onClick={handleCopy}
|
||||
disabled={!!disabled}
|
||||
>
|
||||
{copied ? (
|
||||
<CheckCircleFilled
|
||||
style={{ color: 'var(--ant-color-success)', fontSize: '14px' }}
|
||||
/>
|
||||
) : (
|
||||
<CopyOutlined
|
||||
style={{ color: 'var(--ant-color-primary)', fontSize: '14px' }}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
icon={
|
||||
copied ? (
|
||||
<CheckCircleFilled
|
||||
style={{ color: 'var(--ant-color-success)', fontSize: fontSize }}
|
||||
/>
|
||||
) : (
|
||||
<CopyOutlined style={{ fontSize: fontSize, ...style }} />
|
||||
)
|
||||
}
|
||||
></Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const EditorWrap: React.FC<EditorwrapProps> = ({
|
||||
showHeader = true
|
||||
}) => {
|
||||
const handleChangeLang = (value: string) => {
|
||||
onChangeLang && onChangeLang(value);
|
||||
onChangeLang?.(value);
|
||||
};
|
||||
const renderHeader = () => {
|
||||
if (header) {
|
||||
@@ -39,7 +39,13 @@ const EditorWrap: React.FC<EditorwrapProps> = ({
|
||||
options={langOptions}
|
||||
onChange={handleChangeLang}
|
||||
></Select>
|
||||
<CopyButton text={copyText} />
|
||||
<CopyButton
|
||||
text={copyText}
|
||||
size="small"
|
||||
style={{
|
||||
color: 'rgba(255,255,255,.7)'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,4 +7,10 @@
|
||||
text-align: center;
|
||||
font-size: var(--font-size-middle);
|
||||
color: var(--color-text-2);
|
||||
|
||||
.footer-content-left-text {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
import { GPUStackVersionAtom } from '@/atoms/user';
|
||||
import { getAtomStorage } from '@/atoms/utils';
|
||||
import VersionInfo from '@/components/version-info';
|
||||
import externalLinks from '@/config/external-links';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Space } from 'antd';
|
||||
import { Button, Modal, Space } from 'antd';
|
||||
import './index.less';
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const showVersion = () => {
|
||||
Modal.info({
|
||||
icon: null,
|
||||
centered: false,
|
||||
width: 500,
|
||||
content: <VersionInfo intl={intl} />
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="footer">
|
||||
<div className="footer-content">
|
||||
@@ -14,6 +28,19 @@ const Footer: React.FC = () => {
|
||||
<span> {new Date().getFullYear()}</span>
|
||||
<span> {intl.formatMessage({ id: 'settings.company' })}</span>
|
||||
</Space>
|
||||
<Space size={8} style={{ marginLeft: 18 }}>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
href={externalLinks.documentation}
|
||||
target="_blank"
|
||||
>
|
||||
{intl.formatMessage({ id: 'common.button.help' })}
|
||||
</Button>
|
||||
<Button type="link" size="small" onClick={showVersion}>
|
||||
{getAtomStorage(GPUStackVersionAtom)?.version}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,12 +20,17 @@ type StatusTagProps = {
|
||||
text: string;
|
||||
message?: string;
|
||||
};
|
||||
type?: 'tag' | 'circle';
|
||||
download?: {
|
||||
percent: number;
|
||||
};
|
||||
};
|
||||
|
||||
const StatusTag: React.FC<StatusTagProps> = ({ statusValue, download }) => {
|
||||
const StatusTag: React.FC<StatusTagProps> = ({
|
||||
statusValue,
|
||||
download,
|
||||
type = 'tag'
|
||||
}) => {
|
||||
const { text, status } = statusValue;
|
||||
const [statusColor, setStatusColor] = useState<{
|
||||
text: string;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
.version-box {
|
||||
display: flex;
|
||||
margin-bottom: 40px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.img {
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
height: 30px;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-align: center;
|
||||
font-size: var(--font-size-middle);
|
||||
margin-block: 30px 10px;
|
||||
}
|
||||
|
||||
.ver {
|
||||
line-height: 32px;
|
||||
display: flex;
|
||||
font-size: var(--font-size-middle);
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
width: 60px;
|
||||
font-size: var(--font-size-middle);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.val {
|
||||
color: var(--ant-color-text-secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import Logo from '@/assets/images/gpustack-logo.png';
|
||||
import { GPUStackVersionAtom } from '@/atoms/user';
|
||||
import { getAtomStorage } from '@/atoms/utils';
|
||||
import React from 'react';
|
||||
import './index.less';
|
||||
|
||||
const VersionInfo: React.FC<{ intl: any }> = ({ intl }) => {
|
||||
// get the data attr from html
|
||||
const version = document.documentElement.getAttribute('data-version');
|
||||
|
||||
return (
|
||||
<div className="version-box">
|
||||
<div className="img">
|
||||
<img src={Logo} alt="logo" />
|
||||
</div>
|
||||
<div className="title">
|
||||
{intl.formatMessage({ id: 'common.footer.version.title' })}
|
||||
</div>
|
||||
<div>
|
||||
<div className="ver">
|
||||
<span className="label">
|
||||
{' '}
|
||||
{intl.formatMessage({ id: 'common.footer.version.server' })}
|
||||
</span>
|
||||
<span className="val">
|
||||
{getAtomStorage(GPUStackVersionAtom)?.version ||
|
||||
getAtomStorage(GPUStackVersionAtom)?.git_commit}
|
||||
</span>
|
||||
</div>
|
||||
<div className="ver">
|
||||
<span className="label">UI </span>
|
||||
<span className="val"> {version}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VersionInfo;
|
||||
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
documentation: 'https://docs.gpustack.ai/',
|
||||
github: 'https://github.com/gpustack/gpustack',
|
||||
discord: 'https://discord.gg/2ZvXuaYq',
|
||||
site: 'https://seal.io/'
|
||||
};
|
||||
Vendored
+2
@@ -21,4 +21,6 @@ declare namespace Global {
|
||||
require_password_change: boolean;
|
||||
id: number;
|
||||
}
|
||||
|
||||
type SearchParams = Pagination & { search?: string };
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
// 应用前置、全局运行的逻辑时 会在这里执行
|
||||
// 应用前置、全局运行的逻辑时 会在这里执行
|
||||
|
||||
+14
-1
@@ -1,10 +1,10 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { userAtom } from '@/atoms/user';
|
||||
import VersionInfo from '@/components/version-info';
|
||||
import { logout } from '@/pages/login/apis';
|
||||
import { useAccessMarkedRoutes } from '@@/plugin-access';
|
||||
import { useModel } from '@@/plugin-model';
|
||||
|
||||
import { ProLayout } from '@ant-design/pro-components';
|
||||
import {
|
||||
Link,
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
useNavigate,
|
||||
type IRoute
|
||||
} from '@umijs/max';
|
||||
import { Modal } from 'antd';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useMemo, useState } from 'react';
|
||||
import Exception from './Exception';
|
||||
@@ -102,6 +103,15 @@ export default (props: any) => {
|
||||
return intl.formatMessage({ id: args.id });
|
||||
};
|
||||
|
||||
const showVersion = () => {
|
||||
Modal.info({
|
||||
icon: null,
|
||||
centered: false,
|
||||
width: 500,
|
||||
content: <VersionInfo intl={intl} />
|
||||
});
|
||||
};
|
||||
|
||||
const runtimeConfig = {
|
||||
...initialInfo,
|
||||
logout: async (userInfo) => {
|
||||
@@ -109,6 +119,9 @@ export default (props: any) => {
|
||||
await logout();
|
||||
navigate(loginPath);
|
||||
},
|
||||
showVersion: () => {
|
||||
return showVersion();
|
||||
},
|
||||
notFound: <span>404 not found</span>
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import avatarImg from '@/assets/images/avatar.png';
|
||||
import externalLinks from '@/config/external-links';
|
||||
import langConfigMap from '@/locales/lang-config-map';
|
||||
import {
|
||||
DiscordOutlined,
|
||||
@@ -27,6 +28,7 @@ export function getRightRenderContent(opts: {
|
||||
intl: any;
|
||||
}) {
|
||||
const { intl, collapsed, siderWidth } = opts;
|
||||
|
||||
const allLocals = getAllLocales();
|
||||
if (opts.runtimeConfig.rightRender) {
|
||||
return opts.runtimeConfig.rightRender(
|
||||
@@ -73,22 +75,25 @@ export function getRightRenderContent(opts: {
|
||||
key: 'site',
|
||||
icon: <HomeOutlined />,
|
||||
label: 'GPUStack',
|
||||
url: 'https://gpustack.ai/'
|
||||
url: externalLinks.site
|
||||
},
|
||||
{
|
||||
key: 'github',
|
||||
icon: <GithubOutlined />,
|
||||
label: 'GitHub'
|
||||
label: 'GitHub',
|
||||
url: externalLinks.github
|
||||
},
|
||||
{
|
||||
key: 'Discord',
|
||||
icon: <DiscordOutlined />,
|
||||
label: 'Discord'
|
||||
label: 'Discord',
|
||||
url: externalLinks.discord
|
||||
},
|
||||
{
|
||||
key: 'docs',
|
||||
icon: <ReadOutlined />,
|
||||
label: intl.formatMessage({ id: 'common.button.docs' })
|
||||
label: intl.formatMessage({ id: 'common.button.docs' }),
|
||||
url: externalLinks.documentation
|
||||
},
|
||||
{
|
||||
key: 'version',
|
||||
@@ -118,11 +123,26 @@ export function getRightRenderContent(opts: {
|
||||
label: (
|
||||
<span className="flex flex-center">
|
||||
{item.icon}
|
||||
<a className="m-l-8" href="#" target="_blank">
|
||||
{item.label}
|
||||
</a>
|
||||
{item.key === 'version' ? (
|
||||
<a className="m-l-8">{item.label}</a>
|
||||
) : (
|
||||
<a
|
||||
className="m-l-8"
|
||||
href={item.url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{item.label}
|
||||
</a>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
),
|
||||
onClick() {
|
||||
if (item.key === 'version') {
|
||||
// opts.runtimeConfig.showVersion();
|
||||
opts.runtimeConfig.showVersion();
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
]
|
||||
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
'playground.params.topp.tips':
|
||||
'Controls diversity via nucleus sampling: 0.5 means half of all likelihood-weighted options are considered.',
|
||||
'playground.params.seed.tips':
|
||||
'Specify a random seed to ensure deterministic sampling. Using the same seed and parameters will produce the same results for repeated requests.',
|
||||
'If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result.',
|
||||
'playground.params.stop.tips':
|
||||
'A stop sequence is a predefined or user-specified text string that signals the AI to stop generating further tokens when these sequences appear.'
|
||||
};
|
||||
|
||||
@@ -20,9 +20,9 @@ export default {
|
||||
'playground.params.maxtokens.tips':
|
||||
'生成的最大 token 数。输入标记和生成的标记的总长度受模型上下文长度的限制。',
|
||||
'playground.params.topp.tips':
|
||||
'通过核采样控制多样性:0.5 表示考虑所有基于概率权重选项的一半。',
|
||||
'通过核心采样控制多样性:0.5 表示考虑所有基于概率权重选项的一半。',
|
||||
'playground.params.seed.tips':
|
||||
'指定随机种子以确保确定性采样。使用相同的种子和参数对于重复请求将产生相同的结果。',
|
||||
'如果指定,我们的系统将尽最大努力进行确定性采样,以便使用相同种子和参数的重复请求应返回相同的结果。',
|
||||
'playground.params.stop.tips':
|
||||
'停止序列是一个预定义或用户指定的文本字符串,当这些序列出现时,它会提示 AI 停止生成后续的标记。'
|
||||
};
|
||||
|
||||
@@ -3,9 +3,7 @@ import { FormData, ListItem } from '../config/types';
|
||||
|
||||
export const APIS_KEYS_API = '/api-keys';
|
||||
|
||||
export async function queryApisKeysList(
|
||||
params: Global.Pagination & { query?: string }
|
||||
) {
|
||||
export async function queryApisKeysList(params: Global.SearchParams) {
|
||||
return request<Global.PageResponse<ListItem>>(`${APIS_KEYS_API}`, {
|
||||
method: 'GET',
|
||||
params
|
||||
|
||||
@@ -42,7 +42,7 @@ const Models: React.FC = () => {
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
query: ''
|
||||
search: ''
|
||||
});
|
||||
|
||||
const handleShowSizeChange = (page: number, size: number) => {
|
||||
@@ -90,7 +90,7 @@ const Models: React.FC = () => {
|
||||
const handleNameChange = (e: any) => {
|
||||
setQueryParams({
|
||||
...queryParams,
|
||||
query: e.target.value
|
||||
search: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export const MODEL_INSTANCE_API = '/model-instances';
|
||||
|
||||
// ===================== Models =====================
|
||||
export async function queryModelsList(
|
||||
params: Global.Pagination & { query?: string },
|
||||
params: Global.SearchParams,
|
||||
options?: any
|
||||
) {
|
||||
return request<Global.PageResponse<ListItem>>(`${MODELS_API}`, {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import DropdownButtons from '@/components/drop-down-buttons';
|
||||
import RowChildren from '@/components/seal-table/components/row-children';
|
||||
import StatusTag from '@/components/status-tag';
|
||||
import { DeleteOutlined, FieldTimeOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
FieldTimeOutlined,
|
||||
InfoCircleOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Col, Row, Space } from 'antd';
|
||||
import { Col, Row, Space, Tooltip } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
@@ -59,35 +63,44 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const getWorkerIp = (item: ModelInstanceListItem) => {
|
||||
const renderWorkerInfo = (item: ModelInstanceListItem) => {
|
||||
let workerIp = '-';
|
||||
if (item.worker_ip) {
|
||||
return item.port ? `${item.worker_ip}:${item.port}` : item.worker_ip;
|
||||
workerIp = item.port ? `${item.worker_ip}:${item.port}` : item.worker_ip;
|
||||
}
|
||||
return '-';
|
||||
return (
|
||||
<div>
|
||||
<div>{item.worker_name}</div>
|
||||
<div>{workerIp}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Space size={16} direction="vertical" style={{ width: '100%' }}>
|
||||
{_.map(list, (item: ModelInstanceListItem, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className="_2Q2Yw"
|
||||
key={`${item.id}`}
|
||||
style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}
|
||||
>
|
||||
<RowChildren key={`${item.id}_row`}>
|
||||
<Row style={{ width: '100%' }} align="middle">
|
||||
<Col span={4}>{item.name}</Col>
|
||||
<Col span={3}>{item.worker_name || '-'}</Col>
|
||||
<Col span={4}>
|
||||
<span>
|
||||
{item.source === 'huggingface'
|
||||
? item.huggingface_filename
|
||||
: item.ollama_library_model_name}
|
||||
</span>
|
||||
<Col
|
||||
span={5}
|
||||
style={{
|
||||
paddingInline: 'var(--ant-table-cell-padding-inline)'
|
||||
}}
|
||||
>
|
||||
<Tooltip title={renderWorkerInfo(item)}>
|
||||
<span className="m-r-5">{item.name}</span>
|
||||
<InfoCircleOutlined />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
|
||||
<Col span={3}>
|
||||
<Col span={6}></Col>
|
||||
<Col span={4}>
|
||||
<span
|
||||
style={{ paddingLeft: '0px' }}
|
||||
style={{ paddingLeft: '56px' }}
|
||||
className="flex justify-center"
|
||||
>
|
||||
{item.state && (
|
||||
@@ -107,11 +120,11 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
||||
</span>
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
<span style={{ paddingLeft: 36 }}>
|
||||
<span style={{ paddingLeft: 38 }}>
|
||||
{dayjs(item.updated_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</span>
|
||||
</Col>
|
||||
<Col span={5}>
|
||||
<Col span={4}>
|
||||
<div style={{ paddingLeft: 39 }}>
|
||||
<DropdownButtons
|
||||
items={setChildActionList(item)}
|
||||
|
||||
@@ -337,15 +337,21 @@ const Models: React.FC<ModelsProps> = ({
|
||||
dataIndex="name"
|
||||
key="name"
|
||||
width={400}
|
||||
span={6}
|
||||
span={5}
|
||||
/>
|
||||
<SealColumn
|
||||
title={intl.formatMessage({ id: 'models.form.source' })}
|
||||
dataIndex="source"
|
||||
key="source"
|
||||
span={4}
|
||||
render={(text) => {
|
||||
return modelSourceMap[text] || '-';
|
||||
span={6}
|
||||
render={(text, record: ListItem) => {
|
||||
return (
|
||||
<span>
|
||||
{record.source === modelSourceMap.huggingface_value
|
||||
? `${modelSourceMap.huggingface} / ${record.huggingface_filename}`
|
||||
: `${modelSourceMap.ollama_library} / ${record.ollama_library_model_name}`}
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<SealColumn
|
||||
@@ -369,7 +375,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
}}
|
||||
/>
|
||||
<SealColumn
|
||||
span={5}
|
||||
span={4}
|
||||
title={intl.formatMessage({ id: 'common.table.operation' })}
|
||||
key="operation"
|
||||
render={(text, record) => {
|
||||
|
||||
@@ -15,7 +15,10 @@ export const ollamaModelOptions = [
|
||||
export const modelSourceMap: Record<string, string> = {
|
||||
huggingface: 'Hugging Face',
|
||||
ollama_library: 'Ollama Library',
|
||||
s3: 'S3'
|
||||
s3: 'S3',
|
||||
huggingface_value: 'huggingface',
|
||||
ollama_library_value: 'ollama_library',
|
||||
s3_value: 's3'
|
||||
};
|
||||
|
||||
export const InstanceStatusMap = {
|
||||
|
||||
@@ -2,6 +2,8 @@ export interface ListItem {
|
||||
source: string;
|
||||
huggingface_repo_id: string;
|
||||
huggingface_file_name: string;
|
||||
huggingface_filename: string;
|
||||
ollama_library_model_name: string;
|
||||
s3Address: string;
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
@@ -24,7 +24,7 @@ const Models: React.FC = () => {
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
query: ''
|
||||
search: ''
|
||||
});
|
||||
// request data
|
||||
|
||||
@@ -110,7 +110,7 @@ const Models: React.FC = () => {
|
||||
(e: any) => {
|
||||
setQueryParams({
|
||||
...queryParams,
|
||||
query: e.target.value
|
||||
search: e.target.value
|
||||
});
|
||||
},
|
||||
[queryParams]
|
||||
|
||||
@@ -122,13 +122,16 @@ const MessageItem: React.FC<{
|
||||
<div className="delete-btn">
|
||||
<Space size={5}>
|
||||
{message.content && (
|
||||
<CopyButton text={message.content} size="small"></CopyButton>
|
||||
<CopyButton
|
||||
text={message.content}
|
||||
size="small"
|
||||
shape="default"
|
||||
type="default"
|
||||
fontSize="12px"
|
||||
></CopyButton>
|
||||
)}
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
size="small"
|
||||
style={{ color: 'var(--ant-color-primary)' }}
|
||||
onClick={handleDelete}
|
||||
icon={<MinusCircleOutlined />}
|
||||
></Button>
|
||||
|
||||
@@ -66,7 +66,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
const systemList = systemMessage
|
||||
? [{ role: 'system', content: systemMessage }]
|
||||
: [];
|
||||
const code = `import OpenAI from "openai";\nconst openai = new OpenAI({\n"base_url": "/v1-openai", \n "gpustack_api_key": "$\{GPUSTACK_API_KEY}"\n });\n\nasync function main(){\nconst params = ${JSON.stringify(
|
||||
const code = `import OpenAI from "openai";\nconst openai = new OpenAI();\n\nasync function main(){\nconst params = ${JSON.stringify(
|
||||
{
|
||||
...parameters,
|
||||
messages: [...systemList, ...messageList]
|
||||
@@ -92,7 +92,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
const systemList = systemMessage
|
||||
? [{ role: 'system', content: systemMessage }]
|
||||
: [];
|
||||
const code = `from openai import OpenAI\nclient = OpenAI({\n "base_url": "/v1-openai", \n "gpustack_api_key": "$\{GPUSTACK_API_KEY}"\n })\n\ncompletion = client.chat.completions.create(\n${formattedParams} messages=${JSON.stringify([...systemList, ...messageList], null, 2)})\nprint(completion.choices[0].message)`;
|
||||
const code = `from openai import OpenAI\nclient = OpenAI()\n\ncompletion = client.chat.completions.create(\n${formattedParams} messages=${JSON.stringify([...systemList, ...messageList], null, 2)})\nprint(completion.choices[0].message)`;
|
||||
setCodeValue(code);
|
||||
}
|
||||
formatCode();
|
||||
|
||||
@@ -4,18 +4,14 @@ import { GPUDeviceItem, ListItem } from '../config/types';
|
||||
export const WORKERS_API = '/workers';
|
||||
export const GPU_DEVICES_API = '/gpu-devices';
|
||||
|
||||
export async function queryWorkersList(
|
||||
params: Global.Pagination & { query?: string }
|
||||
) {
|
||||
export async function queryWorkersList(params: Global.SearchParams) {
|
||||
return request<Global.PageResponse<ListItem>>(`${WORKERS_API}`, {
|
||||
methos: 'GET',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
export async function queryGpuDevicesList(
|
||||
params: Global.Pagination & { query?: string }
|
||||
) {
|
||||
export async function queryGpuDevicesList(params: Global.SearchParams) {
|
||||
return request<Global.PageResponse<GPUDeviceItem>>(`${GPU_DEVICES_API}`, {
|
||||
methos: 'GET',
|
||||
params
|
||||
|
||||
@@ -22,7 +22,7 @@ const GPUList: React.FC = () => {
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
query: ''
|
||||
search: ''
|
||||
});
|
||||
const handleShowSizeChange = (current: number, size: number) => {
|
||||
setQueryParams({
|
||||
@@ -67,7 +67,7 @@ const GPUList: React.FC = () => {
|
||||
const handleNameChange = (e: any) => {
|
||||
setQueryParams({
|
||||
...queryParams,
|
||||
query: e.target.value
|
||||
search: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ const Resources: React.FC = () => {
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
query: ''
|
||||
search: ''
|
||||
});
|
||||
|
||||
const fetchData = async () => {
|
||||
@@ -73,7 +73,7 @@ const Resources: React.FC = () => {
|
||||
const handleNameChange = (e: any) => {
|
||||
setQueryParams({
|
||||
...queryParams,
|
||||
query: e.target.value
|
||||
search: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ import { FormData, ListItem } from '../config/types';
|
||||
|
||||
export const USERS_API = '/users';
|
||||
|
||||
export async function queryUsersList(
|
||||
params: Global.Pagination & { query?: string }
|
||||
) {
|
||||
export async function queryUsersList(params: Global.SearchParams) {
|
||||
return request<Global.PageResponse<ListItem>>(`${USERS_API}`, {
|
||||
methos: 'GET',
|
||||
params
|
||||
|
||||
@@ -43,7 +43,7 @@ const Users: React.FC = () => {
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
query: ''
|
||||
search: ''
|
||||
});
|
||||
|
||||
const ActionList = [
|
||||
@@ -104,7 +104,7 @@ const Users: React.FC = () => {
|
||||
const handleNameChange = (e: any) => {
|
||||
setQueryParams({
|
||||
...queryParams,
|
||||
query: e.target.value
|
||||
search: e.target.value
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { clearAtomStorage } from '@/atoms/utils';
|
||||
import { RequestConfig, history } from '@umijs/max';
|
||||
import { message } from 'antd';
|
||||
|
||||
const NoBaseURLAPIs = ['/auth', '/v1-openai'];
|
||||
const NoBaseURLAPIs = ['/auth', '/v1-openai', '/version'];
|
||||
|
||||
export const requestConfig: RequestConfig = {
|
||||
errorConfig: {
|
||||
|
||||
@@ -6,3 +6,9 @@ export async function queryCurrentUserState(opts?: Record<string, any>) {
|
||||
...opts
|
||||
});
|
||||
}
|
||||
|
||||
export async function queryVersionInfo() {
|
||||
return request(`/version`, {
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user