DongyoungKwon

Add WebSpeech API && Sentence-Similarity API

# Teleprompter-SST
<!-- TABLE OF CONTENTS -->
## Table of Contents
- [ν”„λ‘œμ νŠΈ μ†Œκ°œ](#ν”„λ‘œμ νŠΈ-μ†Œκ°œ)
- [μ£Όμš”κΈ°λŠ₯](#μ£Όμš”κΈ°λŠ₯)
- [Directory ꡬ쑰](#directory-ꡬ쑰)
- [μ„€μΉ˜ 방법](#μ„€μΉ˜-방법)
- [νŒ€μ›](#νŒ€μ›)
- [Reference](#reference)
- [License](#license)
### ν”„λ‘œμ νŠΈ μ†Œκ°œ
- πŸŽ™ μŒμ„±μ— 맞좰 λŒ€λ³Έμ„ 화면에 μ‹€μ‹œκ°„μœΌλ‘œ 좜λ ₯ν•˜λŠ” 프둬프터 μ„œλΉ„μŠ€ πŸ“œ
<!-- ν”„λ‘œμ νŠΈ μ†Œκ°œ -->
## πŸŽ™ ν”„λ‘œμ νŠΈ μ†Œκ°œ
---
- μŒμ„±μ— 맞좰 λŒ€λ³Έμ„ 화면에 μ‹€μ‹œκ°„μœΌλ‘œ 좜λ ₯ν•˜λŠ” 프둬프터 μ„œλΉ„μŠ€
- Untactμ‹œλŒ€μ— ν™”μƒνšŒμ˜μ—μ„œ νŽΈν•˜κ²Œ λ°œν‘œν•  수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” μ„œλΉ„μŠ€
<br />
<!-- μ£Όμš”κΈ°λŠ₯ -->
## πŸ“œ μ£Όμš”κΈ°λŠ₯
---
- [**Web Speech API**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API) && [**string-similarity API**](https://www.npmjs.com/package/) μ‚¬μš©
- Real-time Script Output
<br />
<!-- Directory ꡬ쑰 -->
## πŸ—‚ Directory ꡬ쑰
---
```bash
Teleprompter-SST
β”œβ”€β”€ client ---> Front-end
β”‚ β”œβ”€β”€ public ---> 정적 파일 보관
β”‚ β”‚ β”œβ”€β”€ favicon.ico
β”‚ β”‚ β”œβ”€β”€ index.html
β”‚ β”‚ β”œβ”€β”€ manifest.json
β”‚ β”‚ └── robots.txt
β”‚ β”œβ”€β”€ src
β”‚ β”‚ β”œβ”€β”€ components
β”‚ β”‚ β”‚ └── Teleprompter.js ---> μŒμ„±μΈμ‹ && λ¬Έμž₯μœ μ‚¬λ„ μˆ˜ν–‰
β”‚ β”‚ β”œβ”€β”€ pages
β”‚ β”‚ β”‚ β”œβ”€β”€ MainPage.js ---> 메인 ν™”λ©΄
β”‚ β”‚ β”‚ └── PrompterPage.js ---> λŒ€λ³Έ 좜λ ₯ ν™”λ©΄
β”‚ β”‚ β”œβ”€β”€ App.css
β”‚ β”‚ β”œβ”€β”€ App.js ---> Router
β”‚ β”‚ β”œβ”€β”€ App.test.js
β”‚ β”‚ β”œβ”€β”€ index.css
β”‚ β”‚ β”œβ”€β”€ index.js
β”‚ β”‚ β”œβ”€β”€ reportWebVitals.js
β”‚ β”‚ β”œβ”€β”€ serviceWorker.js
β”‚ β”‚ β”œβ”€β”€ setupTests.js
β”‚ β”‚ └── styles.js ---> PrompterPage.js Style
β”‚ β”œβ”€β”€ .gitignore
β”‚ β”œβ”€β”€ package-lock.json
β”‚ β”œβ”€β”€ package.json
β”‚ └── yarn.lock
β”‚
β”œβ”€β”€ .gitignore
β”œβ”€β”€ LICENSE ---> MIT License
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ README.md
β”œβ”€β”€ server.js ---> Back-end
└── yarn.lock
```
<br />
<!-- μ„€μΉ˜ 방법 -->
## ⌨️ μ„€μΉ˜ 방법
---
### μ£Όμš”κΈ°λŠ₯
- Google Speech-to-Text API && ADAMS.ai λ¬Έμž₯ μœ μ‚¬λ„ API μ‚¬μš©
- Real-time Script Output
#### client 폴더 이동
`$ cd Teleprompter-SST/client`
### νŒ€μ›
- κΆŒλ™μ˜ (2016110307)
#### package.json에 λͺ…μ‹œλœ λͺ¨λ“ˆ μ„€μΉ˜
`$ npm install`
#### Teleprompter-SST 폴더 이동
`$ cd ..`
#### package.json에 λͺ…μ‹œλœ λͺ¨λ“ˆ μ„€μΉ˜
`$ npm install`
#### μ‹œμž‘
`$ npm run dev`
#### Local Address 접속
`http://localhost:3000`
<!-- νŒ€μ› -->
## πŸ§‘β€πŸ’» νŒ€μ›
---
- κΆŒλ™μ˜ (2016110307)
- 김닀솔 (2017110268)
#### Start
- `$ yarn global add create-react-app`
- `$ create-react-app teleprompt-sst`
- `$ yarn add @material-ui/core`
\ No newline at end of file
<!-- document -->
## πŸ“‹ Reference
---
- [**Web Speech API**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API)
- [**string-similarity API**](https://www.npmjs.com/package/)
<!-- license -->
## πŸ“‹ License
---
Teleprompter-SST is [MIT licensed](./LICENSE).
<br></br>
[πŸ‘†Back To The Top](#Teleprompter-SST)
\ No newline at end of file
......
This diff could not be displayed because it is too large.
......@@ -11,7 +11,9 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
"react-scripts": "^4.0.1",
"string-similarity": "^4.0.3",
"styled-components": "^5.2.1",
"web-vitals": "^0.2.4"
},
"scripts": {
......
......@@ -9,35 +9,12 @@
name="description"
content="Web site created using create-react-app"
/>
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>프둬프터 μ„œλΉ„μŠ€</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
......
......@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import MainPage from './pages/MainPage';
import PrompterPage from './pages/PrompterPage';
// import test from './pages/test';
class App extends Component {
render() {
......@@ -9,6 +10,7 @@ class App extends Component {
<>
<Route path="/" component={MainPage} exact={true} />
<Route path="/prompter" component={PrompterPage} exact={true} />
{/* <Route path="/prompter" component={test} exact={true} /> */}
</>
);
}
......
import React from 'react'
import styled from 'styled-components'
import stringSimilarity from 'string-similarity'
const StyledTeleprompter = styled.div`
font-size: 9rem;
width: 100%;
height: 56rem;
scroll-behavior: smooth;
overflow: scroll;
display: block;
margin-bottom: 1rem;
`
// Userκ°€ μ§€κΈˆ λ§ν•˜κ³  μžˆλŠ” 단어 style
const Interim = styled.div`
background: rgb(0, 0, 0, 0.25);
color: white;
flex: 0 0 auto;
padding: 0.5rem;
border-radius: 1rem;
display: inline-block;
`
// Script λ¬Έμžμ—΄ 처리 ["I", "am", "happy"] -> "iamhappy"
const onlyWord = (word) =>
word
.trim() // λ¬Έμžμ—΄ μ’Œμš°μ—μ„œ 곡백 제거
.toLocaleLowerCase() // μ•ŒνŒŒλ²³ μ†Œλ¬Έμžλ‘œ λ³€ν™˜
.replace(/[^κ°€-νž£γ„±-γ…Žγ…-γ…£a-z]/gi, '') // μ •κ·œμ‹μ„ μ΄μš©ν•΄ ν•œκΈ€ λ˜λŠ” μ•ŒνŒŒλ²³μ΄ μ•„λ‹Œ 문자 빈칸으둜 λ³€ν™˜
export default function Teleprompter({ words, progress, listening, onChange }) {
const recog = React.useRef(null)
const scrollRef = React.useRef(null)
const [ results, setResults ] = React.useState('')
React.useEffect(() => {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition
recog.current = new SpeechRecognition()
recog.current.continuous = true
recog.current.interimResults = true
}, [])
React.useEffect(() => {
if (listening) {
recog.current.start()
}
else {
recog.current.stop()
}
}, [listening])
React.useEffect(() => {
const handleResult = ({ results }) => {
const interim = Array.from(results)
.filter(r => !r.isFinal)
.map(r => r[0].transcript)
.join(' ')
setResults(interim)
const newIndex = interim
.split(' ')
.reduce((memo, word) => {
if ( memo >= words.length) {
return memo
}
const similarity = stringSimilarity.compareTwoStrings(
onlyWord(word),
onlyWord(words[memo])
)
memo +=
similarity > 0.3 // μœ μ‚¬λ„ 민감도 μ„€μ •
? 1
: 0
return memo
}, progress)
if ( newIndex > progress && newIndex <= words.length ) {
onChange(newIndex)
}
}
recog.current.addEventListener(
'result',
handleResult
)
return () => {
recog.current.removeEventListener(
'result',
handleResult
)
}
}, [onChange, progress, words])
React.useEffect(() => {
/* eslint-disable no-unused-expressions */
scrollRef.current
.querySelector(
`[data-index='${
progress + 8 // ν˜„μž¬ μ§„ν–‰ μƒνƒœμ— 따라 Scroll μ„€μ •
}']`
)
?.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'start'
})
}, [progress])
return (
<>
<StyledTeleprompter ref={scrollRef}>
{words.map((word, i) => (
<span
key={`${word}:${i}`}
data-index={i}
style={{
color:
i < progress
? '#000' // 아직 읽지 μ•Šμ€ wordλŠ” 흰색
: '#ccc' // 읽은 wordλŠ” κ²€μ€μƒ‰μœΌλ‘œ λ³€κ²½
}}
>
{word}{' '}
</span>
))}
</StyledTeleprompter>
{results && ( <Interim>{results}</Interim> )}
</>
)
}
\ No newline at end of file
......@@ -14,17 +14,3 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
\ No newline at end of file
/* body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
} */
......
import React, { Component, Fragment } from 'react';
import React, { Fragment } from 'react';
import axios from 'axios'
import {
GlobalStyles,
StyledApp,
StyledTeleprompter as Teleprompter,
Controls,
Buttons,
Button,
} from "../styles";
// import { withStyles, Typography, Paper, Button, TextField} from '@material-ui/core';
// const styles = theme => ({
......@@ -30,17 +39,57 @@ import React, { Component, Fragment } from 'react';
// },
// });
class PrompterPage extends Component {
// const INITIAL_TEXT = ``;
function PrompterPage() {
const [listening, setListening] = React.useState(false);
const [words, setWords] = React.useState("".split(" "));
// const [words, setWords] = React.useState("");
const [progress, setProgress] = React.useState(0);
// Serverλ‘œλΆ€ν„° Script λ°›μ•„μ˜΄
axios.get("api/script")
.then(res => { // .then : 응닡(μƒνƒœμ½”λ“œ200~300미만)μ„±κ³΅μ‹œ
console.log(res.data);
setWords(res.data.split(" ")); // λ°›μ•„μ˜¨ Script λ¬Έμžμ—΄ 처리
})
.catch(error => {
console.log(error);
});
// const handleInput = (e) => {
// setWords(e.target.value.split(" "));
// progress && setProgress(0);
// };
const handleListening = () => {
if (listening) {
setListening(false);
} else {
setProgress(0);
setListening(true);
}
};
const handleReset = () => setProgress(0);
const handleChange = (progress) => setProgress(progress);
render() {
// const { classes } = this.props;
return (
<Fragment>
<h1>{this.props.script}</h1>
</Fragment>
<>
<GlobalStyles />
<StyledApp>
<Controls>
<Buttons>
<Button onClick={handleListening}>{listening ? "Stop" : "Start"}</Button>
<Button onClick={handleReset} disabled={listening} secondary>Reset</Button>
</Buttons>
</Controls>
<Teleprompter words={words} listening={listening} progress={progress} onChange={handleChange} />
</StyledApp>
</>
);
}
}
// export default withStyles(styles)(PrompterPage);
export default PrompterPage;
\ No newline at end of file
......
import styled, { createGlobalStyle, css } from "styled-components";
import Teleprompter from "./components/Teleprompter";
export const GlobalStyles = createGlobalStyle`
* {
box-sizing: border-box;
}
html,
body,
#root {
height: 100%;
font-family: sans-serif;
margin: 0;
overflow: hidden;
background: #282828;
}
`;
export const StyledApp = styled.div`
font-family: sans-serif;
text-align: center;
height: 100%;
height: 100vh;
margin: 1rem;
`;
export const StyledTeleprompter = styled(Teleprompter)`
display: flex;
flex-direction: column;
justify-content: space-around;
height: 100%;
`;
export const Controls = styled.div`
display: flex;
flex-direction: column;
margin-bottom: 1rem;
`;
export const Buttons = styled.div`
display: flex;
justify-content: flex-start;
`;
export const Input = styled.textarea`
height: 5rem;
border: 1px solid rgb(0, 0, 0, 0.25);
padding: 0.5rem;
font-family: Tahoma, sans-serif;
background: transparent;
margin-bottom: 1rem;
width: 100%;
`;
export const Button = styled.button`
display: inline-block;
border: none;
padding: 0.5rem 1rem;
margin: 0;
text-decoration: none;
background: #666ba5;
border: 1px solid rgb(0, 0, 0, 0.25);
color: white;
font-size: 1rem;
cursor: pointer;
text-align: center;
transition: background 250ms ease-in-out, transform 150ms ease;
margin-right: 1rem;
min-width: 5rem;
${(p) =>
p.secondary &&
css`
background: #666;
`}
&:last-child {
margin-right: 0;
}
&:hover,
&:focus {
transform: scale(1.1);
}
&:focus {
outline: 1px solid #fff;
}
&:active {
transform: scale(0.99);
}
`;
......@@ -67,7 +67,7 @@
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.10.4":
"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
......@@ -1116,6 +1116,21 @@
globals "^11.1.0"
lodash "^4.17.19"
"@babel/traverse@^7.4.5":
version "7.12.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.9.tgz#fad26c972eabbc11350e0b695978de6cc8e8596f"
integrity sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/generator" "^7.12.5"
"@babel/helper-function-name" "^7.10.4"
"@babel/helper-split-export-declaration" "^7.11.0"
"@babel/parser" "^7.12.7"
"@babel/types" "^7.12.7"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.19"
"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
version "7.12.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13"
......@@ -1153,6 +1168,28 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/is-prop-valid@^0.8.8":
version "0.8.8"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
dependencies:
"@emotion/memoize" "0.7.4"
"@emotion/memoize@0.7.4":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
"@emotion/stylis@^0.8.4":
version "0.8.5"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
"@emotion/unitless@^0.7.4":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@eslint/eslintrc@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.1.tgz#f72069c330461a06684d119384435e12a5d76e3c"
......@@ -2654,6 +2691,21 @@ babel-plugin-named-asset-import@^0.3.7:
resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz#156cd55d3f1228a5765774340937afc8398067dd"
integrity sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==
"babel-plugin-styled-components@>= 1":
version "1.12.0"
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz#1dec1676512177de6b827211e9eda5a30db4f9b9"
integrity sha512-FEiD7l5ZABdJPpLssKXjBUJMYqzbcNzBowfXDCdJhOpbhWiewapUaY+LZGT8R4Jg2TwOjGjG4RKeyrO5p9sBkA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
"@babel/helper-module-imports" "^7.0.0"
babel-plugin-syntax-jsx "^6.18.0"
lodash "^4.17.11"
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
......@@ -3130,6 +3182,11 @@ camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
camelize@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
......@@ -3682,6 +3739,11 @@ css-blank-pseudo@^0.1.4:
dependencies:
postcss "^7.0.5"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
css-color-names@0.0.4, css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
......@@ -3753,6 +3815,15 @@ css-select@^2.0.0:
domutils "^1.7.0"
nth-check "^1.0.2"
css-to-react-native@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756"
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
postcss-value-parser "^4.0.2"
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
......@@ -5539,7 +5610,7 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2:
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
......@@ -9235,7 +9306,7 @@ react-router@5.2.0:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-scripts@4.0.1:
react-scripts@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-4.0.1.tgz#34974c0f4cfdf1655906c95df6a04d80db8b88f0"
integrity sha512-NnniMSC/wjwhcJAyPJCWtxx6CWONqgvGgV9+QXj1bwoW/JI++YF1eEf3Upf/mQ9KmP57IBdjzWs1XvnPq7qMTQ==
......@@ -9998,6 +10069,11 @@ shallow-clone@^3.0.0:
dependencies:
kind-of "^6.0.2"
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
......@@ -10361,6 +10437,11 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
string-similarity@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.3.tgz#ef52d6fc59c8a0fc93b6307fbbc08cc6e18cde21"
integrity sha512-QEwJzNFCqq+5AGImk5z4vbsEPTN/+gtyKfXBVLBcbPBRPNganZGfQnIuf9yJ+GiwSnD65sT8xrw/uwU1Q1WmfQ==
string-width@^3.0.0, string-width@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
......@@ -10500,6 +10581,22 @@ style-loader@1.3.0:
loader-utils "^2.0.0"
schema-utils "^2.7.0"
styled-components@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.2.1.tgz#6ed7fad2dc233825f64c719ffbdedd84ad79101a"
integrity sha512-sBdgLWrCFTKtmZm/9x7jkIabjFNVzCUeKfoQsM6R3saImkUnjx0QYdLwJHBjY9ifEcmjDamJDVfknWm1yxZPxQ==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/traverse" "^7.4.5"
"@emotion/is-prop-valid" "^0.8.8"
"@emotion/stylis" "^0.8.4"
"@emotion/unitless" "^0.7.4"
babel-plugin-styled-components ">= 1"
css-to-react-native "^3.0.0"
hoist-non-react-statics "^3.0.0"
shallowequal "^1.1.0"
supports-color "^5.5.0"
stylehacks@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
......@@ -10509,7 +10606,7 @@ stylehacks@^4.0.0:
postcss "^7.0.0"
postcss-selector-parser "^3.0.0"
supports-color@^5.3.0:
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
......
This diff is collapsed. Click to expand it.
......@@ -16,8 +16,7 @@
"license": "MIT",
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"multer": "^1.4.2"
"express": "^4.17.1"
},
"devDependencies": {
"concurrently": "^5.3.0",
......
......@@ -7,39 +7,14 @@ const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
// const data = fs.readFileSync('./database.json');
// const conf = JSON.parse(data);
// const mysql = require('mysql');
const multer = require('multer');
// app.get('/api/customers', (req, res) => {
// connection.query(
// "SELECT * FROM course",
// (err, rows, fields) => {
// res.send(rows);
// }
// );
// });
// app.get('/api/customers/:id', (req, res) => {
// let sql = 'SELECT * FROM course WHERE id=?';
// let params = [req.params.id];
// connection.query(sql, params,
// (err, rows, fields) => {
// res.send(rows);
// }
// );
// });
let scriptReceived = "";
app.get('/api/script', (req, res) => {
res.send(
scriptReceived
)
});
app.post('/api/script', (req, res) => {
scriptReceived = req.body.script;
});
......
  • λ³€κ²½ 사항

    1. PrompterPage κ΅¬ν˜„ μ™„λ£Œ
      • Material-Ui 적용 μ˜ˆμ •
    2. WebSpeech API && Sentence-Similarity API μ‚¬μš©ν•˜μ—¬ μ£Όμš” κΈ°λŠ₯ μ™„μ„±
      • μ’€ 더 λ§€λ„λŸ½κ²Œ μ§„ν–‰ν•˜κ³ μž μ•Œκ³ λ¦¬μ¦˜ μˆ˜μ • μ˜ˆμ •
    3. README.md μˆ˜μ •ν–ˆμœΌλ‚˜ GitHUB와 GitLAB의 문법 차이둜 μ΄μƒν•˜κ²Œ ν‘œμ‹œ
      • λ‹€μŒ Commit에 μˆ˜μ • μ˜ˆμ •
    Edited