Blank, 자료 수집 챗봇, 2020

JISU YANG·2022년 11월 17일
1

프로젝트 회고록

목록 보기
6/10
post-thumbnail

개요

서비스

미리보기

  • Demo
    일상 대화는 작동하지 않음. 현재 심심이 API는 비용 문제로 유로 플랜을 중지.
  • Github

소개

  • 서비스 명: Blank
  • 서비스 주제: 자료 수집 챗봇
  • 서비스 플랫폼: 데스크탑 웹 서비스

핵심 기능

  1. 사용자가 질문을 하면 그에 대한 정보 수집 결과를 메시지로 받을 수 있다.
  2. 사용자는 Blank에 관한 질문했을때 소개 메시지를 받을 수 있다.
  3. 사용자가 일상적인 대화에 대답 메시지를 받을 수 있다.

프로젝트

규모

기간, 3일

  • 20.07.27 ~ 20.07.29

인원, 1명

  • 🤚
    기획, 개발, UX/UI

기술 스택

언어

  • Java
  • JSP/Servlet
  • JavaScript
  • HTML/CSS

기술

  • Spring Framework
  • Maven

API

  • 네이버 뉴스 API
  • 심심이 API

라이브러리

  • JSON-SIMPLE
  • OkHttp
  • Jsoup



기획

1. 영화가 너무 멋있는걸

1-1. 왜 시작하게 되었나?

많은 이들이 그랬을 것이다. 나는 아이언맨을 보고 항상 자비스(Jarvis)를 향한 동경과 갈증이 있었다. 비슷하게라도 업무를 도와줄 수 있는 BOT을 제작할 수는 없을까?라는 질문을 계속 가슴 속에서 지울 수 없었고 몇 번을 포기하려했지만 계속 눈 앞에서 아른거림에 지고 말았다.


2. 현실적으로 바라보기

2-1. 가능한가?

일단 최대한 이론적으로 가능한 스케일을 생각했다. 하지만 과한 욕심이 담겨있었다. 간단하게 흐름도를 작성해 보았다.

  1. 사용자가 질문을 하고
  2. 어떠한 질문인지 판단하여 그에 맞는 대답을 하고
  3. 비슷한 유형의 질문을 찾아 연관시키고 만약 존재하지 않는다면
  4. 대답을 학습하는 것이다.

추가로 원하는 기능을 호출하면 위젯형식으로 답하는 것도 더했다. (예를 들면 날씨와 계산 등) 기본적인 대화에서부터 사실 머신러닝과 자연어 처리을 피해갈 수가 없는 분야여서 완성된 그림을 아무리 떠올려보아도 실망스럽고 도저히 힘이 나지 않았다. 그래서 완벽하게 처음부터 다시 생각해보았다.

2-2. 현실적으로 가능한 스케일

  1. 내가 구현가능해야 한다.
  2. 최소한의 시간으로 퀄리티를 내야한다.

이 두가지 전제를 지키면서 내가 원하는 봇을 만들어야하는데 주제의 스케일을 좁힐 필요가 있었다. 그래서 위젯형식의 기능적이 요구되는 답을 제공하는 걸 배제했다. 그리고 2번 전제를 지키기 위해 기간상 불가능한 부분은 API(+RESTful)로 대체하기로 했다. 그리고 API를 사용함으로 DB를 사용하지 않기로 했다. 그다지 불필요한 회원기능도 뺐다. 3가지 기능으로 주제를 줄일 수 있었다.

  1. 자신에 대해 물어봤을때 소개하는 것
  2. 정보수집을 요구할때 대답할 수 있는 것
  3. 일상적인 대화(감성적인 대화)에도 대답할 수 있는 것

질문의 유형을 판단하는 로직은 API와 라이브러리를 사용하기로 하고 작업을 시작했다.

  • 일상대화가 가능한 API
  • 정보수집을 위한 크롤링



개발

1. 우리는 친구가 필요해

1-1. 심심이 API

