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

Support query_template optional field for ML search request processor #270

Merged
merged 2 commits into from
Aug 7, 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
2 changes: 2 additions & 0 deletions common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type ConfigFieldType =
| 'string'
| 'json'
| 'jsonArray'
| 'jsonString'
| 'select'
| 'model'
| 'map'
Expand Down Expand Up @@ -218,6 +219,7 @@ export type MLInferenceProcessor = IngestProcessor & {
model_id: string;
input_map?: {};
output_map?: {};
[key: string]: any;
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,12 @@ export class MLSearchRequestProcessor extends MLProcessor {
constructor() {
super();
this.id = generateId('ml_processor_search_request');
this.optionalFields = [
{
id: 'query_template',
type: 'jsonString',
},
...(this.optionalFields || []),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
SelectField,
BooleanField,
NumberField,
JsonField,
} from './input_fields';
import { IConfigField } from '../../../../common';
import { camelCaseToTitleString } from '../../../utils';
Expand Down Expand Up @@ -97,6 +98,33 @@ export function ConfigFieldList(props: ConfigFieldListProps) {
);
break;
}
case 'json': {
el = (
<EuiFlexItem key={idx}>
<JsonField
label={camelCaseToTitleString(field.id)}
fieldPath={`${props.baseConfigPath}.${props.configId}.${field.id}`}
onFormChange={props.onFormChange}
/>
<EuiSpacer size={CONFIG_FIELD_SPACER_SIZE} />
</EuiFlexItem>
);
break;
}
case 'jsonString': {
el = (
<EuiFlexItem key={idx}>
<JsonField
validate={false}
label={camelCaseToTitleString(field.id)}
fieldPath={`${props.baseConfigPath}.${props.configId}.${field.id}`}
onFormChange={props.onFormChange}
/>
<EuiSpacer size={CONFIG_FIELD_SPACER_SIZE} />
</EuiFlexItem>
);
break;
}
}
return el;
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { camelCaseToTitleString } from '../../../../utils';
interface JsonFieldProps {
fieldPath: string; // the full path in string-form to the field (e.g., 'ingest.enrich.processors.text_embedding_processor.inputField')
onFormChange: () => void;
validate?: boolean;
label?: string;
helpLink?: string;
helpText?: string;
Expand All @@ -29,6 +30,8 @@ interface JsonFieldProps {
* in some custom JSON
*/
export function JsonField(props: JsonFieldProps) {
const validate = props.validate !== undefined ? props.validate : true;

const { errors, touched, values } = useFormikContext<WorkspaceFormValues>();

// temp input state. only format when users click out of the code editor
Expand Down Expand Up @@ -61,8 +64,12 @@ export function JsonField(props: JsonFieldProps) {
) : undefined
}
helpText={props.helpText || undefined}
error={getIn(errors, field.name)}
isInvalid={getIn(errors, field.name) && getIn(touched, field.name)}
error={validate ? getIn(errors, field.name) : undefined}
isInvalid={
validate
? getIn(errors, field.name) && getIn(touched, field.name)
: false
}
>
<EuiCodeEditor
mode="json"
Expand All @@ -89,6 +96,7 @@ export function JsonField(props: JsonFieldProps) {
readOnly={props.readOnly || false}
setOptions={{
fontSize: '14px',
useWorker: validate,
}}
aria-label="Code Editor"
tabSize={2}
Expand Down
3 changes: 2 additions & 1 deletion public/utils/config_to_form_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ export function getInitialValue(fieldType: ConfigFieldType): ConfigFieldValue {
case 'map': {
return [];
}
case 'json': {
case 'json':
case 'jsonString': {
return '{}';
}
case 'jsonArray': {
Expand Down
4 changes: 4 additions & 0 deletions public/utils/config_to_schema_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ function getFieldSchema(

break;
}
case 'jsonString': {
baseSchema = yup.string().min(1, 'Too short');
break;
}
case 'mapArray': {
baseSchema = yup.array().of(
yup.array().of(
Expand Down
53 changes: 42 additions & 11 deletions public/utils/config_to_template_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,30 +147,61 @@ export function processorConfigsToTemplateProcessors(
processorConfigs.forEach((processorConfig) => {
switch (processorConfig.type) {
case PROCESSOR_TYPE.ML: {
const { model, input_map, output_map } = processorConfigToFormik(
processorConfig
) as {
model: ModelFormValue;
input_map: MapArrayFormValue;
output_map: MapArrayFormValue;
};
const {
model,
input_map,
output_map,
model_config,
...formValues
} = processorConfigToFormik(processorConfig);

let processor = {
ml_inference: {
model_id: model.id,
},
} as MLInferenceProcessor;

// process input/output maps
if (input_map?.length > 0) {
processor.ml_inference.input_map = input_map.map((mapFormValue) =>
mergeMapIntoSingleObj(mapFormValue)
processor.ml_inference.input_map = input_map.map(
(mapFormValue: MapFormValue) => mergeMapIntoSingleObj(mapFormValue)
);
}

if (output_map?.length > 0) {
processor.ml_inference.output_map = output_map.map((mapFormValue) =>
mergeMapIntoSingleObj(mapFormValue)
processor.ml_inference.output_map = output_map.map(
(mapFormValue: MapFormValue) => mergeMapIntoSingleObj(mapFormValue)
);
}

// process optional fields
let additionalFormValues = {} as FormikValues;
Object.keys(formValues).forEach((formKey: string) => {
const formValue = formValues[formKey];
additionalFormValues = optionallyAddToFinalForm(
additionalFormValues,
formKey,
formValue
);
});

// process model config.
// TODO: this special handling, plus the special handling on index settings/mappings
// could be improved if the 'json' obj returned {} during the conversion instead
// of "{}". We may have future JSON fields which right now are going to require
// this manual parsing before adding to the template.
let finalModelConfig = {};
try {
// @ts-ignore
finalModelConfig = JSON.parse(model_config);
} catch (e) {}

processor.ml_inference = {
...processor.ml_inference,
...additionalFormValues,
model_config: finalModelConfig,
};

processorsList.push(processor);
break;
}
Expand Down
Loading