Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

How to dynamically update the content of a task? #1511

Open
Emily-0616 opened this issue Jul 19, 2023 · 3 comments
Open

How to dynamically update the content of a task? #1511

Emily-0616 opened this issue Jul 19, 2023 · 3 comments

Comments

@Emily-0616
Copy link

label-studio-frontend: 1.4.0。

I am using React , However, I don't know how to dynamically update annotations.result and task.data.image using axios. I look forward to your reply.

@Emily-0616
Copy link
Author

@hlomzik @makseq Please help me.

@simobrazz
Copy link

@hlomzik you mentioned that using assignTask + other functions should allow to solve the issue.

Anyway, there is no evidence / example of how to do It.

Could someone provide a practical example starting from this?

@richardcoder
Copy link

123

I make a simple sample to use React / label-studio-frontend: 1.4.0 to dynamically update annotations.result and task.data.image by fetch (similar as axios), you need your own backend server and database, but the frontend logic is same.

At the begining I show a typical bounding box annotation structure, you need to get your annotation from database and load it into "initLabelStudio" function below. In "onSubmitAnnotation", "onUpdateAnnotation", "onSkipTask" I show how to send the annotation to backend.

I use two arrow function "switchPrev" and "switchNext" to init / destroy labelstudio to achieve switching between tasks (images)

I am not good at React, but hope this work can give you some help.

/* a typical annotation for bounding box
{
"from_name":"tag",
"id":"rXzQ2hWsi7",
"image_rotation":0,
"origin":"manual",
"origin_height":449,
"origin_width":1200,
"to_name":"img",
"type":"rectanglelabels",
"value": {
"rectanglelabels":["bank"],
"rotation":0,
"width":66.13333333333333,
"height":57.651245551601434,
"x":9.466666666666667,
"y":21.352313167259787
}
}
*/