일상대화가 가능한 API를 찾아보던 중 심심이가 API로 제공되는 것을 발견했다.

하하.. 어떻게 보내야 하는거지? 라는 생각이 들었다. 지금까지는 form 데이터, Ajax 비동기 데이터 통신 밖에 해보지 않아서 낯설었다. 하지만 예전에 잠깐 공부한 RESTful이라는 것을 알 수 있었고 java를 통해서도 사용할 수 있도록 라이브러리가 존재했다.


1-2. OkHttp 라이브러리

그 중 OkHttp라는 라이브러리를 사용했다. 가이드는 적합한게 생각보다 얼마 없었지만 사용하기 수월해보여 결정했다. 심심이 API는 데모 프로젝트를 위해 요청 100회를 무료로 지원해준다. "100번 안에 완성하면 성공이다." 라는 작은 미션을 두고 라이브러리의 여러 예시들을 참고하여 구조를 파악하기 시작했다.

그로부터 3시간쯤 걸렸을까 성공해냈다. 정말 오랜만에 가슴이 뛰기 시작했다. 이어지는 성취감과 멋진걸 만들 수 있을거란 예감에 잠도 오지 않았다.


1-3. JSON-SIMPLE 라이브러리

받아온 JSON 데이터에서 무식하게 문자열 자르기를 시전했다가 후에 다른 파트에서도 JSON 데이터로 받아야 해서 구글 코드에서 제공하는 JSON-SIMPLE이라는 라이브러리를 사용해 JSON 객체로 파싱한 후 추출했다.


2. 유용한 정보를 찾아줘

정보수집을 위해 크롤링할 수 있는 경로를 생각해보았다.

  1. 뉴스
  2. 사전
  3. 위키

2-1. 네이버 뉴스

첫번째로 네이버에 검색했을때 가장 먼저 나오는 뉴스를 가져오고 싶었다. 그런데 구글링을 통해 알아본 정보(몇년 전 포스팅된 글들)를 참고하여 시도를 해보았지만 안되길래 다시 조사를 해보았다.

아...? 자체적으로 REST API를 제공한다. 이용 신청해서 TOKEN을 발급받은 뒤 심심이 API 때 학습한 방법으로 OkHTTP 라이브러리를 이용해 시도해보았지만 GET방식과 POST방식의 차이가 조금 있어서 조금 해맸다. 하지만 금방 해결할 수 있었다.

JSON 타입으로 받을 수 있어서 같은 JSON-SIMPLE 라이브러리를 사용하여 추출했다. (여기서 라이브러리를 사용하기로 결심했다.)


2-2. 위키백과

두번째는 나무위키를 크롤링하고 싶었지만 원하는 기본적인 정의에 대한 요약을 정제하는게 쉽지 않았다. 태그가 구조화가 잘 되어있지 않았다. HTML의 기본은 well-formed하고 valid 해야한다 했건만. 다양한 사용자 기반으로 만들어지는 서비스다 보니 이해는 된다.

여러시도 끝에 타겟을 변경하기로 했다. 위키백과는 다행히 적합했다. 그리고 크롤링은 훈련 때 간단하게 하고 넘어가서 가물가물했지만 쉬는시간에 혼자 게임 랭킹을 이용해 닉네임으로 썸네일과 기타 정보를 가져오는 걸 몰래(!?) 해본 덕에 금방 기억이 났고 DOM(Document Object Model)과 셀렉터 표현식에 대한 이해는 그때보다 충분했기에 생각보다 엄청 간단했다. Jsoup이라는 라이브러리를 사용하여 파싱했다.

위키 특유의 참조를 안내하는 text[1]의 [1]를 제거하기 위해 정해진 몇줄을 가져온 뒤 제거해주는 과정을 추가해줬다.


2-3. 네이버 통합사전

위키와 비슷했지만 추가로 생각해주어야 하는 것 들이 있었다.

  1. 단어와 일치하고 있지 않으면 포함하는 단어를 반환한다.
  2. "play","중요"와 같은 제공하는 기능에 관련된 텍스트도 같이 반환된다.
  3. 공백이 불규칙하게 있다.

