chore: draft model downloading
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
.cell-header {
|
.cell-header {
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.light {
|
&.light {
|
||||||
|
|||||||
@@ -73,4 +73,4 @@ const SimpleTabel: React.FC<SimpleTableProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(SimpleTabel);
|
export default SimpleTabel;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const TagWrapper = styled(Tag)`
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
margin: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ThemeTag: React.FC<TagProps & { opacity?: number }> = ({
|
const ThemeTag: React.FC<TagProps & { opacity?: number }> = ({
|
||||||
|
|||||||
@@ -1,23 +1,35 @@
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
|
||||||
|
type MessageType = 'input' | 'select';
|
||||||
|
|
||||||
const useAppUtils = () => {
|
const useAppUtils = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [messageApi, contextHolder] = message.useMessage();
|
const [messageApi, contextHolder] = message.useMessage();
|
||||||
|
|
||||||
const getRuleMessage = (
|
const getRuleMessage = (
|
||||||
type: 'input' | 'select',
|
type: MessageType | MessageType[],
|
||||||
name: string,
|
name: string,
|
||||||
locale = true
|
locale = true
|
||||||
) => {
|
) => {
|
||||||
const nameStr = locale ? intl.formatMessage({ id: name }) : name;
|
const nameStr = locale ? intl.formatMessage({ id: name }) : name;
|
||||||
|
// transform type to array
|
||||||
|
const typeList = Array.isArray(type) ? type : [type];
|
||||||
|
|
||||||
if (type === 'input') {
|
if (typeList.includes('select') && typeList.includes('input')) {
|
||||||
|
return intl.formatMessage(
|
||||||
|
{ id: 'common.form.rule.selectInput' },
|
||||||
|
{ name: nameStr }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeList.includes('input')) {
|
||||||
return intl.formatMessage(
|
return intl.formatMessage(
|
||||||
{ id: 'common.form.rule.input' },
|
{ id: 'common.form.rule.input' },
|
||||||
{ name: nameStr }
|
{ name: nameStr }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return intl.formatMessage(
|
return intl.formatMessage(
|
||||||
{ id: 'common.form.rule.select' },
|
{ id: 'common.form.rule.select' },
|
||||||
{ name: nameStr }
|
{ name: nameStr }
|
||||||
|
|||||||
@@ -262,5 +262,6 @@ export default {
|
|||||||
'common.button.terminal': 'Terminal',
|
'common.button.terminal': 'Terminal',
|
||||||
'common.button.addItem': 'Add Item',
|
'common.button.addItem': 'Add Item',
|
||||||
'common.help.default': 'Default: {content}',
|
'common.help.default': 'Default: {content}',
|
||||||
'common.filter.status': 'Filter by status'
|
'common.filter.status': 'Filter by status',
|
||||||
|
'common.form.rule.selectInput': 'Please select or enter a {name}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export default {
|
|||||||
'The model will consume approximately {ram} RAM.',
|
'The model will consume approximately {ram} RAM.',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'Changes will only apply after you delete and recreate the instance.',
|
'Changes will only apply after you delete and recreate the instance.',
|
||||||
'models.table.download.progress': 'Download Progress',
|
'models.table.download.progress': 'Progress',
|
||||||
'models.table.button.apiAccessInfo': 'API Access Info',
|
'models.table.button.apiAccessInfo': 'API Access Info',
|
||||||
'models.table.button.apiAccessInfo.tips': `To integrate this model with third-party applications, use the following details: access URL, model name, and API key. These credentials are required to ensure proper connection and usage of the model service.`,
|
'models.table.button.apiAccessInfo.tips': `To integrate this model with third-party applications, use the following details: access URL, model name, and API key. These credentials are required to ensure proper connection and usage of the model service.`,
|
||||||
'models.table.apiAccessInfo.endpoint': 'Access URL',
|
'models.table.apiAccessInfo.endpoint': 'Access URL',
|
||||||
@@ -227,11 +227,14 @@ export default {
|
|||||||
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
||||||
'models.form.mode.throughput': 'High-Throughput',
|
'models.form.mode.throughput': 'High-Throughput',
|
||||||
'models.form.mode.latency': 'Low-Latency',
|
'models.form.mode.latency': 'Low-Latency',
|
||||||
'models.form.mode.baseline': 'Baseline',
|
'models.form.mode.baseline': 'Standard',
|
||||||
'models.form.mode.throughput.tips':
|
'models.form.mode.throughput.tips':
|
||||||
'optimized for high throughput under high request concurrency.',
|
'optimized for high throughput under high request concurrency.',
|
||||||
'models.form.mode.latency.tips':
|
'models.form.mode.latency.tips':
|
||||||
'optimized for low latency under low request concurrency.',
|
'optimized for low latency under low request concurrency.',
|
||||||
'models.form.mode.baseline.tips':
|
'models.form.mode.baseline.tips':
|
||||||
'Runs at full (original) precision and prioritizes compatibility.'
|
'Runs at full (original) precision and prioritizes compatibility.',
|
||||||
|
'models.form.draftModel.placeholder': 'Please select or enter a draft model',
|
||||||
|
'models.form.draftModel.tips':
|
||||||
|
'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -262,7 +262,8 @@ export default {
|
|||||||
'common.button.terminal': 'Terminal',
|
'common.button.terminal': 'Terminal',
|
||||||
'common.button.addItem': 'Add Item',
|
'common.button.addItem': 'Add Item',
|
||||||
'common.help.default': 'Default: {content}',
|
'common.help.default': 'Default: {content}',
|
||||||
'common.filter.status': 'Filter by status'
|
'common.filter.status': 'Filter by status',
|
||||||
|
'common.form.rule.selectInput': 'Please select or enter a {name}'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -291,4 +292,5 @@ export default {
|
|||||||
// 23. 'common.button.addItem': 'Add Item',
|
// 23. 'common.button.addItem': 'Add Item',
|
||||||
// 24. 'common.help.default': 'Default: {content}',
|
// 24. 'common.help.default': 'Default: {content}',
|
||||||
// 25. 'common.filter.status': 'Filter by status'
|
// 25. 'common.filter.status': 'Filter by status'
|
||||||
|
// 26. 'common.form.rule.selectInput': 'Please select or enter a {name}'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export default {
|
|||||||
'models.form.check.claims3': 'このモデルには約{ram}のメモリが必要です。',
|
'models.form.check.claims3': 'このモデルには約{ram}のメモリが必要です。',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'変更はインスタンスを削除して再作成した後にのみ適用されます。',
|
'変更はインスタンスを削除して再作成した後にのみ適用されます。',
|
||||||
'models.table.download.progress': 'ダウンロード進行状況',
|
'models.table.download.progress': '進行状況',
|
||||||
'models.table.button.apiAccessInfo': 'APIアクセス情報',
|
'models.table.button.apiAccessInfo': 'APIアクセス情報',
|
||||||
'models.table.button.apiAccessInfo.tips':
|
'models.table.button.apiAccessInfo.tips':
|
||||||
'このモデルをサードパーティアプリケーションと統合するには、以下の詳細を使用してください: アクセスURL、モデル名、APIキー。これらの資格情報は、モデルサービスの適切な接続と使用を確保するために必要です。',
|
'このモデルをサードパーティアプリケーションと統合するには、以下の詳細を使用してください: アクセスURL、モデル名、APIキー。これらの資格情報は、モデルサービスの適切な接続と使用を確保するために必要です。',
|
||||||
@@ -227,13 +227,16 @@ export default {
|
|||||||
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
||||||
'models.form.mode.throughput': 'Throughput',
|
'models.form.mode.throughput': 'Throughput',
|
||||||
'models.form.mode.latency': 'Latency',
|
'models.form.mode.latency': 'Latency',
|
||||||
'models.form.mode.baseline': 'Baseline',
|
'models.form.mode.baseline': 'Standard',
|
||||||
'models.form.mode.throughput.tips':
|
'models.form.mode.throughput.tips':
|
||||||
'optimized for high throughput under high request concurrency.',
|
'optimized for high throughput under high request concurrency.',
|
||||||
'models.form.mode.latency.tips':
|
'models.form.mode.latency.tips':
|
||||||
'optimized for low latency under low request concurrency.',
|
'optimized for low latency under low request concurrency.',
|
||||||
'models.form.mode.baseline.tips':
|
'models.form.mode.baseline.tips':
|
||||||
'the most compatible option with full precision.'
|
'the most compatible option with full precision.',
|
||||||
|
'models.form.draftModel.placeholder': 'Please select or enter a draft model',
|
||||||
|
'models.form.draftModel.tips':
|
||||||
|
'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -294,9 +297,11 @@ export default {
|
|||||||
// 38. 'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
// 38. 'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
||||||
// 39. 'models.form.mode.throughput': 'Throughput',
|
// 39. 'models.form.mode.throughput': 'Throughput',
|
||||||
// 40. 'models.form.mode.latency': 'Latency',
|
// 40. 'models.form.mode.latency': 'Latency',
|
||||||
// 41. 'models.form.mode.baseline': 'Baseline',
|
// 41. 'models.form.mode.baseline': 'Standard',
|
||||||
// 42. 'models.form.mode.throughput.tips': 'optimized for high throughput under high request concurrency.',
|
// 42. 'models.form.mode.throughput.tips': 'optimized for high throughput under high request concurrency.',
|
||||||
// 43. 'models.form.mode.latency.tips': 'optimized for low latency under low request concurrency.',
|
// 43. 'models.form.mode.latency.tips': 'optimized for low latency under low request concurrency.',
|
||||||
// 44. 'models.form.mode.baseline.tips': 'the most compatible option with full precision
|
// 44. 'models.form.mode.baseline.tips': 'the most compatible option with full precision,
|
||||||
|
// 45. 'models.form.draftModel.placeholder': 'Please select or enter a draft model',
|
||||||
|
// 46. 'models.form.draftModel.tips': 'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
|
||||||
|
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -261,9 +261,11 @@ export default {
|
|||||||
'common.button.terminal': 'Терминал',
|
'common.button.terminal': 'Терминал',
|
||||||
'common.button.addItem': 'Добавить элемент',
|
'common.button.addItem': 'Добавить элемент',
|
||||||
'common.help.default': 'По умолчанию: {content}',
|
'common.help.default': 'По умолчанию: {content}',
|
||||||
'common.filter.status': 'Filter by status'
|
'common.filter.status': 'Filter by status',
|
||||||
|
'common.form.rule.selectInput': 'Please select or enter a {name}'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
// 1. 'common.filter.status': 'Filter by status'
|
// 1. 'common.filter.status': 'Filter by status'
|
||||||
|
// 2. 'common.form.rule.selectInput': 'Please select or enter a {name}'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ export default {
|
|||||||
'models.form.check.claims3': 'Модель требует примерно {ram} RAM.',
|
'models.form.check.claims3': 'Модель требует примерно {ram} RAM.',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'Изменения вступят в силу только после удаления и повторного создания инстанса.',
|
'Изменения вступят в силу только после удаления и повторного создания инстанса.',
|
||||||
'models.table.download.progress': 'Прогресс загрузки',
|
'models.table.download.progress': 'Прогресс',
|
||||||
'models.table.button.apiAccessInfo': 'Доступ к API',
|
'models.table.button.apiAccessInfo': 'Доступ к API',
|
||||||
'models.table.button.apiAccessInfo.tips': `Для интеграции этой модели со сторонними приложениями используйте следующие данные: URL доступа, имя модели и ключ API. Эти учетные данные необходимы для обеспечения правильного подключения и использования сервиса модели.`, // Translated
|
'models.table.button.apiAccessInfo.tips': `Для интеграции этой модели со сторонними приложениями используйте следующие данные: URL доступа, имя модели и ключ API. Эти учетные данные необходимы для обеспечения правильного подключения и использования сервиса модели.`, // Translated
|
||||||
'models.table.apiAccessInfo.endpoint': 'URL доступа',
|
'models.table.apiAccessInfo.endpoint': 'URL доступа',
|
||||||
@@ -227,13 +227,16 @@ export default {
|
|||||||
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
||||||
'models.form.mode.throughput': 'Throughput',
|
'models.form.mode.throughput': 'Throughput',
|
||||||
'models.form.mode.latency': 'Latency',
|
'models.form.mode.latency': 'Latency',
|
||||||
'models.form.mode.baseline': 'Baseline',
|
'models.form.mode.baseline': 'Standard',
|
||||||
'models.form.mode.throughput.tips':
|
'models.form.mode.throughput.tips':
|
||||||
'optimized for high throughput under high request concurrency.',
|
'optimized for high throughput under high request concurrency.',
|
||||||
'models.form.mode.latency.tips':
|
'models.form.mode.latency.tips':
|
||||||
'optimized for low latency under low request concurrency.',
|
'optimized for low latency under low request concurrency.',
|
||||||
'models.form.mode.baseline.tips':
|
'models.form.mode.baseline.tips':
|
||||||
'the most compatible option with full precision.'
|
'the most compatible option with full precision.',
|
||||||
|
'models.form.draftModel.placeholder': 'Please select or enter a draft model',
|
||||||
|
'models.form.draftModel.tips':
|
||||||
|
'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
// ========== To-Do: Translate Keys (Remove After Translation) ==========
|
||||||
@@ -257,8 +260,10 @@ export default {
|
|||||||
// 30. 'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
// 30. 'models.form.ngramMaxMatchLength': 'N-gram Maximum Match Length',
|
||||||
// 31. 'models.form.mode.throughput': 'Throughput',
|
// 31. 'models.form.mode.throughput': 'Throughput',
|
||||||
// 32. 'models.form.mode.latency': 'Latency',
|
// 32. 'models.form.mode.latency': 'Latency',
|
||||||
// 33. 'models.form.mode.baseline': 'Baseline',
|
// 33. 'models.form.mode.baseline': 'Standard',
|
||||||
// 34. 'models.form.mode.throughput.tips': 'optimized for high throughput under high request concurrency.',
|
// 34. 'models.form.mode.throughput.tips': 'optimized for high throughput under high request concurrency.',
|
||||||
// 35. 'models.form.mode.latency.tips': 'optimized for low latency under low request concurrency.',
|
// 35. 'models.form.mode.latency.tips': 'optimized for low latency under low request concurrency.',
|
||||||
// 36. 'models.form.mode.baseline.tips': 'the most compatible option with full precision.'
|
// 36. 'models.form.mode.baseline.tips': 'the most compatible option with full precision.'
|
||||||
|
// 37. 'models.form.draftModel.placeholder': 'Please select or enter a draft model',
|
||||||
|
// 38. 'models.form.draftModel.tips': 'You can enter a local path (e.g., /path/to/model) or select a model from Hugging Face or ModelScope (e.g., Tengyunw/qwen3_8b_eagle3). The system will automatically match based on the primary model source.'
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -254,5 +254,6 @@ export default {
|
|||||||
'common.button.terminal': '终端',
|
'common.button.terminal': '终端',
|
||||||
'common.button.addItem': '添加项',
|
'common.button.addItem': '添加项',
|
||||||
'common.help.default': '默认: {content}',
|
'common.help.default': '默认: {content}',
|
||||||
'common.filter.status': '按状态筛选'
|
'common.filter.status': '按状态筛选',
|
||||||
|
'common.form.rule.selectInput': '请选择或输入{name}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export default {
|
|||||||
'models.form.check.claims2': '该模型大约需要消耗 {vram} 显存。',
|
'models.form.check.claims2': '该模型大约需要消耗 {vram} 显存。',
|
||||||
'models.form.check.claims3': '该模型大约需要消耗 {ram} 内存。',
|
'models.form.check.claims3': '该模型大约需要消耗 {ram} 内存。',
|
||||||
'models.form.update.tips': '更改仅在删除并重新创建实例后生效。',
|
'models.form.update.tips': '更改仅在删除并重新创建实例后生效。',
|
||||||
'models.table.download.progress': '下载进度',
|
'models.table.download.progress': '进度',
|
||||||
'models.table.button.apiAccessInfo': 'API 接入信息',
|
'models.table.button.apiAccessInfo': 'API 接入信息',
|
||||||
'models.table.button.apiAccessInfo.tips': `当您需要将本模型与第三方应用集成时,请使用以下信息:接入地址、模型名称和 API 密钥。这些信息是确保外部系统能正确连接并调用模型服务的关键凭证。`,
|
'models.table.button.apiAccessInfo.tips': `当您需要将本模型与第三方应用集成时,请使用以下信息:接入地址、模型名称和 API 密钥。这些信息是确保外部系统能正确连接并调用模型服务的关键凭证。`,
|
||||||
'models.table.apiAccessInfo.endpoint': '接入地址',
|
'models.table.apiAccessInfo.endpoint': '接入地址',
|
||||||
@@ -220,5 +220,9 @@ export default {
|
|||||||
'models.form.mode.baseline': '标准',
|
'models.form.mode.baseline': '标准',
|
||||||
'models.form.mode.throughput.tips': '在高并发请求下优化吞吐性能。',
|
'models.form.mode.throughput.tips': '在高并发请求下优化吞吐性能。',
|
||||||
'models.form.mode.latency.tips': '在低并发请求下优化响应延迟。',
|
'models.form.mode.latency.tips': '在低并发请求下优化响应延迟。',
|
||||||
'models.form.mode.baseline.tips': '以完整(原始)精度运行,并优先保证兼容性。'
|
'models.form.mode.baseline.tips':
|
||||||
|
'以完整(原始)精度运行,并优先保证兼容性。',
|
||||||
|
'models.form.draftModel.placeholder': '请选择或输入草稿模型',
|
||||||
|
'models.form.draftModel.tips':
|
||||||
|
'可填写本地路径(如 /path/to/model),或从 Hugging Face、ModelScope 选择模型(如 Tengyunw/qwen3_8b_eagle3)。系统将根据主模型来源自动匹配。'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ const Catalog: React.FC = () => {
|
|||||||
allowClear
|
allowClear
|
||||||
showSearch={false}
|
showSearch={false}
|
||||||
placeholder={intl.formatMessage({ id: 'models.filter.category' })}
|
placeholder={intl.formatMessage({ id: 'models.filter.category' })}
|
||||||
style={{ width: 180 }}
|
style={{ width: 200 }}
|
||||||
size="large"
|
size="large"
|
||||||
maxTagCount={1}
|
maxTagCount={1}
|
||||||
onChange={handleCategoryChange}
|
onChange={handleCategoryChange}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ const CatalogItem: React.FC<CatalogItemProps> = (props) => {
|
|||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="tags">
|
<div className="tags gap-6">
|
||||||
{data.categories.map((sItem, i) => {
|
{data.categories.map((sItem, i) => {
|
||||||
return (
|
return (
|
||||||
<ThemeTag
|
<ThemeTag
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ import CompatibilityAlert from './compatible-alert';
|
|||||||
|
|
||||||
const ModesMap: Record<string, string> = {
|
const ModesMap: Record<string, string> = {
|
||||||
latency: 'models.form.mode.latency',
|
latency: 'models.form.mode.latency',
|
||||||
baseline: 'models.form.mode.baseline',
|
standard: 'models.form.mode.baseline',
|
||||||
throughput: 'models.form.mode.throughput'
|
throughput: 'models.form.mode.throughput'
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModesTipsMap: Record<string, string> = {
|
const ModesTipsMap: Record<string, string> = {
|
||||||
latency: 'models.form.mode.latency.tips',
|
latency: 'models.form.mode.latency.tips',
|
||||||
baseline: 'models.form.mode.baseline.tips',
|
standard: 'models.form.mode.baseline.tips',
|
||||||
throughput: 'models.form.mode.throughput.tips'
|
throughput: 'models.form.mode.throughput.tips'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import styled from 'styled-components';
|
|||||||
import { MODEL_INSTANCE_API } from '../apis';
|
import { MODEL_INSTANCE_API } from '../apis';
|
||||||
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
|
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
|
||||||
import { backendOptionsMap } from '../config/backend-parameters';
|
import { backendOptionsMap } from '../config/backend-parameters';
|
||||||
|
import { generateSource } from '../config/button-actions';
|
||||||
import {
|
import {
|
||||||
DistributedServerItem,
|
DistributedServerItem,
|
||||||
DistributedServers,
|
DistributedServers,
|
||||||
@@ -55,12 +56,7 @@ const fieldList = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const downloadList: ColumnProps[] = [
|
const statusColumn: ColumnProps[] = [
|
||||||
{
|
|
||||||
title: 'Worker',
|
|
||||||
key: 'worker_name',
|
|
||||||
width: 200
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'models.table.download.progress',
|
title: 'models.table.download.progress',
|
||||||
locale: true,
|
locale: true,
|
||||||
@@ -83,6 +79,25 @@ const downloadList: ColumnProps[] = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
const downloadList: ColumnProps[] = [
|
||||||
|
{
|
||||||
|
title: 'resources.worker',
|
||||||
|
locale: true,
|
||||||
|
key: 'worker_name',
|
||||||
|
width: 280
|
||||||
|
},
|
||||||
|
...statusColumn
|
||||||
|
];
|
||||||
|
|
||||||
|
const draftModelDownloadList: ColumnProps[] = [
|
||||||
|
{
|
||||||
|
title: 'models.form.draftModel',
|
||||||
|
locale: true,
|
||||||
|
key: 'draft_model',
|
||||||
|
width: 280
|
||||||
|
},
|
||||||
|
...statusColumn
|
||||||
|
];
|
||||||
|
|
||||||
const WorkerInfo = (props: {
|
const WorkerInfo = (props: {
|
||||||
title: React.ReactNode;
|
title: React.ReactNode;
|
||||||
@@ -128,7 +143,7 @@ const RenderRayactorDownloading = (props: {
|
|||||||
workerList: WorkerListItem[];
|
workerList: WorkerListItem[];
|
||||||
}) => {
|
}) => {
|
||||||
const { severList, instanceData, workerList } = props;
|
const { severList, instanceData, workerList } = props;
|
||||||
if (!severList.length) {
|
if (!severList.length && !instanceData.draft_model_download_progress) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const list = _.map(severList, (item: any) => {
|
const list = _.map(severList, (item: any) => {
|
||||||
@@ -148,14 +163,33 @@ const RenderRayactorDownloading = (props: {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const draftModelList = [];
|
||||||
|
if (instanceData.draft_model_download_progress > 0) {
|
||||||
|
draftModelList.push({
|
||||||
|
draft_model: generateSource(instanceData.draft_model_source),
|
||||||
|
download_progress: _.round(instanceData.draft_model_download_progress, 2)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SimpleTabel
|
{severList.length > 0 && (
|
||||||
columns={downloadList}
|
<SimpleTabel
|
||||||
dataSource={[...mainWorker, ...list]}
|
columns={downloadList}
|
||||||
rowKey="worker_name"
|
dataSource={[...mainWorker, ...list]}
|
||||||
theme="light"
|
rowKey="worker_name"
|
||||||
></SimpleTabel>
|
theme="light"
|
||||||
|
></SimpleTabel>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{draftModelList.length > 0 && (
|
||||||
|
<SimpleTabel
|
||||||
|
columns={draftModelDownloadList}
|
||||||
|
dataSource={[...draftModelList]}
|
||||||
|
rowKey="worker_name"
|
||||||
|
theme="light"
|
||||||
|
></SimpleTabel>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -171,11 +205,12 @@ const RenderWorkerDownloading = (props: {
|
|||||||
const severList: DistributedServerItem[] =
|
const severList: DistributedServerItem[] =
|
||||||
distributed_servers?.subordinate_workers || [];
|
distributed_servers?.subordinate_workers || [];
|
||||||
|
|
||||||
if (
|
const isWorkerNotDownloading =
|
||||||
instanceData.state !== InstanceStatusMap.Downloading ||
|
instanceData.state !== InstanceStatusMap.Downloading ||
|
||||||
!severList.length ||
|
!severList.length ||
|
||||||
backend === backendOptionsMap.llamaBox
|
backend === backendOptionsMap.llamaBox;
|
||||||
) {
|
|
||||||
|
if (isWorkerNotDownloading && !instanceData.draft_model_download_progress) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -183,7 +218,7 @@ const RenderWorkerDownloading = (props: {
|
|||||||
arrow={true}
|
arrow={true}
|
||||||
styles={{
|
styles={{
|
||||||
body: {
|
body: {
|
||||||
width: 300,
|
width: 360,
|
||||||
backgroundColor: 'var(--color-spotlight-bg)'
|
backgroundColor: 'var(--color-spotlight-bg)'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -204,8 +239,10 @@ const RenderWorkerDownloading = (props: {
|
|||||||
size={16}
|
size={16}
|
||||||
strokeColor="var(--ant-color-success)"
|
strokeColor="var(--ant-color-success)"
|
||||||
percent={
|
percent={
|
||||||
|
instanceData.draft_model_download_progress ||
|
||||||
_.find(severList, (item: any) => item.download_progress < 100)
|
_.find(severList, (item: any) => item.download_progress < 100)
|
||||||
?.download_progress || 0
|
?.download_progress ||
|
||||||
|
0
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -543,6 +580,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
|||||||
const renderOffloadInfo = useMemo(() => {
|
const renderOffloadInfo = useMemo(() => {
|
||||||
const total_layers = instanceData.computed_resource_claim?.total_layers;
|
const total_layers = instanceData.computed_resource_claim?.total_layers;
|
||||||
const offload_layers = instanceData.computed_resource_claim?.offload_layers;
|
const offload_layers = instanceData.computed_resource_claim?.offload_layers;
|
||||||
|
|
||||||
if (total_layers === offload_layers || !total_layers) {
|
if (total_layers === offload_layers || !total_layers) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -640,7 +678,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
paddingLeft: '58px',
|
paddingLeft: '58px',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
gap: '5px'
|
gap: '8px'
|
||||||
}}
|
}}
|
||||||
className="flex align-center"
|
className="flex align-center"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export default {
|
|||||||
speculative_config: {
|
speculative_config: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
algorithm: 'eagle3',
|
algorithm: 'eagle3',
|
||||||
draft_model_name: 'Qwen3-30B-A3B-EAGLE3',
|
draft_model: 'Qwen3-30B-A3B-EAGLE3',
|
||||||
num_draft_tokens: 8,
|
num_draft_tokens: 8,
|
||||||
ngram_min_match_length: null,
|
ngram_min_match_length: null,
|
||||||
ngram_max_match_length: null
|
ngram_max_match_length: null
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export interface FormData {
|
|||||||
speculative_config: {
|
speculative_config: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
algorithm: string;
|
algorithm: string;
|
||||||
draft_model_name: string;
|
draft_model: string;
|
||||||
num_draft_tokens: number;
|
num_draft_tokens: number;
|
||||||
ngram_min_match_length: number;
|
ngram_min_match_length: number;
|
||||||
ngram_max_match_length: number;
|
ngram_max_match_length: number;
|
||||||
@@ -135,6 +135,16 @@ export interface ModelInstanceListItem {
|
|||||||
id: number;
|
id: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
|
draft_model_source: {
|
||||||
|
source: string;
|
||||||
|
huggingface_repo_id: string;
|
||||||
|
huggingface_filename: string;
|
||||||
|
model_scope_model_id: string;
|
||||||
|
model_scope_file_path: string;
|
||||||
|
local_path: string;
|
||||||
|
};
|
||||||
|
draft_model_download_progress: 0;
|
||||||
|
draft_model_resolved_path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelInstanceFormData {
|
export interface ModelInstanceFormData {
|
||||||
@@ -214,7 +224,7 @@ export interface CatalogSpec {
|
|||||||
speculative_config: {
|
speculative_config: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
algorithm: string;
|
algorithm: string;
|
||||||
draft_model_name: string;
|
draft_model: string;
|
||||||
num_draft_tokens: number;
|
num_draft_tokens: number;
|
||||||
ngram_min_match_length: number;
|
ngram_min_match_length: number;
|
||||||
ngram_max_match_length: number;
|
ngram_max_match_length: number;
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
speculative_config: {
|
speculative_config: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
algorithm: '',
|
algorithm: '',
|
||||||
draft_model_name: null,
|
draft_model: null,
|
||||||
num_draft_tokens: 3,
|
num_draft_tokens: 3,
|
||||||
ngram_min_match_length: 1,
|
ngram_min_match_length: 1,
|
||||||
ngram_max_match_length: 10
|
ngram_max_match_length: 10
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ const KVCacheForm = () => {
|
|||||||
} else {
|
} else {
|
||||||
configCacheRef.current = form.getFieldValue('extended_kv_cache');
|
configCacheRef.current = form.getFieldValue('extended_kv_cache');
|
||||||
}
|
}
|
||||||
await new Promise((resolve) => {
|
|
||||||
setTimeout(resolve, 200);
|
|
||||||
});
|
|
||||||
onValuesChange?.({}, form.getFieldsValue());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const builtInBackend = useMemo(() => {
|
const builtInBackend = useMemo(() => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import AutoComlete from '@/components/seal-form/auto-complete';
|
||||||
import CheckboxField from '@/components/seal-form/checkbox-field';
|
import CheckboxField from '@/components/seal-form/checkbox-field';
|
||||||
import SealInputNumber from '@/components/seal-form/input-number';
|
import SealInputNumber from '@/components/seal-form/input-number';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
@@ -41,14 +42,16 @@ const SpeculativeDecode = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSpeculativeEnabledChange = (e: any) => {
|
const handleSpeculativeEnabledChange = (e: any) => {
|
||||||
|
const speculativeConfig = form.getFieldValue('speculative_config');
|
||||||
|
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
form.setFieldValue('speculative_config', {
|
form.setFieldValue('speculative_config', {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
algorithm: AlgorithmMap.Eagle3,
|
algorithm: speculativeConfig.algorithm || AlgorithmMap.Eagle3,
|
||||||
draft_model_name: null,
|
draft_model: speculativeConfig.draft_model || '',
|
||||||
num_draft_tokens: 3,
|
num_draft_tokens: speculativeConfig.num_draft_tokens || 3,
|
||||||
ngram_min_match_length: 1,
|
ngram_min_match_length: speculativeConfig.ngram_min_match_length || 1,
|
||||||
ngram_max_match_length: 10
|
ngram_max_match_length: speculativeConfig.ngram_max_match_length || 10
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -100,19 +103,29 @@ const SpeculativeDecode = () => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
{algorithm === AlgorithmMap.Eagle3 && (
|
{algorithm === AlgorithmMap.Eagle3 && (
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name={['speculative_config', 'draft_model_name']}
|
name={['speculative_config', 'draft_model']}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: getRuleMessage('select', 'models.form.draftModel')
|
message: getRuleMessage(
|
||||||
|
['select', 'input'],
|
||||||
|
'models.form.draftModel'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<SealSelect
|
<AutoComlete
|
||||||
required
|
required
|
||||||
|
allowClear
|
||||||
label={intl.formatMessage({ id: 'models.form.draftModel' })}
|
label={intl.formatMessage({ id: 'models.form.draftModel' })}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'models.form.draftModel.placeholder'
|
||||||
|
})}
|
||||||
|
description={intl.formatMessage({
|
||||||
|
id: 'models.form.draftModel.tips'
|
||||||
|
})}
|
||||||
options={draftModelList}
|
options={draftModelList}
|
||||||
></SealSelect>
|
></AutoComlete>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@@ -80,7 +82,6 @@
|
|||||||
height: 3px;
|
height: 3px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: var(--ant-color-text-quaternary);
|
background-color: var(--ant-color-text-quaternary);
|
||||||
margin-right: 8px;
|
|
||||||
flex: none;
|
flex: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user