Showing
6 changed files
with
176 additions
and
76 deletions
1 | -### 오픈소스sw개발 개인 프로젝트 | 1 | +README referred to [Github](https://github.com/othneildrew/Best-README-Template) |
2 | -## CHATBOT WITH CRAWLING | 2 | + |
3 | + | ||
4 | +<!-- PROJECT LOGO --> | ||
5 | +<br /> | ||
6 | +<p align="center"> | ||
7 | + <h3 align="center">SEARCH AND CHAT</h3> | ||
8 | + | ||
9 | + <p align="center"> | ||
10 | + 웹 페이지로 구현된 챗봇과 대화 및 '@'를 이용하여 최신 영상, 정확도 높은 영상, 소식을 카드로 제공합니다. | ||
11 | + "http://khuhub.khu.ac.kr/2017103084/oss-chatbot" | ||
12 | + <a href="http://khuhub.khu.ac.kr/2017103084/oss-chatbot/">View Demo</a> | ||
13 | + · | ||
14 | + <a href="http://khuhub.khu.ac.kr/2017103084/oss-chatbot/issues">Report Bug</a> | ||
15 | + · | ||
16 | + <a href="http://khuhub.khu.ac.kr/2017103084/oss-chatbot/merge_requests">Request Feature</a> | ||
17 | + </p> | ||
18 | +</p> | ||
19 | + | ||
20 | + | ||
21 | + | ||
22 | +<!-- TABLE OF CONTENTS --> | ||
23 | +## Table of Contents | ||
24 | + | ||
25 | +* [About the Project](#about-the-project) | ||
26 | + * [Built With](#built-with) | ||
27 | +* [Getting Started](#getting-started) | ||
28 | + * [Prerequisites](#prerequisites) | ||
29 | + * [Installation](#installation) | ||
30 | +* [Usage](#usage) | ||
31 | +* [Roadmap](#roadmap) | ||
32 | +* [Contributing](#contributing) | ||
33 | +* [License](#license) | ||
34 | +* [Contact](#contact) | ||
35 | +* [Acknowledgements](#acknowledgements) | ||
36 | + | ||
37 | + | ||
38 | + | ||
39 | +<!-- ABOUT THE PROJECT --> | ||
40 | +## About The Project | ||
41 | + | ||
42 | +[![Product Name Screen Shot](./projectScreenShot.PNG) | ||
43 | + | ||
44 | +카카오톡, 라인 등에서 제공하는 챗봇 어플리케이션과 같이 웹에서도 작동할 수 있는 챗봇을 만들어, 웹 사용자들과 대화할 수 있는 봇을 만들고 싶어 이 프로젝트를 진행하게 되었습니다. 간단한 대화와 더불어 좋아하는 가수, 또는 배우 등의 이름과 함께 검색어를 입력하면 봇이 대신 정보를 가져와주는 편의성을 더하였습니다. | ||
45 | + | ||
46 | + | ||
47 | +### Built With | ||
48 | + | ||
49 | +* [Nodejs](https://nodejs.org/en/) | ||
50 | +* [React](https://ko.reactjs.org/) | ||
51 | +* [Google Cloud API](https://cloud.google.com/apis) | ||
52 | +* [Dialogflow API](https://dialogflow.cloud.google.com/) | ||
53 | + | ||
54 | + | ||
55 | +<!-- GETTING STARTED --> | ||
56 | +## Getting Started | ||
57 | + | ||
58 | +로컬 컴퓨터에서 실행시킬 수 있는 방법입니다. | ||
59 | + | ||
60 | +### Prerequisites | ||
61 | + | ||
62 | +먼저, 이 프로젝트를 실행시키기 위해 필요한 요구사항입니다. | ||
63 | + | ||
64 | +* Node | ||
65 | +[Official Node.js Website](https://nodejs.org/)에서 Node.js를 설치합니다. | ||
66 | +또한 `npm` 의 설치도 필요합니다. | ||
67 | + | ||
68 | +### Installation | ||
69 | + | ||
70 | +1. 이 리포지토리를 Clone 합니다. | ||
71 | +```sh | ||
72 | +git clone http://khuhub.khu.ac.kr/2017103084/oss-chatbot/ | ||
73 | +``` | ||
74 | +2. root 폴더와 client 폴더에서 아래 명령을 실행합니다. | ||
75 | +```sh | ||
76 | +npm install | ||
77 | +``` | ||
78 | +3. [Google Developers](https://console.developers.google.com/project)에서 프로젝트를 생성한 뒤, API 키를 발급 받습니다. 이 때, 프로젝트 명(ID)과 API 키의 json 파일이 필요합니다. | ||
79 | + | ||
80 | +4. [Dialogflow](https://dialogflow.cloud.google.com/)에서 에이전트를 생성합니다. 이 때, GOOGLE PROJECT 탭의 Project ID는 앞서 (3)에서 생성한 프로젝트의 ID를 선택합니다. | ||
81 | + | ||
82 | +5. root 폴더에 .env 파일을 생성한 뒤, 아래 내용을 채워 넣습니다. | ||
83 | +``` | ||
84 | +googleProjectID = (3)에서 생성한 구글 프로젝트 ID | ||
85 | +dialogFlowSessionID = bot-session #원하는 것으로 입력. | ||
86 | +dialogFlowSessionLanguageCode = Dialogflow 에이전트 생성 시 설정한 언어 코드 (ex. 한글일 경우에는 "ko" 입니다.) | ||
87 | +googleClientEmail = 구글 프로젝트 생성 시 제공되는 이메일 (ex. [프로젝트 명]@[프로젝트명 2].iam.gserviceaccount.com) | ||
88 | +``` | ||
89 | + | ||
90 | +6. **중요** 로컬에서 실행하는 경우에는 root의 package.json 중 "@google-cloud/storage": "^5.0.1" 를 지웁니다. 이 패키지는 herokuapp에서 GOOGLE_APPLICATION_CREDENTIALS를 활용하기 위해 설치되어있는 패키지입니다. | ||
91 | + | ||
92 | +7. 모두 완료 되었다면, 아래 명령어를 입력하여 클라이언트와 서버를 모두 실행시킬 수 있습니다. | ||
93 | +``` | ||
94 | +npm run dev | ||
95 | +``` | ||
96 | + | ||
97 | + | ||
98 | +<!-- USAGE EXAMPLES --> | ||
99 | +## Usage | ||
100 | + | ||
101 | +해당 프로젝트의 실제 동작 화면은 [SEARCH-AND-CHAT](https://search-and-chat.herokuapp.com/)에서 확인하실 수 있습니다. | ||
102 | +React 의 특성 상 뒤로가기 및 Reload 시 오류가 발생할 수 있습니다. 이 때는 아래 URL로 재접속하시면 원활히 사용하실 수 있습니다. 또한 heroku 로 빌드되어 사용이 없는 경우에는 첫 접속 시 로딩 시간이 걸릴 수 있습니다. 조금만 기다려주시면 프로젝트가 실행될 것입니다 😊 | ||
103 | + | ||
104 | +* URL : <https://search-and-chat.herokuapp.com/> | ||
105 | + | ||
106 | + | ||
107 | +<!-- CONTRIBUTING --> | ||
108 | +## Contributing | ||
109 | + | ||
110 | +이 프로젝트를 더욱 발전시키고 싶으신 분들은 아래와 같은 절차를 따라주세요! | ||
111 | + | ||
112 | +1. Fork the Project | ||
113 | +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) | ||
114 | +3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) | ||
115 | +4. Push to the Branch (`git push origin feature/AmazingFeature`) | ||
116 | +5. Open a Pull Request | ||
117 | + | ||
118 | +<!-- CONTACT --> | ||
119 | +## Contact | ||
120 | + | ||
121 | +프로젝트에 문제가 있거나 궁금하신 사항은 아래 메일로 연락주세요. | ||
122 | +* Email : <mathmjseo@khu.ac.kr> | ||
3 | 123 | ||
4 | --readme 수정하기 | ||
5 | --로그인 시 페이지렌더링 안됨 ..... 수정하기 | ... | ... |
... | @@ -8,18 +8,13 @@ import Card from "./Sections/Card"; | ... | @@ -8,18 +8,13 @@ import Card from "./Sections/Card"; |
8 | import CheckString from './Check'; | 8 | import CheckString from './Check'; |
9 | import { text } from 'body-parser'; | 9 | import { text } from 'body-parser'; |
10 | 10 | ||
11 | -let userKeyword = ""; | 11 | +function Chatbot(props) { |
12 | -let userName = "유저"; | ||
13 | -let autoSearch = 0; | ||
14 | -if(sessionStorage.length){ | ||
15 | - userKeyword = sessionStorage.getItem("Now_userKeyword"); | ||
16 | - userName = sessionStorage.getItem("Now_userName"); | ||
17 | - autoSearch = 1; | ||
18 | - sessionStorage.clear(); | ||
19 | -} | ||
20 | 12 | ||
13 | + console.log("실행") | ||
14 | + var userName = props.userName; | ||
15 | + var userKeyword = props.userKeyword; | ||
16 | + var autoSearch = props.autoSearch; | ||
21 | 17 | ||
22 | -function Chatbot() { | ||
23 | console.log("이름",userName); | 18 | console.log("이름",userName); |
24 | console.log("키워드",userKeyword); | 19 | console.log("키워드",userKeyword); |
25 | 20 | ||
... | @@ -32,6 +27,22 @@ function Chatbot() { | ... | @@ -32,6 +27,22 @@ function Chatbot() { |
32 | 27 | ||
33 | }, []) | 28 | }, []) |
34 | 29 | ||
30 | + if(autoSearch){ | ||
31 | + useEffect(() => { | ||
32 | + console.log("I am in autoSearch!!"); | ||
33 | + setTimeout(function(){ | ||
34 | + eventQuery('008_AutoSearch'); | ||
35 | + }, 500); | ||
36 | + | ||
37 | + setTimeout(function(){ | ||
38 | + textQuery(`@${userKeyword}_최신`); | ||
39 | + textQuery(`@${userKeyword}_정확도`); | ||
40 | + textQuery(`@${userKeyword}_소식`); | ||
41 | + }, 1000); | ||
42 | + | ||
43 | + }, []) | ||
44 | + } | ||
45 | + | ||
35 | const textQuery = async (text) => { | 46 | const textQuery = async (text) => { |
36 | // First Need to take care of the message I sent | 47 | // First Need to take care of the message I sent |
37 | let conversation = { | 48 | let conversation = { |
... | @@ -147,20 +158,14 @@ function Chatbot() { | ... | @@ -147,20 +158,14 @@ function Chatbot() { |
147 | 158 | ||
148 | } | 159 | } |
149 | 160 | ||
150 | - if(autoSearch === 1){ | 161 | + // if(autoSearch === 1){ |
151 | - setTimeout(function(){ | ||
152 | - eventQuery('008_AutoSearch'); | ||
153 | - }, 500); | ||
154 | 162 | ||
155 | - setTimeout(function(){ | ||
156 | - textQuery(`@${userKeyword}_최신`); | ||
157 | - textQuery(`@${userKeyword}_정확도`); | ||
158 | - textQuery(`@${userKeyword}_소식`); | ||
159 | - }, 1000); | ||
160 | 163 | ||
161 | - autoSearch = 0; | 164 | + |
162 | - console.log("I am in autoSearch!!"); | 165 | + |
163 | - } | 166 | + // autoSearch = 0; |
167 | + // console.log("I am in autoSearch!!"); | ||
168 | + // } | ||
164 | 169 | ||
165 | 170 | ||
166 | const keyPressHanlder = (e) => { | 171 | const keyPressHanlder = (e) => { | ... | ... |
... | @@ -3,16 +3,29 @@ import { Typography, Icon } from 'antd'; | ... | @@ -3,16 +3,29 @@ import { Typography, Icon } from 'antd'; |
3 | import Chatbot from '../Chatbot/Chatbot'; | 3 | import Chatbot from '../Chatbot/Chatbot'; |
4 | import { withRouter } from "react-router-dom"; | 4 | import { withRouter } from "react-router-dom"; |
5 | const { Title } = Typography; | 5 | const { Title } = Typography; |
6 | - | 6 | +let userKeyword = ""; |
7 | +let userName = "유저"; | ||
8 | +let autoSearch = 0; | ||
9 | +console.log("챗페이지 밖"); | ||
7 | 10 | ||
8 | function chatpage() { | 11 | function chatpage() { |
12 | + console.log("챗페이지 안") | ||
13 | + if(sessionStorage.length === 2){ | ||
14 | + console.log("세션스토리지 안") | ||
15 | + userKeyword = sessionStorage.getItem("Now_userKeyword"); | ||
16 | + userName = sessionStorage.getItem("Now_userName"); | ||
17 | + sessionStorage.clear(); | ||
18 | + | ||
19 | + autoSearch = 1; | ||
20 | + } | ||
21 | + | ||
9 | return ( | 22 | return ( |
10 | <div> | 23 | <div> |
11 | <div style={{ display: 'flex', justifyContent: 'center', marginTop: '1rem' }}> | 24 | <div style={{ display: 'flex', justifyContent: 'center', marginTop: '1rem' }}> |
12 | <Title level={2} >CHATBOT <Icon type="robot" /></Title> | 25 | <Title level={2} >CHATBOT <Icon type="robot" /></Title> |
13 | </div> | 26 | </div> |
14 | <div style={{ display: 'flex', justifyContent: 'center' }}> | 27 | <div style={{ display: 'flex', justifyContent: 'center' }}> |
15 | - <Chatbot /> | 28 | + <Chatbot userName = {userName} userKeyword = {userKeyword} autoSearch = {autoSearch}/> |
16 | </div> | 29 | </div> |
17 | </div> | 30 | </div> |
18 | ) | 31 | ) | ... | ... |
... | @@ -6,10 +6,13 @@ import Axios from 'axios'; | ... | @@ -6,10 +6,13 @@ import Axios from 'axios'; |
6 | const { Title } = Typography; | 6 | const { Title } = Typography; |
7 | 7 | ||
8 | console.log("start"); | 8 | console.log("start"); |
9 | +let url = "/"; | ||
9 | 10 | ||
10 | -const userInfo = async (info) => { | 11 | +async function userInfo(){ |
11 | const email = document.getElementById('email').value; | 12 | const email = document.getElementById('email').value; |
12 | const pw = document.getElementById('password').value; | 13 | const pw = document.getElementById('password').value; |
14 | + | ||
15 | + | ||
13 | if(email && pw){ | 16 | if(email && pw){ |
14 | const userVariables = { | 17 | const userVariables = { |
15 | email, | 18 | email, |
... | @@ -18,6 +21,7 @@ const userInfo = async (info) => { | ... | @@ -18,6 +21,7 @@ const userInfo = async (info) => { |
18 | 21 | ||
19 | const response = await Axios.post('/api/login/userInfo', userVariables); | 22 | const response = await Axios.post('/api/login/userInfo', userVariables); |
20 | if(response.data !== 'FAIL'){ | 23 | if(response.data !== 'FAIL'){ |
24 | + url = "/chat"; | ||
21 | // loginForm.action = `/chat?${response.data}`; | 25 | // loginForm.action = `/chat?${response.data}`; |
22 | // loginForm.submit(); | 26 | // loginForm.submit(); |
23 | var keyword = response.data.keyword; | 27 | var keyword = response.data.keyword; |
... | @@ -25,14 +29,16 @@ const userInfo = async (info) => { | ... | @@ -25,14 +29,16 @@ const userInfo = async (info) => { |
25 | 29 | ||
26 | sessionStorage.setItem("Now_userKeyword", keyword); | 30 | sessionStorage.setItem("Now_userKeyword", keyword); |
27 | sessionStorage.setItem("Now_userName", name); | 31 | sessionStorage.setItem("Now_userName", name); |
28 | - window.history.replaceState('login','','/chat'); | 32 | + // window.history.replaceState('login','','/chat'); |
29 | - window.history.go(); | 33 | + // window.history.go(); |
30 | // window.location.href = "/chat"; | 34 | // window.location.href = "/chat"; |
31 | } else{ | 35 | } else{ |
36 | + url = "/"; | ||
32 | alert("입력하신 정보와 일치하는 회원이 존재하지 않습니다 😥"); | 37 | alert("입력하신 정보와 일치하는 회원이 존재하지 않습니다 😥"); |
33 | } | 38 | } |
34 | } | 39 | } |
35 | else{ | 40 | else{ |
41 | + url = "/"; | ||
36 | alert("이메일과 패스워드를 입력해주세요!"); | 42 | alert("이메일과 패스워드를 입력해주세요!"); |
37 | } | 43 | } |
38 | } | 44 | } |
... | @@ -67,9 +73,11 @@ function loginpage() { | ... | @@ -67,9 +73,11 @@ function loginpage() { |
67 | 73 | ||
68 | <Form.Item> | 74 | <Form.Item> |
69 | <div> | 75 | <div> |
70 | - <Button type="primary" className="login-form-button" style={{ minWidth: '100%' }} onClick={userInfo}> | 76 | + <Link to= {`${url}`} onClick= {userInfo} name = "loginLink"> |
77 | + <Button type="primary" className="login-form-button" style={{ minWidth: '100%' }}> | ||
71 | Log in | 78 | Log in |
72 | </Button> | 79 | </Button> |
80 | + </Link> | ||
73 | </div> | 81 | </div> |
74 | <Link to ="/register">가입하기</Link> Or <Link to = "/chat">비회원으로 사용하기</Link> | 82 | <Link to ="/register">가입하기</Link> Or <Link to = "/chat">비회원으로 사용하기</Link> |
75 | </Form.Item> | 83 | </Form.Item> | ... | ... |
note.md
deleted
100644 → 0
1 | -1. dialogflow로 기본 기능 구현 | ||
2 | -2. React로 프론트엔드 구현 | ||
3 | -3. routing으로 @가수명 입력하면 해당 라우팅(크롤링) 함수로 들어가게 구현 | ||
4 | -4. 크롤링 구현 (네이버TV 최신 영상 3개 json으로 가져오기) | ||
5 | -5. json파일 카드로 넘겨주기 | ||
6 | - | ||
7 | - | ||
8 | ---- | ||
9 | -검색결과가 없을 때 -> 다시 dialogflow 라우터로 넘겨줘서 무슨 말인지 이해하지 못했어요 | ||
10 | -관련 영상이 3가지 미만일 때 -> 없다고 판단함. | ||
11 | ---- | ||
12 | - | ||
13 | - | ||
14 | -node 서버: localhost: 5000 | ||
15 | -프론트엔드/ localhost: 3000 | ||
16 | - | ||
17 | ----- 정리 | ||
18 | - | ||
19 | -리덕스 참고: https://velopert.com/3528 | ||
20 | - | ||
21 | -dialogflow | ||
22 | -화자의 의도 intent ,사용자가 말하는 것과 dialogflow가 수행해야할 작업간의 매핑을 나타내는 것. | ||
23 | -fallback intent : 사용자의 대화가 어떤 intent 와도 매칭되지 않을 때 선택되어지는 intent | ||
24 | - | ||
25 | -화자의 속성 entity | ||
26 | -ex. 내일 오후 2시 되나요? 에서 '내일', '오후 2시'를 파라미터로 뽑아내는 것. | ||
27 | - | ||
28 | -문맥 context | ||
29 | -내일 오후 2시 되나요? 에서 무엇을 위한 내일 오후 2시인가를 파악하기 위해서 그 전에 대화가 되었던 '수리'라는 것을 기억하는 것을 의미함 | ||
30 | - | ||
31 | -uuid 제대로 이해하고 다시 작성하기 | ||
32 | - | ||
33 | - | ||
34 | - | ||
35 | - | ||
36 | ------ | ||
37 | -001 - welcome | ||
38 | -002 - 인사 | ||
39 | -003 - @'가수명' | ||
40 | --> 해당 가수명으로 크롤링을 했을 때 null이 3개이상 나오면 가수명이 없다고 판단함. | ||
41 | --> 만약 가수가 아니더라도 크롤링 시 해당되는 내용이 3개 이상 나오면 해당 내용을 리턴함. | ||
42 | ------ | ||
43 | - | ||
44 | - |
projectScreenShot.PNG
0 → 100644
54 KB
-
Please register or login to post a comment