-
Notifications
You must be signed in to change notification settings - Fork 17
コンポーネント分割 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+187
−104
Merged
コンポーネント分割 #1
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
d963cbf
refactor: 💡 Add notice component
yoidea 306e7bd
refactor: 💡 Add upload button component
yoidea 04c0146
feat: 🎸 Add tag field component
yoidea 5a18fbf
refactor: 💡 Add transcript component
yoidea 9d10a47
fix: 🐛 Extend multi type file
yoidea 8ec1e02
refactor: 💡 Add comment
yoidea 929e9ad
style: 💄 Format
yoidea 85f1cc4
fix: 🐛 Fix Audio place
yoidea 3ee56be
style: 💄 Format
yoidea File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import React from "react"; | ||
| import Snackbar from "@material-ui/core/Snackbar"; | ||
| import MuiAlert from "@material-ui/lab/Alert"; | ||
| import { bool, node, string, func } from "prop-types"; | ||
|
|
||
| const Notice = props => ( | ||
| <Snackbar open={props.open} autoHideDuration={6000} onClose={props.onClose}> | ||
| <MuiAlert | ||
| elevation={6} | ||
| variant="filled" | ||
| onClose={props.onClose} | ||
| severity={props.severity} | ||
| > | ||
| {props.children} | ||
| </MuiAlert> | ||
| </Snackbar> | ||
| ); | ||
|
|
||
| Notice.propTypes = { | ||
| open: bool, | ||
| severity: string, | ||
| onClose: func, | ||
| children: node | ||
| }; | ||
|
|
||
| export default Notice; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import React from "react"; | ||
| import Chip from "@material-ui/core/Chip"; | ||
| import Autocomplete from "@material-ui/lab/Autocomplete"; | ||
| import TextField from "@material-ui/core/TextField"; | ||
| import { bool, func, array, string } from "prop-types"; | ||
|
|
||
| const TagField = props => ( | ||
| <Autocomplete | ||
| disabled={props.disabled} | ||
| multiple | ||
| id="tags-filled" | ||
| options={props.options} | ||
| freeSolo | ||
| defaultValue={props.defaultValue} | ||
| onChange={(event, values) => { | ||
| props.onTagChange(values); | ||
| }} | ||
| renderTags={(value, getTagProps) => | ||
| value.map((option, index) => ( | ||
| <Chip variant="outlined" label={option} {...getTagProps({ index })} /> | ||
| )) | ||
| } | ||
| renderInput={params => { | ||
| return ( | ||
| <TextField | ||
| {...params} | ||
| variant="outlined" | ||
| label={props.label} | ||
| placeholder={props.placeholder} | ||
| /> | ||
| ); | ||
| }} | ||
| /> | ||
| ); | ||
|
|
||
| TagField.propTypes = { | ||
| options: array, | ||
| defaultValue: array, | ||
| disabled: bool, | ||
| onTagChange: func, | ||
| label: string, | ||
| placeholder: string | ||
| }; | ||
|
|
||
| export default TagField; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import React from "react"; | ||
| import { bool, string } from "prop-types"; | ||
|
|
||
| const TranscriptField = props => ( | ||
| <p> | ||
| {props.finalText} | ||
| <span style={{ color: props.isMatch ? "#f00" : "#aaa" }}> | ||
| {props.transcript} | ||
| </span> | ||
| </p> | ||
| ); | ||
|
|
||
| TranscriptField.propTypes = { | ||
| isMatch: bool, | ||
| finalText: string, | ||
| transcript: string | ||
| }; | ||
|
|
||
| export default TranscriptField; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import React from "react"; | ||
| import IconButton from "@material-ui/core/IconButton"; | ||
| import LibraryMusicIcon from "@material-ui/icons/LibraryMusic"; | ||
| import { bool, func, string } from "prop-types"; | ||
|
|
||
| const UploadButton = props => ( | ||
| <div> | ||
| <input | ||
| accept={`${props.fileType}/*`} | ||
| id="file-input" | ||
| multiple | ||
| type="file" | ||
| style={{ display: "none" }} | ||
| onChange={event => { | ||
| const file = event.target.files[0]; | ||
| if (!(file instanceof File)) return; | ||
| if (file.type.indexOf(props.fileType) === -1) { | ||
| props.onInvalidFileError(); | ||
| return; | ||
| } | ||
| props.onFileChange(file); | ||
| }} | ||
| /> | ||
| <label htmlFor="file-input"> | ||
| <IconButton | ||
| color="primary" | ||
| size="large" | ||
| disabled={props.disabled} | ||
| aria-label="upload audio" | ||
| component="span" | ||
| > | ||
| <LibraryMusicIcon /> | ||
| </IconButton> | ||
| </label> | ||
| </div> | ||
| ); | ||
|
|
||
| UploadButton.propTypes = { | ||
| onFileChange: func, | ||
| onInvalidFileError: func, | ||
| fileType: string, | ||
| disabled: bool | ||
| }; | ||
|
|
||
| export default UploadButton; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,41 @@ | ||
| import React, { useState, useEffect, useRef } from "react"; | ||
| import Link from "next/link"; | ||
| import Head from "../components/head"; | ||
| import Container from "@material-ui/core/Container"; | ||
| import Chip from "@material-ui/core/Chip"; | ||
| import Autocomplete from "@material-ui/lab/Autocomplete"; | ||
| import TextField from "@material-ui/core/TextField"; | ||
| import Snackbar from "@material-ui/core/Snackbar"; | ||
| import MuiAlert from "@material-ui/lab/Alert"; | ||
| import Box from "@material-ui/core/Box"; | ||
| import Grid from "@material-ui/core/Grid"; | ||
| import Button from "@material-ui/core/Button"; | ||
| import IconButton from "@material-ui/core/IconButton"; | ||
| import LibraryMusicIcon from "@material-ui/icons/LibraryMusic"; | ||
| import Notice from "../components/notice"; | ||
| import UploadButton from "../components/uploadButton"; | ||
| import TagField from "../components/tagField"; | ||
| import TranscriptField from "../components/transcriptField"; | ||
|
|
||
| const Home = () => { | ||
| // 音声認識インスタンス | ||
| const recognizerRef = useRef(); | ||
| const inputRef = useRef(); | ||
| const [finalText, setFinalText] = useState(""); | ||
| const [transcript, setTranscript] = useState("ボタンを押して検知開始"); | ||
| const initialTagValues = ["年収"]; | ||
| const [tagValues, setTagValues] = useState(initialTagValues); | ||
| const [detecting, setDetecting] = useState(false); | ||
| const candidates = ["年収", "自由", "成功"]; | ||
| const [alertOpen, setAlertOpen] = useState(false); | ||
| const [fileLoaded, setFileLoaded] = useState(false); | ||
| const [userMusic, setUserMusic] = useState(null); | ||
| const [userMusicName, setUserMusicName] = useState(""); | ||
| // スナックバー表示 | ||
| const [alertOpen, setAlertOpen] = useState(false); // 自慢検知アラート | ||
| const [fileLoaded, setFileLoaded] = useState(false); // ファイル読み込み完了 | ||
| // 音声認識 | ||
| const [detecting, setDetecting] = useState(false); // 音声認識ステータス | ||
| const [finalText, setFinalText] = useState(""); // 確定された文章 | ||
| const [transcript, setTranscript] = useState("ボタンを押して検知開始"); // 認識中の文章 | ||
| // 単語検知 | ||
| const initialTagValues = ["年収"]; // デフォルト検知単語 | ||
| const candidates = ["年収", "自由", "成功"]; // 検知単語候補 | ||
| const [tagValues, setTagValues] = useState(initialTagValues); // 検知単語一覧 | ||
| // 効果音 | ||
| const [userMusic, setUserMusic] = useState(null); // ユーザー追加音 | ||
| const [userMusicName, setUserMusicName] = useState(""); // ファイル名 | ||
|
|
||
| useEffect(() => { | ||
| const music = new Audio("/static/warning01.mp3"); | ||
| const music = new Audio("/static/warning01.mp3"); // デフォルト音 | ||
| // NOTE: Web Speech APIが使えるブラウザか判定 | ||
| // https://developer.mozilla.org/ja/docs/Web/API/Web_Speech_API | ||
| if (!window.SpeechRecognition && !window.webkitSpeechRecognition) { | ||
| alert("お使いのブラウザには未対応です"); | ||
| return; | ||
| } | ||
| // NOTE: 将来的にwebkit prefixが取れる可能性があるため | ||
| const SpeechRecognition = | ||
| window.SpeechRecognition || window.webkitSpeechRecognition; | ||
| recognizerRef.current = new SpeechRecognition(); | ||
|
|
@@ -49,12 +52,15 @@ const Home = () => { | |
| [...event.results].slice(event.resultIndex).forEach(result => { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const transcript = result[0].transcript; | ||
| if (result.isFinal) { | ||
| // 音声認識が完了して文章が確定 | ||
| setFinalText(prevState => { | ||
| return prevState + transcript; | ||
| }); | ||
| setTranscript(""); | ||
| } else { | ||
| // 音声認識の途中経過 | ||
| if (tagValues.some(value => transcript.includes(value))) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 認識した文章に検知する単語が含まれていれば |
||
| // NOTE: ユーザーが効果音を追加しなければデフォルトを鳴らす | ||
| (userMusic || music).play(); | ||
| setAlertOpen(true); | ||
| } | ||
|
|
@@ -66,124 +72,66 @@ const Home = () => { | |
|
|
||
| return ( | ||
| <div> | ||
| <Head title="Home" /> | ||
| <Snackbar | ||
| <Head title="自慢ディテクター" /> | ||
| <Notice | ||
| open={alertOpen} | ||
| autoHideDuration={6000} | ||
| severity="error" | ||
| onClose={() => { | ||
| setAlertOpen(false); | ||
| }} | ||
| > | ||
| <MuiAlert | ||
| elevation={6} | ||
| variant="filled" | ||
| onClose={() => { | ||
| setAlertOpen(false); | ||
| }} | ||
| severity="error" | ||
| > | ||
| 自慢を検知しました | ||
| </MuiAlert> | ||
| </Snackbar> | ||
| <Snackbar | ||
| 自慢を検知しました | ||
| </Notice> | ||
| <Notice | ||
| open={fileLoaded} | ||
| autoHideDuration={6000} | ||
| severity="success" | ||
| onClose={() => { | ||
| setFileLoaded(false); | ||
| }} | ||
| > | ||
| <MuiAlert | ||
| elevation={6} | ||
| variant="filled" | ||
| onClose={() => { | ||
| setFileLoaded(false); | ||
| }} | ||
| severity="success" | ||
| > | ||
| {userMusicName}を読み込みました | ||
| </MuiAlert> | ||
| </Snackbar> | ||
| {userMusicName}を読み込みました | ||
| </Notice> | ||
| <Container> | ||
| <Grid container alignItems="center" justify="center"> | ||
| <Grid item> | ||
| <img src="/static/logo.png" height="200px" /> | ||
| <img src="/static/logo.png" height="200px" alt="自慢ディテクター" /> | ||
| </Grid> | ||
| </Grid> | ||
| <Box fontSize={25}> | ||
| <p> | ||
| {finalText} | ||
| <span style={{ color: alertOpen ? "#f00" : "#aaa" }}> | ||
| {transcript} | ||
| </span> | ||
| </p> | ||
| <div id="result-div"></div> | ||
| <TranscriptField | ||
| finalText={finalText} | ||
| transcript={transcript} | ||
| isMatch={alertOpen} | ||
| /> | ||
| </Box> | ||
| <Grid container spacing={2}> | ||
| <Grid item xs={11}> | ||
| <Autocomplete | ||
| <TagField | ||
| disabled={detecting} | ||
| multiple | ||
| id="tags-filled" | ||
| options={candidates} | ||
| freeSolo | ||
| defaultValue={initialTagValues} | ||
| onChange={(event, values) => { | ||
| label="反応する単語" | ||
| placeholder="単語を追加 +" | ||
| onTagChange={values => { | ||
| setTagValues(values); | ||
| }} | ||
| renderTags={(value, getTagProps) => | ||
| value.map((option, index) => ( | ||
| <Chip | ||
| variant="outlined" | ||
| label={option} | ||
| {...getTagProps({ index })} | ||
| /> | ||
| )) | ||
| } | ||
| renderInput={params => { | ||
| return ( | ||
| <TextField | ||
| {...params} | ||
| variant="outlined" | ||
| label="反応する単語" | ||
| placeholder="単語を追加 +" | ||
| /> | ||
| ); | ||
| }} | ||
| /> | ||
| </Grid> | ||
| <Grid item> | ||
| <input | ||
| ref={inputRef} | ||
| accept="audio/*" | ||
| id="file-input" | ||
| multiple | ||
| type="file" | ||
| style={{ display: "none" }} | ||
| onChange={event => { | ||
| const file = event.target.files[0]; | ||
| if (!(file instanceof File)) return; | ||
| if (file.type.indexOf("audio") === -1) { | ||
| alert("オーディオファイルを選択してください"); | ||
| return; | ||
| } | ||
| <UploadButton | ||
| disabled={detecting} | ||
| fileType="audio" | ||
| onFileChange={file => { | ||
| const src = window.URL.createObjectURL(file); | ||
| const audio = new Audio(src); | ||
| setUserMusic(audio); | ||
| setUserMusicName(file.name); | ||
| setFileLoaded(true); | ||
| }} | ||
| onInvalidFileError={() => { | ||
| alert("オーディオファイルを選択してください"); | ||
| }} | ||
| /> | ||
| <label htmlFor="file-input"> | ||
| <IconButton | ||
| color="primary" | ||
| size="large" | ||
| disabled={detecting} | ||
| aria-label="upload audio" | ||
| component="span" | ||
| > | ||
| <LibraryMusicIcon /> | ||
| </IconButton> | ||
| </label> | ||
| </Grid> | ||
| </Grid> | ||
| <Box m={2}> | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
デプロイ時に
Audioインスタンスでエラーが出たから、useEffect内に含めて必ずクライアントのみで実行するようにした。