Showing
1 changed file
with
545 additions
and
0 deletions
chatbotPlus.js
0 → 100644
1 | +var express = require('express'); | ||
2 | +var client_id = 'v3M4wjolGLkrvNA3GUIW'; | ||
3 | +var client_secret = 'fKF6vjkWhE'; | ||
4 | +const request = require('request'); | ||
5 | +const TARGET_URL = 'https://api.line.me/v2/bot/message/reply' | ||
6 | +const TOKEN = 'hMnfhBQc8nadyn5Ow6aejAVDUoUEp9N8YxOFxfOB2V83TOf0vjquT4cC8ll4Ccq4hkWJ8xHij53FzjMteqLLuUL6bZs+ZONI+f5aawIulRg4Y4FFBGp1O03awvgxGn503iyI7+5iQCEi80Kus6cRZQdB04t89/1O/w1cDnyilFU=' | ||
7 | +const SECRET = '270103fd4cbd81695ceb6d0ed7f85f4b' | ||
8 | +const fs = require('fs'); | ||
9 | +const path = require('path'); | ||
10 | +const HTTPS = require('https'); | ||
11 | +const domain = "www.osschatbot.tk" | ||
12 | +const sslport = 23023; | ||
13 | +const line = require('@line/bot-sdk'); | ||
14 | + | ||
15 | +const bodyParser = require('body-parser'); | ||
16 | +const { assert } = require('console'); | ||
17 | +var app = express(); | ||
18 | +app.use(bodyParser.json()); | ||
19 | + | ||
20 | +var usingMessage = '' | ||
21 | +var content_id = '' | ||
22 | +var imgDownloaded = false; | ||
23 | +var downloadedImg = '' | ||
24 | + | ||
25 | +//search | ||
26 | +var search_client_id = 'cnS9zzj0OZ3xPgHqtaLJ'; | ||
27 | +var search_client_secret = 'oQGaxdr7aq'; | ||
28 | + | ||
29 | +//data parsing | ||
30 | +var data=''; | ||
31 | +var title=''; | ||
32 | +var link=''; | ||
33 | +var category=''; | ||
34 | +var address=''; | ||
35 | +var roadAddress=''; | ||
36 | + | ||
37 | + | ||
38 | +app.post('/hook', function (req, res) { | ||
39 | + | ||
40 | + var eventObj = req.body.events[0]; | ||
41 | + var text = eventObj.message.text; | ||
42 | + | ||
43 | + // request log | ||
44 | + if (!(eventObj.message.type == 'image')) { | ||
45 | + console.log('======================', new Date() ,'======================'); | ||
46 | + console.log('[request]', req.body); | ||
47 | + console.log('[request source] ', eventObj.source); | ||
48 | + console.log('[request message]', eventObj.message); | ||
49 | + } | ||
50 | + | ||
51 | + if (eventObj.message.type == 'location') { | ||
52 | + | ||
53 | + //위치 받아서 맛집 추천해주는 함수 | ||
54 | + var chatbotaddress=eventObj.message; | ||
55 | + var chatbotdata1=chatbotaddress.address; | ||
56 | + var chatbotdata2=chatbotdata1.split(' '); | ||
57 | + var place=chatbotdata2[0]; | ||
58 | + | ||
59 | + console.log(place); | ||
60 | + var menu=''; | ||
61 | + var query= place + ' ' + menu + ' 맛집'; //검색 원하는 문자열 | ||
62 | + RecommendationResult(eventObj.replyToken, query); | ||
63 | + | ||
64 | + res.sendStatus(200); | ||
65 | + } else if (text == 'Cfr:Yes') { | ||
66 | + QuickReplyCfrYes(eventObj.replyToken); | ||
67 | + res.sendStatus(200); | ||
68 | + } else if (text == 'Cfr:No') { | ||
69 | + QuickReplyCfrNo(eventObj.replyToken); | ||
70 | + res.sendStatus(200); | ||
71 | + } else if (text == '랜덤 추천' || text == '위치 기반 추천') { | ||
72 | + if (text == '랜덤 추천') { | ||
73 | + | ||
74 | + //랜덤으로 맛집 추천해주는 함수 | ||
75 | + var query = '맛집'; | ||
76 | + RecommendationResult(eventObj.replyToken, query); | ||
77 | + | ||
78 | + res.sendStatus(200); | ||
79 | + } | ||
80 | + else { | ||
81 | + SendingLocation(eventObj.replyToken); | ||
82 | + res.sendStatus(200); | ||
83 | + } | ||
84 | + } else if (eventObj.message.type == 'image') { | ||
85 | + content_id = eventObj.message.id; | ||
86 | + const downloadPath = path.join(__dirname, 'sample.jpg'); | ||
87 | + downloadContent(content_id, downloadPath); | ||
88 | + //downloadedImg = content_id; | ||
89 | + //imgDownloaded = true; | ||
90 | + Checking(eventObj.replyToken); | ||
91 | + res.sendStatus(200); | ||
92 | + } else if (text == '계속 진행') { | ||
93 | + //사진으로 얼굴 인식해주는 함수 | ||
94 | + imgtodata('sample.jpg'); | ||
95 | + SendingLocation(eventObj.replyToken); | ||
96 | + res.sendStatus(200); | ||
97 | + } | ||
98 | + else { | ||
99 | + usingMessage = text; | ||
100 | + initReply(eventObj.replyToken); | ||
101 | + res.sendStatus(200); | ||
102 | + } | ||
103 | + | ||
104 | +}); | ||
105 | + | ||
106 | +const quickReplyLocation = { | ||
107 | + "items": [ | ||
108 | + { | ||
109 | + "type": "action", | ||
110 | + "action": { | ||
111 | + "type": "location", | ||
112 | + "label": "위치 입력" | ||
113 | + } | ||
114 | + } | ||
115 | + ] | ||
116 | +}; | ||
117 | + | ||
118 | +const quickReplyCfrYes = { | ||
119 | + "items": [ | ||
120 | + { | ||
121 | + "type": "action", | ||
122 | + "action": { | ||
123 | + "type": "cameraRoll", | ||
124 | + "label": "사진 가져오기" | ||
125 | + } | ||
126 | + }, | ||
127 | + { | ||
128 | + "type": "action", | ||
129 | + "action": { | ||
130 | + "type": "camera", | ||
131 | + "label": "사진 찍기" | ||
132 | + } | ||
133 | + }, | ||
134 | + ] | ||
135 | + }; | ||
136 | + | ||
137 | +const quickReplyCfrNo = { | ||
138 | + items: [ | ||
139 | + /* | ||
140 | + { | ||
141 | + "type": "action", | ||
142 | + "action": { | ||
143 | + "type": "message", | ||
144 | + "label": "weather", | ||
145 | + "text": "날씨" | ||
146 | + } | ||
147 | + }, | ||
148 | + { | ||
149 | + "type": "action", | ||
150 | + "action": { | ||
151 | + "type": "message", | ||
152 | + "label": "menu", | ||
153 | + "text": "메뉴" | ||
154 | + } | ||
155 | + }, | ||
156 | + */ | ||
157 | + { | ||
158 | + "type": "action", | ||
159 | + "action": { | ||
160 | + "type": "message", | ||
161 | + "label": "random", | ||
162 | + "text": "랜덤 추천" | ||
163 | + } | ||
164 | + }, | ||
165 | + { | ||
166 | + "type": "action", | ||
167 | + "action": { | ||
168 | + "type": "message", | ||
169 | + "label": "location", | ||
170 | + "text": "위치 기반 추천" | ||
171 | + } | ||
172 | + } | ||
173 | + ] | ||
174 | + }; | ||
175 | + | ||
176 | +//기본 reply | ||
177 | +function initReply (replyToken) { | ||
178 | + request.post( | ||
179 | + { | ||
180 | + url: TARGET_URL, | ||
181 | + headers: { | ||
182 | + 'Authorization': `Bearer ${TOKEN}` | ||
183 | + }, | ||
184 | + json: { | ||
185 | + "replyToken":replyToken, | ||
186 | + "messages":[ | ||
187 | + { | ||
188 | + "type": "sticker", | ||
189 | + "packageId": "11537", | ||
190 | + "stickerId": "52002738" | ||
191 | + }, | ||
192 | + { | ||
193 | + "type": "text", | ||
194 | + "text": "안녕하세요.\nCFR을 이용한 얼굴인식 맛집 추천봇입니다." | ||
195 | + }, | ||
196 | + { | ||
197 | + "type": "template", | ||
198 | + "altText": "얼굴 인식을 위해 사진을 가져오시겠습니까?", | ||
199 | + "template": { | ||
200 | + "type": "confirm", | ||
201 | + "text": "얼굴 인식을 위해 사진을 가져오시겠습니까?", | ||
202 | + "actions": [ | ||
203 | + { | ||
204 | + "type": "message", | ||
205 | + "label": "Cfr:Yes", | ||
206 | + "text": "Cfr:Yes" | ||
207 | + }, | ||
208 | + { | ||
209 | + "type": "message", | ||
210 | + "label": "Cfr:No", | ||
211 | + "text": "Cfr:No" | ||
212 | + } | ||
213 | + ] | ||
214 | + } | ||
215 | + } | ||
216 | + ] | ||
217 | + } | ||
218 | + },(error, response, body) => { | ||
219 | + console.log(body) | ||
220 | + }); | ||
221 | +} | ||
222 | + | ||
223 | +//위치 입력 reply | ||
224 | +function SendingLocation(replyToken) { | ||
225 | + request.post( | ||
226 | + { | ||
227 | + url: TARGET_URL, | ||
228 | + headers: { | ||
229 | + 'Authorization': `Bearer ${TOKEN}` | ||
230 | + }, | ||
231 | + json: { | ||
232 | + "replyToken": replyToken, | ||
233 | + "messages": [ | ||
234 | + { | ||
235 | + "type": "text", | ||
236 | + "text": "위치를 입력해주세요.", | ||
237 | + "quickReply": quickReplyLocation | ||
238 | + } | ||
239 | + ] | ||
240 | + }, | ||
241 | + body: request | ||
242 | + },(error, response, body) => { | ||
243 | + console.log(body) | ||
244 | + }); | ||
245 | +} | ||
246 | + | ||
247 | +//cfr 이용할 때 reply | ||
248 | +function QuickReplyCfrYes(replyToken) { | ||
249 | + request.post( | ||
250 | + { | ||
251 | + url: TARGET_URL, | ||
252 | + headers: { | ||
253 | + 'Authorization': `Bearer ${TOKEN}` | ||
254 | + }, | ||
255 | + json: { | ||
256 | + "replyToken": replyToken, | ||
257 | + "messages": [ | ||
258 | + { | ||
259 | + "type": "text", | ||
260 | + "text": "사진을 입력해주세요.", | ||
261 | + "quickReply": quickReplyCfrYes | ||
262 | + } | ||
263 | + ] | ||
264 | + } | ||
265 | + },(error, response, body) => { | ||
266 | + console.log(body) | ||
267 | + }); | ||
268 | +} | ||
269 | + | ||
270 | +//cfr 이용하지 않을 때 reply | ||
271 | +function QuickReplyCfrNo (replyToken) { | ||
272 | + request.post( | ||
273 | + { | ||
274 | + url: TARGET_URL, | ||
275 | + headers: { | ||
276 | + 'Authorization': `Bearer ${TOKEN}` | ||
277 | + }, | ||
278 | + json: { | ||
279 | + "replyToken": replyToken, | ||
280 | + "messages": [ | ||
281 | + { | ||
282 | + "type": "text", | ||
283 | + "text": "랜덤 추천 옵션을 선택해주세요.", | ||
284 | + "quickReply": quickReplyCfrNo | ||
285 | + } | ||
286 | + ] | ||
287 | + } | ||
288 | + },(error, response, body) => { | ||
289 | + console.log(body) | ||
290 | + }); | ||
291 | +} | ||
292 | + | ||
293 | +function Checking (replyToken) { | ||
294 | + request.post( | ||
295 | + { | ||
296 | + url: TARGET_URL, | ||
297 | + headers: { | ||
298 | + 'Authorization': `Bearer ${TOKEN}` | ||
299 | + }, | ||
300 | + json: { | ||
301 | + "replyToken": replyToken, | ||
302 | + "messages": [ | ||
303 | + { | ||
304 | + "type": "text", | ||
305 | + "label": "계속 진행", | ||
306 | + "text": "계속 진행하시려면 '계속 진행'을 입력해주세요." | ||
307 | + }, | ||
308 | + ], | ||
309 | + } | ||
310 | + },(error, response, body) => { | ||
311 | + console.log(body) | ||
312 | + }); | ||
313 | +} | ||
314 | + | ||
315 | + | ||
316 | +//추천 결과 + Search | ||
317 | +function RecommendationResult(replyToken, query) { | ||
318 | + | ||
319 | + console.log(query); | ||
320 | + var display = '1'; //검색 결과 출력 건수. 최대 5개 | ||
321 | + var start = '1'; //검색 시작 위치. 1만 가능 | ||
322 | + var sort = 'comment'; //정렬 옵션 (random : 유사도순, comment : 카페/블로그 리뷰 개수 순) | ||
323 | + | ||
324 | + var api_url = 'https://openapi.naver.com/v1/search/local?query=' + encodeURI(query) + '&display=' + encodeURI(display) + '&start=' + encodeURI(start) + '&sort=' + encodeURI(sort); | ||
325 | + var options = { | ||
326 | + url: api_url, | ||
327 | + headers: { 'X-Naver-Client-Id': search_client_id, 'X-Naver-Client-Secret': search_client_secret } | ||
328 | + }; | ||
329 | + request.get(options, function (error, response, body) { | ||
330 | + if (!error && response.statusCode == 200) { | ||
331 | + //response.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'}); | ||
332 | + console.log(body); | ||
333 | + | ||
334 | + //데이터 parsing | ||
335 | + data = JSON.parse(body); | ||
336 | + title = data.items[0].title; | ||
337 | + console.log(title); | ||
338 | + | ||
339 | + link = data.items[0].link; | ||
340 | + console.log(link); | ||
341 | + | ||
342 | + category = data.items[0].category; | ||
343 | + console.log(category); | ||
344 | + | ||
345 | + address = data.items[0].address; | ||
346 | + console.log(address); | ||
347 | + | ||
348 | + roadAddress = data.items[0].roadAddress; | ||
349 | + console.log(roadAddress); | ||
350 | + | ||
351 | + request.post( | ||
352 | + { | ||
353 | + url: TARGET_URL, | ||
354 | + headers: { | ||
355 | + 'Authorization': `Bearer ${TOKEN}` | ||
356 | + }, | ||
357 | + json: { | ||
358 | + "replyToken": replyToken, | ||
359 | + "messages": [ | ||
360 | + /*{ | ||
361 | + "type": "imagemap", | ||
362 | + // 이미지 불러올 수 없습니다 뜸 | ||
363 | + "baseUrl": "https://www.flaticon.com/free-icon/food-store_2934069?term=restaurant&page=1&position=7&related_item_id=2934069", | ||
364 | + "altText": "이미지를 누르시면 해당 가게로 이동합니다.", | ||
365 | + "baseSize": { | ||
366 | + "width": 1040, | ||
367 | + "height": 1040 | ||
368 | + }, | ||
369 | + "actions": [ | ||
370 | + { | ||
371 | + "type": "uri", | ||
372 | + "linkUri": link, // 가게 링크 | ||
373 | + "area": { | ||
374 | + "x": 0, | ||
375 | + "y": 0, | ||
376 | + "width": 1040, | ||
377 | + "height": 1040 | ||
378 | + } | ||
379 | + } | ||
380 | + ] | ||
381 | + },*/ | ||
382 | + { | ||
383 | + "type": "text", | ||
384 | + "text": "맛집 이름: " + title | ||
385 | + }, | ||
386 | + { | ||
387 | + "type":"text", | ||
388 | + "text": "맛집 주소: " + address | ||
389 | + } | ||
390 | + /*{ | ||
391 | + "type":"location", | ||
392 | + "title":"맛집 주소", | ||
393 | + "address":address | ||
394 | + }*/ | ||
395 | + ] | ||
396 | + } | ||
397 | + }, (error, response, body) => { | ||
398 | + console.log(body) | ||
399 | + }); | ||
400 | + | ||
401 | + } else { | ||
402 | + res.status(response.statusCode).end(); | ||
403 | + console.log('error = ' + response.statusCode); | ||
404 | + } | ||
405 | + }) | ||
406 | + | ||
407 | +} | ||
408 | + | ||
409 | +imgtodata = function(dir){ | ||
410 | + var api_url = 'https://openapi.naver.com/v1/vision/face'; // 얼굴 감지 | ||
411 | + | ||
412 | + var _formData = { | ||
413 | + image:'image', | ||
414 | + image: fs.createReadStream(path.join(__dirname, dir)) // FILE 이름 | ||
415 | + }; | ||
416 | + | ||
417 | + request.post( | ||
418 | + { url:api_url, | ||
419 | + formData:_formData, | ||
420 | + headers: {'X-Naver-Client-Id':client_id, | ||
421 | + 'X-Naver-Client-Secret': client_secret} | ||
422 | + }, (err,response,body) =>{ | ||
423 | + console.log(response.statusCode); // 200 | ||
424 | + //console.log(response.headers['content-type']) | ||
425 | + console.log(body); | ||
426 | + var cfrdata=JSON.parse(body); | ||
427 | + | ||
428 | + var cfrgender=cfrdata.faces[0].gender.value; //CFR의 성별 데이터 (json) | ||
429 | + var cfremotion=cfrdata.faces[0].emotion.value; //CFR의 감정 데이터 (json) | ||
430 | + | ||
431 | + var gender = cfrgender; //사용자 성별 | ||
432 | + var emotion = cfremotion; //사용자 감정 | ||
433 | + | ||
434 | + | ||
435 | + console.log(gender); | ||
436 | + console.log(emotion); | ||
437 | + | ||
438 | + if(gender=='male'){ | ||
439 | + if(emotion=='angry'){ | ||
440 | + menu='술'; | ||
441 | + } | ||
442 | + else if(emotion=='disgust'){ | ||
443 | + menu='야식'; | ||
444 | + } | ||
445 | + else if(emotion=='fear'){ | ||
446 | + menu='한식'; | ||
447 | + } | ||
448 | + else if(emotion=='laugh'){ | ||
449 | + menu='치킨'; | ||
450 | + } | ||
451 | + else if(emotion=='neutral'){ | ||
452 | + menu='양식'; | ||
453 | + } | ||
454 | + else if(emotion=='sad'){ | ||
455 | + menu='중식'; | ||
456 | + } | ||
457 | + else if(emotion=='surprise'){ | ||
458 | + menu='일식'; | ||
459 | + } | ||
460 | + else if(emotion=='smile'){ | ||
461 | + menu='고기'; | ||
462 | + } | ||
463 | + else if(emotion=='talking'){ | ||
464 | + menu='술'; | ||
465 | + } | ||
466 | + else{ | ||
467 | + menu=''; | ||
468 | + } | ||
469 | + } | ||
470 | + else if(gender=='female'){ | ||
471 | + if(emotion=='angry'){ | ||
472 | + menu='고기'; | ||
473 | + } | ||
474 | + else if(emotion=='disgust'){ | ||
475 | + menu='디저트'; | ||
476 | + } | ||
477 | + else if(emotion=='fear'){ | ||
478 | + menu='한식'; | ||
479 | + } | ||
480 | + else if(emotion=='laugh'){ | ||
481 | + menu='일식'; | ||
482 | + } | ||
483 | + else if(emotion=='neutral'){ | ||
484 | + menu='중식'; | ||
485 | + } | ||
486 | + else if(emotion=='sad'){ | ||
487 | + menu='야식'; | ||
488 | + } | ||
489 | + else if(emotion=='surprise'){ | ||
490 | + menu='중식'; | ||
491 | + } | ||
492 | + else if(emotion=='smile'){ | ||
493 | + menu='치킨'; | ||
494 | + } | ||
495 | + else if(emotion=='talking'){ | ||
496 | + menu='카페'; | ||
497 | + } | ||
498 | + else{ | ||
499 | + menu=''; | ||
500 | + } | ||
501 | + } | ||
502 | + else{ | ||
503 | + menu=''; | ||
504 | + } | ||
505 | + | ||
506 | + console.log(menu); | ||
507 | + | ||
508 | + | ||
509 | + //return {gender:gender,emotion:emotion}; | ||
510 | + }); | ||
511 | + } | ||
512 | + | ||
513 | +//사용자가 보낸 사진 저장 | ||
514 | +const config = ({ | ||
515 | + channelAccessToken: `${TOKEN}`, | ||
516 | + channelSecret: `${SECRET}`, | ||
517 | +}); | ||
518 | + | ||
519 | +const client = new line.Client(config); | ||
520 | +function downloadContent(messageId, downloadPath) { | ||
521 | + return client.getMessageContent(messageId) | ||
522 | + .then((stream) => new Promise((resolve, reject) => { | ||
523 | + const writable = fs.createWriteStream(downloadPath); | ||
524 | + stream.pipe(writable); | ||
525 | + stream.on('end', () => resolve(downloadPath)); | ||
526 | + stream.on('error', reject); | ||
527 | + })); | ||
528 | +} | ||
529 | + | ||
530 | + | ||
531 | +try { | ||
532 | + const option = { | ||
533 | + ca: fs.readFileSync('/etc/letsencrypt/live/' + domain +'/fullchain.pem'), | ||
534 | + key: fs.readFileSync(path.resolve(process.cwd(), '/etc/letsencrypt/live/' + domain +'/privkey.pem'), 'utf8').toString(), | ||
535 | + cert: fs.readFileSync(path.resolve(process.cwd(), '/etc/letsencrypt/live/' + domain +'/cert.pem'), 'utf8').toString(), | ||
536 | + }; | ||
537 | + if (usingMessage == '') { | ||
538 | + HTTPS.createServer(option, app).listen(sslport, () => { | ||
539 | + console.log(`[HTTPS] Server is started on port ${sslport}`); | ||
540 | + }); | ||
541 | + } | ||
542 | + } catch (error) { | ||
543 | + console.log('[HTTPS] HTTPS 오류가 발생하였습니다. HTTPS 서버는 실행되지 않습니다.'); | ||
544 | + console.log(error); | ||
545 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment