From 4a67b1543ddcc8d92caf79114c01defce63b9ce1 Mon Sep 17 00:00:00 2001 From: Samiul Monir Date: Thu, 26 Dec 2024 18:35:45 -0500 Subject: [PATCH] Adding flyout to add inference endpoint from index management for semantic_text field --- .../common/types/inference.ts | 13 ++++ .../add_inference_flyout/inference_form.tsx | 7 -- .../field_parameters/select_inference_id.tsx | 46 +++++++----- .../application/hooks/use_add_endpoint.ts | 4 +- .../public/application/services/api.ts | 23 +++++- .../public/application/services/index.ts | 2 + .../hooks/use_ml_model_status_toasts.ts | 21 +++++- .../server/lib/add_inference_endpoint.ts | 2 +- .../server/lib/fetch_inference_services.ts | 2 +- .../inference_models/register_get_route.ts | 74 +++++++++++++++++++ .../shared/index_management/tsconfig.json | 2 + 11 files changed, 159 insertions(+), 37 deletions(-) create mode 100644 x-pack/platform/plugins/shared/index_management/common/types/inference.ts diff --git a/x-pack/platform/plugins/shared/index_management/common/types/inference.ts b/x-pack/platform/plugins/shared/index_management/common/types/inference.ts new file mode 100644 index 0000000000000..3af5388b5c08d --- /dev/null +++ b/x-pack/platform/plugins/shared/index_management/common/types/inference.ts @@ -0,0 +1,13 @@ +/* + * 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 type { Config, Secrets } from '@kbn/inference-endpoint-ui-common'; + +export interface InferenceEndpoint { + config: Config; + secrets: Secrets; +} diff --git a/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/add_inference_flyout/inference_form.tsx b/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/add_inference_flyout/inference_form.tsx index b14f3058484ad..412cf5ed257e4 100644 --- a/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/add_inference_flyout/inference_form.tsx +++ b/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/add_inference_flyout/inference_form.tsx @@ -11,11 +11,9 @@ import React, { useCallback, useEffect, useState } from 'react'; import { InferenceProvider, InferenceServiceFormFields } from '@kbn/inference-endpoint-ui-common'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -// import { useAddEndpoint } from '../../hooks/use_add_endpoint'; import { InferenceEndpoint } from '../../../../../../../../common/types/inference'; import { useProviders } from '../../../../../../hooks/use_providers'; import { useAddEndpoint } from '../../../../../../hooks/use_add_endpoint'; -import { useLoadInferenceEndpoints } from '../../../../../../services'; interface InferenceFormProps { onSubmitSuccess: () => void; @@ -44,13 +42,8 @@ export const InferenceForm: React.FC = ({ onSubmitSuccess, r const { isValid, data } = await form.submit(); if (isValid) { - console.log('form is valid', data); - // addEndpoint({ - // inferenceEndpoint: data as InferenceEndpoint, - // }); addInferenceEndpoint(data as InferenceEndpoint); } else { - console.log('form in not valid'); setIsLoading(false); } }, [addInferenceEndpoint, form]); diff --git a/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx b/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx index 813cc1023c06d..0321c1caacb3d 100644 --- a/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx +++ b/x-pack/platform/plugins/shared/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx @@ -29,7 +29,6 @@ import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { SUPPORTED_PYTORCH_TASKS, TRAINED_MODEL_TYPE } from '@kbn/ml-trained-models-utils'; import { InferenceTaskType } from '@elastic/elasticsearch/lib/api/types'; import { ModelConfig } from '@kbn/inference_integration_flyout/types'; -import { InferenceFlyoutWrapper } from '@kbn/inference_integration_flyout/components/inference_flyout_wrapper'; import { TrainedModelConfigResponse } from '@kbn/ml-plugin/common/types/trained_models'; import { getFieldConfig } from '../../../lib'; import { useAppContext } from '../../../../../app_context'; @@ -37,6 +36,7 @@ import { useLoadInferenceEndpoints } from '../../../../../services/api'; import { useMLModelNotificationToasts } from '../../../../../../hooks/use_ml_model_status_toasts'; import { CustomInferenceEndpointConfig } from '../../../types'; import { UseField } from '../../../shared_imports'; +import { AddInferenceFlyoutWrapper } from './add_inference_flyout/add_inference_flyout_wrapper'; export interface SelectInferenceIdProps { createInferenceEndpoint: ( @@ -234,8 +234,26 @@ const SelectInferenceIdContent: React.FC = ({ panelPaddingSize="m" closePopover={() => setIsInferencePopoverVisible(!isInferencePopoverVisible)} > - {inferenceEndpointsPageLink && ( - + + { + e.preventDefault(); + setIsInferenceFlyoutVisible(true); + setIsInferencePopoverVisible(!isInferencePopoverVisible); + }} + > + {i18n.translate( + 'xpack.idxMgmt.mappingsEditor.parameters.inferenceId.popover.createInferenceEndpointButton', + { + defaultMessage: 'Add inference endpoint', + } + )} + + {inferenceEndpointsPageLink && ( = ({ } )} - - )} + )} + @@ -327,22 +345,12 @@ const SelectInferenceIdContent: React.FC = ({ {inferencePopover()} - {isInferenceFlyoutVisible && ( - - )} + ) : null} void, onError?: () => void) => { const { services } = useKibana(); diff --git a/x-pack/platform/plugins/shared/index_management/public/application/services/api.ts b/x-pack/platform/plugins/shared/index_management/public/application/services/api.ts index f2600220612e7..e21d24ae7dca4 100644 --- a/x-pack/platform/plugins/shared/index_management/public/application/services/api.ts +++ b/x-pack/platform/plugins/shared/index_management/public/application/services/api.ts @@ -10,6 +10,7 @@ import type { SerializedEnrichPolicy } from '@kbn/index-management-shared-types' import { IndicesStatsResponse } from '@elastic/elasticsearch/lib/api/types'; import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; import { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { InferenceProvider } from '@kbn/inference-endpoint-ui-common'; import { API_BASE_PATH, INTERNAL_API_BASE_PATH, @@ -47,8 +48,7 @@ import { import { useRequest, sendRequest } from './use_request'; import { httpService } from './http'; import { UiMetricService } from './ui_metric'; -import type { FieldFromIndicesRequest } from '../../../common'; -import { Fields } from '../components/mappings_editor/types'; +import type { FieldFromIndicesRequest, InferenceEndpoint } from '../../../common'; interface ReloadIndicesOptions { asSystemRequest?: boolean; @@ -473,6 +473,25 @@ export function getInferenceEndpoints() { }); } +export function getInferenceServices() { + return sendRequest({ + path: `${API_BASE_PATH}/inference/services`, + method: 'get', + }); +} + +export function createInferenceEndpoint( + taskType: string, + inferenceId: string, + inferenceEndpoint: InferenceEndpoint +) { + return sendRequest({ + path: `${API_BASE_PATH}/inference/${taskType}/${inferenceId}`, + method: 'put', + body: JSON.stringify(inferenceEndpoint), + }); +} + export function useLoadInferenceEndpoints() { return useRequest({ path: `${API_BASE_PATH}/inference/all`, diff --git a/x-pack/platform/plugins/shared/index_management/public/application/services/index.ts b/x-pack/platform/plugins/shared/index_management/public/application/services/index.ts index 5c34d83186c6a..1bb45114faf4e 100644 --- a/x-pack/platform/plugins/shared/index_management/public/application/services/index.ts +++ b/x-pack/platform/plugins/shared/index_management/public/application/services/index.ts @@ -29,6 +29,8 @@ export { useLoadIndexSettings, createIndex, useLoadInferenceEndpoints, + getInferenceServices, + createInferenceEndpoint, } from './api'; export { sortTable } from './sort_table'; diff --git a/x-pack/platform/plugins/shared/index_management/public/hooks/use_ml_model_status_toasts.ts b/x-pack/platform/plugins/shared/index_management/public/hooks/use_ml_model_status_toasts.ts index 7b553f37498d5..e0ee3976e4bbe 100644 --- a/x-pack/platform/plugins/shared/index_management/public/hooks/use_ml_model_status_toasts.ts +++ b/x-pack/platform/plugins/shared/index_management/public/hooks/use_ml_model_status_toasts.ts @@ -43,13 +43,26 @@ export function useMLModelNotificationToasts() { }), }); }; - const showErrorToasts = (error: ErrorType) => { + const showErrorToasts = (error: ErrorType, errorTitle: string = 'Model deployment failed') => { const errorObj = extractErrorProperties(error); return toasts.addError(new MLRequestFailure(errorObj, error), { - title: i18n.translate('xpack.idxMgmt.mappingsEditor.createField.modelDeploymentErrorTitle', { - defaultMessage: 'Model deployment failed', + title: i18n.translate('xpack.idxMgmt.mappingsEditor.createField.inferenceErrorTitle', { + defaultMessage: errorTitle, }), }); }; - return { showSuccessToasts, showErrorToasts, showSuccessfullyDeployedToast }; + + const showInferenceSuccessToast = () => { + return toasts.addSuccess({ + title: i18n.translate('xpack.idxMgmt.mappingsEditor.createField.endpointAddedSuccess', { + defaultMessage: 'Endpoint added', + }), + }); + }; + return { + showSuccessToasts, + showErrorToasts, + showSuccessfullyDeployedToast, + showInferenceSuccessToast, + }; } diff --git a/x-pack/platform/plugins/shared/index_management/server/lib/add_inference_endpoint.ts b/x-pack/platform/plugins/shared/index_management/server/lib/add_inference_endpoint.ts index a8c7e5cc91c28..54e0b62f2f677 100644 --- a/x-pack/platform/plugins/shared/index_management/server/lib/add_inference_endpoint.ts +++ b/x-pack/platform/plugins/shared/index_management/server/lib/add_inference_endpoint.ts @@ -8,7 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { InferenceTaskType } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { Config, Secrets } from '../../../../../packages/shared/kbn-inference-endpoint-ui-common'; +import type { Config, Secrets } from '@kbn/inference-endpoint-ui-common'; import { unflattenObject } from '../services/unflatten_object'; export const addInferenceEndpoint = async ( diff --git a/x-pack/platform/plugins/shared/index_management/server/lib/fetch_inference_services.ts b/x-pack/platform/plugins/shared/index_management/server/lib/fetch_inference_services.ts index 7c2a332fcd9cb..5a176c7af742f 100644 --- a/x-pack/platform/plugins/shared/index_management/server/lib/fetch_inference_services.ts +++ b/x-pack/platform/plugins/shared/index_management/server/lib/fetch_inference_services.ts @@ -6,7 +6,7 @@ */ import { FieldType } from '@kbn/search-connectors/types'; -import { InferenceProvider } from '../../../../../packages/shared/kbn-inference-endpoint-ui-common'; +import type { InferenceProvider } from '@kbn/inference-endpoint-ui-common'; export const fetchInferenceServices = (): InferenceProvider[] => [ { diff --git a/x-pack/platform/plugins/shared/index_management/server/routes/api/inference_models/register_get_route.ts b/x-pack/platform/plugins/shared/index_management/server/routes/api/inference_models/register_get_route.ts index 4709abadc3345..a56153ddafff0 100644 --- a/x-pack/platform/plugins/shared/index_management/server/routes/api/inference_models/register_get_route.ts +++ b/x-pack/platform/plugins/shared/index_management/server/routes/api/inference_models/register_get_route.ts @@ -6,8 +6,17 @@ */ import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; +import { schema } from '@kbn/config-schema'; +import { KibanaServerError } from '@kbn/kibana-utils-plugin/common'; import { addBasePath } from '..'; import { RouteDependencies } from '../../../types'; +import { fetchInferenceServices } from '../../../lib/fetch_inference_services'; +import { InferenceEndpoint } from '../../../../common/types/inference'; +import { addInferenceEndpoint } from '../../../lib/add_inference_endpoint'; + +function isKibanaServerError(error: any): error is KibanaServerError { + return error.statusCode && error.message; +} export function registerGetAllRoute({ router, lib: { handleEsError } }: RouteDependencies) { // Get all inference models @@ -36,4 +45,69 @@ export function registerGetAllRoute({ router, lib: { handleEsError } }: RouteDep } } ); + + router.get( + { + path: addBasePath('/inference/services'), + validate: {}, + }, + async (context, request, response) => { + try { + const providers = fetchInferenceServices(); + + return response.ok({ + body: providers, + headers: { 'content-type': 'application/json' }, + }); + } catch (error) { + if (isKibanaServerError(error)) { + return response.customError({ statusCode: error.statusCode, body: error.message }); + } + throw error; + } + } + ); + + router.put( + { + path: addBasePath(`/inference/{taskType}/{inferenceId}`), + validate: { + params: schema.object({ + taskType: schema.string(), + inferenceId: schema.string(), + }), + body: schema.object({ + config: schema.object({ + inferenceId: schema.string(), + provider: schema.string(), + taskType: schema.string(), + providerConfig: schema.any(), + }), + secrets: schema.object({ + providerSecrets: schema.any(), + }), + }), + }, + }, + async (context, request, response) => { + try { + const { + client: { asCurrentUser }, + } = (await context.core).elasticsearch; + + const { config, secrets }: InferenceEndpoint = request.body; + const result = await addInferenceEndpoint(asCurrentUser, config, secrets); + + return response.ok({ + body: result, + headers: { 'content-type': 'application/json' }, + }); + } catch (error) { + if (isKibanaServerError(error)) { + return response.customError({ statusCode: error.statusCode, body: error.message }); + } + throw error; + } + } + ); } diff --git a/x-pack/platform/plugins/shared/index_management/tsconfig.json b/x-pack/platform/plugins/shared/index_management/tsconfig.json index 41514049a13a8..87cfc2ccbf567 100644 --- a/x-pack/platform/plugins/shared/index_management/tsconfig.json +++ b/x-pack/platform/plugins/shared/index_management/tsconfig.json @@ -55,6 +55,8 @@ "@kbn/unsaved-changes-prompt", "@kbn/shared-ux-table-persist", "@kbn/core-application-browser", + "@kbn/inference-endpoint-ui-common", + "@kbn/safer-lodash-set" ], "exclude": ["target/**/*"] }