export default function DatasetAnnotationPage() {
  const navigate = useNavigate();
  const {state} = useLocation();
  const { dataset_id } = state;
  const [activeIndex, setActiveIndex] = useState(0);
  const [configXML, setConfigXML] = useState('');
  const [annotations, setAnnotations, refAnnotations] = useState([]);
  const [uploadIds, setUploadIds, refUploadIds] = useState([]);
  const [taskImages, setTaskImages, refTaskImages] = useState([]);
  const [labelList, setLabelList, refLabelList] = useState([]);
  const [refreshFlag, setRefreshFlag] = useState(false);
  const rootRef = useRef();
  const lsf = useRef(null);

  const initLabelStudio = useCallback((index,config_xml,annotation_list) => {
    var userName= localStorage.getItem("userName");
    return new LabelStudio(rootRef.current, {
      config: config_xml,
      interfaces: [
        "panel",
        "skip",
        "update",
        "submit",
        "controls",
        "side-column",
        'topbar',
        'annotations:tabs',
        "annotations:menu",
        "annotations:add-new",
        "predictions:menu",
      ],
      user: {
        pk: 1,
        firstName: userName,
        lastName: ""
      },
      task: {
        annotations: annotation_list,
        predictions: [],
        id: index+1,
        data: {
          image: refTaskImages.current[index]
        }
      },
      onLabelStudioLoad: function(LS) {
        var c = LS.annotationStore.addAnnotation({
          userGenerate: true
        });
        LS.annotationStore.selectAnnotation(c.id);
      },
      onSubmitAnnotation: function (LS, annotation) {
        // retrive an annotation and send it to backend (save in database)
        var annotation_list = annotation.serializeAnnotation();
        console.log(annotation_list);
        if(annotation_list.length>0){
          var annotation_form = new FormData();
          annotation_form.append("upload_id",refUploadIds.current[index]);
          var annotation_submit_list = [];
          for(var i=0; i<annotation_list.length; i++){
            var annotation = annotation_list[i];
            console.log("annotation.id: ",annotation.id);
            annotation_form.append("original_height",annotation.original_height);
            annotation_form.append("original_width",annotation.original_width);
            annotation_form.append("from_name",annotation.from_name);
            annotation_form.append("to_name",annotation.to_name);
            annotation_form.append("id",annotation.id);
            annotation_form.append("type",annotation.type);
            var annotation_type = annotation.type;
            annotation_form.append("label",annotation.value[annotation.type][0]);
            annotation_form.append("x",annotation.value.x);
            annotation_form.append("y",annotation.value.y);
            annotation_form.append("width",annotation.value.width);
            annotation_form.append("height",annotation.value.height);
            var value = {
              "rotation": 0,
              "width": annotation.value.width,
              "height": annotation.value.height,
              "x": annotation.value.x,
              "y": annotation.value.y
            }
            value[annotation_type] = [annotation.value[annotation_type][0]]
            var annotation_item = {
              "from_name": annotation.from_name,
              "id": annotation.id,
              "source": "$image",
              "to_name": annotation.to_name,
              "type": annotation_type,
              "value": value
            }
            annotation_submit_list.push(annotation_item);
          }
          var annotation_submit = {
            "id": "1001",
            "result": annotation_submit_list
          }
          var annotation_submit_url = SLP_UI_url+"/annotation/submit";
          fetch(annotation_submit_url, {
            method: 'POST',
            body: annotation_form
          })
          .then(response => response.json())
          .then(data => {
            var result = data.result;
            if(result == "success"){
              var insert_rowcount = data.insert_rowcount;
              var new_annotation = Object.assign({},refAnnotations.current);
              new_annotation[refUploadIds.current[index]] = annotation_submit;
              setAnnotations(new_annotation);
              alert("Successfully submit "+insert_rowcount+" annotations.");
            }
          })
          .catch(error => console.error(error));
        }else{
          alert("Warning: submitted an empty annotation.");
        }
      },
      onUpdateAnnotation: function (LS, annotation) {
        // retrive an annotation and send it to backend (save in database)
        console.log(annotation.serializeAnnotation());
        var annotation_list = annotation.serializeAnnotation();
        if(annotation_list.length>0){
          console.log(annotation_list.length);
          console.log(annotations);
          var annotation_form = new FormData();
          annotation_form.append("upload_id",refUploadIds.current[index]);
          annotation_form.append("annotation_number",annotation_list.length);
          var annotation_submit_list = [];
          for(var i=0; i<annotation_list.length; i++){
            var annotation = annotation_list[i];
            console.log("annotation.id: ",annotation.id);
            annotation_form.append("original_height",annotation.original_height);
            annotation_form.append("original_width",annotation.original_width);
            annotation_form.append("from_name",annotation.from_name);
            annotation_form.append("to_name",annotation.to_name);
            annotation_form.append("id",annotation.id);
            annotation_form.append("type",annotation.type);
            var annotation_type = annotation.type;
            annotation_form.append("label",annotation.value[annotation.type][0]);
            annotation_form.append("x",annotation.value.x);
            annotation_form.append("y",annotation.value.y);
            annotation_form.append("width",annotation.value.width);
            annotation_form.append("height",annotation.value.height);
            var value = {
              "rotation": 0,
              "width": annotation.value.width,
              "height": annotation.value.height,
              "x": annotation.value.x,
              "y": annotation.value.y
            }
            value[annotation_type] = [annotation.value[annotation_type][0]]
            var annotation_item = {
              "from_name": annotation.from_name,
              "id": annotation.id,
              "source": "$image",
              "to_name": annotation.to_name,
              "type": annotation_type,
              "value": value
            }
            annotation_submit_list.push(annotation_item);
          }
          var annotation_submit = {
            "id": "1001",
            "result": annotation_submit_list
          }
          console.log("annotation_submit: ",annotation_submit);
          var annotation_submit_url = SLP_UI_url+"/annotation/update";
          fetch(annotation_submit_url, {
            method: 'POST',
            body: annotation_form
          })
          .then(response => response.json())
          .then(data => {
            var result = data.result;
            if(result == "success"){
              console.log(data);
              var insert_rowcount = data.insert_rowcount;
              var delete_rowcount = data.delete_rowcount;
              var new_annotation = Object.assign({},refAnnotations.current);
              new_annotation[refUploadIds.current[index]] = annotation_submit;
              setAnnotations(new_annotation);
              alert("Successfully delete "+delete_rowcount+" annotations and insert "+insert_rowcount+" annotations.");
            }
          })
          .catch(error => console.error(error));
        }else{
          var annotation_form = new FormData();
          annotation_form.append("upload_id",refUploadIds.current[index]);
          annotation_form.append("annotation_number",annotation_list.length);
          var annotation_submit_url = SLP_UI_url+"/annotation/update";
          fetch(annotation_submit_url, {
            method: 'POST',
            body: annotation_form
          })
          .then(response => response.json())
          .then(data => {
            var result = data.result;
            if(result == "success"){
              console.log(data);
              var insert_rowcount = data.insert_rowcount;
              var delete_rowcount = data.delete_rowcount;
              var new_annotation = Object.assign({},refAnnotations.current);
              new_annotation[refUploadIds.current[index]] = {};
              setAnnotations(new_annotation);
              alert("Successfully delete "+delete_rowcount+" annotations and insert "+insert_rowcount+" annotations.");
            }
          })
          .catch(error => console.error(error));
        }
        // setSelected(!selected);
      },
      onSkipTask: function(){
        if(refUploadIds.current.length == 1){
          alert("This is the last image in dataset, please import some more before you can skip this image.");
        }else{
          console.log("start skip task");
          var upload_form = new FormData();
          upload_form.append("upload_id",refUploadIds.current[index]);
          var task_skip_url = SLP_UI_url+"/task/skip";
          fetch(task_skip_url, {
            method: 'POST',
            body: upload_form
          })
          .then(response => response.json())
          .then(data => {
            var result = data.result;
            if(result == "success"){
              console.log(data);
              // var insert_rowcount = data.insert_rowcount;
              var skip_upload_id = data.upload_id;
              alert("Successfully skip task "+skip_upload_id);
              setRefreshFlag(!refreshFlag);
            }
          })
          .catch(error => console.error(error));
        }
      }
    });
  })

  const switchPrev = () => {
    lsf.current.destroy();
    var upload_id = refUploadIds.current[activeIndex-1];
    var annotation = refAnnotations.current[upload_id];
    if(Object.keys(annotation).length == 0){
      // no annotation
      lsf.current = initLabelStudio(activeIndex-1,configXML,[]);
    }else{
      lsf.current = initLabelStudio(activeIndex-1,configXML,[annotation]);
    }
    setActiveIndex(activeIndex-1);
  }

  const switchNext = () => {
    lsf.current.destroy();
    var upload_id = refUploadIds.current[activeIndex+1];
    var annotation = refAnnotations.current[upload_id];
    if(Object.keys(annotation).length == 0){
      // no annotation
      lsf.current = initLabelStudio(activeIndex+1,configXML,[]);
    }else{
      lsf.current = initLabelStudio(activeIndex+1,configXML,[annotation]);
    }
    setActiveIndex(activeIndex+1);
  }

  useEffect(() => {
    var load_dataset_form = new FormData();
    load_dataset_form.append("datasetId",dataset_id);
    var dataset_query_url = SLP_UI_url+"/dataset/annotations/query";
    fetch(dataset_query_url, {
      method: 'POST',
      body: load_dataset_form
    })
    .then(response => response.json())
    .then(data => {
      var result = data.result;
      if(result == "success"){
        var dataset_annotations_result = data.dataset_annotations_result;
        var upload_ids = dataset_annotations_result.upload_ids;
        var taskImages = dataset_annotations_result.taskImages.map((item,index)=>{
          return item.replace(annotation_upload_path, apache_url);
        });
        var annotations = dataset_annotations_result.annotations;
        var labels_list = dataset_annotations_result.labels_str.split(",");
        setUploadIds(upload_ids);
        setTaskImages(taskImages);
        setAnnotations(annotations);
        setLabelList(labels_list);

        var config_xml = '<View>';
        config_xml += '<Image name="img" value="$image"></Image>';
        config_xml += '<RectangleLabels name="tag" toName="img">';
        for(var i=0; i<labels_list.length; i++){
          config_xml += '<Label value="'+labels_list[i]+'"></Label>>';
        }
        config_xml += '</RectangleLabels>';
        config_xml += '</View>';
        setConfigXML(config_xml);
        var upload_init_id = upload_ids[0];
        var annotation = annotations[upload_init_id];
        if(Object.keys(annotation).length == 0){
          // no annotation
          if(lsf.current!=null){
            lsf.current.destroy();
          }
          lsf.current = initLabelStudio(0,config_xml,[]);
          setActiveIndex(0);
        }else{
          if(lsf.current!=null){
            lsf.current.destroy();
          }
          lsf.current = initLabelStudio(0,config_xml,[annotation]);
          setActiveIndex(0);
        }
      }else{
        var error_msg = data.error;
        alert(error_msg);
      }
    })
    .catch(error => console.error(error));
  },[refreshFlag]);
  

  return (
    <div className={`${styles.page} flex-col`}>
      <CommonHeader subtitle="模型数据/标注数据"/>
      <div className={`${styles['main_content']} flex-row`}>
        <CommonMenu activePage={4}/>
        <div className={`${styles['dataAnnotation_content']} flex-col`}>
          <div className={`${styles['label_studio_switch']}`}>
            {
              activeIndex!=0?
              <div className={`${styles['label_studio_switch_prev']}`} onClick={switchPrev}><TbPlayerTrackPrevFilled size={30} color='white' className={`${styles['label_studio_switch_icon']}`}/></div>
              :
              <div className={`${styles['label_studio_switch_prev_disable']}`}><TbPlayerTrackPrevFilled size={30} color='white' className={`${styles['label_studio_switch_icon']}`}/></div>
            }
            {
              activeIndex!=(refUploadIds.current.length-1)?
              <div className={`${styles['label_studio_switch_next']}`} onClick={switchNext}><TbPlayerTrackNextFilled size={30} color='white' className={`${styles['label_studio_switch_icon']}`}/></div>
              :
              <div className={`${styles['label_studio_switch_next_disable']}`}><TbPlayerTrackNextFilled size={30} color='white' className={`${styles['label_studio_switch_icon']}`}/></div>
            } 
          </div>
          <div className={`${styles['label_studio_import_btn']}`}>Import</div>
          <div className={`${styles['label_studio_export_btn']}`} onClick={exportDataset}>Export</div>
          <div className={`${styles['label_studio_container']}`} id="label-studio" ref={rootRef}></div>
        </div>
      </div>
    </div>
  );
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants