Skip to content

Commit

Permalink
Add quick-create fields in the create flow and form pre-population (o…
Browse files Browse the repository at this point in the history
…pensearch-project#309)

Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler authored Aug 26, 2024
1 parent cad5eab commit 8f276e3
Show file tree
Hide file tree
Showing 7 changed files with 492 additions and 113 deletions.
38 changes: 22 additions & 16 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,14 @@ export const DELIMITER_OPTIONAL_FIELDS = ['delimiter'];
export const SHARED_OPTIONAL_FIELDS = ['max_chunk_limit', 'description', 'tag'];

/**
* QUERIES
* QUERY PRESETS
*/
export const VECTOR_FIELD_PATTERN = `{{vector_field}}`;
export const TEXT_FIELD_PATTERN = `{{text_field}}`;
export const QUERY_TEXT_PATTERN = `{{query_text}}`;
export const QUERY_IMAGE_PATTERN = `{{query_image}}`;
export const MODEL_ID_PATTERN = `{{model_id}}`;

export const FETCH_ALL_QUERY = {
query: {
match_all: {},
Expand All @@ -156,52 +162,52 @@ export const FETCH_ALL_QUERY = {
};
export const SEMANTIC_SEARCH_QUERY = {
_source: {
excludes: [`{{vector_field}}`],
excludes: [VECTOR_FIELD_PATTERN],
},
query: {
neural: {
[`{{vector_field}}`]: {
query_text: `{{query_text}}`,
model_id: `{{model_id}}`,
[VECTOR_FIELD_PATTERN]: {
query_text: QUERY_TEXT_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 100,
},
},
},
};
export const MULTIMODAL_SEARCH_QUERY = {
_source: {
excludes: [`{{vector_field}}`],
excludes: [VECTOR_FIELD_PATTERN],
},
query: {
neural: {
[`{{vector_field}}`]: {
query_text: `{{query_text}}`,
query_image: `{{query_image}}`,
model_id: `{{model_id}}`,
[VECTOR_FIELD_PATTERN]: {
query_text: QUERY_TEXT_PATTERN,
query_image: QUERY_IMAGE_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 100,
},
},
},
};
export const HYBRID_SEARCH_QUERY = {
_source: {
excludes: [`{{vector_field}}`],
excludes: [VECTOR_FIELD_PATTERN],
},
query: {
hybrid: {
queries: [
{
match: {
[`{{text_field}}`]: {
query: `{{query_text}}`,
[TEXT_FIELD_PATTERN]: {
query: QUERY_TEXT_PATTERN,
},
},
},
{
neural: {
[`{{vector_field}}`]: {
query_text: `{{query_text}}`,
model_id: `{{model_id}}`,
[VECTOR_FIELD_PATTERN]: {
query_text: QUERY_TEXT_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 5,
},
},
Expand Down
7 changes: 7 additions & 0 deletions common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,13 @@ export type QueryPreset = {
query: string;
};

export type QuickConfigureFields = {
embeddingModelId?: string;
vectorField?: string;
textField?: string;
embeddingLength?: number;
};

/**
********** OPENSEARCH TYPES/INTERFACES ************
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function EditQueryModal(props: EditQueryModalProps) {
setFieldValue(props.queryFieldPath, preset.query);
setPopoverOpen(false);
},
size: 's',
size: 'full',
})),
},
]}
Expand Down
21 changes: 18 additions & 3 deletions public/pages/workflows/new_workflow/new_workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ import {
} from '@elastic/eui';
import { useSelector } from 'react-redux';
import { UseCase } from './use_case';
import { Workflow, WorkflowTemplate } from '../../../../common';
import { AppState, useAppDispatch, getWorkflowPresets } from '../../../store';
import {
FETCH_ALL_QUERY,
Workflow,
WorkflowTemplate,
} from '../../../../common';
import {
AppState,
useAppDispatch,
getWorkflowPresets,
searchModels,
} from '../../../store';
import { enrichPresetWorkflowWithUiMetadata } from './utils';
import { getDataSourceId } from '../../../utils';

interface NewWorkflowProps {}

Expand All @@ -27,6 +37,7 @@ interface NewWorkflowProps {}
*/
export function NewWorkflow(props: NewWorkflowProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();

// workflows state
const { presetWorkflows, loading } = useSelector(
Expand All @@ -43,9 +54,13 @@ export function NewWorkflow(props: NewWorkflowProps) {
setSearchQuery(query);
}, 200);

// initial state
// on initial load:
// 1. fetch the workflow presets persisted on server-side
// 2. fetch the ML models. these may be used in quick-create views when selecting a preset,
// so we optimize by fetching once at the top-level here.
useEffect(() => {
dispatch(getWorkflowPresets());
dispatch(searchModels({ apiBody: FETCH_ALL_QUERY, dataSourceId }));
}, []);

// initial hook to populate all workflows
Expand Down
163 changes: 163 additions & 0 deletions public/pages/workflows/new_workflow/quick_configure_inputs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';
import {
EuiCompressedFormRow,
EuiText,
EuiSpacer,
EuiCompressedSuperSelect,
EuiSuperSelectOption,
EuiAccordion,
EuiCompressedFieldText,
EuiCompressedFieldNumber,
} from '@elastic/eui';
import {
MODEL_STATE,
Model,
QuickConfigureFields,
WORKFLOW_TYPE,
} from '../../../../common';
import { AppState } from '../../../store';

interface QuickConfigureInputsProps {
workflowType?: WORKFLOW_TYPE;
setFields(fields: QuickConfigureFields): void;
}

// Dynamic component to allow optional input configuration fields for different use cases.
// Hooks back to the parent component with such field values
export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
const models = useSelector((state: AppState) => state.models.models);

// Deployed models state
const [deployedModels, setDeployedModels] = useState<Model[]>([]);

// Hook to update available deployed models
useEffect(() => {
if (models) {
setDeployedModels(
Object.values(models).filter(
(model) => model.state === MODEL_STATE.DEPLOYED
)
);
}
}, [models]);

// Local field values state
const [fieldValues, setFieldValues] = useState<QuickConfigureFields>({});

// Hook to update the parent field values
useEffect(() => {
props.setFields(fieldValues);
}, [fieldValues]);

return (
<>
{(props.workflowType === WORKFLOW_TYPE.SEMANTIC_SEARCH ||
props.workflowType === WORKFLOW_TYPE.MULTIMODAL_SEARCH ||
props.workflowType === WORKFLOW_TYPE.HYBRID_SEARCH) && (
<>
<EuiSpacer size="m" />
<EuiAccordion
id="optionalConfiguration"
buttonContent="Optional configuration"
initialIsOpen={true}
>
<EuiSpacer size="m" />
<EuiCompressedFormRow
label={'Embedding model'}
isInvalid={false}
helpText="The model to generate embeddings"
>
<EuiCompressedSuperSelect
options={deployedModels.map(
(option) =>
({
value: option.id,
inputDisplay: (
<>
<EuiText size="s">{option.name}</EuiText>
</>
),
dropdownDisplay: (
<>
<EuiText size="s">{option.name}</EuiText>
<EuiText size="xs" color="subdued">
Deployed
</EuiText>
<EuiText size="xs" color="subdued">
{option.algorithm}
</EuiText>
</>
),
disabled: false,
} as EuiSuperSelectOption<string>)
)}
valueOfSelected={fieldValues?.embeddingModelId || ''}
onChange={(option: string) => {
setFieldValues({
...fieldValues,
embeddingModelId: option,
});
}}
isInvalid={false}
/>
</EuiCompressedFormRow>
<EuiSpacer size="s" />
<EuiCompressedFormRow
label={'Text field'}
isInvalid={false}
helpText="The name of the document field containing plaintext"
>
<EuiCompressedFieldText
value={fieldValues?.textField || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
textField: e.target.value,
});
}}
/>
</EuiCompressedFormRow>
<EuiSpacer size="s" />
<EuiCompressedFormRow
label={'Vector field'}
isInvalid={false}
helpText="The name of the document field containing the vector embedding"
>
<EuiCompressedFieldText
value={fieldValues?.vectorField || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
vectorField: e.target.value,
});
}}
/>
</EuiCompressedFormRow>
<EuiSpacer size="s" />
<EuiCompressedFormRow
label={'Embedding length'}
isInvalid={false}
helpText="The length / dimension of the generated vector embeddings"
>
<EuiCompressedFieldNumber
value={fieldValues?.embeddingLength || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
embeddingLength: Number(e.target.value),
});
}}
/>
</EuiCompressedFormRow>
</EuiAccordion>
</>
)}
</>
);
}
Loading

0 comments on commit 8f276e3

Please sign in to comment.