Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 2.x] Onboard basic sentiment analysis with defaults #353

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export enum WORKFLOW_TYPE {
SEMANTIC_SEARCH = 'Semantic search',
MULTIMODAL_SEARCH = 'Multimodal search',
HYBRID_SEARCH = 'Hybrid search',
SENTIMENT_ANALYSIS = 'Sentiment analysis',
CUSTOM = 'Custom',
UNKNOWN = 'Unknown',
}
Expand Down Expand Up @@ -181,9 +182,14 @@ export const SHARED_OPTIONAL_FIELDS = ['max_chunk_limit', 'description', 'tag'];
/**
* QUERY PRESETS
*/
export const DEFAULT_TEXT_FIELD = 'my_text';
export const DEFAULT_VECTOR_FIELD = 'my_embedding';
export const DEFAULT_IMAGE_FIELD = 'my_image';
export const DEFAULT_LABEL_FIELD = 'label';
export const VECTOR_FIELD_PATTERN = `{{vector_field}}`;
export const TEXT_FIELD_PATTERN = `{{text_field}}`;
export const IMAGE_FIELD_PATTERN = `{{image_field}}`;
export const LABEL_FIELD_PATTERN = `{{label_field}}`;
export const QUERY_TEXT_PATTERN = `{{query_text}}`;
export const QUERY_IMAGE_PATTERN = `{{query_image}}`;
export const MODEL_ID_PATTERN = `{{model_id}}`;
Expand All @@ -198,7 +204,7 @@ export const FETCH_ALL_QUERY = {
},
size: 1000,
};
export const TERM_QUERY = {
export const TERM_QUERY_TEXT = {
query: {
term: {
[TEXT_FIELD_PATTERN]: {
Expand All @@ -207,6 +213,15 @@ export const TERM_QUERY = {
},
},
};
export const TERM_QUERY_LABEL = {
query: {
term: {
[LABEL_FIELD_PATTERN]: {
value: QUERY_TEXT_PATTERN,
},
},
},
};
export const KNN_QUERY = {
_source: {
excludes: [VECTOR_FIELD_PATTERN],
Expand Down Expand Up @@ -353,7 +368,7 @@ export const QUERY_PRESETS = [
},
{
name: 'Term',
query: customStringify(TERM_QUERY),
query: customStringify(TERM_QUERY_TEXT),
},
{
name: 'Basic k-NN',
Expand Down
3 changes: 2 additions & 1 deletion common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,10 +483,11 @@ export type QueryPreset = {
};

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

Expand Down
166 changes: 107 additions & 59 deletions public/pages/workflows/new_workflow/quick_configure_inputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
} from '@elastic/eui';
import {
COHERE_DIMENSIONS,
DEFAULT_IMAGE_FIELD,
DEFAULT_LABEL_FIELD,
DEFAULT_TEXT_FIELD,
DEFAULT_VECTOR_FIELD,
MODEL_STATE,
Model,
OPENAI_DIMENSIONS,
Expand All @@ -30,10 +34,6 @@ interface QuickConfigureInputsProps {
setFields(fields: QuickConfigureFields): void;
}

const DEFAULT_TEXT_FIELD = 'my_text';
const DEFAULT_VECTOR_FIELD = 'my_embedding';
const DEFAULT_IMAGE_FIELD = 'my_image';

// 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) {
Expand All @@ -60,26 +60,38 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
// defaults for the field values for certain workflow types
useEffect(() => {
let defaultFieldValues = {} as QuickConfigureFields;
if (
props.workflowType === WORKFLOW_TYPE.SEMANTIC_SEARCH ||
props.workflowType === WORKFLOW_TYPE.MULTIMODAL_SEARCH ||
props.workflowType === WORKFLOW_TYPE.HYBRID_SEARCH
) {
defaultFieldValues = {
textField: DEFAULT_TEXT_FIELD,
vectorField: DEFAULT_VECTOR_FIELD,
};
}
if (props.workflowType === WORKFLOW_TYPE.MULTIMODAL_SEARCH) {
defaultFieldValues = {
...defaultFieldValues,
imageField: DEFAULT_IMAGE_FIELD,
};
switch (props.workflowType) {
case WORKFLOW_TYPE.SEMANTIC_SEARCH:
case WORKFLOW_TYPE.HYBRID_SEARCH: {
defaultFieldValues = {
textField: DEFAULT_TEXT_FIELD,
vectorField: DEFAULT_VECTOR_FIELD,
};
break;
}
case WORKFLOW_TYPE.MULTIMODAL_SEARCH: {
defaultFieldValues = {
textField: DEFAULT_TEXT_FIELD,
vectorField: DEFAULT_VECTOR_FIELD,
imageField: DEFAULT_IMAGE_FIELD,
};
break;
}
case WORKFLOW_TYPE.SENTIMENT_ANALYSIS: {
defaultFieldValues = {
textField: DEFAULT_TEXT_FIELD,
labelField: DEFAULT_LABEL_FIELD,
};
break;
}
case WORKFLOW_TYPE.CUSTOM:
default:
break;
}
if (deployedModels.length > 0) {
defaultFieldValues = {
...defaultFieldValues,
embeddingModelId: deployedModels[0].id,
modelId: deployedModels[0].id,
};
}
setFieldValues(defaultFieldValues);
Expand All @@ -93,7 +105,7 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
// Try to pre-fill the dimensions based on the chosen model
useEffect(() => {
const selectedModel = deployedModels.find(
(model) => model.id === fieldValues.embeddingModelId
(model) => model.id === fieldValues.modelId
);
if (selectedModel?.connectorId !== undefined) {
const connector = connectors[selectedModel.connectorId];
Expand Down Expand Up @@ -127,13 +139,14 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
}
}
}
}, [fieldValues.embeddingModelId, deployedModels, connectors]);
}, [fieldValues.modelId, deployedModels, connectors]);

return (
<>
{(props.workflowType === WORKFLOW_TYPE.SEMANTIC_SEARCH ||
props.workflowType === WORKFLOW_TYPE.MULTIMODAL_SEARCH ||
props.workflowType === WORKFLOW_TYPE.HYBRID_SEARCH) && (
props.workflowType === WORKFLOW_TYPE.HYBRID_SEARCH ||
props.workflowType === WORKFLOW_TYPE.SENTIMENT_ANALYSIS) && (
<>
<EuiSpacer size="m" />
<EuiAccordion
Expand All @@ -143,9 +156,17 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
>
<EuiSpacer size="m" />
<EuiCompressedFormRow
label={'Embedding model'}
label={
props.workflowType === WORKFLOW_TYPE.SENTIMENT_ANALYSIS
? 'Model'
: 'Embedding model'
}
isInvalid={false}
helpText="The model to generate embeddings"
helpText={
props.workflowType === WORKFLOW_TYPE.SENTIMENT_ANALYSIS
? 'The sentiment analysis model'
: 'The model to generate embeddings'
}
>
<EuiCompressedSuperSelect
options={deployedModels.map(
Expand All @@ -171,11 +192,11 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
disabled: false,
} as EuiSuperSelectOption<string>)
)}
valueOfSelected={fieldValues?.embeddingModelId || ''}
valueOfSelected={fieldValues?.modelId || ''}
onChange={(option: string) => {
setFieldValues({
...fieldValues,
embeddingModelId: option,
modelId: option,
});
}}
isInvalid={false}
Expand All @@ -185,7 +206,11 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
<EuiCompressedFormRow
label={'Text field'}
isInvalid={false}
helpText="The name of the text document field to be embedded"
helpText={`The name of the text document field to be ${
props.workflowType === WORKFLOW_TYPE.SENTIMENT_ANALYSIS
? 'analyzed'
: 'embedded'
}`}
>
<EuiCompressedFieldText
value={fieldValues?.textField || ''}
Expand Down Expand Up @@ -218,37 +243,60 @@ export function QuickConfigureInputs(props: QuickConfigureInputsProps) {
<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. Autofilled values may be inaccurate."
>
<EuiCompressedFieldNumber
value={fieldValues?.embeddingLength || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
embeddingLength: Number(e.target.value),
});
}}
/>
</EuiCompressedFormRow>
{(props.workflowType === WORKFLOW_TYPE.SEMANTIC_SEARCH ||
props.workflowType === WORKFLOW_TYPE.MULTIMODAL_SEARCH ||
props.workflowType === WORKFLOW_TYPE.HYBRID_SEARCH) && (
<>
<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. Autofilled values may be inaccurate."
>
<EuiCompressedFieldNumber
value={fieldValues?.embeddingLength || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
embeddingLength: Number(e.target.value),
});
}}
/>
</EuiCompressedFormRow>
</>
)}
{props.workflowType === WORKFLOW_TYPE.SENTIMENT_ANALYSIS && (
<EuiCompressedFormRow
label={'Label field'}
isInvalid={false}
helpText="The name of the document field containing the sentiment label"
>
<EuiCompressedFieldText
value={fieldValues?.labelField || ''}
onChange={(e) => {
setFieldValues({
...fieldValues,
labelField: e.target.value,
});
}}
/>
</EuiCompressedFormRow>
)}
</EuiAccordion>
</>
)}
Expand Down
Loading
Loading