Autocomplete dimension denotation
This commit is contained in:
Родитель
5e3c55e182
Коммит
f036b95e3d
|
@ -41,13 +41,13 @@ class KeyValueEditor extends React.Component<IComponentProperties, IComponentSta
|
|||
// Don't suggesting adding keys that already exist
|
||||
(x) => Object.keys(this.props.keyValueObject || {}).every((key) => !this.areSameKeys(key, x)));
|
||||
const options = knownKeys.map((key: string) => ({ key, text: key }));
|
||||
let rows = [];
|
||||
let rows: Array<React.ReactElement<HTMLDivElement>> = [];
|
||||
|
||||
if (this.props.keyValueObject) {
|
||||
const [keyErrors, valueErrors] = this.validateSchema(this.state.caseInsensitiveSchema, this.props.keyValueObject);
|
||||
const schemaEntries = Object.entries(properties);
|
||||
|
||||
rows = Object.keys(this.props.keyValueObject!).reduce((acc: any[], x: string) => {
|
||||
rows = Object.keys(this.props.keyValueObject!).map((x: string) => {
|
||||
const lowerCaseKey = x.toLowerCase();
|
||||
const keyChangedCallback = (option?: IComboBoxOption, index?: number, value?: string) => {
|
||||
const key = value || option!.text;
|
||||
|
@ -80,7 +80,7 @@ class KeyValueEditor extends React.Component<IComponentProperties, IComponentSta
|
|||
}
|
||||
|
||||
const keyErrorsState = this.state.keyErrors[lowerCaseKey];
|
||||
acc.push(
|
||||
return (
|
||||
<div key={`${x}${keyErrorsState}`} className='KeyValueItem'>
|
||||
{ this.props.actionCreator &&
|
||||
<Icon className='RemoveIcon' iconName='Cancel' onClick={removeCallback} />
|
||||
|
@ -106,8 +106,7 @@ class KeyValueEditor extends React.Component<IComponentProperties, IComponentSta
|
|||
/>
|
||||
</div>
|
||||
);
|
||||
return acc;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
const addButtonDisabled = !(this.props.keyValueObject && Object.keys(this.props.keyValueObject).every((x) => !!x));
|
||||
|
@ -121,11 +120,11 @@ class KeyValueEditor extends React.Component<IComponentProperties, IComponentSta
|
|||
className='KeyValueEditorButtonContainer'
|
||||
iconProps={{ iconName: 'Add' }}
|
||||
disabled={addButtonDisabled}
|
||||
onClick={this.addMetadataProp}
|
||||
onClick={this.addProp}
|
||||
split={!!knownKeys.length}
|
||||
menuProps={knownKeys.length ? {
|
||||
items: options,
|
||||
onItemClick: this.addMetadataProp,
|
||||
onItemClick: this.addProp,
|
||||
} : undefined}
|
||||
// The Office UI includes a spam element in it when split = true, which is not of display type block
|
||||
// and ignores the parent width. We do a hack to get it to 100% of the parent width.
|
||||
|
@ -188,14 +187,14 @@ class KeyValueEditor extends React.Component<IComponentProperties, IComponentSta
|
|||
}
|
||||
|
||||
private toLowerCaseObject = (obj: { [key: string]: string }) => {
|
||||
return Object.entries(obj).reduce((acc: {}, keyValue: [string, string]) => {
|
||||
return Object.entries(obj).reduce((acc: {}, keyValue: [string, any]) => {
|
||||
const [key, value] = keyValue;
|
||||
acc[key.toLowerCase()] = value.toLowerCase();
|
||||
acc[key.toLowerCase()] = value.toString().toLowerCase();
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
private addMetadataProp = (event: any, item?: any) => {
|
||||
private addProp = (event: any, item?: any) => {
|
||||
const key = item && item.key || '';
|
||||
if (this.props.keyValueObject) {
|
||||
this.props.updateKeyValueObject!({ ...this.props.keyValueObject, [key]: ''});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { IMetadataProps, IProperties } from './state';
|
||||
|
||||
export const SET_INPUTS = 'SET_INPUTS';
|
||||
export const SET_METADATA_PROPS = 'UPDATE_METADATA_PROPS';
|
||||
export const SET_MODEL_INPUTS = 'UPDATE_MODEL_INPUTS';
|
||||
export const SET_MODEL_OUTPUTS = 'UPDATE_MODEL_OUTPUTS';
|
||||
export const SET_NODES = 'UPDATE_NODES';
|
||||
export const SET_METADATA_PROPS = 'SET_METADATA_PROPS';
|
||||
export const SET_MODEL_INPUTS = 'SET_MODEL_INPUTS';
|
||||
export const SET_MODEL_OUTPUTS = 'SET_MODEL_OUTPUTS';
|
||||
export const SET_NODES = 'SET_NODES';
|
||||
export const SET_OUTPUTS = 'SET_OUTPUTS';
|
||||
export const SET_PROPERTIES = 'UPDATE_PROPERTIES';
|
||||
export const SET_SELECTED_NODE = 'UPDATE_SELECTED_NODE';
|
||||
export const SET_PROPERTIES = 'SET_PROPERTIES';
|
||||
export const SET_SELECTED_NODE = 'SET_SELECTED_NODE';
|
||||
|
||||
export interface IAction {
|
||||
nodes: { [key: string]: any },
|
||||
|
|
|
@ -5,13 +5,13 @@ export const protoMiddleware = (store: any) => (next: (action: IAction) => any)
|
|||
switch (action.type) {
|
||||
case SET_INPUTS:
|
||||
ModelProtoSingleton.setInputs(action.inputs);
|
||||
return next(action);
|
||||
break;
|
||||
case SET_METADATA_PROPS:
|
||||
ModelProtoSingleton.setMetadata(action.metadataProps);
|
||||
return next(action);
|
||||
break;
|
||||
case SET_OUTPUTS:
|
||||
ModelProtoSingleton.setOutputs(action.outputs);
|
||||
return next(action);
|
||||
break;
|
||||
}
|
||||
return next(action);
|
||||
}
|
||||
|
|
|
@ -7,26 +7,25 @@ class ModelProto extends Proto {
|
|||
if (!Proto.getOnnx() || !this.proto) {
|
||||
return;
|
||||
}
|
||||
this.proto.graph.input = inputs;
|
||||
this.proto.graph.input = Object.keys(inputs).map((name: string) => ({ name, ...inputs[name] }));
|
||||
}
|
||||
|
||||
public setMetadata(metadata: IMetadataProps) {
|
||||
if (!Proto.getOnnx() || !this.proto) {
|
||||
return;
|
||||
}
|
||||
this.proto.metadataProps = Object.keys(metadata).reduce((acc: any[], x: string) => {
|
||||
this.proto.metadataProps = Object.keys(metadata).map((x: string) => {
|
||||
const entry = new Proto.types.StringStringEntryProto();
|
||||
entry.key = x;
|
||||
entry.value = metadata[x];
|
||||
acc.push(entry);
|
||||
return acc;
|
||||
}, []);
|
||||
return entry;
|
||||
});
|
||||
}
|
||||
public setOutputs(outputs: { [key: string]: any }) {
|
||||
if (!Proto.getOnnx() || !this.proto) {
|
||||
return;
|
||||
}
|
||||
this.proto.graph.output = outputs;
|
||||
this.proto.graph.outputs = Object.keys(outputs).map((name: string) => ({ name, ...outputs[name] }));
|
||||
}
|
||||
|
||||
public serialize() {
|
||||
|
|
|
@ -4,6 +4,7 @@ export class Proto {
|
|||
public static types: {
|
||||
ModelProto: any,
|
||||
StringStringEntryProto: any,
|
||||
ValueInfoProto: any,
|
||||
};
|
||||
|
||||
public static getOnnx() {
|
||||
|
@ -15,10 +16,7 @@ export class Proto {
|
|||
return;
|
||||
}
|
||||
this.onnx = browserGlobal.protobuf.roots.onnx.onnx;
|
||||
this.types = {
|
||||
ModelProto: this.onnx.ModelProto,
|
||||
StringStringEntryProto: this.onnx.StringStringEntryProto,
|
||||
};
|
||||
this.types = this.onnx;
|
||||
}
|
||||
return this.onnx;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,17 @@ interface IComponentProperties {
|
|||
setOutputs: typeof setOutputs,
|
||||
}
|
||||
|
||||
const denotationOptions = ['', 'IMAGE', 'AUDIO', 'TEXT', 'TENSOR'].map((key: string) => ({ key, text: key }));
|
||||
const dimensionDenotationOptions = [
|
||||
'DATA_BATCH',
|
||||
'DATA_CHANNEL',
|
||||
'DATA_TIME',
|
||||
'DATA_FEATURE',
|
||||
'FILTER_IN_CHANNEL',
|
||||
'FILTER_OUT_CHANNEL',
|
||||
'FILTER_SPATIAL',
|
||||
].map((key) => ({ key, text: key }));
|
||||
|
||||
const tensorProtoDataType = [
|
||||
'UNDEFINED',
|
||||
'float',
|
||||
|
@ -92,16 +103,14 @@ class LeftPanel extends React.Component<IComponentProperties, {}> {
|
|||
}
|
||||
|
||||
private buildConnectionList = (connections: any[]) => {
|
||||
const denotationOptions = ['', 'IMAGE', 'AUDIO', 'TEXT', 'TENSOR'].map((key: string) => ({ key, text: key }));
|
||||
return connections.reduce((acc: any[], x: any) => {
|
||||
return connections.map((x: any) => {
|
||||
const valueInfoProto = this.props.inputs[x] || this.props.outputs[x];
|
||||
if (!valueInfoProto) {
|
||||
acc.push(
|
||||
return (
|
||||
<div key={x}>
|
||||
<Label className='TensorName' disabled={true}>{x}</Label>
|
||||
<Label className='TensorName' disabled={true}>{`${x} (type: internal model connection)`}</Label>
|
||||
</div>
|
||||
);
|
||||
return acc;
|
||||
}
|
||||
|
||||
const onnxType = Object.keys(valueInfoProto.type).find((t: string) => ['tensorType', 'sequenceType', 'mapType'].includes(t)) || 'unknownType';
|
||||
|
@ -128,6 +137,7 @@ class LeftPanel extends React.Component<IComponentProperties, {}> {
|
|||
|
||||
const isModelInput = this.props.modelInputs.includes(x)
|
||||
const isModelOutput = this.props.modelOutputs.includes(x);
|
||||
const disabled = !isModelInput && !isModelOutput;
|
||||
let keyChangedCallback;
|
||||
if (isModelInput) {
|
||||
keyChangedCallback = (option?: IComboBoxOption, index?: number, value?: string) => {
|
||||
|
@ -145,36 +155,46 @@ class LeftPanel extends React.Component<IComponentProperties, {}> {
|
|||
|
||||
let shapeEditor;
|
||||
if (type === 'tensor') {
|
||||
shapeEditor = (
|
||||
<span className='Shape'>
|
||||
<TextField inputMode='numeric' type='number' placeholder='N' className='ShapeTextField' />
|
||||
<TextField inputMode='numeric' type='number' placeholder='C' className='ShapeTextField' />
|
||||
<TextField inputMode='numeric' type='number' placeholder='H' className='ShapeTextField' />
|
||||
<TextField inputMode='numeric' type='number' placeholder='W' className='ShapeTextField' />
|
||||
</span>
|
||||
)
|
||||
shapeEditor = valueInfoProto.type.tensorType.shape.dim.map((dim: any, index: number) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
<div className='DenotationDiv'>
|
||||
<TextField
|
||||
className='DenotationLabel'
|
||||
label={`Dimension [${index}]`}
|
||||
inputMode='numeric'
|
||||
type='number'
|
||||
placeholder='None'
|
||||
disabled={disabled} />
|
||||
<ComboBox
|
||||
label='Denotation'
|
||||
defaultSelectedKey={valueInfoProto.type.denotation}
|
||||
className='DenotationComboBox'
|
||||
options={dimensionDenotationOptions}
|
||||
disabled={disabled} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
acc.push(
|
||||
return (
|
||||
<div key={x}>
|
||||
{tensorName}
|
||||
<div className='TensorTypeDenotationDiv'>
|
||||
<Label className='TensorTypeDenotationLabel'>Type denotation</Label>
|
||||
<div className='DenotationDiv'>
|
||||
<ComboBox
|
||||
className='TensorTypeDenotation'
|
||||
placeholder='Type denotation'
|
||||
className='DenotationComboBox'
|
||||
label='Type denotation'
|
||||
allowFreeform={true}
|
||||
text={valueInfoProto.type.denotation}
|
||||
options={denotationOptions}
|
||||
disabled={!isModelInput && !isModelOutput}
|
||||
onChanged={keyChangedCallback}
|
||||
/>
|
||||
onChanged={keyChangedCallback} />
|
||||
</div>
|
||||
{shapeEditor}
|
||||
</div>
|
||||
);
|
||||
return acc;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,6 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.ShapeTextField {
|
||||
width: 70px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.TensorName, .TensorDocumentationHover {
|
||||
display: block;
|
||||
margin: 5px 5px;
|
||||
|
@ -23,15 +17,17 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.TensorTypeDenotationDiv {
|
||||
.DenotationDiv {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.TensorTypeDenotationLabel {
|
||||
margin: 3px 5px;
|
||||
.DenotationLabel {
|
||||
margin: 2px;
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.TensorTypeDenotation {
|
||||
.DenotationComboBox {
|
||||
margin: 2px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
@ -42,10 +38,6 @@
|
|||
margin: 20px;
|
||||
}
|
||||
|
||||
.Shape {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.FormatIsNotOnnx {
|
||||
margin: 10px;
|
||||
font-size: medium;
|
||||
|
|
|
@ -150,8 +150,8 @@ class NetronComponent extends React.Component<IComponentProperties, IComponentSt
|
|||
|
||||
private valueListToObject(values: any) {
|
||||
return values.reduce((acc: { [key: string]: any }, x: any) => {
|
||||
acc[x.name] = x;
|
||||
delete x.name;
|
||||
const {name, ...props} = x;
|
||||
acc[name] = props;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
@ -189,10 +189,7 @@ class NetronComponent extends React.Component<IComponentProperties, IComponentSt
|
|||
// FIXME What to do when model has multiple graphs?
|
||||
const graph = model.graphs[0];
|
||||
if (graph.constructor.name === 'OnnxGraph') {
|
||||
const getNames = (list: any[]): string[] => list.reduce((acc: string[], x: any) => {
|
||||
acc.push(x.name);
|
||||
return acc;
|
||||
}, []);
|
||||
const getNames = (list: any[]): string[] => list.map((x: any) => x.name);
|
||||
const inputs = getNames(graph.inputs);
|
||||
const outputs = getNames(graph.outputs);
|
||||
this.props.setModelInputs(inputs);
|
||||
|
|
Загрузка…
Ссылка в новой задаче