Skip to content

Commit 09a3efe

Browse files
Integrate legacy presets with quick-configure fields (#602) (#603)
(cherry picked from commit 8998cf8) Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent c9dd036 commit 09a3efe

File tree

10 files changed

+128
-21
lines changed

10 files changed

+128
-21
lines changed

public/configs/ingest_processors/text_embedding_ingest_processor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export class TextEmbeddingIngestProcessor extends Processor {
1010
this.id = generateId('text_embedding_processor_ingest');
1111
this.fields = [
1212
{
13-
id: 'model_id',
14-
type: 'string',
13+
id: 'model',
14+
type: 'model',
1515
},
1616
{
1717
id: 'field_map',

public/configs/ingest_processors/text_image_embedding_ingest_processor.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export class TextImageEmbeddingIngestProcessor extends Processor {
1010
this.id = generateId('text_image_embedding_processor_ingest');
1111
this.fields = [
1212
{
13-
id: 'model_id',
14-
type: 'string',
13+
id: 'model',
14+
type: 'model',
1515
},
1616
{
1717
id: 'embedding',

public/pages/workflow_detail/workflow_detail.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import {
3333
getWorkflow,
3434
searchConnectors,
3535
searchModels,
36+
setIngestPipelineErrors,
37+
setSearchPipelineErrors,
3638
useAppDispatch,
3739
} from '../../store';
3840
import { ResizableWorkspace } from './resizable_workspace';
@@ -82,13 +84,16 @@ export function WorkflowDetail(props: WorkflowDetailProps) {
8284
// - fetch workflow
8385
// - fetch available models & connectors as their IDs may be used when building flows
8486
// - fetch all indices
87+
// - clear any processor-level errors
8588
useEffect(() => {
8689
dispatch(getWorkflow({ workflowId, dataSourceId }));
8790
dispatch(searchModels({ apiBody: FETCH_ALL_QUERY_LARGE, dataSourceId }));
8891
dispatch(
8992
searchConnectors({ apiBody: FETCH_ALL_QUERY_LARGE, dataSourceId })
9093
);
9194
dispatch(catIndices({ pattern: OMIT_SYSTEM_INDEX_PATTERN, dataSourceId }));
95+
dispatch(setIngestPipelineErrors({ errors: {} }));
96+
dispatch(setSearchPipelineErrors({ errors: {} }));
9297
}, []);
9398

9499
// data-source-related states

public/pages/workflow_detail/workflow_inputs/config_field_list.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
BooleanField,
1212
NumberField,
1313
JsonField,
14+
MapField,
15+
ModelField,
1416
} from './input_fields';
1517
import { IConfigField } from '../../../../common';
1618
import { camelCaseToTitleString } from '../../../utils';
@@ -108,6 +110,31 @@ export function ConfigFieldList(props: ConfigFieldListProps) {
108110
);
109111
break;
110112
}
113+
case 'map': {
114+
el = (
115+
<EuiFlexItem key={idx}>
116+
<MapField
117+
label={camelCaseToTitleString(field.id)}
118+
fieldPath={fieldPath}
119+
/>
120+
<EuiSpacer size={CONFIG_FIELD_SPACER_SIZE} />
121+
</EuiFlexItem>
122+
);
123+
break;
124+
}
125+
case 'model': {
126+
el = (
127+
<EuiFlexItem key={idx}>
128+
<ModelField
129+
field={field}
130+
fieldPath={fieldPath}
131+
showMissingInterfaceCallout={false}
132+
/>
133+
<EuiSpacer size={CONFIG_FIELD_SPACER_SIZE} />
134+
</EuiFlexItem>
135+
);
136+
break;
137+
}
111138
}
112139
return el;
113140
})}

public/pages/workflow_detail/workflow_inputs/input_fields/map_field.tsx

+4-8
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,14 @@ export function MapField(props: MapFieldProps) {
182182
<SelectWithCustomOptions
183183
fieldPath={`${props.fieldPath}.${idx}.key`}
184184
options={props.keyOptions as any[]}
185-
placeholder={
186-
props.keyPlaceholder || 'Input'
187-
}
185+
placeholder={props.keyPlaceholder || 'Key'}
188186
allowCreate={true}
189187
/>
190188
) : (
191189
<TextField
192190
fullWidth={true}
193191
fieldPath={`${props.fieldPath}.${idx}.key`}
194-
placeholder={
195-
props.keyPlaceholder || 'Input'
196-
}
192+
placeholder={props.keyPlaceholder || 'Key'}
197193
showError={false}
198194
/>
199195
)}
@@ -220,7 +216,7 @@ export function MapField(props: MapFieldProps) {
220216
fieldPath={`${props.fieldPath}.${idx}.value`}
221217
options={props.valueOptions || []}
222218
placeholder={
223-
props.valuePlaceholder || 'Output'
219+
props.valuePlaceholder || 'Value'
224220
}
225221
allowCreate={true}
226222
/>
@@ -229,7 +225,7 @@ export function MapField(props: MapFieldProps) {
229225
fullWidth={true}
230226
fieldPath={`${props.fieldPath}.${idx}.value`}
231227
placeholder={
232-
props.valuePlaceholder || 'Output'
228+
props.valuePlaceholder || 'Value'
233229
}
234230
showError={false}
235231
/>

public/pages/workflow_detail/workflow_inputs/input_fields/model_field.tsx

+12-5
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ import { AppState } from '../../../../store';
3030
interface ModelFieldProps {
3131
field: IConfigField;
3232
fieldPath: string; // the full path in string-form to the field (e.g., 'ingest.enrich.processors.text_embedding_processor.inputField')
33-
hasModelInterface: boolean;
34-
onModelChange: (modelId: string) => void;
33+
hasModelInterface?: boolean;
34+
onModelChange?: (modelId: string) => void;
35+
showMissingInterfaceCallout?: boolean;
3536
}
3637

3738
type ModelItem = ModelFormValue & {
@@ -47,7 +48,10 @@ export function ModelField(props: ModelFieldProps) {
4748
// re-fetch here as it could overload client-side if user clicks back and forth /
4849
// keeps re-rendering this component (and subsequently re-fetching data) as they're building flows
4950
const models = useSelector((state: AppState) => state.ml.models);
50-
//const models = {};
51+
52+
// Set defaults for optional props
53+
const showMissingInterfaceCallout = props.showMissingInterfaceCallout ?? true;
54+
const hasModelInterface = props.hasModelInterface ?? false;
5155

5256
const { errors, touched, values } = useFormikContext<WorkflowFormValues>();
5357

@@ -74,7 +78,8 @@ export function ModelField(props: ModelFieldProps) {
7478

7579
return (
7680
<>
77-
{!props.hasModelInterface &&
81+
{showMissingInterfaceCallout &&
82+
!hasModelInterface &&
7883
!isEmpty(getIn(values, props.fieldPath)?.id) && (
7984
<>
8085
<EuiCallOut
@@ -156,7 +161,9 @@ export function ModelField(props: ModelFieldProps) {
156161
form.setFieldValue(props.fieldPath, {
157162
id: option,
158163
} as ModelFormValue);
159-
props.onModelChange(option);
164+
if (props.onModelChange) {
165+
props.onModelChange(option);
166+
}
160167
}}
161168
isInvalid={
162169
getIn(errors, field.name) && getIn(touched, field.name)

public/pages/workflow_detail/workflow_inputs/processors_list.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export function ProcessorsList(props: ProcessorsListProps) {
140140
const isPreV219 =
141141
semver.gte(version, MIN_SUPPORTED_VERSION) &&
142142
semver.lt(version, MINIMUM_FULL_SUPPORTED_VERSION);
143+
143144
const ingestProcessors = [
144145
...(isPreV219
145146
? [

public/pages/workflows/new_workflow/quick_configure_modal.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
isVectorSearchUseCase,
4949
WORKFLOW_NAME_RESTRICTIONS,
5050
MAX_DESCRIPTION_LENGTH,
51+
MapFormValue,
5152
} from '../../../../common';
5253
import { APP_PATH } from '../../../utils';
5354
import { AppState, createWorkflow, useAppDispatch } from '../../../store';
@@ -411,6 +412,41 @@ function updateIngestProcessors(
411412
field.value = [outputMap] as OutputMapArrayFormValue;
412413
}
413414
});
415+
} else if (processor.type === PROCESSOR_TYPE.TEXT_EMBEDDING) {
416+
config.ingest.enrich.processors[idx].fields.forEach((field) => {
417+
if (field.id === 'model' && fields.embeddingModelId) {
418+
field.value = { id: fields.embeddingModelId };
419+
}
420+
if (field.id === 'field_map') {
421+
field.value = [
422+
{
423+
key: fields.textField || '',
424+
value: fields.vectorField || '',
425+
},
426+
] as MapFormValue;
427+
}
428+
});
429+
} else if (processor.type === PROCESSOR_TYPE.TEXT_IMAGE_EMBEDDING) {
430+
config.ingest.enrich.processors[idx].fields.forEach((field) => {
431+
if (field.id === 'model' && fields.embeddingModelId) {
432+
field.value = { id: fields.embeddingModelId };
433+
}
434+
if (field.id === 'field_map') {
435+
field.value = [
436+
{
437+
key: 'text',
438+
value: fields.textField || '',
439+
},
440+
{
441+
key: 'image',
442+
value: fields.imageField || '',
443+
},
444+
] as MapFormValue;
445+
}
446+
if (field.id === 'embedding') {
447+
field.value = fields.vectorField || '';
448+
}
449+
});
414450
}
415451
});
416452
return config;

public/utils/config_to_template_utils.ts

+35
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,44 @@ export function processorConfigsToTemplateProcessors(
363363
});
364364
break;
365365
}
366+
case PROCESSOR_TYPE.TEXT_EMBEDDING:
367+
case PROCESSOR_TYPE.TEXT_IMAGE_EMBEDDING: {
368+
const formValues = processorConfigToFormik(processorConfig);
369+
let finalFormValues = {} as FormikValues;
370+
// iterate through the form values, ignoring any empty
371+
// field (empty fields can be possible if the field is optional)
372+
Object.keys(formValues).forEach((formKey: string) => {
373+
const formValue = formValues[formKey];
374+
finalFormValues = optionallyAddToFinalForm(
375+
finalFormValues,
376+
formKey,
377+
formValue
378+
);
379+
});
380+
// remove the model field, update to just the required model ID
381+
const model = finalFormValues.model;
382+
delete finalFormValues.model;
383+
finalFormValues = {
384+
...finalFormValues,
385+
model_id: model.id,
386+
};
387+
388+
// add the field map config obj
389+
finalFormValues = {
390+
...finalFormValues,
391+
field_map: mergeMapIntoSingleObj(
392+
formValues['field_map'] as MapFormValue
393+
),
394+
};
395+
processorsList.push({
396+
[processorConfig.type]: finalFormValues,
397+
});
398+
break;
399+
}
366400
case PROCESSOR_TYPE.SPLIT:
367401
case PROCESSOR_TYPE.SORT:
368402
case PROCESSOR_TYPE.COLLAPSE:
403+
case PROCESSOR_TYPE.COPY:
369404
default: {
370405
const formValues = processorConfigToFormik(processorConfig);
371406
let finalFormValues = {} as FormikValues;

public/utils/utils.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -728,14 +728,14 @@ export function getUpdatedIndexSettings(
728728
function getEmbeddingFieldFromConnector(
729729
connector: Connector
730730
): string | undefined {
731-
if (connector.parameters?.model !== undefined) {
731+
if (connector?.parameters?.model !== undefined) {
732732
return (
733733
// @ts-ignore
734-
COHERE_CONFIGS[connector.parameters?.model]?.fieldName ||
734+
COHERE_CONFIGS[connector?.parameters?.model]?.fieldName ||
735735
// @ts-ignore
736-
OPENAI_CONFIGS[connector.parameters?.model]?.fieldName ||
736+
OPENAI_CONFIGS[connector?.parameters?.model]?.fieldName ||
737737
// @ts-ignore
738-
BEDROCK_CONFIGS[connector.parameters?.model]?.fieldName
738+
BEDROCK_CONFIGS[connector?.parameters?.model]?.fieldName
739739
);
740740
} else {
741741
return undefined;

0 commit comments

Comments
 (0)