Showing
2 changed files
with
89 additions
and
23 deletions
QR.PNG
0 → 100644
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 = {} |
| 135 | + // checker란 언어 번역시 옵션의 존재 유뮤이다. 사용자가 영어가 아닌 다른 언어의 번역을 원할 경우 | ||
| 136 | + // 뒤에 옵션 .xx 가 붙게 되며 checker 는 true가 된다. | ||
| 137 | + if (checker) | ||
| 138 | + { | ||
| 139 | + options = { | ||
| 87 | url: translate_api_url, | 140 | url: translate_api_url, |
| 88 | - form: {'source':source, 'target': target, 'text':event.message.text}, | 141 | + // checker가 true이면 메세지 끝에 옵션이 붙기 때문에 번역시 이를 무시할 필요가 있다. |
| 142 | + form: {'source':detect_body.langCode, 'target': target, 'text':event.message.text.slice(0,-3)}, | ||
| 89 | headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret} | 143 | headers: {'X-Naver-Client-Id': client_id, 'X-Naver-Client-Secret': client_secret} |
| 90 | }; | 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 | }); | ... | ... |
-
Please register or login to post a comment