Skip to content

Commit

Permalink
Speech to text input (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
kycarr authored Feb 13, 2024
1 parent cd422cc commit 1c57b3e
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 4 deletions.
2 changes: 2 additions & 0 deletions client/gatsby-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The full terms of this copyright and license should always be found in the root
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/

import "regenerator-runtime/runtime";

import wrapWithProvider from "./wrap-with-provider";

import { loadSentry } from "./src/utils";
Expand Down
13 changes: 11 additions & 2 deletions client/gatsby-ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ Permission to use, copy, modify, and distribute this software and its documentat
The full terms of this copyright and license should always be found in the root directory of this software deliverable as "license.txt" and if these terms are not found with this software, please contact the USC Stevens Center for the full license.
*/
/**
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
* Implement Gatsby's Browser APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/ssr-apis/
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/

import "regenerator-runtime/runtime";

import wrapWithProvider from "./wrap-with-provider";

import { loadSentry } from "./src/utils";

if (process.env.GATSBY_IS_SENTRY_ENABLED === "true") {
console.log("Loading sentry");
loadSentry();
}

export const wrapRootElement = wrapWithProvider;
25 changes: 25 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"react-redux": "^7.2.9",
"react-resize-detector": "^7.1.2",
"react-scroll": "^1.8.9",
"react-speech-recognition": "^3.10.0",
"redux": "^4.1.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.4.2",
Expand All @@ -45,6 +46,7 @@
"@types/react-dom": "^17.0.18",
"@types/react-redux": "^7.1.25",
"@types/react-scroll": "^1.8.6",
"@types/react-speech-recognition": "^3.9.5",
"@types/smoothscroll-polyfill": "^0.3.1",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^4.29.1",
Expand Down
54 changes: 52 additions & 2 deletions client/src/components/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,24 @@ The full terms of this copyright and license should always be found in the root
*/
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Button, Divider, Paper, InputBase } from "@mui/material";
import SpeechRecognition, {
useSpeechRecognition,
} from "react-speech-recognition";
import {
Button,
Divider,
Paper,
InputBase,
InputAdornment,
IconButton,
} from "@mui/material";
import { Mic, MicOutlined } from "@mui/icons-material";
import SendRoundedIcon from "@mui/icons-material/SendRounded";
import { makeStyles } from "tss-react/mui";

import { sendQuestion, userInputChanged } from "store/actions";
import { Config, MentorQuestionSource, QuestionInput, State } from "types";
import { isMobile } from "react-device-detect";
import SendRoundedIcon from "@mui/icons-material/SendRounded";

import "styles/layout.css";
import { useWithScreenOrientation } from "use-with-orientation";
Expand Down Expand Up @@ -65,6 +76,13 @@ function Input(): JSX.Element {
(s) => s.questionInput
);
const { displayFormat } = useWithScreenOrientation();
const {
transcript,
listening,
browserSupportsSpeechRecognition,
resetTranscript,
} = useSpeechRecognition();
const [stt, setSTT] = React.useState<string>("");

const [animatingInputField, setAnimatingInputField] =
useState<boolean>(false);
Expand All @@ -75,6 +93,13 @@ function Input(): JSX.Element {
: setAnimatingInputField(true);
}, [questionInput]);

useEffect(() => {
onQuestionInputChanged(
questionInput.question + transcript.substr(stt.length)
);
setSTT(transcript);
}, [transcript]);

function handleQuestionChanged(
question: string,
source: MentorQuestionSource
Expand Down Expand Up @@ -114,6 +139,18 @@ function Input(): JSX.Element {
onQuestionInputSend();
}

function toggleSTT() {
if (listening) {
SpeechRecognition.stopListening();
resetTranscript();
setSTT("");
} else {
resetTranscript();
setSTT("");
SpeechRecognition.startListening();
}
}

// Input field keyboard was lowered
const onBlur = () => {
if (isMobile) {
Expand Down Expand Up @@ -147,6 +184,19 @@ function Input(): JSX.Element {
onClick={onQuestionInputSelected}
onBlur={onBlur}
onKeyPress={onKeyPress}
startAdornment={
browserSupportsSpeechRecognition ? (
<InputAdornment position="start">
<IconButton color="primary" edge="end" onClick={toggleSTT}>
{listening ? (
<Mic color="secondary" />
) : (
<MicOutlined color="primary" />
)}
</IconButton>
</InputAdornment>
) : undefined
}
/>
<Divider className={classes.divider} />
<Button
Expand Down

0 comments on commit 1c57b3e

Please sign in to comment.