Skip to content

Commit

Permalink
[Enterprise Search] Support for starting ELSER model deployment (#156080
Browse files Browse the repository at this point in the history
)

## Summary

We're adding action buttons to the ELSER model deployment panel,
specifically to the state where the trained model has been downloaded
but not started yet. The user has two options here:
- Start the model (synchronously) with a basic configuration using the
"Start single-threaded" button
- Navigate to the Trained Models page and fine-tune the model deployment
with the "Fine-tune performance" button

In addition a 4th state of the panel is being introduced: the ELSER
model has started.


![ELSER_start](https://user-images.githubusercontent.com/14224983/234971172-a99917dd-ec55-4df3-acd1-a6b390262104.gif)


### Checklist
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [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
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
demjened and kibanamachine authored May 1, 2023
1 parent 23d47b7 commit 5897708
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { ELSER_MODEL_ID } from '../../../../../../common/ml_inference_pipeline';
import { Actions, createApiLogic } from '../../../../shared/api_logic/create_api_logic';
import { HttpLogic } from '../../../../shared/http';

export type StartTextExpansionModelArgs = undefined;

export interface StartTextExpansionModelResponse {
deploymentState: string;
modelId: string;
}

export const startTextExpansionModel = async (): Promise<StartTextExpansionModelResponse> => {
const route = `/internal/enterprise_search/ml/models/${ELSER_MODEL_ID}/deploy`;
return await HttpLogic.values.http.post<StartTextExpansionModelResponse>(route, {
body: undefined,
});
};

export const StartTextExpansionModelApiLogic = createApiLogic(
['start_text_expansion_model_api_logic'],
startTextExpansionModel
);

export type StartTextExpansionModelApiLogicActions = Actions<
StartTextExpansionModelArgs,
StartTextExpansionModelResponse
>;
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ export const InferencePipelineCard: React.FC<InferencePipeline> = (pipeline) =>
)}
>
<EuiButtonIcon
aria-label={i18n.translate(
'xpack.enterpriseSearch.inferencePipelineCard.modelState.notDeployed.fixLink',
{
defaultMessage: 'Fix issue in Trained Models',
}
)}
data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-inferencePipeline-fixIssueInTrainedModels`}
href={http.basePath.prepend(ML_MANAGE_TRAINED_MODELS_PATH)}
display="base"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import {
ModelDeploymentInProgress,
ModelDeployed,
TextExpansionDismissButton,
ModelStarted,
} from './text_expansion_callout';

jest.mock('./text_expansion_callout_data', () => ({
useTextExpansionCallOutData: jest.fn(() => ({
dismiss: jest.fn(),
isCreateButtonDisabled: false,
isDismissable: false,
isStartButtonDisabled: false,
show: true,
})),
}));
Expand All @@ -34,6 +36,8 @@ const DEFAULT_VALUES = {
isCreateButtonDisabled: false,
isModelDownloadInProgress: false,
isModelDownloaded: false,
isModelStarted: false,
isStartButtonDisabled: false,
};

describe('TextExpansionCallOut', () => {
Expand Down Expand Up @@ -63,6 +67,15 @@ describe('TextExpansionCallOut', () => {
const wrapper = shallow(<TextExpansionCallOut />);
expect(wrapper.find(ModelDeployed).length).toBe(1);
});
it('renders panel with deployment in progress status if the model has been started', () => {
setMockValues({
...DEFAULT_VALUES,
isModelStarted: true,
});

const wrapper = shallow(<TextExpansionCallOut />);
expect(wrapper.find(ModelStarted).length).toBe(1);
});

describe('DeployModel', () => {
it('renders deploy button', () => {
Expand Down Expand Up @@ -109,12 +122,43 @@ describe('TextExpansionCallOut', () => {
});

describe('ModelDeployed', () => {
it('renders start button', () => {
const wrapper = shallow(
<ModelDeployed dismiss={() => {}} isDismissable={false} isStartButtonDisabled={false} />
);
expect(wrapper.find(EuiButton).length).toBe(1);
const button = wrapper.find(EuiButton);
expect(button.prop('disabled')).toBe(false);
});
it('renders disabled start button if it is set to disabled', () => {
const wrapper = shallow(
<ModelDeployed dismiss={() => {}} isDismissable={false} isStartButtonDisabled />
);
expect(wrapper.find(EuiButton).length).toBe(1);
const button = wrapper.find(EuiButton);
expect(button.prop('disabled')).toBe(true);
});
it('renders dismiss button if it is set to dismissable', () => {
const wrapper = shallow(
<ModelDeployed dismiss={() => {}} isDismissable isStartButtonDisabled={false} />
);
expect(wrapper.find(TextExpansionDismissButton).length).toBe(1);
});
it('does not render dismiss button if it is set to non-dismissable', () => {
const wrapper = shallow(
<ModelDeployed dismiss={() => {}} isDismissable={false} isStartButtonDisabled={false} />
);
expect(wrapper.find(TextExpansionDismissButton).length).toBe(0);
});
});

describe('ModelStarted', () => {
it('renders dismiss button if it is set to dismissable', () => {
const wrapper = shallow(<ModelDeployed dismiss={() => {}} isDismissable />);
const wrapper = shallow(<ModelStarted dismiss={() => {}} isDismissable />);
expect(wrapper.find(TextExpansionDismissButton).length).toBe(1);
});
it('does not render dismiss button if it is set to non-dismissable', () => {
const wrapper = shallow(<ModelDeployed dismiss={() => {}} isDismissable={false} />);
const wrapper = shallow(<ModelStarted dismiss={() => {}} isDismissable={false} />);
expect(wrapper.find(TextExpansionDismissButton).length).toBe(0);
});
});
Expand Down
Loading

0 comments on commit 5897708

Please sign in to comment.