이 3가지 추가적인 과정을 보완하는 로직을 추가하여 정보를 가져오는 것은 모두 성공했다.


3. 사람이 말하는 방식

3-1. 내 말 알아들어?

하나의 프로세스 메소드에서 특정 키워드를 아규먼트로 넣어주면 작동하게끔 설계했다. 그때서야 아차싶은 것이 있었다. 챗봇이다 보니 단어만 툭 하고 던지는 것이 아니지 않는가. 그래서 자연어 처리를 피할려고 했지 않은가. 어쩔 수 없이 임시방책으로 어떻게 대화를 자주 던지는지 패턴을 분석했다.

ex)
"민들레가 뭐야?", "해리포터는 뭐니?", "개발이 뭐니?", "아이언맨이 뭐니?", "코로나 알아?"

이 질문들의 공통점은 은, 는, 이, 가 + 공백(white space) 앞에 목적어의 명사가 위치한다.

당연하게도 유연하게 대응은 할 수 없겠지만 대부분의 경우는 처리가 가능하기 때문에 유효한 검색어라고 판단하여 그 부분을 추출하게 하였다.


3-2. 내 말 이해해?

드디어 판단하는 클래스를 생성했다. 처음에는 자바스크립트로 이 부분을 처리를 하려고 했다. (나름 서버의 부담을 줄여보려고?) 하지만 크게 무리가 되지 않을 뿐더러 소스가 노출되면 랜덤으로 뿌려주는 인삿말의 데이터가 공개되기 때문에 미리 재미를 반감시킬 것 같아 서버단계로 옮겼다. 아 이번 프로젝트트 DB를 사용하지 않는다. 그리고 서버에 문장을 던졌을때 대답을 응답해주는 깔끔한 구조도 찬성표를 더한 것 같다.

문장이 서버에 넘어오면 그 문장을 분석한다.

  1. "너는","너를","넌","너","blank","블랭크"와 같은 키워드가 포함되면 본인을 소개한다.
  2. "알아","알려","누구","뭐","무엇","어디","언제","어느"와 같은 키워드가 포함되면 정보를 반환한다.

그리고 위의 두가지가 아니면 일상대화로 간주한다. 이 과정을 통해 각자의 로직을 거쳐 대답을 화면으로 응답한다.


3-3. 데이터를 전달하는 방식

그리고 재밌는 점은 소개, 대화는 한 줄의 문자열이고, 정보는 문자열 배열이다. 평소같았으면 DTO, LIST, MAP과 같은 객체를 사용하여 화면에 응답하게 했을지도 모른다. Ajax를 통해 MAP 객체를 사용하긴 했지만 뉴스 10줄, 사전 1줄, 위키 1줄이 생각보다 길지 않아 구분자와 합쳐주어 화면에서 스크립트로 split해서 뿌려주었다.
(혼자하는 프로젝트니 해보고 싶었는데 멍청한 방법이면 알려주길 바람.)




UI/UX

1. 옷이 사람(?)을 만든다

1-1. 전형적인 챗봇에서 벗어나기

Ajax로 화면으로 넘기는 작업을 하던 중 UX/UI를 고민하게 되었다. 전형적인 챗봇 이미지는 싫고 오로지 1:1 대화이다 보니 색다른 느낌을 주고 싶었다.

그래서 고민 끝에 나온 1차 디자인이다. 다크 테마에 그라디언트 애니메이션이 적용된 로고, 대답은 fade in/out 애니메이션이 적용되었다. jQuery와 CSS를 이용했다.


1-2. 전형적인 챗봇으로 돌아오기

