JSFiddle - React, Tailwind, and code Playground

by morphcast

HTML

<script src="https://ai-sdk.morphcast.com/v1.8.5/ai-sdk.js"></script>
<body>
    <div class="row">
      <canvas id="canvas" class="col-md-8"></canvas>
      <br />
      <button id="start" onclick="onStart()" disabled>Start</button>
      <button id="stop" onclick="onStop()">Stop</button>
      <div class="col-md-4">
        <div style="height:25em;">
          <strong>Mood detection with MorphCast SDK</strong>
          <div id="debug" style="word-wrap:break-word;"></div>
          <h1><div id="av_results" style="word-wrap:break-word;"></div></h1>
      </div>
    </div>
    <div>
      <div>
        <strong>DETECTOR LOG MSGS</strong>
      </div>
      <div id="logs"></div>
      <h3>MorphCast JS SDK detects different mood cards.</h3>
      <p>
        <strong>Instructions</strong>
        <br/>
        Press the start button to start the detector.
        <br/> When a card is detected, the name of the card is written above.
        <br/> Press the stop button to end the detector.
      </p>
    </div>
  </div>
</body>

JavaScript

// Begin of mood detection code

/**
 * Represents a point in 2D dimensions (Arousal and Valence)
 */
class AVPoint {
  constructor(arousal, valence) {
    this.arousal = arousal;
    this.valence = valence;
  }

  distanceTo(point) {
    return Math.sqrt(Math.pow(this.arousal - point.arousal, 2) + Math.pow(this.valence - point.valence, 2));
  }

  toString() {
    return '( A: ' + this.arousal + ', V: ' + this.valence + ')';
  }
}

/**
 * Class for processing AVPoints and estimating moods
 */
class MoodEstimator {
  constructor() {
    this.last_result = null;
    this.same_results = 0;
  }

  static get MIN_STABLE_SAMPLES() {
    return 10;
  }

  static get MIN_DISTANCE() {
    return 0.1;
  }

  static get AVAILABLE_MOODS() {
    return {
      frustrated: new AVPoint(0.01, -0.13),
      excited: new AVPoint(0.13, 0.14),
      sad: new AVPoint(-0.07, -0.13),
      satisfied: new AVPoint(-0.08, 0.07)
    };
  }


  /**
   * Estimate the current mood, after receiving several samples of AVPoints
   * @param sample AVPoint detected
   * @returns {{result: (null|*), is_stable: boolean}} an object with the estimated mood, or null if the new result is not stable yet
   */
  processNext(sample) {
    const {best_mood, min_distance} = MoodEstimator.findBest(sample);
    if (this.last_result && this.last_result === best_mood) {
      this.same_results++;
    } else {
      this.last_result = best_mood;
      this.same_results = 0;
    }
    const is_stable_result = this.last_result && this.same_results >= MoodEstimator.MIN_STABLE_SAMPLES;

    console.log("[DEBUG] min_distance: " + min_distance.toFixed(3) + " ( < " + MoodEstimator.MIN_DISTANCE
      + "); same_results: " + this.same_results + " ( >= " + MoodEstimator.MIN_STABLE_SAMPLES + ")");

    return {
        result: this.last_result,
        is_stable: !!is_stable_result
    }
  }

  static findBest(sample, threshold = MoodEstimator.MIN_DISTANCE) {
    let best_mood = null, min_distance = +Infinity;

    const...