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

Fix preset output map configs for ML processors #473

Merged
merged 5 commits into from
Nov 12, 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
Original file line number Diff line number Diff line change
Expand Up @@ -487,17 +487,7 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
<EuiSpacer size="s" />
<ConfigFieldList
configId={props.config.id}
configFields={
// For ML search request processors, we don't expose the optional query_template field, since we have a dedicated
// UI for configuring that. See override_query_modal.tsx for details.
props.context === PROCESSOR_CONTEXT.SEARCH_REQUEST
? [
...(props.config.optionalFields?.filter(
(optionalField) => optionalField.id !== 'query_template'
) || []),
]
: props.config.optionalFields || []
}
configFields={props.config.optionalFields || []}
baseConfigPath={props.baseConfigPath}
/>
</EuiAccordion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
IngestPipelineConfig,
JSONPATH_ROOT_SELECTOR,
MapArrayFormValue,
MapFormValue,
ModelInterface,
OutputTransformFormValues,
OutputTransformSchema,
Expand Down Expand Up @@ -157,7 +158,7 @@ export function OutputTransformModal(props: OutputTransformModalProps) {
sampleSourceOutput = JSON.parse(sourceOutput);
const output = generateTransform(
sampleSourceOutput,
tempOutputMap[selectedTransformOption]
reverseKeysAndValues(tempOutputMap[selectedTransformOption])
);
setTransformedOutput(customStringify(output));
} catch {}
Expand Down Expand Up @@ -641,3 +642,14 @@ root object selector "${JSONPATH_ROOT_SELECTOR}"`}
</Formik>
);
}

// since we persist the form keys/values reversed, we have a util fn to reverse back, so we can use
// single util fns for manipulation of the form values (generating transforms, etc.)
function reverseKeysAndValues(values: MapFormValue): MapFormValue {
return values.map((mapEntry) => {
return {
key: mapEntry.value,
value: mapEntry.key,
};
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ export function OverrideQueryModal(props: OverrideQueryModalProps) {
);
// TODO: should handle edge case of multiple output maps configured. Currently
// defaulting to prediction 0 / assuming not multiple predictions to track.
const outputMapKeys = getIn(outputMap, '0', []).map(
(mapEntry: MapEntry) => mapEntry.key
const outputMapValues = getIn(outputMap, '0', []).map(
(mapEntry: MapEntry) => mapEntry.value
) as string[];
const finalModelOutputs =
outputMapKeys.length > 0
? outputMapKeys.map((outputMapKey) => {
return { label: outputMapKey };
outputMapValues.length > 0
? outputMapValues.map((outputMapValue) => {
return { label: outputMapValue };
})
: modelOutputs.map((modelOutput) => {
return { label: modelOutput.label };
Expand Down
24 changes: 13 additions & 11 deletions public/pages/workflows/new_workflow/quick_configure_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,10 @@ function updateIngestProcessors(
if (outputMap.length > 0) {
outputMap[0] = {
...outputMap[0],
key: defaultField,
value: defaultField,
};
} else {
outputMap.push({ key: defaultField, value: '' });
outputMap.push({ key: '', value: defaultField });
}
}
field.value = [outputMap] as MapArrayFormValue;
Expand Down Expand Up @@ -344,16 +344,18 @@ function updateSearchRequestProcessors(
}
if (field.id === 'output_map') {
const outputMap = generateMapFromModelOutputs(modelInterface);
const defaultKey = isVectorSearchUseCase ? VECTOR : defaultQueryValue;
const defaultValue = isVectorSearchUseCase
? VECTOR
: defaultQueryValue;
if (outputMap.length > 0) {
outputMap[0] = {
...outputMap[0],
key: defaultKey,
value: defaultValue,
};
} else {
outputMap.push({
key: defaultKey,
value: '',
key: '',
value: defaultValue,
});
}
field.value = [outputMap] as MapArrayFormValue;
Expand Down Expand Up @@ -412,10 +414,10 @@ function updateSearchResponseProcessors(
if (outputMap.length > 0) {
outputMap[0] = {
...outputMap[0],
key: fields.llmResponseField,
value: fields.llmResponseField,
};
} else {
outputMap.push({ key: fields.llmResponseField, value: '' });
outputMap.push({ key: '', value: fields.llmResponseField });
}
}
field.value = [outputMap] as MapArrayFormValue;
Expand Down Expand Up @@ -540,7 +542,7 @@ function generateMapFromModelInputs(
return inputMap;
}

// generate a set of mappings s.t. each value is
// generate a set of mappings s.t. each key is
// a unique model output
function generateMapFromModelOutputs(
modelInterface?: ModelInterface
Expand All @@ -550,8 +552,8 @@ function generateMapFromModelOutputs(
const modelOutputs = parseModelOutputs(modelInterface);
modelOutputs.forEach((modelOutput) => {
outputMap.push({
key: '',
value: modelOutput.label,
key: modelOutput.label,
value: '',
});
});
}
Expand Down
19 changes: 12 additions & 7 deletions public/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,18 @@ function getTransformedResult(
// the entire value. This may happen if full_response_path=false
// and the input is the entire result with nothing else to parse out.
// get() does not cover this case, so we override manually.
return path === '.'
? input
: mapEntry.value.startsWith(JSONPATH_ROOT_SELECTOR)
? // JSONPath transform
jsonpath.value(input, path)
: // Standard dot notation
get(input, path);
const result =
path === '.'
? input
: mapEntry.value.startsWith(JSONPATH_ROOT_SELECTOR)
? // JSONPath transform
jsonpath.query(input, path)
: // Standard dot notation
get(input, path);

// ML processors dynamically handle arrays vs. single values differently when indexing.
// We replicate that logic here to get consistent results
return Array.isArray(result) && result.length === 1 ? result[0] : result;
}

// Derive the collection of model inputs from the model interface JSONSchema into a form-ready list
Expand Down
Loading