문제가 생겼다. 전형적인 챗봇의 UX/UI는 싫은데 한 줄의 대답과 여러 줄의 대답을 전달하는 것이 전혀 자연스럽지가 않았다. 그리고 전체화면으로도 사용할 수 있지만 주로 작게 탭을 띄어서 사용할 예정이라 깨지지 않아야했다. 그래서 다른 방향으로 아이디어를 내려고 노력했다. 이 과정만 3시간은 넘게 걸렸던거 같다. 너무 흔해빠지고 전형적이지 않은 디자인을 css로 구현하는 것도 4시간정도 걸렸다.

컨셉은 바로 1:1 대화가 아니라 팀 채팅이라고 느껴지게 한 후 각자의 맡은 역할을 가진 팀원들이 대답을 해주는 컨셉이였다. 그리고 너무 진지하게 느껴지지 않기 위해 MARVLE의 캐릭터의 특징을 가진 프로필 아이콘을 제작하였다. (구매한 후 흑백으로 편집)

접속한 사용자는 아이피로 닉네임이 대체되고 총 5명의 팀원으로 구성된다. 각자의 맡은 상황에 출동하여 대답을 해주며 헤더부분에 프로필 이미지 우측 상단에 불이 켜지도록 하여 강조했다.

  1. 인사부장(소개)
  2. 언어교수(사전)
  3. 신문기자(뉴스)
  4. 수다쟁이(대화)
  5. 잡학다식(위키)

2. 매너가 사람(?)을 만든다

2-1. 편의성을 위한 기능

채팅을 지울 수 있는 새로고침(body의 태그를 지움, refresh 아님) 함수와 도움말을 hover 했을때 보여줄 수 있는 안내 tip을 안내 받을 수 있게 했는데, 또 이상한 욕심이 생겨 아무것도 없는 div태그 한개로 모든 아이콘에 우려먹는 함수를 만들었다. 사실 위, 아래는 따로 만들려다가 중간에 수식 2줄만 변경되면 돼서 이것도 합쳐버렸다. 재사용성! 그리고 좀 더 채팅의 느낌을 주기 위해 원하는 형식의 시간(타임스탬프)를 반환하는 함수도 만들었다.


2-2. 채팅하는 느낌

먼저 더미 데이터를 넣어 구조를 완성한후 주고 받는 채팅의 효과를 주기위해 jQuery의 append 함수를 사용하는 자체 함수를 만들었다. 경우는 두 가지 이다.

  1. 질문하고(내가 말하고)
  2. 대답을 듣는다.(Bot이 말한다)

질문하는 것은 내가 고정이기때문에 크게 변화가 없다. 어떤 질문을 했는지에 대해 기록이 쌓일 수 있게 해두었다. 대답을 듣는 과정에서(챗봇이 말할 차례) 누가 어떤 이야기를 해야한다. 두 개의 파라미터로 닉네임, 프로필 이미지를 결정하게 했다. 그리고 마지막 채팅이 가장 하단에 올 수 있도록 jQuery의 scrollTop 함수를 이용하였다.




마치며

기대한 것은 자비스가 아니다

결과적으로 기간에 비례해서 만족을 타협하긴 했지만 실질적으로 유용성이 떨어진다. 주제가 아무래도 빅데이터, 딥 러닝같은 전문기술 없이는 매력을 갖추기가 어려운 분야였던 것 같다.

영화 '아이언맨 3'에서 겨우 목숨을 부지하고 아무런 지원과 자원이 없는 외지에서 좌절만 하고 있는 '토니 스타크'에게 꼬마 아이인 '할리 키너'가 이런 말을 건넨다.
"정비공이라고 그랬죠? 뭐라도 만들지 그래요?"

물론 영화 속 '토니 스타크'처럼 천재 엔지니어는 아니지만, 나는 개발자이고 주어진 환경과 내가 사용할 수 있는 기술 수준에서 필요한 것을 최대한 유사하게 실현하려는 경험은 꼭 필요하다고 생각한다. 그것이 더 발전된 기술을 배우고자 하는 동기가 되기도 한다. 이번 과정에서 기술적으로도 새로 알게된 것들과 함께 재밌는 경험으로 남을 것 같다.

profile
Junior Back-End Developer

0개의 댓글