Home Manual Reference Source

src/api/challenges/choice/recognition.js

/**
 * This file contains the readily available functions which interact with the
 * ITSLanguage choice recognition API.
 *
 * Speech recognitions can be stored and retrieved for user submitted audio using the ITSLanguage
 * Speech API. The actual recognitions are performed by the ITSLanguage websocket server.
 *
 * For streaming, note that this is one of the "nested" or "composite" APIs; You can only obtain the
 * data if you provide a reference to the challenge for which you want a recording.
 */

import {
  encodeAndSendAudioOnDataAvailible,
  prepareServerForAudio, waitForUserMediaApproval
} from '../../utils/audio-over-socket';
import {authorisedRequest} from '../../communication';
import {makeWebsocketCall} from '../../communication/websocket';

const url = challengeId => `/challenges/choice/${challengeId}/recognitions`;

/**
 * Get all Choice Recognitions for a specific Choice Challenge.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/api/recognitions/index.html#list-choice-recognitions
 * @param {string} challengeId - ID of the Choice Challenge to get all the recognitions for.
 * @returns {Promise} - Promise with the Choice Recognitions as result if successful.
 */
export function getAllChoiceRecognitions(challengeId) {
  return authorisedRequest('GET', `${url(challengeId)}`);
}

/**
 * Get a single ChoiceRecognition by its ID.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/api/recognitions/index.html#get-a-single-choice-recognition
 * @param {string} challengeId - ID of the Choice Challenge to get all the recognitions for.
 * @param {string} id - ID of the choice recognition to get.
 * @returns {Promise} - Promise with the Choice Recognition as result if successful.
 */
export function getChoiceRecognitionByID(challengeId, id) {
  return authorisedRequest('GET', `${url(challengeId)}/${id}`);
}

/**
 * Submit an audio fragment for recognition. The recognition is created for the current
 * authenticated user.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/api/recognitions/index.html#create-a-choice-recognition
 * @param {string} challengeId - The ID of the challenge to relate the recognition to.
 * @param {Blob} audio - The actual audio.
 * @param {string} recognised - The recognised string.
 * @param {string} [recognitionId=null] - Unique identifier for the recognition. If none is given,
 *                                        one is generated.
 * @returns {Promise} - The created recognition with an url to download the audio if needed.
 */
export function createChoiceRecognition(challengeId, audio, recognised, recognitionId = null) {
  return authorisedRequest(
    'POST',
    `${url(challengeId)}/${recognitionId && recognitionId}`,
    {
      audio,
      recognised
    }
  );
}

/**
 * This is the starting point for a choice recognition. A unique recognition id is generated,
 * which serves a leading role in the recognition. Each other call requires the recognition id
 * as a parameter.
 *
 * If other RPCs are called without this RPC being called first, the error
 * `nl.itslanguage.session_not_initialised` will be returned.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/websocket/choice_recognitions/index.html#initialising-a-choice-recognition
 * @returns {Promise} - Returns a promise. When successfully the ID of the recognition is returned.
 */
export function prepareChoiceRecognition() {
  return makeWebsocketCall('choice.init_recognition');
}

/**
 * Before performing the recognition, a WFST needs to be prepared for the challenge. When the RPC is
 * called, the challenge is initialised asynchronously. When the challenge is to be used, the server
 * automatically waits for the challenge initialisation to finish. If the initialisation results in
 * an error, the error is relayed to the client.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/websocket/choice_recognitions/index.html#initialise-choice-challenge
 * @param {string} recognitionId - The ID of the recognition to prepare the challenge for.
 * @param {string} challengeId - The ID of the challenge to prepare.
 * @returns {Promise} - If succesful the promise returns nothing. On error, there will be an error.
 */
export function prepareChoiceRecognitionChallenge(recognitionId, challengeId) {
  return makeWebsocketCall('choice.init_challenge', {args: [recognitionId, challengeId]});
}

/**
 * The audio that is to be uploaded for recognition is streamed to the server. Some information is
 * required in order for the server to be able to store and use the audio correctly.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/websocket/choice_recognitions/index.html#initialising-audio-for-uploading
 * @param {string} recognitionId - The ID of the recognition to initialise the audio for.
 * @param {Recorder} recorder - Instance of a recorder. The metadata will be extracted elsewhere.
 * @returns {Promise} - If it fails an error will be returned. Otherwise nothing will be returned.
 */
export function prepareAudioForChoiceRecognition(recognitionId, recorder) {
  return prepareServerForAudio(recognitionId, recorder, 'choice.init_audio');
}

/**
 * The streaming works by repeatedly calling this RPC. Each time the RPC is called, the data will be
 * appended to an audio file on the server.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/websocket/choice_recognitions/index.html#stream-recognition-audio
 * @param {string} recognitionId - The ID of the recognition for which to upload audio.
 * @param {Recorder} recorder - Instance of a recorder. The data will be fetched from it.
 * @returns {Promise} - If it fails an error will be returned. Otherwise there will be no result.
 */
export function writeAudioForChoiceRecognition(recognitionId, recorder) {
  return encodeAndSendAudioOnDataAvailible(recognitionId, recorder, 'choice.write');
}

/**
 * After completing the streaming of the audio, the recognition can be performed.
 *
 * @see https://itslanguage.github.io/itslanguage-docs/websocket/choice_recognitions/index.html#perform-the-recognition
 * @param {string} recognitionId - The ID of the recognition to recognise on.
 * @param {Function} progressCb - A function that could be called if progressed results are required.
 * @returns {Promise.<Object>} - It will return a object with the recognition result if successful.
 */
export function recogniseChoiceRecognition(recognitionId, progressCb) {
  return makeWebsocketCall('choice.recognise', {args: [recognitionId], progressCb});
}

/**
 * Expose easy way to run the choice challenge in one go.
 *
 * @param {string} challengeId - The ID of the challenge for the choice recognition.
 * @param {Recorder} recorder - Audio Recorder instance.
 * @param {Function} progressCb - Callback function to call if progressed results are being used.
 * @returns {Promise} - If all good the result will have the recognition performed. Otherwise it
 *                      will return an error.
 */
export function performChoiceRecognition(challengeId, recorder, progressCb) {
  return prepareChoiceRecognition()
    .then(recognitionId =>
      prepareChoiceRecognitionChallenge(recognitionId, challengeId)
        .then(waitForUserMediaApproval(recognitionId, recorder))
        .then(prepareAudioForChoiceRecognition(recognitionId, recorder))
        .then(writeAudioForChoiceRecognition(recognitionId, recorder))
        .then(recogniseChoiceRecognition(recognitionId, progressCb))
    );
}

/*
 * below is some code for the new streaming yet to come.
 *
 * export function prepareAudioStream(recognitionId, recorder) {
 *   const rpc = 'choise.chuck';
 *   return registerAudioStream(recorder, rpc)
 *     .then(() => makeWebsocketCall('choice.recognise', {args: [recognitionId, rpc]}));
 * }
 */