지난주 생각했던 아이디어였던 “그룹 체팅방에 그림을 글자로 옮겨서 보여주기” 아이디어가 여러 사람에 의해 살이 붙어 이 조그만 프로그램을 만들기로 하셨습니다. 원래는 계획을 가지고 실행하려 했으나, 계획을 하면 계획’만’열심히(그러나 성과는 거의 없는)하고 지처서 프로젝트를 진행 하지 않는 저의 게으른 천성(..) 때문에 ‘그냥’만들고 리펙토링을 하는 것으로 결정했습니다.

소스코드!

1차 구조 설계

진행 할 언어는 Javascript입니다. telegram bot으로 검색해본결과 많은 수의 bot들이 다양한 언어로 만들어졌는데 주로 사용되는 언어는 Python, PHP, Javascript(node.js)입니다.

저는 Javascript가 익숙하니 node.js를 이용하여 만들기로 했습니다.

우선 대략적인 구조를 깔고 가야 프로젝트 진행하기가 수월하기 때문에 방향만 잡는 설계를 진행하였습니다. 필요한 것이 무엇인지 파악하고 다음의 기능이 필요하다는 사실을 알았습니다.

  • OCR(Optical character recognition:광학문자인식)
  • telegram bot api

이에 기술조사에 착수하였고 OCR의 경우에는 Google에서 Open Source 라이브러리인 tesseract라는 툴이 가장 범용적으로 쓰이고 한글까지 지원하는 것을 발견하고 이 툴을 사용하기로 합니다.

Telegram bot의 경우에는 공식적으로 api를 지원하고 있고 많은 서드파티들이 존재했기 때문에 아무거나 골라서 쓰면 되겠다는 생각으로 구조 설계를 마쳤습니다.

따라서 process의 흐름은 다음과 같습니다.

process1.png

문제점 발생 - 이놈에 OCR은 왜 항상 미완성 인가.

역시 생각대로 한번에 되는 프로젝트는 없나봅니다 (..) 넓은 그림에 드문드문 있는 글씨로는 tesseract의 인식률은 절망에 가까웠습니다. 제가 인식 시키려고 했던 이미지입니다.

인식을 해야하는 그림

그래서 이미지에서 텍스트 영역을 잡아서 인식시키기로 했습니다. 그림을 영역을 잡기 위해 영역을 나누고 잘라 각각의 파일로 나눈 뒤 각각의 그림을 OCR을 돌리기로 했습니다. 그래서 새로운 툴인 graphicmagick라는 툴을 영입하여 사용하기로 했습니다.

  • OCR(Optical character recognition:광학문자인식)
  • telegram bot api
  • graphicmagick (그림 도구 툴)

process2.png

여러번의 시행착오( 처음에 영역은 2개였으나 차츰 늘어 5개가 됨, 방 이름이 영어라서 인식이 안되어 언어팩을 바꿔가며 사용 등등) 끝에 원하는 텍스트를 추출할 수 있게 되었습니다.(만세!)

telegram bot api는 생각보다 어려웠다.

현재 이 프로젝트는 node.js의 telegram bot api module인 node-telegram-bot-api를 이용하여 체팅 봇의 이벤트 리스너를 사용하고 있다.

이벤트 리스너 기반이라는 것을 알았지만 적용시키는데에는 우리의 봇과 1시간이나 체팅을 하면서 놀아야만 하였다 \=_=//

우여곡절 끝에 bot.on()bot.onText()의 차이(on()는 모든 메시지의 반응하는 이벤트리스너이고 onText()는 bot api의 기능중 하나인 command를 사용하기 위해 만들어진 것이였다.)를 알아내었고 “안녕”이라는 키워드에 반응 하도록 하는데 또 1시간이 들었다. 그럼 이제 추출된 값을 보내줄수 있게 되었다!

process3.png

마지막인가…?

이제 가장 중요한 그림을 가져오는 것만 하면된다. 고맙게도 telegram bot api에선 각 메시지 노드가 어떤 값을 가지고 있는지 잘 구분 할 수 있도록 되어있었고, 그림이나 파일을 올리면 각각의 메시지가 다르게 나오도록 구성해놨다. 또한 메시지로 보내졌던 파일을 바로 받아서 저장할 수 있도록 하였기 때문에 다운로드 받기도 편헀다. 일이 이상하게도(?) 순조롭게 진행 되는 것 같다.

if (msg.document) {
    ...
} else if (msg.photo) {
    ...
} else if (mes.text) {
    ...
}

위와 같은 코드를 통해 메시지를 분류하여 처리하였다. 일단 계획한 대로 잘 처리되는 프로그램이 완성되었다.

process4.png

뭔가 허전한데..

이 작업을 하루만에(그것도 저녁이 되기전에!) 끝내고 뿌듯해 하고 있을 때, 문득 떠올랐다. “아.. 이거 캘린더 링크 만들어 주기로 했지..”. 무려 구글켈린더를 안쓴다는 한 친구에 말이 같이 떠오르면서…

만들면 되지!

추가 과제가 출몰하였습니다. 구글 켈린더 링크와 애플 켈린더 링크를 보내주는 것 까지를 목표로 하게 되었습니다.

process5.png

애플 캘린더는 복잡하구나..

링크를 어떻게 만들면 좋을까 라는 고민에 문득 떠오른 사이트가 있었으니 그것은 onoffmix였습니다. 2~3년전 자주 사용했지만 이제는 이용이 뜸해진 그 곳에서는 이벤트 등록 편의를 위해 구글 켈린더 링크와 ics 파일을 다운로드 받을 수 있도록 되어있습니다. 순간 스치는 의문점.. “왜 애플 캘린더는 이벤트 추가 링크가 없지?”라는 생각과 검색 끝에 확실한 정보는 찾을 수 없었지만, 브라우져로 서비스되지 않기 때문이라는 추론만 남긴체 결국 ics파일을 만드는 방향으로 프로세스를 수정합니다.

process6.png

ics는 표준 규격이 존재한다.

일단 모험심이 강한 필자는 ics파일을 까서 어떤 형식을 취하는 지를 확인하고 내가 (쉽게!) 만들수 있는지를 조사하기로 했습니다.

in_icsFile.png

위 그림처럼 얼마안되는 양의 양식이였기 때문에 별로 어렵지 않다고 생각한 필자는 field부분을 어떻게 채워 나가야 하는지 파악하며 나아가는 중 UID부분에서 정보를 찾지 못하였고 결국 npm의 ics 모듈과 노드의 기본모듈인 fs모듈을 사용하여 ics를 만들고 보내는 방식으로 프로그램을 제작하였습니다.

역시 갓 구글! 찬양하라!

구글은 짱이다. 구글은 편리하다. 찬양하라 구글! 구글 링크 만드는 코드를 공개합니다.

eventLinkToGoogle = "http://www.google.com/calendar/render?action=TEMPLATE&text=[이벤트제목]&dates="+(new Date(시작시간 [YYYY-MM-DD HH:MM])).toISOString().replace(/-|:|\.\d\d\d/g,"")+"/"+(new Date(종료시간 [YYYY-MM-DD HH:MM])).toISOString().replace(/-|:|\.\d\d\d/g,"")+"&sprop=name:주최자&location=장소";

process7.png

진짜 마지막인가…?

result.png

잘 작동 되는 것이 확인 되었습니다. 이제 라즈베리 파이로 옮기기만 하면 됩니다.

끝!

rasp-pi.png

라즈베리파이에 이식 또한 완료되었습니다!

다 쓰고 나서 생각난 이야기

  1. 사실 이 프로세스를 진행하는 도중 엉뚱한 이미지 파일을 올리면 저장해놓은 스케쥴 데이터가 망가지는 (..) 사태를 한번 발생 시킨 적이 있습니다.. 그래서 graphicmagick의 compare라는 기능을 이용해 처음 등록되는 스케쥴 이미지와 다를 경우 이미지 분석을 하지 않고 넘기는 기능도 구현해놨습니다.
  2. 이 프로그램은 2일만에 만들어졌고, 리팩토링을 하기 위해 많은 ‘검색’(좀 그만해 ㅠ)을 하였고, 디렉토리 구조를 바꾸는 일과 함수 쪼게기 등을 진행하였습니다.
  3. 리팩토링을 진행 하는 도중에 webpack이나 gulp, jankins, travis CI 등등 많은 툴을 조사 하고 적용 시키려고 하였으나, 이건 마치 5천원 짜리 물건에 10만원 짜리 보험을 드는 일 같아 보류하기로 했습니다. 이 프로그램이 조금 더 커지고 리팩토링이 어느정도 진행되어야만 사용 할 수 있을 것 같습니다.
  4. 사실 이번주에 mocha를 이용하여 TDD를 이용하는 리팩토리를 진행하려고 했습니다.(사실 CI를 돌리려면 필요해서 진행한건 안 비밀..) 하지만 필자는 게을렀고 TDD를 진행해야지라고 생각하고 오늘 좀 보다가 결국 글만 올리게 되었습니다.

마무리 지으며

이 프로그램이 얼마나 더 발전될지는 모르겠지만 (개인적으론 좀 더 가지고 놀 수 있도록, 혹은 많은 사람들이 범용적으로 쓸 수 있도록 개발되었으면 좋겠습니다.) 당분간은 이 프로그램과 다른 프로젝트는 겸하여 진행하려고 합니다. 끗!