Merge branch 'queueingmp3' into 'master'
Add: 음성 재생 작업 Queue, Add: Cloud Infra, Dockerize 어제 회의에서 얘기 나눴던 대로 음성이 중복해서 계속 재생되는 것이 아닌 Queueing 방식을 이용해 하나씩 재생할 수 있도록 수정했습니다. local에서 docker build 하는 방법을 작성했습니다. EC2 Server에서도 docker-compose up까지는 동작하도록 해놨으니, 마무리 통합 과정만 거치면 될 듯 합니다. See merge request !16
Showing
7 changed files
with
103 additions
and
34 deletions
... | @@ -4,10 +4,6 @@ khuwitch는 다국어 번역 지원하며, 이를 음성으로도 들을 수 있 | ... | @@ -4,10 +4,6 @@ khuwitch는 다국어 번역 지원하며, 이를 음성으로도 들을 수 있 |
4 | 4 | ||
5 | khuwitch를 이용하면 채널 관리자는 자신의 채널의 외국어 채팅을 한국어로 바로 번역해 볼 수 있고, 필요한 경우 이를 음성파일로 변환하여 재생한 뒤 시청자들에게 송출할 수도 있습니다. | 5 | khuwitch를 이용하면 채널 관리자는 자신의 채널의 외국어 채팅을 한국어로 바로 번역해 볼 수 있고, 필요한 경우 이를 음성파일로 변환하여 재생한 뒤 시청자들에게 송출할 수도 있습니다. |
6 | 6 | ||
7 | -## 아키텍쳐 | ||
8 | - | ||
9 | -> 추후 추가 예정 | ||
10 | - | ||
11 | ## 사용되는 API | 7 | ## 사용되는 API |
12 | 8 | ||
13 | * [Papago 언어 감지 API](https://developers.naver.com/docs/papago/papago-detectlangs-overview.md) | 9 | * [Papago 언어 감지 API](https://developers.naver.com/docs/papago/papago-detectlangs-overview.md) |
... | @@ -15,6 +11,11 @@ khuwitch를 이용하면 채널 관리자는 자신의 채널의 외국어 채 | ... | @@ -15,6 +11,11 @@ khuwitch를 이용하면 채널 관리자는 자신의 채널의 외국어 채 |
15 | * [Twitch Authentication API](https://dev.twitch.tv/docs/authentication) | 11 | * [Twitch Authentication API](https://dev.twitch.tv/docs/authentication) |
16 | * [Twitch Chatbot API](https://dev.twitch.tv/docs/irc) | 12 | * [Twitch Chatbot API](https://dev.twitch.tv/docs/irc) |
17 | 13 | ||
14 | + | ||
15 | +## 아키텍쳐 | ||
16 | + | ||
17 | +![infra.png](infra.png) | ||
18 | + | ||
18 | ## 사용된 기술 및 동작 방법 | 19 | ## 사용된 기술 및 동작 방법 |
19 | 20 | ||
20 | khuwitch는 크게 아래의 항목들로 동작한다고 볼 수 있습니다. | 21 | khuwitch는 크게 아래의 항목들로 동작한다고 볼 수 있습니다. |
... | @@ -31,44 +32,48 @@ khuwitch는 크게 아래의 항목들로 동작한다고 볼 수 있습니다. | ... | @@ -31,44 +32,48 @@ khuwitch는 크게 아래의 항목들로 동작한다고 볼 수 있습니다. |
31 | 3. 채팅 메시지가 외국어인 경우 Papago의 번역 API를 이용해 내용을 번역한 뒤 채팅으로 번역 내용을 전송하고, socket io를 통해 현재 khuwith 서비스에 접속 중인 사용자에게도 번역 내용을 전송합니다. | 32 | 3. 채팅 메시지가 외국어인 경우 Papago의 번역 API를 이용해 내용을 번역한 뒤 채팅으로 번역 내용을 전송하고, socket io를 통해 현재 khuwith 서비스에 접속 중인 사용자에게도 번역 내용을 전송합니다. |
32 | 4. frontend에서는 수신한 text를 `AWS Polly` 를 이용해 음성 파일로 변환한 뒤, 접속자의 브라우저에서 재생합니다. | 33 | 4. frontend에서는 수신한 text를 `AWS Polly` 를 이용해 음성 파일로 변환한 뒤, 접속자의 브라우저에서 재생합니다. |
33 | 34 | ||
34 | -## 빌드 및 실행 방법 | 35 | +## 빌드 및 배포 방법 |
35 | 36 | ||
36 | -> 추후 보완 예정 | 37 | +우선은 docker-compose를 이용해 서버에서 실행할 것이기 때문에 이미지 빌드를 위해 docker를 설치해야하고, 서버에는 docker와 docker-compose를 설치해야합니다. |
37 | 38 | ||
38 | -### local에서 실행하기 | 39 | +### 빌드 |
39 | - | ||
40 | -**frontend** | ||
41 | 40 | ||
41 | +frontend를 예시로하겠습니다. backend의 경우 `frontend` 를 `server`로 변경하면 됩니다. | ||
42 | ```bash | 42 | ```bash |
43 | -$ PORT=8000 npm start | 43 | +# docker 설치 후 |
44 | +$ cd frontend | ||
45 | +$ docker build . -t umi0410/khuwitch-frontend | ||
46 | +$ docker push umi0410/khuwitch-frontend | ||
44 | ``` | 47 | ``` |
45 | 48 | ||
46 | -**backend** | 49 | +### 배포 |
50 | + | ||
51 | +배포는 frontend든 backend든 상관없이 docker-compose로 한 번에 배포합니다. 빌드 때와 마찬가지로 docker를 설치해주시고, 추가적으로 docker-compose를 설치한 뒤 서비스를 구동시킵니다. | ||
47 | ```bash | 52 | ```bash |
48 | -$ KHUWITCH_PORT=3000 npm start | 53 | +# 서버 접속 후 docker 설치 후 docker-compose 설치 |
54 | +$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | ||
55 | +$ sudo chmod +x /usr/local/bin/docker-compose | ||
56 | +$ curl http://khuhub.khu.ac.kr/2016101168/khuwitch/raw/queueingmp3/docker-compose.yml -o /tmp/docker-compose.yml | ||
57 | +$ sudo docker-compose pull && sudo docker-compose /tmp/docker-compose.yml up -d # or docker-compose up -d | ||
49 | ``` | 58 | ``` |
50 | 59 | ||
51 | -### docker image 빌드 후 docker-compose로 실행 | 60 | +### 개발을 위해 실행하기 |
52 | - | ||
53 | -**frontend 빌드** | ||
54 | 61 | ||
55 | -```bash | 62 | +**frontend** |
56 | -$ docker build -f Dockerfile-frontend -t khuwitch/frontend | ||
57 | -``` | ||
58 | 63 | ||
59 | -**backend 빌드** | ||
60 | ```bash | 64 | ```bash |
61 | -$ docker build -f Dockerfile-backend -t khuwitch/backend | 65 | +$ cd frontend |
66 | +$ npm install | ||
67 | +$ PORT=8000 npm start | ||
62 | ``` | 68 | ``` |
63 | 69 | ||
64 | -**docker-compose로 실행** | 70 | +**backend** |
65 | - | ||
66 | ```bash | 71 | ```bash |
67 | -$ docker-compose -f docker-compose.yml -f docker-compose-dev.yml up | 72 | +$ cd server |
73 | +$ npm install | ||
74 | +$ npm start | ||
68 | ``` | 75 | ``` |
69 | 76 | ||
70 | -기본적 설정으로 존재하는 `docker-compose.yml` 에 추가적인 내용을 담은 `docker-compose-{{NAME}}.yml` 을 전달함으로써 설정을 Override할 수 있습니다. | ||
71 | - | ||
72 | ## 사용 방법 | 77 | ## 사용 방법 |
73 | 78 | ||
74 | _로그인 화면 추후 추가.png_ | 79 | _로그인 화면 추후 추가.png_ | ... | ... |
docker-compose.yml
0 → 100644
frontend/Dockerfile
0 → 100644
1 | +# docker build . -t umi0410/khuwitch-react | ||
2 | +# docker push umi0410/khuwitch-react | ||
3 | +FROM node:13 | ||
4 | +COPY node_modules node_modules | ||
5 | +COPY package.json package.json | ||
6 | +RUN npm i | ||
7 | +COPY . . | ||
8 | +ENV PORT 8000 | ||
9 | +ENTRYPOINT ["npm"] | ||
10 | +CMD ["start"] | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -8,6 +8,9 @@ import { WatchOutlined } from "@material-ui/icons"; | ... | @@ -8,6 +8,9 @@ import { WatchOutlined } from "@material-ui/icons"; |
8 | import io from 'socket.io-client' | 8 | import io from 'socket.io-client' |
9 | import tts from './tts'; | 9 | import tts from './tts'; |
10 | 10 | ||
11 | +// audioQueue에서 하나씩 뽑아서 재생한다. | ||
12 | +tts.enableAudio() | ||
13 | + | ||
11 | const socket = io.connect("http://localhost:3303") | 14 | const socket = io.connect("http://localhost:3303") |
12 | socket.on("connect", event=>{ | 15 | socket.on("connect", event=>{ |
13 | // 테스트용으로 umi0410에게 입장. | 16 | // 테스트용으로 umi0410에게 입장. |
... | @@ -19,7 +22,8 @@ socket.on("connect", event=>{ | ... | @@ -19,7 +22,8 @@ socket.on("connect", event=>{ |
19 | socket.on('chat message', (name, msg)=>{ | 22 | socket.on('chat message', (name, msg)=>{ |
20 | console.log(msg) | 23 | console.log(msg) |
21 | console.log("got message") | 24 | console.log("got message") |
22 | - tts.speak(msg) | 25 | + //tts를 audio로 변경해 audioQueue에 집어넣는다. |
26 | + tts.enqueueTTS(msg) | ||
23 | }) | 27 | }) |
24 | 28 | ||
25 | // 해당 채널을 재생하고자할 때 실행시켜주세요. | 29 | // 해당 채널을 재생하고자할 때 실행시켜주세요. | ... | ... |
... | @@ -7,7 +7,29 @@ const polly = new AWS.Polly({ | ... | @@ -7,7 +7,29 @@ const polly = new AWS.Polly({ |
7 | region: 'ap-northeast-2', | 7 | region: 'ap-northeast-2', |
8 | }); | 8 | }); |
9 | 9 | ||
10 | -function speak(text){ | 10 | +const audioQueue = [] |
11 | +// test data | ||
12 | +// const audioQueue = ["https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3", "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3", "https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3"] | ||
13 | + | ||
14 | +const audio = new Audio() | ||
15 | + | ||
16 | +// queue에서 작업(재생할 내용)을 0.5초마다 폴링하는 방식 | ||
17 | +function enableAudio(){ | ||
18 | + setInterval(()=>{ | ||
19 | + // 앞선 tts 재생이 종료된 경우에만 새 tts를 실행 | ||
20 | + if( !audio.paused){ return;} | ||
21 | + | ||
22 | + let audioFile = audioQueue.shift() | ||
23 | + // 재생할 게 있으면 재생 | ||
24 | + if (audioFile){ | ||
25 | + console.log(audioFile) | ||
26 | + audio.setAttribute("src", audioFile) | ||
27 | + audio.play() | ||
28 | + } | ||
29 | + }, 500) | ||
30 | +} | ||
31 | + | ||
32 | +function enqueueTTS(text){ | ||
11 | let params = { | 33 | let params = { |
12 | 'Text': text, | 34 | 'Text': text, |
13 | 'OutputFormat': 'mp3', | 35 | 'OutputFormat': 'mp3', |
... | @@ -19,15 +41,22 @@ function speak(text){ | ... | @@ -19,15 +41,22 @@ function speak(text){ |
19 | tts.getSynthesizeSpeechUrl(params, function(error, url) { | 41 | tts.getSynthesizeSpeechUrl(params, function(error, url) { |
20 | if (error) { | 42 | if (error) { |
21 | } else { | 43 | } else { |
22 | - setTimeout(()=>{ | 44 | + audioQueue.push(url) |
23 | - console.log("실행") | ||
24 | - let audio = new Audio(url) | ||
25 | - audio.play() | ||
26 | - // .then(delete audio); | ||
27 | - }, 3000) | ||
28 | } | 45 | } |
29 | }) | 46 | }) |
30 | } | 47 | } |
48 | + | ||
49 | +console.log("테스트용 TTS 데이터를 주입합니다.") | ||
50 | +enqueueTTS(`전에 data hazards에서 3가지 data-dependence를 배웠다. mips인 경우에는 in-order이라 True data dependency 문제밖에 안생겼었다 | ||
51 | + | ||
52 | +근데 out-of-order 관점에서는 3개의 명령어가 동시에 fetch되는 경우를 생각해보자. | ||
53 | + | ||
54 | +만약 1, 3 line 순서 바뀌면 당연히 결과가 이상해진다. 전에 고려하지 못했던 output dependency 와 anti dependency 고려해줘야한다. `) | ||
55 | +enqueueTTS("복잡한 브랜치") | ||
56 | +enqueueTTS("빵상 아주머니는 말씀하셨다.") | ||
57 | +enqueueTTS("니가가라 하와이") | ||
58 | + | ||
31 | export default { | 59 | export default { |
32 | - "speak": speak, | 60 | + enableAudio, |
61 | + enqueueTTS, | ||
33 | } | 62 | } | ... | ... |
infra.png
0 → 100644
198 KB
server/Dockerfile
0 → 100644
1 | +# docker build . -t umi0410/khuwitch-express | ||
2 | +# docker push umi0410/khuwitch-express | ||
3 | +FROM node:13 | ||
4 | +COPY node_modules node_modules | ||
5 | +COPY package.json package.json | ||
6 | +RUN npm i | ||
7 | +COPY . . | ||
8 | +ENV PORT 3303 | ||
9 | +ENTRYPOINT ["npm"] | ||
10 | +CMD ["start"] | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment