Hone logo
Hone
Problems

Custom React Hook for Text-to-Speech Synthesis

This challenge asks you to build a custom React hook, useSpeechSynthesis, that encapsulates the functionality of the Web Speech API's Speech Synthesis. This hook will allow developers to easily integrate text-to-speech capabilities into their React applications, making content more accessible and engaging.

Problem Description

You need to create a reusable React hook named useSpeechSynthesis that provides an interface for controlling text-to-speech synthesis. The hook should abstract away the complexities of the SpeechSynthesis API, allowing users to speak text, control speaking, and get the current speaking status.

Key Requirements:

  • speak(text: string) function: A function to initiate speech synthesis for a given string of text.
  • cancel() function: A function to stop any ongoing speech synthesis.
  • isSpeaking boolean state: A state variable indicating whether speech synthesis is currently active.
  • Support for voices: The hook should ideally allow selecting a voice from available system voices.
  • Error handling: Basic error handling for cases where the Speech Synthesis API is not supported.

Expected Behavior:

When speak() is called with text, the hook should:

  1. Check if the browser supports speechSynthesis.
  2. Create a SpeechSynthesisUtterance object with the provided text.
  3. If voices are available, select a default or specified voice.
  4. Initiate speaking using window.speechSynthesis.speak().
  5. Update isSpeaking to true when speaking starts and false when it finishes or is cancelled.

When cancel() is called, the hook should:

  1. Stop any ongoing speech using window.speechSynthesis.cancel().
  2. Set isSpeaking to false.

Edge Cases to Consider:

  • Browser Support: The speechSynthesis API might not be available in all browsers or environments. The hook should gracefully handle this.
  • No Voices Available: Some systems might not have any speech synthesis voices installed.
  • Empty Text: What happens when speak() is called with an empty string?
  • Cancelling while not speaking: Calling cancel() when nothing is being spoken should not cause errors.

Examples

Example 1: Basic Usage

import React, { useEffect } from 'react';
import { useSpeechSynthesis } from './useSpeechSynthesis'; // Assuming hook is in this file

function App() {
  const { speak, cancel, isSpeaking } = useSpeechSynthesis();

  const handleSpeak = () => {
    speak('Hello, world!');
  };

  return (
    <div>
      <button onClick={handleSpeak} disabled={isSpeaking}>
        Speak
      </button>
      <button onClick={cancel} disabled={!isSpeaking}>
        Cancel
      </button>
      {isSpeaking && <p>Speaking...</p>}
    </div>
  );
}

export default App;

Explanation: The useSpeechSynthesis hook is called, returning speak, cancel, and isSpeaking. Clicking the "Speak" button calls speak('Hello, world!'), initiating text-to-speech. The "Cancel" button calls cancel(), stopping the speech. The isSpeaking state dynamically updates the UI.

Example 2: Handling Browser Incompatibility

import React from 'react';
import { useSpeechSynthesis } from './useSpeechSynthesis';

function App() {
  const { speak, cancel, isSpeaking, isSupported } = useSpeechSynthesis();

  if (!isSupported) {
    return <p>Speech synthesis is not supported in your browser.</p>;
  }

  return (
    <div>
      <button onClick={() => speak('This is a test.')} disabled={isSpeaking}>
        Speak
      </button>
      <button onClick={cancel} disabled={!isSpeaking}>
        Cancel
      </button>
    </div>
  );
}

export default App;

Explanation: The hook now also returns an isSupported boolean. If the browser doesn't support speechSynthesis, a message is displayed, and the buttons are not rendered.

Constraints

  • The solution must be implemented in TypeScript.
  • The hook should only rely on native browser APIs (SpeechSynthesis, SpeechSynthesisUtterance) and React hooks. No external libraries for speech synthesis are allowed.
  • The speak function should ideally handle basic text sanitization if necessary (though for this challenge, assume input text is valid for speech synthesis).
  • The isSpeaking state should update accurately based on the lifecycle of the speech synthesis process (start, end, cancellation).

Notes

  • You can access available voices via window.speechSynthesis.getVoices(). Note that these voices are often loaded asynchronously. You might need to listen for the voiceschanged event.
  • Consider how you will manage the SpeechSynthesisUtterance object within the hook's lifecycle.
  • Think about how to clean up any event listeners or prevent memory leaks when the component using the hook unmounts.
  • The initial implementation can focus on the core speak and cancel functionality, with optional enhancements for voice selection and more robust error handling.
Loading editor...
typescript