@@ -28,7 +28,7 @@ import { Canvas, convertShapesForInteractor } from 'cvat-canvas-wrapper';
2828import getCore from 'cvat-core-wrapper' ;
2929import openCVWrapper from 'utils/opencv-wrapper/opencv-wrapper' ;
3030import {
31- CombinedState , ActiveControl , Model , ObjectType , ShapeType , ToolsBlockerState ,
31+ CombinedState , ActiveControl , Model , ObjectType , ShapeType , ToolsBlockerState , ModelAttribute ,
3232} from 'reducers/interfaces' ;
3333import {
3434 interactWithCanvas ,
@@ -37,9 +37,10 @@ import {
3737 updateAnnotationsAsync ,
3838 createAnnotationsAsync ,
3939} from 'actions/annotation-actions' ;
40- import DetectorRunner from 'components/model-runner-modal/detector-runner' ;
40+ import DetectorRunner , { DetectorRequestBody } from 'components/model-runner-modal/detector-runner' ;
4141import LabelSelector from 'components/label-selector/label-selector' ;
4242import CVATTooltip from 'components/common/cvat-tooltip' ;
43+ import { Attribute , Label } from 'components/labels-editor/common' ;
4344
4445import ApproximationAccuracy , {
4546 thresholdFromAccuracy ,
@@ -374,7 +375,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
374375 }
375376
376377 setTimeout ( ( ) => this . runInteractionRequest ( interactionId ) ) ;
377- } catch ( err ) {
378+ } catch ( err : any ) {
378379 notification . error ( {
379380 description : err . toString ( ) ,
380381 message : 'Interaction error occured' ,
@@ -466,7 +467,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
466467
467468 // update annotations on a canvas
468469 fetchAnnotations ( ) ;
469- } catch ( err ) {
470+ } catch ( err : any ) {
470471 notification . error ( {
471472 description : err . toString ( ) ,
472473 message : 'Tracking error occured' ,
@@ -706,7 +707,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
706707 Array . prototype . push . apply ( statefullContainer . states , serverlessStates ) ;
707708 trackingData . statefull [ trackerID ] = statefullContainer ;
708709 delete trackingData . stateless [ trackerID ] ;
709- } catch ( error ) {
710+ } catch ( error : any ) {
710711 notification . error ( {
711712 message : 'Tracker initialization error' ,
712713 description : error . toString ( ) ,
@@ -757,7 +758,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
757758 trackedShape . shapePoints = shape ;
758759 } ) ;
759760 }
760- } catch ( error ) {
761+ } catch ( error : any ) {
761762 notification . error ( {
762763 message : 'Tracking error' ,
763764 description : error . toString ( ) ,
@@ -1022,41 +1023,106 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
10221023 } ) ;
10231024 } ) ;
10241025
1026+ function checkAttributesCompatibility (
1027+ functionAttribute : ModelAttribute | undefined ,
1028+ dbAttribute : Attribute | undefined ,
1029+ value : string ,
1030+ ) : boolean {
1031+ if ( ! dbAttribute || ! functionAttribute ) {
1032+ return false ;
1033+ }
1034+
1035+ const { inputType } = ( dbAttribute as any as { inputType : string } ) ;
1036+ if ( functionAttribute . input_type === inputType ) {
1037+ if ( functionAttribute . input_type === 'number' ) {
1038+ const [ min , max , step ] = dbAttribute . values ;
1039+ return ! Number . isNaN ( + value ) && + value >= + min && + value <= + max && ! ( + value % + step ) ;
1040+ }
1041+
1042+ if ( functionAttribute . input_type === 'checkbox' ) {
1043+ return [ 'true' , 'false' ] . includes ( value . toLowerCase ( ) ) ;
1044+ }
1045+
1046+ if ( [ 'select' , 'radio' ] . includes ( functionAttribute . input_type ) ) {
1047+ return dbAttribute . values . includes ( value ) ;
1048+ }
1049+
1050+ return true ;
1051+ }
1052+
1053+ switch ( functionAttribute . input_type ) {
1054+ case 'number' :
1055+ return dbAttribute . values . includes ( value ) || inputType === 'text' ;
1056+ case 'text' :
1057+ return [ 'select' , 'radio' ] . includes ( dbAttribute . input_type ) && dbAttribute . values . includes ( value ) ;
1058+ case 'select' :
1059+ return ( inputType === 'radio' && dbAttribute . values . includes ( value ) ) || inputType === 'text' ;
1060+ case 'radio' :
1061+ return ( inputType === 'select' && dbAttribute . values . includes ( value ) ) || inputType === 'text' ;
1062+ case 'checkbox' :
1063+ return dbAttribute . values . includes ( value ) || inputType === 'text' ;
1064+ default :
1065+ return false ;
1066+ }
1067+ }
1068+
10251069 return (
10261070 < DetectorRunner
10271071 withCleanup = { false }
10281072 models = { detectors }
10291073 labels = { jobInstance . labels }
10301074 dimension = { jobInstance . dimension }
1031- runInference = { async ( model : Model , body : object ) => {
1075+ runInference = { async ( model : Model , body : DetectorRequestBody ) => {
10321076 try {
10331077 this . setState ( { mode : 'detection' , fetching : true } ) ;
10341078 const result = await core . lambda . call ( jobInstance . taskId , model , { ...body , frame } ) ;
10351079 const states = result . map (
1036- ( data : any ) : any => new core . classes . ObjectState ( {
1037- shapeType : data . type ,
1038- label : jobInstance . labels . filter ( ( label : any ) : boolean => label . name === data . label ) [ 0 ] ,
1039- points : data . points ,
1040- objectType : ObjectType . SHAPE ,
1041- frame,
1042- occluded : false ,
1043- source : 'auto' ,
1044- attributes : ( data . attributes as { name : string , value : string } [ ] )
1045- . reduce ( ( mapping , attr ) => {
1046- mapping [ attrsMap [ data . label ] [ attr . name ] ] = attr . value ;
1047- return mapping ;
1048- } , { } as Record < number , string > ) ,
1049- zOrder : curZOrder ,
1050- } ) ,
1051- ) ;
1080+ ( data : any ) : any => {
1081+ const jobLabel = ( jobInstance . labels as Label [ ] )
1082+ . find ( ( jLabel : Label ) : boolean => jLabel . name === data . label ) ;
1083+ const [ modelLabel ] = Object . entries ( body . mapping )
1084+ . find ( ( [ , { name } ] ) => name === data . label ) || [ ] ;
1085+
1086+ if ( ! jobLabel || ! modelLabel ) return null ;
1087+
1088+ return new core . classes . ObjectState ( {
1089+ shapeType : data . type ,
1090+ label : jobLabel ,
1091+ points : data . points ,
1092+ objectType : ObjectType . SHAPE ,
1093+ frame,
1094+ occluded : false ,
1095+ source : 'auto' ,
1096+ attributes : ( data . attributes as { name : string , value : string } [ ] )
1097+ . reduce ( ( acc , attr ) => {
1098+ const [ modelAttr ] = Object . entries ( body . mapping [ modelLabel ] . attributes )
1099+ . find ( ( value : string [ ] ) => value [ 1 ] === attr . name ) || [ ] ;
1100+ const areCompatible = checkAttributesCompatibility (
1101+ model . attributes [ modelLabel ] . find ( ( mAttr ) => mAttr . name === modelAttr ) ,
1102+ jobLabel . attributes . find ( ( jobAttr : Attribute ) => (
1103+ jobAttr . name === attr . name
1104+ ) ) ,
1105+ attr . value ,
1106+ ) ;
1107+
1108+ if ( areCompatible ) {
1109+ acc [ attrsMap [ data . label ] [ attr . name ] ] = attr . value ;
1110+ }
1111+
1112+ return acc ;
1113+ } , { } as Record < number , string > ) ,
1114+ zOrder : curZOrder ,
1115+ } ) ;
1116+ } ,
1117+ ) . filter ( ( state : any ) => state ) ;
10521118
10531119 createAnnotations ( jobInstance , frame , states ) ;
10541120 const { onSwitchToolsBlockerState } = this . props ;
10551121 onSwitchToolsBlockerState ( { buttonVisible : false } ) ;
1056- } catch ( error ) {
1122+ } catch ( error : any ) {
10571123 notification . error ( {
10581124 description : error . toString ( ) ,
1059- message : 'Detection error occured ' ,
1125+ message : 'Detection error occurred ' ,
10601126 } ) ;
10611127 } finally {
10621128 this . setState ( { fetching : false } ) ;
0 commit comments