0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

見切り発車と2024の振り返りAdvent Calendar 2024

Day 7

見切り発車で平仮名の学習アプリを作る【7日目】

Posted at

2024年のアドベントカレンダー7日目の記事です。

わからないボタンクリックで問題文を読み上げたい

よめないひらがなが出てきたときに確認できるように読み上げ機能を作ります。
TTSの機能についてもweb speech apiのSpeechSynthesisUtteranceで用意されているため、こちらを利用することにしました。

わからないボタンをクリックしたときに呼び出せるように以下のようなメソッドを作成します。

App.js
  const speakText = (text) => {
    if (!('speechSynthesis' in window)) {
      alert('なんかだめみたい。おじさんにきいてみて');
      return;
    }
    
    const utterance = new SpeechSynthesisUtterance(text);
    utterance.lang = 'ja-JP';
    utterance.rate = 2;
    window.speechSynthesis.speak(utterance);
  }

utterance.lang = 'ja-JP';utterance.rate = 2;で言語、読み上げ速度の指定を入れた以外あまり労力なく読み上げ機能の作成ができました。

問題文自体はstate管理しているので上記で作成したメソッドに対してstateを渡すだけで読み上げが可能になりました。

App.js
import './App.css';
import { Provider } from './components/ui/provider';
import { Box, AbsoluteCenter, Heading, VStack, HStack } from '@chakra-ui/react';
import { useState, useRef } from 'react';
import { Button } from './components/ui/button';

function App() {
  const [question, setQuestion] = useState('あとですぷしからしゅとくするようにします');
  const [answer, setAnswer] = useState('ここがおんせいにゅうりょくでかわるところ');
  const [isRecording, setIsRecording] = useState(false);
  const recognitionRef = useRef(null);

  const startRecording = () => {
    if (!('webkitSpeechRecognition' in window)) {
      alert('なんかだめみたい。おじさんにきいてみて');
      return;
    }

    recognitionRef.current = new window.webkitSpeechRecognition();
    recognitionRef.current.lang = 'ja-JP';
    recognitionRef.current.continuous = false;
    recognitionRef.current.interimResults = false;

    recognitionRef.current.onstart = () => {
      setIsRecording(true);
    };

    recognitionRef.current.onresult = (event) => {
      const transcript = event.results[0][0].transcript;
      setAnswer(transcript);
    };

    recognitionRef.current.onerror = (event) => {
      console.error(event.error);
    };

    recognitionRef.current.onend = () => {
      setIsRecording(false);
    };

    recognitionRef.current.start();
  };

  const stopRecording = () => {
    if (recognitionRef.current) {
      recognitionRef.current.stop();
    }
  };

  const speakText = (text) => {
    if (!('speechSynthesis' in window)) {
      alert('なんかだめみたい。おじさんにきいてみて');
      return;
    }
    
    const utterance = new SpeechSynthesisUtterance(text);
    utterance.lang = 'ja-JP';
    utterance.rate = 2;
    window.speechSynthesis.speak(utterance);
  }

  return (
    <Provider>
      <Box bg="blue.100" w="100vw" h="100vh">
        <AbsoluteCenter>
          <VStack gap="20">
            <Heading size="5xl">
              {question}
            </Heading>
            <HStack gap="20">
              <Button size="2xl" variant="outline" borderColor="green.600" color="green.600" onClick={isRecording ? stopRecording : startRecording}>
                {isRecording ? "こたえた" : "こたえる"}
              </Button>
              <Button size="2xl" variant="outline" borderColor="orange.600" color="orange.600" onClick={() => speakText(question)}>
                わからない
              </Button>
            </HStack>
            <Heading size="5xl">
              {answer}
            </Heading>
          </VStack>
        </AbsoluteCenter>
      </Box>
    </Provider>
  );
}

export default App;

ファイルを分けずにApp.jsに詰め込んでいるのでどこかのタイミングで整理したいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?