Autocomplete dimension denotation

This commit is contained in:
Tiago Koji Castro Shibata 2018-08-01 17:23:49 -07:00
Родитель 5e3c55e182
Коммит f036b95e3d
8 изменённых файлов: 76 добавлений и 71 удалений

Просмотреть файл

@ -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);