<commit_before>/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */
import * as posedetection from '@tensorflow-models/pose-detection';
import * as tf from '@tensorflow/tfjs-core';

import * as params from './params';

/**
 * Records each flag's default value under the runtime environment and is a
 * constant in runtime.
 */
let TUNABLE_FLAG_DEFAULT_VALUE_MAP;

let enableTrackingController;

const stringValueMap = {};

export async function setupDatGui(urlParams) {
  const gui = new dat.GUI({width: 300});
  gui.domElement.id = 'gui';

  // The camera folder contains options for video settings.
  const cameraFolder = gui.addFolder('Camera');
  const fpsController = cameraFolder.add(params.STATE.camera, 'targetFPS');
  fpsController.onFinishChange((_) => {
    params.STATE.isTargetFPSChanged = true;
  });
  const sizeController = cameraFolder.add(
      params.STATE.camera, 'sizeOption', Object.keys(params.VIDEO_SIZE));
  sizeController.onChange(_ => {
    params.STATE.isSizeOptionChanged = true;
  });
  cameraFolder.open();

  // The model folder contains options for model selection.
  const modelFolder = gui.addFolder('Model');

  const model = urlParams.get('model');
  let type = urlParams.get('type');

  switch (model) {
    case 'posenet':
      params.STATE.model = posedetection.SupportedModels.PoseNet;
      break;
    case 'movenet':
      params.STATE.model = posedetection.SupportedModels.MoveNet;
      if (type !== 'lightning' && type !== 'thunder' && type !== 'multipose') {
        // Nulify invalid value.
        type = null;
      }
      break;
    case 'blazepose':
      params.STATE.model = posedetection.SupportedModels.BlazePose;
      if (type !== 'full' && type !== 'lite' && type !== 'heavy') {
        // Nulify invalid value.
        type = null;
      }
      break;
    default:
      alert(`${urlParams.get('model')}`);
      break;
  }

  const modelController = modelFolder.add(
      params.STATE, 'model', Object.values(posedetection.SupportedModels));

  modelController.onChange(_ => {
    params.STATE.isModelChanged = true;
    showModelConfigs(modelFolder);
    showBackendConfigs(backendFolder);
  });

  showModelConfigs(modelFolder, type);

  modelFolder.open();

  const backendFolder = gui.addFolder('Backend');

  showBackendConfigs(backendFolder);

  backendFolder.open();

  return gui;
}

async function showBackendConfigs(folderController) {
  // Clean up backend configs for the previous model.
  const fixedSelectionCount = 0;
  while (folderController.__controllers.length > fixedSelectionCount) {
    folderController.remove(
        folderController
            .__controllers[folderController.__controllers.length - 1]);
  }
  const backends = params.MODEL_BACKEND_MAP[params.STATE.model];
  // The first element of the array is the default backend for the model.
  params.STATE.backend = backends[0];
  const backendController =
      folderController.add(params.STATE, 'backend', backends);
  backendController.name('runtime-backend');
  backendController.onChange(async backend => {
    params.STATE.isBackendChanged = true;
    await showFlagSettings(folderController, backend);
  });
  await showFlagSettings(folderController, params.STATE.backend);
}

function showModelConfigs(folderController, type) {
  // Clean up model configs for the previous model.
  // The first constroller under the `folderController` is the model
  // selection.
  const fixedSelectionCount = 1;
  while (folderController.__controllers.length > fixedSelectionCount) {
    folderController.remove(
        folderController
            .__controllers[folderController.__controllers.length - 1]);
  }

  switch (params.STATE.model) {
    case posedetection.SupportedModels.PoseNet:
      addPoseNetControllers(folderController);
      break;
    case posedetection.SupportedModels.MoveNet:
      addMoveNetControllers(folderController, type);
      break;
    case posedetection.SupportedModels.BlazePose:
      addBlazePoseControllers(folderController, type);
      break;
    default:
      alert(`Model ${params.STATE.model} is not supported.`);
  }
}

// The PoseNet model config folder contains options for PoseNet config
// settings.
function addPoseNetControllers(modelConfigFolder) {
  params.STATE.modelConfig = {...params.POSENET_CONFIG};

  modelConfigFolder.add(params.STATE.modelConfig, 'maxPoses', [1, 2, 3, 4, 5]);
  modelConfigFolder.add(params.STATE.modelConfig, 'scoreThreshold', 0, 1);
}

