Skip to content

Commit

Permalink
Add guardrails to doc and query JSON inputs (#231)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler committed Jul 23, 2024
1 parent 9de232b commit 1b8486e
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 99 deletions.
6 changes: 6 additions & 0 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ export enum COMPONENT_CLASS {
RESULTS = 'results',
}

/**
* LINKS
*/
export const ML_INFERENCE_DOCS_LINK =
'https://opensearch.org/docs/latest/ingest-pipelines/processors/ml-inference/#configuration-parameters';

/**
* MISCELLANEOUS
*/
Expand Down
9 changes: 1 addition & 8 deletions common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@ export interface IConfigField {
type: ConfigFieldType;
id: string;
value?: ConfigFieldValue;
// TODO: remove below fields out of this interface and directly into the necessary components.
// This is to minimize what we persist here, which is added into ui_metadata and indexed.
// Once the config for ML inference processors is finalized, we can migrate these out.
label?: string;
placeholder?: string;
helpText?: string;
helpLink?: string;
}
export interface IConfig {
id: string;
Expand Down Expand Up @@ -71,7 +64,7 @@ export type IngestConfig = {
};

export type SearchConfig = {
request: {};
request: IConfigField;
enrichRequest: ProcessorsConfig;
enrichResponse: ProcessorsConfig;
};
Expand Down
2 changes: 1 addition & 1 deletion public/pages/workflow_detail/resizable_workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
// Initialize the form state based on the current UI config
useEffect(() => {
if (uiConfig) {
const initFormValues = uiConfigToFormik(uiConfig, ingestDocs, query);
const initFormValues = uiConfigToFormik(uiConfig, ingestDocs);
const initFormSchema = uiConfigToSchema(uiConfig);
setFormValues(initFormValues);
setFormSchema(initFormSchema);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect } from 'react';
import { useFormikContext } from 'formik';
import React, { useEffect, useState } from 'react';
import { useFormikContext, getIn } from 'formik';
import {
EuiButton,
EuiCodeBlock,
EuiFilePicker,
EuiFlexGroup,
EuiFlexItem,
EuiModal,
EuiModalBody,
EuiModalFooter,
EuiModalHeader,
EuiModalHeaderTitle,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { JsonField } from '../input_fields';
Expand All @@ -25,6 +34,9 @@ interface SourceDataProps {
export function SourceData(props: SourceDataProps) {
const { values, setFieldValue } = useFormikContext<WorkspaceFormValues>();

// edit modal state
const [isEditModalOpen, setIsEditModalOpen] = useState<boolean>(false);

// files state. when a file is read, update the form value.
const fileReader = new FileReader();
fileReader.onload = (e) => {
Expand All @@ -42,36 +54,79 @@ export function SourceData(props: SourceDataProps) {
}, [values?.ingest?.docs]);

return (
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2>Source data</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFilePicker
accept="application/json"
multiple={false}
initialPromptText="Select a JSON file containing documents"
onChange={(files) => {
if (files && files.length > 0) {
fileReader.readAsText(files[0]);
}
}}
display="default"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<JsonField
label="Upload JSON documents"
fieldPath={'ingest.docs'}
helpText="Documents should be formatted as a valid JSON array."
// when ingest doc values change, don't update the form
// since we initially only support running ingest once per configuration
onFormChange={() => {}}
editorHeight="25vh"
/>
</EuiFlexItem>
</EuiFlexGroup>
<>
{isEditModalOpen && (
<EuiModal
onClose={() => setIsEditModalOpen(false)}
style={{ width: '70vw' }}
>
<EuiModalHeader>
<EuiModalHeaderTitle>
<p>{`Edit source data`}</p>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<>
<EuiText color="subdued">
Upload a JSON file or enter manually.
</EuiText>{' '}
<EuiSpacer size="s" />
<EuiFilePicker
accept="application/json"
multiple={false}
initialPromptText="Upload file"
onChange={(files) => {
if (files && files.length > 0) {
fileReader.readAsText(files[0]);
}
}}
display="default"
/>
<EuiSpacer size="s" />
<JsonField
fieldPath={'ingest.docs'}
helpText="Documents should be formatted as a valid JSON array."
// when ingest doc values change, don't update the form
// since we initially only support running ingest once per configuration
onFormChange={() => {}}
editorHeight="25vh"
readOnly={false}
/>
</>
</EuiModalBody>
<EuiModalFooter>
<EuiButton
onClick={() => setIsEditModalOpen(false)}
fill={false}
color="primary"
>
Close
</EuiButton>
</EuiModalFooter>
</EuiModal>
)}
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h2>Source data</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
fill={false}
style={{ width: '100px' }}
size="s"
onClick={() => setIsEditModalOpen(true)}
>
Edit
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiCodeBlock language="json" fontSize="m" isCopyable={false}>
{getIn(values, 'ingest.docs')}
</EuiCodeBlock>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { WorkspaceFormValues } from '../../../../../common';
interface JsonFieldProps {
fieldPath: string; // the full path in string-form to the field (e.g., 'ingest.enrich.processors.text_embedding_processor.inputField')
onFormChange: () => void;
label: string;
label?: string;
helpLink?: string;
helpText?: string;
editorHeight?: string;
readOnly?: boolean;
}

/**
Expand Down Expand Up @@ -79,7 +80,7 @@ export function JsonField(props: JsonFieldProps) {
props.onFormChange();
}
}}
readOnly={false}
readOnly={props.readOnly || false}
setOptions={{
fontSize: '14px',
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
IProcessorConfig,
IngestPipelineConfig,
JSONPATH_ROOT_SELECTOR,
ML_INFERENCE_DOCS_LINK,
PROCESSOR_CONTEXT,
SimulateIngestPipelineDoc,
SimulateIngestPipelineResponse,
Expand Down Expand Up @@ -135,9 +136,7 @@ export function InputTransformModal(props: InputTransformModalProps) {
fieldPath={props.inputMapFieldPath}
label="Input map"
helpText={`An array specifying how to map fields from the ingested document to the model’s input.`}
helpLink={
'https://opensearch.org/docs/latest/ingest-pipelines/processors/ml-inference/#configuration-parameters'
}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder="Model input field"
valuePlaceholder="Document field"
onFormChange={props.onFormChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
PROCESSOR_CONTEXT,
WorkflowConfig,
JSONPATH_ROOT_SELECTOR,
ML_INFERENCE_DOCS_LINK,
} from '../../../../../common';
import { MapField, ModelField } from '../input_fields';
import { isEmpty } from 'lodash';
Expand Down Expand Up @@ -128,9 +129,7 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
fieldPath={inputMapFieldPath}
label="Input map"
helpText={`An array specifying how to map fields from the ingested document to the model’s input.`}
helpLink={
'https://opensearch.org/docs/latest/ingest-pipelines/processors/ml-inference/#configuration-parameters'
}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder="Model input field"
valuePlaceholder="Document field"
onFormChange={props.onFormChange}
Expand All @@ -141,9 +140,7 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
fieldPath={outputMapFieldPath}
label="Output map"
helpText={`An array specifying how to map the model’s output to new fields.`}
helpLink={
'https://opensearch.org/docs/latest/ingest-pipelines/processors/ml-inference/#configuration-parameters'
}
helpLink={ML_INFERENCE_DOCS_LINK}
keyPlaceholder="New document field"
valuePlaceholder="Model output field"
onFormChange={props.onFormChange}
Expand Down
Loading

0 comments on commit 1b8486e

Please sign in to comment.