이유혁

Project done

7.33 KB

...@@ -2,7 +2,6 @@ const express = require('express'); ...@@ -2,7 +2,6 @@ const express = require('express');
2 const config = require('./API_config'); 2 const config = require('./API_config');
3 const line = require('@line/bot-sdk'); 3 const line = require('@line/bot-sdk');
4 const request = require('request'); 4 const request = require('request');
5 -
6 const app = express(); 5 const app = express();
7 6
8 //번역 api_url 7 //번역 api_url
...@@ -11,6 +10,15 @@ const translate_api_url = 'https://openapi.naver.com/v1/papago/n2mt'; ...@@ -11,6 +10,15 @@ const translate_api_url = 'https://openapi.naver.com/v1/papago/n2mt';
11 //언어감지 api_url 10 //언어감지 api_url
12 const languagedetect_api_url = 'https://openapi.naver.com/v1/papago/detectLangs'; 11 const languagedetect_api_url = 'https://openapi.naver.com/v1/papago/detectLangs';
13 12
13 +// API_config.js 의 형태는 다음과 같다.
14 +// const client_id = 'xxxx';
15 +// const client_secret = 'xxxx';
16 +
17 +// const line_channel = {
18 +// channelAccessToken: 'xxxx',
19 +// channelSecret: 'xxxx',
20 +// };
21 +
14 // Naver Auth Key 22 // Naver Auth Key
15 //새로 발급받은 naver papago api id, pw 입력 23 //새로 발급받은 naver papago api id, pw 입력
16 const client_id = config.client_id; 24 const client_id = config.client_id;
...@@ -30,15 +38,19 @@ app.get('/', (req, res) => { ...@@ -30,15 +38,19 @@ app.get('/', (req, res) => {
30 38
31 // register a webhook handler with middleware 39 // register a webhook handler with middleware
32 app.post('/webhook', line.middleware(line_channel), (req, res) => { 40 app.post('/webhook', line.middleware(line_channel), (req, res) => {
33 - // webhook post 요청에 대해 promises를 전체 수행한다. 41 + // webhook 요청에 대해 순차적으로 다음을 수행한다.
34 // 전체 수행은 순차수행이기 때문에 동기처리 필요 => async await 패턴을 사용한다 42 // 전체 수행은 순차수행이기 때문에 동기처리 필요 => async await 패턴을 사용한다
35 const promises = req.body.events.map(async (event) => { 43 const promises = req.body.events.map(async (event) => {
44 + // 메세지의 속성을 확인하고 API connector를 만든다
36 let api_connector = await api_connect(event); 45 let api_connector = await api_connect(event);
46 + // connector를 통해 언어 감지, 번역 target 언어를 설정한다
37 let options = await option_maker(api_connector, event); 47 let options = await option_maker(api_connector, event);
48 + // 설정된 source 및 target으로 번역 결과를 저장한다
38 let result = await receive_result(options, event); 49 let result = await receive_result(options, event);
50 + // 모든 작업이 끝나면 client api를 통해 reply를 진행한다.
39 client.replyMessage(event.replyToken,result); 51 client.replyMessage(event.replyToken,result);
40 }) 52 })
41 - Promise 53 + Promise // promise all은 일괄 수행이 완료될 때 then이 수행된다
42 .all(promises) 54 .all(promises)
43 .then((result) => res.json(result)) 55 .then((result) => res.json(result))
44 .catch((err) => { 56 .catch((err) => {
...@@ -47,24 +59,24 @@ app.post('/webhook', line.middleware(line_channel), (req, res) => { ...@@ -47,24 +59,24 @@ app.post('/webhook', line.middleware(line_channel), (req, res) => {
47 }); 59 });
48 }); 60 });
49 61
50 -// 이벤트 타입 검사 이후
51 // language detector api url 및 client id, secret 을 담은 connector를 반환한다. 62 // language detector api url 및 client id, secret 을 담은 connector를 반환한다.
52 const api_connect = (event) => { 63 const api_connect = (event) => {
53 return new Promise((resolve, reject) => { 64 return new Promise((resolve, reject) => {
65 + // 이벤트 타입 검사
54 if (event.type !== 'message' || event.message.type !== 'text'){ 66 if (event.type !== 'message' || event.message.type !== 'text'){
55 - //언어 감지 option 67 + // 비정상에 대한 reject 처리
68 + reject(new Error('메세지 혹은, 텍스트가 아닙니다.'));
69 + } else {
70 + // 정상요청에 대한 connector 생성 및 resolve
56 resolve({ 71 resolve({
57 url : languagedetect_api_url, 72 url : languagedetect_api_url,
58 form : {'query': event.message.text}, 73 form : {'query': event.message.text},
59 headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret} 74 headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret}
60 }); 75 });
61 - } else {
62 - reject(new Error('메세지 혹은, 텍스트가 아닙니다.'));
63 } 76 }
64 }) 77 })
65 } 78 }
66 79
67 -
68 // post 요청으로 api connector를 이용해 language를 분석한 뒤 80 // post 요청으로 api connector를 이용해 language를 분석한 뒤
69 // source 및 target 설정, 번역 API url을 포함한 options을 반환한다 81 // source 및 target 설정, 번역 API url을 포함한 options을 반환한다
70 const option_maker = (api_connector, event) => { 82 const option_maker = (api_connector, event) => {
...@@ -73,26 +85,78 @@ const option_maker = (api_connector, event) => { ...@@ -73,26 +85,78 @@ const option_maker = (api_connector, event) => {
73 console.log(response.statusCode); 85 console.log(response.statusCode);
74 if(!error && response.statusCode == 200){ 86 if(!error && response.statusCode == 200){
75 let detect_body = JSON.parse(response.body); 87 let detect_body = JSON.parse(response.body);
76 - let source = '';
77 - let target = '';
78 - if (detect_body.langCode == 'ko'||detect_body.langCode =='en'){
79 - source = detect_body.langCode =='ko'? 'ko':'en';
80 - target = detect_body.langCode =='ko'? 'en':'ko';
81 - }
82 //언어 감지가 제대로 됐는지 확인 88 //언어 감지가 제대로 됐는지 확인
83 console.log(detect_body.langCode); 89 console.log(detect_body.langCode);
84 - source = detect_body.langCode; 90 + // 3.zh-CN : 중국어 간체
91 + // 4.zh-TW : 중국어 번체
92 + // 5.es : 스페인어
93 + // 6.fr : 프랑스어
94 + // 7.vi : 베트남어
95 + // 8.th : 태국어
96 + // 9.id : 인도네시아어
97 + let target = '';
98 + let checker = true;
99 + if (detect_body.langCode == 'ko') {
100 + target = 'en';
101 + switch (event.message.text.slice(-3)) {
102 + case '.cn':
103 + target = 'zh-CN';
104 + break;
105 + case '.tw':
106 + target = 'zh-TW';
107 + break;
108 + case '.es':
109 + target = 'es';
110 + break;
111 + case '.fr':
112 + target = 'fr';
113 + break;
114 + case '.vi':
115 + target = 'vi';
116 + break;
117 + case '.th':
118 + target = 'th';
119 + break;
120 + case '.id':
121 + target = 'id';
122 + break;
123 + default:
124 + checker = false;
125 + break;
126 + }
127 + } else {
128 + checker = false;
129 + target = 'ko';
130 + }
131 + // 전송된 메세지가 한국어일 경우 default target은 영어이며 설정에 따라 바뀐다.
132 + // 전송된 메세지가 한국어가 아닐 경우 모든 target language는 한국어가 된다.
85 133
86 - var options = { 134 + let options = {}
87 - url: translate_api_url, 135 + // checker란 언어 번역시 옵션의 존재 유뮤이다. 사용자가 영어가 아닌 다른 언어의 번역을 원할 경우
88 - form: {'source':source, 'target': target, 'text':event.message.text}, 136 + // 뒤에 옵션 .xx 가 붙게 되며 checker 는 true가 된다.
89 - headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret} 137 + if (checker)
90 - }; 138 + {
139 + options = {
140 + url: translate_api_url,
141 + // checker가 true이면 메세지 끝에 옵션이 붙기 때문에 번역시 이를 무시할 필요가 있다.
142 + form: {'source':detect_body.langCode, 'target': target, 'text':event.message.text.slice(0,-3)},
143 + headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret}
144 + };
145 + }
146 + // 기타 옵션 없는 한 -> 영, 외국어 -> 한글 번역은 checker false
147 + else{
148 + options = {
149 + url: translate_api_url,
150 + form: {'source':detect_body.langCode, 'target': target, 'text':event.message.text},
151 + headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret}
152 + }
153 + }
154 + // 모든 번역 준비를 마친 options 를 resolve 한다
91 resolve(options); 155 resolve(options);
92 } 156 }
93 else{ 157 else{
94 - // 예외처리 158 + // language detection에 대한 예외 reject
95 - reject(new Error("request is failed")); 159 + reject(new Error("언어 감지 실패"));
96 } 160 }
97 }) 161 })
98 }) 162 })
...@@ -103,6 +167,7 @@ const option_maker = (api_connector, event) => { ...@@ -103,6 +167,7 @@ const option_maker = (api_connector, event) => {
103 const receive_result = (options, event) => { 167 const receive_result = (options, event) => {
104 return new Promise((resolve, reject) => { 168 return new Promise((resolve, reject) => {
105 var result = { type:'text', text: ''}; 169 var result = { type:'text', text: ''};
170 + // 번역에 관련된 options 객체를 번역 API로 post요청
106 request.post(options, (error, response) => { 171 request.post(options, (error, response) => {
107 // Translate API Sucess 172 // Translate API Sucess
108 if(!error && response.statusCode == 200){ 173 if(!error && response.statusCode == 200){
...@@ -114,15 +179,16 @@ const receive_result = (options, event) => { ...@@ -114,15 +179,16 @@ const receive_result = (options, event) => {
114 resolve(result); 179 resolve(result);
115 } 180 }
116 else{ 181 else{
117 - // 예외처리 182 + // 번역 정상적으로 불가능시 reject 처리
118 - result.text = '언어를 감지할 수 없습니다. \n 번역 언어는 한글 또는 영어만 가능합니다.'; 183 + result.text = '번역할 수 없는 언어입니다.';
119 - client.replyMessage(event.replyToken,result).then(resolve).catch(reject); 184 + client.replyMessage(event.replyToken,result);
120 - reject(new Error("request is failed")); 185 + reject(new Error("번역 실패"));
121 } 186 }
122 }) 187 })
123 }) 188 })
124 } 189 }
125 190
191 +// app running
126 app.listen(3000, function () { 192 app.listen(3000, function () {
127 console.log('Linebot listening on port 3000!'); 193 console.log('Linebot listening on port 3000!');
128 }); 194 });
......