<commit_before>import EventDispatcher from './common/event-dispatcher';
import WakeWordRecogniser from './wakeword/recogniser';
import SpeechRecogniser from './speech/recogniser';
import SpeechSynthesis from './speech/synthesis';
import IntentParser from './intent-parser/index';

const p = Object.freeze({
  // Properties
  wakewordRecogniser: Symbol('wakewordRecogniser'),
  speechRecogniser: Symbol('speechRecogniser'),
  speechSynthesis: Symbol('speechSynthesis'),
  idle: Symbol('idle'),

  // Methods
  stopListeningForWakeword: Symbol('stopListeningForWakeword'),
  listenForUtterance: Symbol('listenForUtterance'),
  handleSpeechRecognitionEnd: Symbol('handleSpeechRecognitionEnd'),
  intentParser: Symbol('intentParser'),
});

const EVENT_INTERFACE = [
  // Emit when the wakeword is being listened for
  'wakelistenstart',

  // Emit when the wakeword is no longer being listened for
  'wakelistenstop',

  // Emit when the wakeword is heard
  'wakeheard',

  // Emit when the speech recognition engine starts listening
  // (And _could_ be sending speech over the network)
  'speechrecognitionstart',

  // Emit when the speech recognition engine returns a recognised phrase
  'speechrecognitionstop',

  // Emit when an intent is successfully parsed and we have a reminder object.
  'reminder',

  // Emit when a reminder could not be parsed from a text.
  'parsing-failed',
];

export default class SpeechController extends EventDispatcher {
  constructor() {
    super(EVENT_INTERFACE);

    this[p.idle] = true;

    this[p.speechRecogniser] = new SpeechRecogniser();
    this[p.speechSynthesis] = new SpeechSynthesis();
    this[p.wakewordRecogniser] = new WakeWordRecogniser();
    this[p.intentParser] = new IntentParser();

    this[p.wakewordRecogniser].setOnKeywordSpottedCallback(() => {
      this.emit(EVENT_INTERFACE[2], { type: EVENT_INTERFACE[2] });

      this.startSpeechRecognition();
    });

    Object.seal(this);
  }

  get idle() {
    return this[p.idle];
  }

  start() {
    return this.startListeningForWakeword();
  }

  startSpeechRecognition() {
    this[p.idle] = false;

    return this[p.stopListeningForWakeword]()
      .then(this[p.listenForUtterance].bind(this))
      .then(this[p.handleSpeechRecognitionEnd].bind(this))
      .catch((err) => {
        console.log('startSpeechRecognition err', err);
        this.emit(EVENT_INTERFACE[4], { type: EVENT_INTERFACE[4] });
      });
  }

  stopSpeechRecognition() {
    return this[p.speechRecogniser].abort()
      .then(this.startListeningForWakeword.bind(this));
  }

  /**
   * Speak a text aloud.
   *
   * @param {string} text
   * @return {Promise} A promise that resolves when the utterance is finished.
   */<commit_msg>On speech recognition failure, restart the wakelisten after emitting an event r=gmarty (#100)<commit_after>import EventDispatcher from './common/event-dispatcher';
import WakeWordRecogniser from './wakeword/recogniser';
import SpeechRecogniser from './speech/recogniser';
import SpeechSynthesis from './speech/synthesis';
import IntentParser from './intent-parser/index';

const p = Object.freeze({
  // Properties
  wakewordRecogniser: Symbol('wakewordRecogniser'),
  speechRecogniser: Symbol('speechRecogniser'),
  speechSynthesis: Symbol('speechSynthesis'),
  idle: Symbol('idle'),

  // Methods
  stopListeningForWakeword: Symbol('stopListeningForWakeword'),
  listenForUtterance: Symbol('listenForUtterance'),
  handleSpeechRecognitionEnd: Symbol('handleSpeechRecognitionEnd'),
  intentParser: Symbol('intentParser'),
});

const EVENT_INTERFACE = [
  // Emit when the wakeword is being listened for
  'wakelistenstart',

  // Emit when the wakeword is no longer being listened for
  'wakelistenstop',

  // Emit when the wakeword is heard
  'wakeheard',

  // Emit when the speech recognition engine starts listening
  // (And _could_ be sending speech over the network)
  'speechrecognitionstart',

  // Emit when the speech recognition engine returns a recognised phrase
  'speechrecognitionstop',

  // Emit when an intent is successfully parsed and we have a reminder object.
  'reminder',

  // Emit when a reminder could not be parsed from a text.
  'parsing-failed',
];

export default class SpeechController extends EventDispatcher {
  constructor() {
    super(EVENT_INTERFACE);

    this[p.idle] = true;

    this[p.speechRecogniser] = new SpeechRecogniser();
    this[p.speechSynthesis] = new SpeechSynthesis();
    this[p.wakewordRecogniser] = new WakeWordRecogniser();
    this[p.intentParser] = new IntentParser();

    this[p.wakewordRecogniser].setOnKeywordSpottedCallback(() => {
      this.emit(EVENT_INTERFACE[2], { type: EVENT_INTERFACE[2] });

      this.startSpeechRecognition();
    });

    Object.seal(this);
  }

  get idle() {
    return this[p.idle];
  }

  start() {
    return this.startListeningForWakeword();
  }

  startSpeechRecognition() {
    this[p.idle] = false;

    return this[p.stopListeningForWakeword]()
      .then(this[p.listenForUtterance].bind(this))
      .then(this[p.handleSpeechRecognitionEnd].bind(this))
      .catch((err) => {
        console.log('startSpeechRecognition err', err);
        this.emit(EVENT_INTERFACE[4], { type: EVENT_INTERFACE[4] });
        this.stopSpeechRecognition();
      });
  }

  stopSpeechRecognition() {
    return this[p.speechRecogniser].abort()
      .then(this.startListeningForWakeword.bind(this));
  }

  /**
   * Speak a text aloud.
   *
   * @param {string} text
   * @return {Promise} A promise that resolves when the utterance is finished.
   */
{'fraction_non_alphanumeric': 0.11867145421903053, 'fraction_numerical': 0.0019748653500897668, 'mean_word_length': 4.078395624430264, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3689362', 'n_tokens_mistral': 1780, 'n_tokens_neox': 1675, 'n_words': 403}