// The MoveNet model config folder contains options for MoveNet config
// settings.
function addMoveNetControllers(modelConfigFolder, type) {
  params.STATE.modelConfig = {...params.MOVENET_CONFIG};
  params.STATE.modelConfig.type = type != null ? type : 'lightning';

  if (params.STATE.modelConfig.type === 'multipose') {
    params.STATE.modelConfig.enableTracking = true;
  }

  const typeController = modelConfigFolder.add(
      params.STATE.modelConfig, 'type', ['lightning', 'thunder', 'multipose']);
  typeController.onChange(type => {
    // Set isModelChanged to true, so that we don't render any result during
    // changing models.
    params.STATE.isModelChanged = true;
    if (type === 'multipose') {
      // Default to enable tracking for multi pose
      if (enableTrackingController) {
        enableTrackingController.setValue(true);
      }
    } else {
      enableTrackingController.setValue(false);
    }
  });

  const customModelController =
      modelConfigFolder.add(params.STATE.modelConfig, 'customModel');
  customModelController.onFinishChange(_ => {
    params.STATE.isModelChanged = true;
  });

  modelConfigFolder.add(params.STATE.modelConfig, 'scoreThreshold', 0, 1);

  enableTrackingController = modelConfigFolder.add(
      params.STATE.modelConfig,
      'enableTracking',
  );
  enableTrackingController.onChange(_ => {
    // Set isModelChanged to true, so that we don't render any result during
    // changing models.
    params.STATE.isModelChanged = true;
  })
}

// The BlazePose model config folder contains options for BlazePose config
// settings.
function addBlazePoseControllers(modelConfigFolder, type) {
  params.STATE.modelConfig = {...params.BLAZEPOSE_CONFIG};
  params.STATE.modelConfig.type = type != null ? type : 'full';
<commit_msg>[pose-detection]Update MoveNet demo to use a lower scoreThreshold for multipose. (#816)<commit_after>/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =============================================================================
 */
import * as posedetection from '@tensorflow-models/pose-detection';
import * as tf from '@tensorflow/tfjs-core';

import * as params from './params';

/**
 * Records each flag's default value under the runtime environment and is a
 * constant in runtime.
 */
let TUNABLE_FLAG_DEFAULT_VALUE_MAP;

let enableTrackingController;
let scoreThresholdController;

const stringValueMap = {};

export async function setupDatGui(urlParams) {
  const gui = new dat.GUI({width: 300});
  gui.domElement.id = 'gui';

  // The camera folder contains options for video settings.
  const cameraFolder = gui.addFolder('Camera');
  const fpsController = cameraFolder.add(params.STATE.camera, 'targetFPS');
  fpsController.onFinishChange((_) => {
    params.STATE.isTargetFPSChanged = true;
  });
  const sizeController = cameraFolder.add(
      params.STATE.camera, 'sizeOption', Object.keys(params.VIDEO_SIZE));
  sizeController.onChange(_ => {
    params.STATE.isSizeOptionChanged = true;
  });
  cameraFolder.open();

  // The model folder contains options for model selection.
  const modelFolder = gui.addFolder('Model');

  const model = urlParams.get('model');
  let type = urlParams.get('type');

  switch (model) {
    case 'posenet':
      params.STATE.model = posedetection.SupportedModels.PoseNet;
      break;
    case 'movenet':
      params.STATE.model = posedetection.SupportedModels.MoveNet;
      if (type !== 'lightning' && type !== 'thunder' && type !== 'multipose') {
        // Nulify invalid value.
        type = null;
      }
      break;
    case 'blazepose':
      params.STATE.model = posedetection.SupportedModels.BlazePose;
      if (type !== 'full' && type !== 'lite' && type !== 'heavy') {
        // Nulify invalid value.
        type = null;
      }
      break;
    default:
      alert(`${urlParams.get('model')}`);
      break;
  }

  const modelController = modelFolder.add(
      params.STATE, 'model', Object.values(posedetection.SupportedModels));

  modelController.onChange(_ => {
    params.STATE.isModelChanged = true;
    showModelConfigs(modelFolder);
    showBackendConfigs(backendFolder);
  });

  showModelConfigs(modelFolder, type);

  modelFolder.open();

  const backendFolder = gui.addFolder('Backend');

  showBackendConfigs(backendFolder);

  backendFolder.open();

  return gui;
}

async function showBackendConfigs(folderController) {
  // Clean up backend configs for the previous model.
  const fixedSelectionCount = 0;
  while (folderController.__controllers.length > fixedSelectionCount) {
    folderController.remove(
        folderController
            .__controllers[folderController.__controllers.length - 1]);
  }
  const backends = params.MODEL_BACKEND_MAP[params.STATE.model];
  // The first element of the array is the default backend for the model.
  params.STATE.backend = backends[0];
  const backendController =
      folderController.add(params.STATE, 'backend', backends);
  backendController.name('runtime-backend');
  backendController.onChange(async backend => {
    params.STATE.isBackendChanged = true;
    await showFlagSettings(folderController, backend);
  });
  await showFlagSettings(folderController, params.STATE.backend);
}

function showModelConfigs(folderController, type) {
  // Clean up model configs for the previous model.
  // The first constroller under the `folderController` is the model
  // selection.
  const fixedSelectionCount = 1;
  while (folderController.__controllers.length > fixedSelectionCount) {
    folderController.remove(
        folderController
            .__controllers[folderController.__controllers.length - 1]);
  }

  switch (params.STATE.model) {
    case posedetection.SupportedModels.PoseNet:
      addPoseNetControllers(folderController);
      break;
    case posedetection.SupportedModels.MoveNet:
      addMoveNetControllers(folderController, type);
      break;
    case posedetection.SupportedModels.BlazePose:
      addBlazePoseControllers(folderController, type);
      break;
    default:
      alert(`Model ${params.STATE.model} is not supported.`);
  }
}

// The PoseNet model config folder contains options for PoseNet config
// settings.
function addPoseNetControllers(modelConfigFolder) {
  params.STATE.modelConfig = {...params.POSENET_CONFIG};

  modelConfigFolder.add(params.STATE.modelConfig, 'maxPoses', [1, 2, 3, 4, 5]);
  modelConfigFolder.add(params.STATE.modelConfig, 'scoreThreshold', 0, 1);
}

// The MoveNet model config folder contains options for MoveNet config
// settings.
function addMoveNetControllers(modelConfigFolder, type) {
  params.STATE.modelConfig = {...params.MOVENET_CONFIG};
  params.STATE.modelConfig.type = type != null ? type : 'lightning';

  // Set multipose defaults on initial page load.
  if (params.STATE.modelConfig.type === 'multipose') {
    params.STATE.modelConfig.enableTracking = true;
    params.STATE.modelConfig.scoreThreshold = 0.2;
  }

  const typeController = modelConfigFolder.add(
      params.STATE.modelConfig, 'type', ['lightning', 'thunder', 'multipose']);
  typeController.onChange(type => {
    // Set isModelChanged to true, so that we don't render any result during
    // changing models.
    params.STATE.isModelChanged = true;
    if (type === 'multipose') {
      // Defaults to enable tracking for multi pose.
      if (enableTrackingController) {
        enableTrackingController.setValue(true);
      }
      // Defaults to a lower scoreThreshold for multi pose.
      if (scoreThresholdController) {
        scoreThresholdController.setValue(0.2);
      }
    } else {
      enableTrackingController.setValue(false);
    }
  });

  const customModelController =
      modelConfigFolder.add(params.STATE.modelConfig, 'customModel');
  customModelController.onFinishChange(_ => {
    params.STATE.isModelChanged = true;
  });

  scoreThresholdController =
      modelConfigFolder.add(params.STATE.modelConfig, 'scoreThreshold', 0, 1);

  enableTrackingController = modelConfigFolder.add(
      params.STATE.modelConfig,
      'enableTracking',
  );
  enableTrackingController.onChange(_ => {
    // Set isModelChanged to true, so that we don't render any result during
    // changing models.
    params.STATE.isModelChanged = true;
  })
}

// The BlazePose model config folder contains options for BlazePose config
// settings.
function addBlazePoseControllers(modelConfigFolder, type) {
  params.STATE.modelConfig = {...params.BLAZEPOSE_CONFIG};
  params.STATE.modelConfig.type = type != null ? type : 'full';

{'fraction_non_alphanumeric': 0.11976090014064697, 'fraction_numerical': 0.004008438818565401, 'mean_word_length': 3.828862478777589, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4327268', 'n_tokens_mistral': 4033, 'n_tokens_neox': 3964, 'n_words': 1027}