diff --git a/common/constants.ts b/common/constants.ts
index 05d911a8..873e733a 100644
--- a/common/constants.ts
+++ b/common/constants.ts
@@ -410,6 +410,11 @@ export const QUERY_PRESETS = [
/**
* MISCELLANEOUS
*/
+export enum PROCESSOR_CONTEXT {
+ INGEST = 'ingest',
+ SEARCH_REQUEST = 'search_request',
+ SEARCH_RESPONSE = 'search_response',
+}
export const START_FROM_SCRATCH_WORKFLOW_NAME = 'Start From Scratch';
export const DEFAULT_NEW_WORKFLOW_NAME = 'new_workflow';
export const DEFAULT_NEW_WORKFLOW_DESCRIPTION = 'My new workflow';
@@ -434,9 +439,6 @@ export const MAX_JSON_STRING_LENGTH = 10000;
export const MAX_WORKFLOW_NAME_TO_DISPLAY = 40;
export const WORKFLOW_NAME_REGEXP = RegExp('^[a-zA-Z0-9_-]*$');
export const EMPTY_MAP_ENTRY = { key: '', value: '' } as MapEntry;
-
-export enum PROCESSOR_CONTEXT {
- INGEST = 'ingest',
- SEARCH_REQUEST = 'search_request',
- SEARCH_RESPONSE = 'search_response',
-}
+export const MODEL_OUTPUT_SCHEMA_NESTED_PATH =
+ 'output.properties.inference_results.items.properties.output.items.properties.dataAsMap.properties';
+export const MODEL_OUTPUT_SCHEMA_FULL_PATH = 'output.properties';
diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx
index 6f1b53ad..f6d3be5e 100644
--- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx
@@ -79,6 +79,10 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
) as IConfigField;
const outputMapFieldPath = `${props.baseConfigPath}.${props.config.id}.${outputMapField.id}`;
const outputMapValue = getIn(values, outputMapFieldPath);
+ const fullResponsePath = getIn(
+ values,
+ `${props.baseConfigPath}.${props.config.id}.full_response_path`
+ );
// preview availability states
// if there are preceding search request processors, we cannot fetch and display the interim transformed query.
@@ -228,6 +232,7 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) {
{inputMapValue.length !== outputMapValue.length &&
diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/output_transform_modal.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/output_transform_modal.tsx
index 785e5f16..11b9d922 100644
--- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/output_transform_modal.tsx
+++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/output_transform_modal.tsx
@@ -20,6 +20,10 @@ import {
EuiSmallButton,
EuiSpacer,
EuiText,
+ EuiPopover,
+ EuiSmallButtonEmpty,
+ EuiPopoverTitle,
+ EuiCodeBlock,
} from '@elastic/eui';
import {
IConfigField,
@@ -50,11 +54,16 @@ import {
} from '../../../../store';
import { getCore } from '../../../../services';
import { MapArrayField } from '../input_fields';
-import { getDataSourceId, parseModelOutputs } from '../../../../utils/utils';
+import {
+ getDataSourceId,
+ parseModelOutputs,
+ parseModelOutputsObj,
+} from '../../../../utils/utils';
interface OutputTransformModalProps {
uiConfig: WorkflowConfig;
config: IProcessorConfig;
+ baseConfigPath: string;
context: PROCESSOR_CONTEXT;
outputMapField: IConfigField;
outputMapFieldPath: string;
@@ -77,8 +86,15 @@ export function OutputTransformModal(props: OutputTransformModalProps) {
const [sourceOutput, setSourceOutput] = useState('[]');
const [transformedOutput, setTransformedOutput] = useState('{}');
- // get the current output map
+ // get some current values
const map = getIn(values, props.outputMapFieldPath) as MapArrayFormValue;
+ const fullResponsePath = getIn(
+ values,
+ `${props.baseConfigPath}.${props.config.id}.full_response_path`
+ );
+
+ // popover state containing the model interface details, if applicable
+ const [popoverOpen, setPopoverOpen] = useState(false);
// selected transform state
const transformOptions = map.map((_, idx) => ({
@@ -123,7 +139,44 @@ export function OutputTransformModal(props: OutputTransformModalProps) {
Fetch some sample output data and see how it is transformed.
- Source output
+
+
+ Source output
+
+ {!isEmpty(
+ parseModelOutputsObj(props.modelInterface, fullResponsePath)
+ ) && (
+
+ setPopoverOpen(false)}
+ button={
+ setPopoverOpen(!popoverOpen)}
+ >
+ View output schema
+
+ }
+ >
+
+ The JSON Schema defining the model's expected output
+
+
+ {customStringify(
+ parseModelOutputsObj(
+ props.modelInterface,
+ fullResponsePath
+ )
+ )}
+
+
+
+ )}
+
{
if (isEmpty(curArray)) {
diff --git a/public/utils/utils.ts b/public/utils/utils.ts
index b9684929..d6ce3d22 100644
--- a/public/utils/utils.ts
+++ b/public/utils/utils.ts
@@ -8,6 +8,8 @@ import jsonpath from 'jsonpath';
import { escape, get } from 'lodash';
import {
JSONPATH_ROOT_SELECTOR,
+ MODEL_OUTPUT_SCHEMA_FULL_PATH,
+ MODEL_OUTPUT_SCHEMA_NESTED_PATH,
MapFormValue,
ModelInputFormField,
ModelInterface,
@@ -18,10 +20,13 @@ import {
WORKFLOW_RESOURCE_TYPE,
WORKFLOW_STEP_TYPE,
Workflow,
- customStringify,
} from '../../common';
import { getCore, getDataSourceEnabled } from '../services';
-import { MDSQueryParams, ModelInputMap } from '../../common/interfaces';
+import {
+ MDSQueryParams,
+ ModelInputMap,
+ ModelOutputMap,
+} from '../../common/interfaces';
import queryString from 'query-string';
import { useLocation } from 'react-router-dom';
import * as pluginManifest from '../../opensearch_dashboards.json';
@@ -221,11 +226,19 @@ export function parseModelInputsObj(
) as ModelInputMap;
}
-// Derive the collection of model outputs from the model interface JSONSchema into a form-ready list
+// Derive the collection of model outputs from the model interface JSONSchema into a form-ready list.
+// Expose the full path or nested path depending on fullResponsePath
export function parseModelOutputs(
- modelInterface: ModelInterface | undefined
+ modelInterface: ModelInterface | undefined,
+ fullResponsePath: boolean = false
): ModelOutputFormField[] {
- const modelOutputsObj = get(modelInterface, 'output.properties', {}) as {
+ const modelOutputsObj = get(
+ modelInterface,
+ fullResponsePath
+ ? MODEL_OUTPUT_SCHEMA_FULL_PATH
+ : MODEL_OUTPUT_SCHEMA_NESTED_PATH,
+ {}
+ ) as {
[key: string]: ModelOutput;
};
return Object.keys(modelOutputsObj).map(
@@ -237,6 +250,20 @@ export function parseModelOutputs(
);
}
+// Derive the collection of model outputs as an obj.
+// Expose the full path or nested path depending on fullResponsePath
+export function parseModelOutputsObj(
+ modelInterface: ModelInterface | undefined,
+ fullResponsePath: boolean = false
+): ModelOutputMap {
+ return get(
+ modelInterface,
+ fullResponsePath
+ ? MODEL_OUTPUT_SCHEMA_FULL_PATH
+ : MODEL_OUTPUT_SCHEMA_NESTED_PATH,
+ {}
+ ) as ModelOutputMap;
+}
export const getDataSourceFromURL = (location: {
search: string;
}): MDSQueryParams => {