mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[ML] Support E5 model download from the list view, mark not supported/not optimized models (#189372)
## Summary - Adds the "Show all" switch at the top of the page (off by default) that responsible for hiding unsupported/not optimised model versions - Adds a download action for E5 models - Removes the toast notification on successful start of a model download - Adds a warning icon with an appropriate tooltip text if model version is not supported by the cluster architecture or not optimised for it <img width="1401" alt="image" src="https://github.com/user-attachments/assets/30748315-3018-46e2-91dd-fd5128b0695e"> ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
199d0f60f9
commit
514db549d2
10 changed files with 85 additions and 48 deletions
|
@ -58,7 +58,10 @@ export const BUILT_IN_MODEL_TAG = 'prepackaged';
|
|||
|
||||
export const ELASTIC_MODEL_TAG = 'elastic';
|
||||
|
||||
export const ELASTIC_MODEL_DEFINITIONS: Record<string, ModelDefinition> = Object.freeze({
|
||||
export const ELASTIC_MODEL_DEFINITIONS: Record<
|
||||
string,
|
||||
Omit<ModelDefinition, 'supported'>
|
||||
> = Object.freeze({
|
||||
[ELSER_ID_V1]: {
|
||||
modelName: 'elser',
|
||||
hidden: true,
|
||||
|
@ -156,6 +159,8 @@ export interface ModelDefinition {
|
|||
default?: boolean;
|
||||
/** Indicates if model version is recommended for deployment based on the cluster configuration */
|
||||
recommended?: boolean;
|
||||
/** Indicates if model version is supported by the cluster */
|
||||
supported: boolean;
|
||||
hidden?: boolean;
|
||||
/** Software license of a model, e.g. MIT */
|
||||
license?: string;
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface ListingPageUrlState {
|
|||
sortField: string;
|
||||
sortDirection: string;
|
||||
queryText?: string;
|
||||
showAll?: boolean;
|
||||
}
|
||||
|
||||
export type AppPageState<T> = {
|
||||
|
|
|
@ -15,10 +15,7 @@ import {
|
|||
DEPLOYMENT_STATE,
|
||||
TRAINED_MODEL_TYPE,
|
||||
} from '@kbn/ml-trained-models-utils';
|
||||
import {
|
||||
ELASTIC_MODEL_TAG,
|
||||
MODEL_STATE,
|
||||
} from '@kbn/ml-trained-models-utils/src/constants/trained_models';
|
||||
import { MODEL_STATE } from '@kbn/ml-trained-models-utils/src/constants/trained_models';
|
||||
import {
|
||||
getAnalysisType,
|
||||
type DataFrameAnalysisConfigType,
|
||||
|
@ -409,10 +406,7 @@ export function useModelActions({
|
|||
icon: 'download',
|
||||
type: 'icon',
|
||||
isPrimary: true,
|
||||
available: (item) =>
|
||||
canCreateTrainedModels &&
|
||||
item.tags.includes(ELASTIC_MODEL_TAG) &&
|
||||
item.state === MODEL_STATE.NOT_DOWNLOADED,
|
||||
available: (item) => canCreateTrainedModels && item.state === MODEL_STATE.NOT_DOWNLOADED,
|
||||
enabled: (item) => !isLoading,
|
||||
onClick: async (item) => {
|
||||
onModelDownloadRequest(item.model_id);
|
||||
|
|
|
@ -17,13 +17,15 @@ import {
|
|||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHealth,
|
||||
EuiIcon,
|
||||
EuiInMemoryTable,
|
||||
EuiLink,
|
||||
type EuiSearchBarProps,
|
||||
EuiProgress,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiTitle,
|
||||
EuiToolTip,
|
||||
EuiProgress,
|
||||
type EuiSearchBarProps,
|
||||
} from '@elastic/eui';
|
||||
import { groupBy, isEmpty } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -94,6 +96,7 @@ export type ModelItem = TrainedModelConfigResponse & {
|
|||
*/
|
||||
stateDescription?: string;
|
||||
recommended?: boolean;
|
||||
supported: boolean;
|
||||
/**
|
||||
* Model name, e.g. elser
|
||||
*/
|
||||
|
@ -129,6 +132,7 @@ export const getDefaultModelsListState = (): ListingPageUrlState => ({
|
|||
pageSize: 10,
|
||||
sortField: modelIdColumnName,
|
||||
sortDirection: 'asc',
|
||||
showAll: false,
|
||||
});
|
||||
|
||||
interface Props {
|
||||
|
@ -286,9 +290,13 @@ export const ModelsList: FC<Props> = ({
|
|||
);
|
||||
const forDownload = await trainedModelsApiService.getTrainedModelDownloads();
|
||||
const notDownloaded: ModelItem[] = forDownload
|
||||
.filter(({ model_id: modelId, hidden, recommended }) => {
|
||||
if (recommended && idMap.has(modelId)) {
|
||||
idMap.get(modelId)!.recommended = true;
|
||||
.filter(({ model_id: modelId, hidden, recommended, supported }) => {
|
||||
if (idMap.has(modelId)) {
|
||||
const model = idMap.get(modelId)!;
|
||||
if (recommended) {
|
||||
model.recommended = true;
|
||||
}
|
||||
model.supported = supported;
|
||||
}
|
||||
return !idMap.has(modelId) && !hidden;
|
||||
})
|
||||
|
@ -306,6 +314,7 @@ export const ModelsList: FC<Props> = ({
|
|||
arch: modelDefinition.arch,
|
||||
softwareLicense: modelDefinition.license,
|
||||
licenseUrl: modelDefinition.licenseUrl,
|
||||
supported: modelDefinition.supported,
|
||||
} as ModelItem;
|
||||
});
|
||||
resultItems = [...resultItems, ...notDownloaded];
|
||||
|
@ -530,12 +539,6 @@ export const ModelsList: FC<Props> = ({
|
|||
try {
|
||||
setIsLoading(true);
|
||||
await trainedModelsApiService.installElasticTrainedModelConfig(modelId);
|
||||
displaySuccessToast(
|
||||
i18n.translate('xpack.ml.trainedModels.modelsList.downloadSuccess', {
|
||||
defaultMessage: '"{modelId}" model download has been started successfully.',
|
||||
values: { modelId },
|
||||
})
|
||||
);
|
||||
// Need to fetch model state updates
|
||||
await fetchModelsData();
|
||||
} catch (e) {
|
||||
|
@ -549,7 +552,7 @@ export const ModelsList: FC<Props> = ({
|
|||
setIsLoading(true);
|
||||
}
|
||||
},
|
||||
[displayErrorToast, displaySuccessToast, fetchModelsData, trainedModelsApiService]
|
||||
[displayErrorToast, fetchModelsData, trainedModelsApiService]
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -633,26 +636,28 @@ export const ModelsList: FC<Props> = ({
|
|||
}),
|
||||
truncateText: false,
|
||||
'data-test-subj': 'mlModelsTableColumnDescription',
|
||||
render: ({ description, recommended }: ModelItem) => {
|
||||
render: ({ description, recommended, tags, supported }: ModelItem) => {
|
||||
if (!description) return null;
|
||||
const descriptionText = description.replace('(Tech Preview)', '');
|
||||
return recommended ? (
|
||||
<EuiToolTip
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.recommendedDownloadContent"
|
||||
defaultMessage="Recommended model version for your cluster's hardware configuration"
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
const tooltipContent =
|
||||
supported === false ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.notSupportedDownloadContent"
|
||||
defaultMessage="Model version is not supported by your cluster's hardware configuration"
|
||||
/>
|
||||
) : recommended === false ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.notRecommendedDownloadContent"
|
||||
defaultMessage="Model version is not optimized for your cluster's hardware configuration"
|
||||
/>
|
||||
) : null;
|
||||
|
||||
return tooltipContent ? (
|
||||
<EuiToolTip content={tooltipContent}>
|
||||
<>
|
||||
{descriptionText}
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.recommendedDownloadLabel"
|
||||
defaultMessage="(Recommended)"
|
||||
/>
|
||||
</b>
|
||||
<EuiIcon type={'warning'} color="warning" />
|
||||
</>
|
||||
</EuiToolTip>
|
||||
) : (
|
||||
|
@ -861,6 +866,14 @@ export const ModelsList: FC<Props> = ({
|
|||
const isElserCalloutVisible =
|
||||
!isElserCalloutDismissed && items.findIndex((i) => i.model_id === ELSER_ID_V1) >= 0;
|
||||
|
||||
const tableItems = useMemo(() => {
|
||||
if (pageState.showAll) {
|
||||
return items;
|
||||
} else {
|
||||
return items.filter((item) => item.supported !== false);
|
||||
}
|
||||
}, [items, pageState.showAll]);
|
||||
|
||||
if (!isInitialized) return null;
|
||||
|
||||
return (
|
||||
|
@ -868,8 +881,24 @@ export const ModelsList: FC<Props> = ({
|
|||
<SavedObjectsWarning onCloseFlyout={fetchModelsData} forceRefresh={isLoading} />
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
{modelsStats ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<StatsBar stats={modelsStats} dataTestSub={'mlInferenceModelsStatsBar'} />
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<StatsBar stats={modelsStats} dataTestSub={'mlInferenceModelsStatsBar'} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.trainedModels.modelsList.showAllLabel"
|
||||
defaultMessage="Show all"
|
||||
/>
|
||||
}
|
||||
checked={!!pageState.showAll}
|
||||
onChange={(e) => updatePageState({ showAll: e.target.checked })}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -894,7 +923,7 @@ export const ModelsList: FC<Props> = ({
|
|||
allowNeutralSort={false}
|
||||
columns={columns}
|
||||
itemIdToExpandedRowMap={itemIdToExpandedRowMap}
|
||||
items={items}
|
||||
items={tableItems}
|
||||
itemId={ModelsTableToConfigMapping.id}
|
||||
loading={isLoading}
|
||||
search={search}
|
||||
|
|
|
@ -58,6 +58,7 @@ describe('modelsProvider', () => {
|
|||
config: { input: { field_names: ['text_field'] } },
|
||||
description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)',
|
||||
hidden: true,
|
||||
supported: false,
|
||||
model_id: '.elser_model_1',
|
||||
version: 1,
|
||||
modelName: 'elser',
|
||||
|
@ -66,6 +67,7 @@ describe('modelsProvider', () => {
|
|||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
default: true,
|
||||
supported: true,
|
||||
description: 'Elastic Learned Sparse EncodeR v2',
|
||||
model_id: '.elser_model_2',
|
||||
version: 2,
|
||||
|
@ -79,6 +81,7 @@ describe('modelsProvider', () => {
|
|||
model_id: '.elser_model_2_linux-x86_64',
|
||||
os: 'Linux',
|
||||
recommended: true,
|
||||
supported: true,
|
||||
version: 2,
|
||||
modelName: 'elser',
|
||||
type: ['elastic', 'pytorch', 'text_expansion'],
|
||||
|
@ -88,6 +91,7 @@ describe('modelsProvider', () => {
|
|||
description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)',
|
||||
model_id: '.multilingual-e5-small',
|
||||
default: true,
|
||||
supported: true,
|
||||
version: 1,
|
||||
modelName: 'e5',
|
||||
license: 'MIT',
|
||||
|
@ -102,6 +106,7 @@ describe('modelsProvider', () => {
|
|||
model_id: '.multilingual-e5-small_linux-x86_64',
|
||||
os: 'Linux',
|
||||
recommended: true,
|
||||
supported: true,
|
||||
version: 1,
|
||||
modelName: 'e5',
|
||||
license: 'MIT',
|
||||
|
@ -140,6 +145,7 @@ describe('modelsProvider', () => {
|
|||
config: { input: { field_names: ['text_field'] } },
|
||||
description: 'Elastic Learned Sparse EncodeR v1 (Tech Preview)',
|
||||
hidden: true,
|
||||
supported: false,
|
||||
model_id: '.elser_model_1',
|
||||
version: 1,
|
||||
modelName: 'elser',
|
||||
|
@ -148,6 +154,7 @@ describe('modelsProvider', () => {
|
|||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
recommended: true,
|
||||
supported: true,
|
||||
description: 'Elastic Learned Sparse EncodeR v2',
|
||||
model_id: '.elser_model_2',
|
||||
version: 2,
|
||||
|
@ -163,12 +170,14 @@ describe('modelsProvider', () => {
|
|||
version: 2,
|
||||
modelName: 'elser',
|
||||
type: ['elastic', 'pytorch', 'text_expansion'],
|
||||
supported: false,
|
||||
},
|
||||
{
|
||||
config: { input: { field_names: ['text_field'] } },
|
||||
description: 'E5 (EmbEddings from bidirEctional Encoder rEpresentations)',
|
||||
model_id: '.multilingual-e5-small',
|
||||
recommended: true,
|
||||
supported: true,
|
||||
version: 1,
|
||||
modelName: 'e5',
|
||||
type: ['pytorch', 'text_embedding'],
|
||||
|
@ -182,6 +191,7 @@ describe('modelsProvider', () => {
|
|||
'E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimized for linux-x86_64',
|
||||
model_id: '.multilingual-e5-small_linux-x86_64',
|
||||
os: 'Linux',
|
||||
supported: false,
|
||||
version: 1,
|
||||
modelName: 'e5',
|
||||
type: ['pytorch', 'text_embedding'],
|
||||
|
|
|
@ -476,6 +476,7 @@ export class ModelsProvider {
|
|||
const modelDefinitionResponse = {
|
||||
...def,
|
||||
...(recommended ? { recommended } : {}),
|
||||
supported: !!def.default || recommended,
|
||||
model_id: modelId,
|
||||
};
|
||||
|
||||
|
|
|
@ -28304,7 +28304,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.disableSelectableMessage": "Le modèle a des pipelines associés",
|
||||
"xpack.ml.trainedModels.modelsList.downloadFailed": "Échec du téléchargement de \"{modelId}\"",
|
||||
"xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "Échec de la vérification du statut du téléchargement",
|
||||
"xpack.ml.trainedModels.modelsList.downloadSuccess": "Le téléchargement du modèle \"{modelId}\" a bien été démarré.",
|
||||
"xpack.ml.trainedModels.modelsList.e5Title": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1x86Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations), optimisé for linux-x86_64",
|
||||
|
@ -28362,7 +28361,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.timePerDocHeader": "Temps par document",
|
||||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.typeHeader": "Type de processeur",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadContent": "Version du modèle recommandée pour la configuration matérielle de votre cluster",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadLabel": "(Recommandée)",
|
||||
"xpack.ml.trainedModels.modelsList.selectableMessage": "Sélectionner un modèle",
|
||||
"xpack.ml.trainedModels.modelsList.selectedModelsMessage": "{modelsCount, plural, one{# modèle sélectionné} other {# modèles sélectionnés}}",
|
||||
"xpack.ml.trainedModels.modelsList.startDeployment.cancelButton": "Annuler",
|
||||
|
|
|
@ -28209,7 +28209,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.disableSelectableMessage": "モデルにはパイプラインが関連付けられています",
|
||||
"xpack.ml.trainedModels.modelsList.downloadFailed": "\"{modelId}\"をダウンロードできませんでした",
|
||||
"xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "ダウンロードステータスを確認できませんでした",
|
||||
"xpack.ml.trainedModels.modelsList.downloadSuccess": "\"{modelId}\"モデルのダウンロードが正常に開始しました。",
|
||||
"xpack.ml.trainedModels.modelsList.e5Title": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1Description": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1x86Description": "E5(bidirEctional Encoder rEpresentationsからのEmbEddings)、inux-x86_64向けに最適化",
|
||||
|
@ -28267,7 +28266,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.timePerDocHeader": "ドキュメントごとの時間",
|
||||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.typeHeader": "プロセッサータイプ",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadContent": "クラスターのハードウェア構成に応じた推奨モデルバージョン",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadLabel": "(推奨)",
|
||||
"xpack.ml.trainedModels.modelsList.selectableMessage": "モデルを選択",
|
||||
"xpack.ml.trainedModels.modelsList.selectedModelsMessage": "{modelsCount, plural, other {#個のモデル}}が選択されました",
|
||||
"xpack.ml.trainedModels.modelsList.startDeployment.cancelButton": "キャンセル",
|
||||
|
|
|
@ -28344,7 +28344,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.disableSelectableMessage": "模型有关联的管道",
|
||||
"xpack.ml.trainedModels.modelsList.downloadFailed": "无法下载“{modelId}”",
|
||||
"xpack.ml.trainedModels.modelsList.downloadStatusCheckErrorMessage": "无法检查下载状态",
|
||||
"xpack.ml.trainedModels.modelsList.downloadSuccess": "已成功启动“{modelId}”模型下载。",
|
||||
"xpack.ml.trainedModels.modelsList.e5Title": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1Description": "E5 (EmbEddings from bidirEctional Encoder rEpresentations)",
|
||||
"xpack.ml.trainedModels.modelsList.e5v1x86Description": "针对 linux-x86_64 进行了优化的 E5 (EmbEddings from bidirEctional Encoder rEpresentations)",
|
||||
|
@ -28402,7 +28401,6 @@
|
|||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.timePerDocHeader": "每个文档的时间",
|
||||
"xpack.ml.trainedModels.modelsList.pipelines.processorStats.typeHeader": "处理器类型",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadContent": "为您集群的硬件配置推荐的模型版本",
|
||||
"xpack.ml.trainedModels.modelsList.recommendedDownloadLabel": "(推荐)",
|
||||
"xpack.ml.trainedModels.modelsList.selectableMessage": "选择模型",
|
||||
"xpack.ml.trainedModels.modelsList.selectedModelsMessage": "{modelsCount, plural, other {# 个模型}}已选择",
|
||||
"xpack.ml.trainedModels.modelsList.startDeployment.cancelButton": "取消",
|
||||
|
|
|
@ -51,6 +51,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
{
|
||||
modelName: 'elser',
|
||||
hidden: true,
|
||||
supported: false,
|
||||
version: 1,
|
||||
config: {
|
||||
input: {
|
||||
|
@ -72,6 +73,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
description: 'Elastic Learned Sparse EncodeR v2',
|
||||
type: ['elastic', 'pytorch', 'text_expansion'],
|
||||
model_id: '.elser_model_2',
|
||||
supported: true,
|
||||
...(isIntelBased ? { default: true } : { recommended: true }),
|
||||
},
|
||||
{
|
||||
|
@ -87,7 +89,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
description: 'Elastic Learned Sparse EncodeR v2, optimized for linux-x86_64',
|
||||
type: ['elastic', 'pytorch', 'text_expansion'],
|
||||
model_id: '.elser_model_2_linux-x86_64',
|
||||
...(isIntelBased ? { recommended: true } : {}),
|
||||
...(isIntelBased ? { recommended: true, supported: true } : { supported: false }),
|
||||
},
|
||||
{
|
||||
modelName: 'e5',
|
||||
|
@ -102,6 +104,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small',
|
||||
type: ['pytorch', 'text_embedding'],
|
||||
model_id: '.multilingual-e5-small',
|
||||
supported: true,
|
||||
...(isIntelBased ? { default: true } : { recommended: true }),
|
||||
},
|
||||
{
|
||||
|
@ -120,7 +123,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
licenseUrl: 'https://huggingface.co/elastic/multilingual-e5-small_linux-x86_64',
|
||||
type: ['pytorch', 'text_embedding'],
|
||||
model_id: '.multilingual-e5-small_linux-x86_64',
|
||||
...(isIntelBased ? { recommended: true } : {}),
|
||||
...(isIntelBased ? { recommended: true, supported: true } : { supported: false }),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue