[OCR / Python] (밥에 진심인 사람의) 식단표 자동 알림 프로젝트
오랜만에 블로그에 와서 글을 남깁니다.
오늘은 하루 만에 뚝딱 만들어낸 (스스로도 어떻게 해내었는지 알 수 없는) 프로젝트에 관한 이야기를 해보려고 합니다.
개발 과정에 대해 상세히 담고 싶은데 코딩에 급급하여 스크릿샷도 제대로 찍어둔 게 없네요; 회고처럼 쭉 작성해 볼까 합니다.
1. 계기
제가 다니고 있는 회사는 참 감사하게도 점심, 저녁을 제공합니다. 매주 월요일 (요즘은 금요일)에 식단표가 카톡에 공유가 되는데 매번 식단표를 찾아 카톡에 들어가기도 귀찮고 그렇게 본 메뉴도 늘 까먹어 다시 들어가야 한다는 불편함이 있었습니다. 까짓 거 그냥 점심시간 되면 구내식당 가서 메뉴 보면 되지 뭘 귀찮게 구냐 싶을 수도 있지만 '오늘은 뭐가 나올까?' 하며 행복한 고민하는 것도 업무효율 향상에 도움이 된다고 생각합니다.(??)
이러한 불편함을 느낀 저는 회사 동기들이 있는 단체 슬랙방에 예약메시지를 걸어놓게 됩니다. 매일 아침 10시와 오후 4시 이렇게 두 번 오늘 나올 점심과 저녁 메뉴를 슬랙 알림으로 공유를 하게 됩니다. 그러나 이는 지속성이 떨어지는 방법이었습니다. 왜냐하면 매번 식단표가 올라오면 그걸 손수 타이핑하여 시간까지 일일이 설정해서 예약메시지를 걸어둬야 하기 때문입니다. 예약메시지 쓰다가 자칫하여 보내지기도 하고, 월요일부터 금요일까지 점심, 저녁 총 10개의 예약메시지를 작성해야 하다 보니 빠뜨리는 것도 생겼습니다.
오늘 점심에 뭐가 나오는지 빠르게! 그것도 정확하게! 자동으로 알 수 있는 방법을 고민하다가 OCR을 떠올리게 됩니다.
2. 개발에 필요한 것들
과거 인턴 프로젝트 중 웹툰 말풍선을 추출했던 기억이 파팟! 머리 속을 스쳐 지나갑니다.
네이버 클라우드 콘솔에 들어가서 OCR API를 다시 뒤적거렸습니다.
네이버 클라우드에서 OCR 서비스를 합리적인 가격에 제공하고 있었습니다.
저는 일주일에 한 번 올라오는 식단표 이미지를 OCR로 추출해오는 정도로 고도의 기술 또는 많은 양의 API 호출이 필요하진 않았습니다.
무료 요금제로 CLOVA OCR API를 생성하였고, 글자 인식률을 파악하기 위해 18장의 식단표 이미지를 준비했습니다.
3. CLOVA OCR API로 식단표 이미지 속 메뉴 가져오기
개발 과정은 꽤나 험난했습니다.
먼저 클로바 OCR API를 처음 사용해 보는 거라 (인턴 당시에는 사내 API로 미리 만들어주셨음) 어떤 식으로 사용하는 건지 가이드를 봐도 알 수 없었습니다. '일단 부딪히고 본다'는 무대뽀 정신으로 어찌저찌 OCR 템플릿까지 생성합니다. 하지만 무대뽀 정신은 이내 API Gateway 자동연동이라는 큰 벽에 부딪히고 맙니다.
OCR API <-> API Gateway <-> 외부 접속
OCR API를 외부에서 사용하려면, 직접 OCR API를 호출해서 사용하는 것이 아니라 API Gateway를 통해서 접근이 가능했습니다.
따라서 OCR API를 만들고 API Gateway 자동연동을 하게되면, 말 그대로 자동으로 API Gateway를 생성을 해주었습니다. 하지만 이걸 모르고 무대뽀로 덤볐던 저는 3시간 동안 게이트웨이를 지웠다가 다시 만들었다가 ,, 메서드를 정의했다가 지웠다가를 반복했습니다.
그러다가 Text OCR API 가이드 를 우연히 마주치게 되고 연결까지 하게 됩니다.
이제 내 식단표를 API에 넣어주면 인식할 수 있다는 기쁨도 잠시, 두 번째 벽에 부딪힙니다.
Text OCR API 호출 가이드 예제에서 이미지를 URL의 형태로 넣어주는 겁니다.
내 이미지는 내 데스크탑에 있는 실물 이미지인데 얘를 대체 어떻게 링크로 넣어주지? 깊은 고민에 빠지게 됩니다.
1. 속는 셈치고 네이버 클라우드에서 서버를 새로 파고 거기다가 이미지를 올려두자.
2. 내 컴퓨터를 서버로 만들고 내 이미지를 어떻게든 링크로 만들어보자.
1번의 방법은 가장 쉽고 빠른 길이지만 단점은 돈이 듭니다. 가장 저렴한 서버를 빌린다고 하더라도 얼마가 나올지 모르기 때문에 일단 보류.
2번의 방법은 번거롭고 보안 문제가 존재하지만 내 컴퓨터를 서버로 만드는 귀중한 경험을 할 수 있다는 생각에 2번으로 고고
하지만 2번의 방법도 녹록지 않았습니다. 내 컴퓨터를 외부에서 접속 가능하게 한다고 해도 이미지를 URL 형태로 만들 수는 없었습니다.
아 이렇게 나의 프로젝트는 사그라드는 것인가.. 그치만 어떻게든 해결하고 싶다는 생각이 강했습니다. 다음 주에 또다시 식단표를 슬랙에다 타이핑할 생각 하니 아찔해졌습니다. 다시 API문서를 꼼꼼히 읽어보자.
API 명세를 다시 읽어보니 이미지를 보낼 수 있는 방법이 url 만 있는 것은 아니었습니다. 바로 images.data!!!!!!
images.data는 base64 인코딩 이미지 바이트
이미지를 base64 의 형태로 인코딩하면 내 식단표를 요청에다가 실어 보낼 수 있다!! 번뜩 파이썬이 생각나서 파이썬으로 이미지를 인코딩하여 요청을 보냈고, 마침내 식단표 OCR에 성공하게 됩니다.
사람이 직접 찍은 식단표 사진, 스캔으로 올라온 식단표 사진 등 다양한 18개의 식단표 사진 속 메뉴들을 정확하게 인식해 가져왔습니다!
이제 슬랙봇을 만들어서 정해진 시간에 정해진 메뉴를 정해진 채널에 뿌려주기만 하면 됩니다.
4. 슬랙봇 생성해서 정해진 시간에 메뉴 보내기
슬랙봇을 생성하는 과정에서도 쉽지 않았습니다.
슬랙봇을 생성하고나서 슬랙봇의 scope(워크스페이스 내 권한) 지정하는 게 중요했습니다. 특히 저처럼 봇이 메시지를 보내야 하는 경우라면 write 권한을 주셔야 합니다.
현재 제가 수동으로하고 있던 일을 이제 슬랙봇에게 시켜야 합니다. (드디어!)
slack에서 제공하고 있는 API 중에서 chat.ScheduleMessage 를 사용하면 날짜, 시간을 지정해 메시지를 보낼 수 있습니다.
API 문서를 확인해보면 해당 메서드를 사용하기 위해 필요한 scope들이 나와있으니 참고해서 지정하면 됩니다.
친절히 파이썬 예제도 알려주어서 코딩하는 과정은 어렵지 않았습니다.
하나 고민했던 부분은 한 번의 인식으로 월요일부터 금요일까지 모든 메뉴 예약 메시지를 걸고 싶은데 가능한가? 였습니다.
datetime 모듈로 날짜를 계산하는 방식으로 해결했습니다. 코드를 실행한 날짜에서 메시지를 보내려는 날짜까지의 남은 일수를 계산해서 한 번에 예약메시지를 걸도록 했습니다. 이 부분은 스스로 어떻게 짜길 원하는지도 명확하지 않아서 더 혼란스러웠던 것 같습니다 ;
예약메시지 부분은 사실 예제로 퉁치긴 했는데 코드 정리가 안된 부분이 많아서 정리가 좀 필요한 상황입니다.
5. Cursor에 대해서
요즘 AI가 엄청 핫해지면서 코딩에도 AI 바람이 불고 있습니다.. 저도 이 바람에 편승하고자 cursor라는 IDE를 사용해 보았는데요, 아주아주 만족스러웠습니다. Cursor라는 친구는 맨 처음 나왔을 때는 vscode의 extension과 단축키를 버리고 갈 정도로 대단하다고 느끼지는 못했습니다. 그냥 AI를 탑재한 IDE이군.. 정도였는데 이제는 vscode에서 사용하는 extension을 그대로 가져올 수 있으면서 AI까지 되니까 막강한 IDE라는 생각이 들었습니다.
코드 자동완성과 실시간 채팅으로 코드를 바로바로 짤 수 있다는 점이 아주 만족스러웠습니다. 코드 자동완성의 경우 지금 내가 짜고 있는 코드에 맞게 변수도 알아서 완성시켜줍니다. 코파일럿, 챗지피티에 굳이 돈 쓸 만큼 좋은가? 싶었는데 cursor 쓰면서 처음으로 이거 구독해서 써보고 싶다는 생각이 들었습니다. 한국 돈으로 2만 원 정도인데 그 이상의 가치를 하는 것 같습니다. 그만큼 만족스럽고 코드의 일부분만 부탁해도 알아서 챡챡 짜주니까 시간도 전보다 훨씬 단축이 됩니다.
6. 앞으로..
코딩으로 제가 실생활에서 겪는 문제를 해결해본 첫 사례입니다. (두둥!) '코딩으로 일상 속 문제를 해결하고 싶어요~'라고 말하고 다녔지만 사실 진짜 해결한 건 이번이 처음이라는 게 머쓱합니다. 하루를 꼬박 코딩으로 시간을 보냈는데 원하던 결과물이 나와서 굉장히 뿌듯하네요. 이렇게 글도 작성했으니 뭐라도 남는 게 있겠죠. 당장 쓰기에는 부족한 점이 많아 주말 동안 보완 후 다음 주에 동기 분들께 짜잔~ 공개하려고 합니다. 이번에 코딩을 하면서 왜 구조를 짜는 게 중요한지, 내가 뭘 만들고 싶은지? 어떻게 동작하길 바라는지? 등 이전에 고민하는 단계가 필요함을 절실히 느꼈습니다. 슬랙봇이 어떻게 동작해야 하는지? 스스로도 정의가 안되어있다 보니 지금 글을 쓰는 순간에도 내가 뭘 모르고 뭘 해결했는지 설명하기가 어렵다고 느껴집니다. 이번에 짠 코드들을 주말에 다시 보면서 구조화해 보고 더 보완해 보면서 쓰기에 불편함 없는 그런 슬랙봇이 되기를 희망합니다. 직무가 QA다 보니 더 손볼 곳이 없는지 계속 찾게 되는 건 직업병인가요? 아무튼 앞으로도 이런 경험이 많아지기를 바라며.. 이번 식단표 프로젝트가 그 시작이 되었으면 하는 바람에서 쓴 글입니다.
긴 글 읽어주셔서 감사합니다.
관련하여 코드 및 구조가 궁금하다면, 아래 Github 참고 부탁드립니다.
https://github.com/jjimini98/bob_alarm