Youtube 비디오 기반 쇼츠(Shorts) 콘텐츠 생성 및 추천 서비스
주로 숏폼 콘텐츠를 생산하기 위해, 기존에 업로드된 영상에서 재미있는 혹은 흥미로운 동영상 구간을 설정해 다시 편집해 업로드 하는 프로세스입니다.
1. 서비스 설계
1.1 쇼츠는 어떻게 만들어야할까?
기존 쇼츠 콘텐츠들을 살펴보면 다음과 같은 구조이다. 대다수 메인 영상과 함께 제목, 자막 or 부제목 or 댓글 내용이 주를 이룬다. 영상 길이는 짧게는 10초 길게는 60초까지이다. 대다수의 숏폼 형태의 콘텐츠들은 어느 정도 정형화된 틀을 가져간다.
즉, 모바일 해상도에 맞춰서 숏폼 콘텐츠가 생산되는 것이다. 특별하게 숏폼 콘텐츠를 생산하는
편집툴
을 개발하는 것이 아닌, 기존에 업로드된 영상을 숏폼 형태로 재가공할 수 있는 서비스로 방향을 정했다.- 제목
- 메인 영상
- 자막 or 서브 제목
- 출처
1.2 숏폼 콘텐츠 살펴보기 - 기준을 찾아보자.
유튜브에 올라온 영상을 기준으로 살펴보면 다음과 같다.
- 가장 많이 다시 본 장면
유튜브에는 일정 조회수 이상 혹은 설정에 따라
가장 많이 다시 본 장면
이 기록되는 구조이다. 물론 이러한 장면은 특정한 채널 혹은 규모 이상의 콘텐츠만 가능하기 때문에 숏폼으로 만드는 기준이 될 수 없다.- AI 기반으로 추천 받기
비디오의 특성 상 직접 영상을 분석하고
재미있다
라는 주관적 포인트를 찾기 어렵다. 특정한 테마(카테고리)의 영역이라면 몰라도, 유튜브에 업로되는 영상은 매우 다양하다. 따라서 특정 테마에만 적용되는 AI 학습 모델은 적절치 못하다라고 생각했다. AI 학습 모델은 사용이 불가능할까?
E-스포츠 영역에서는 특정 게임에 따라 다양한 이벤트가 발생하기 때문에 이러한 이벤트를 기반으로 학습을 해나가면 된다. 하지만 핑계고, 너덜트, 킥서비스 등의 예능 그리고 뉴스, 정보 전달형, 방송 편집본 등의 영상에는 해당되지 않는다.
AI 기반으로 추천을 어떻게 받을 수 있을까?
직접 영상을 분석하는 방식이 아닌 다른 방식은 없을까? 고민했다. 유튜브에는 자동으로
자막
(Caption)을 생성해주고 있다. 이러한 자막
은 해당 영상의 내용을 주로 담고 있다. 심지어 한국어의 경우 자동으로 음성을 인식해서 생성된다. 영상을 분석할 수 없다면, 영상에 나온 음성(자막)을 분석하면 어떨까?
실제 해당 자막을 받아서 chatGPT에게 물어보았다. 우선 자막 기반으로 내용을 정리해보았다.
여기서 API 빌링 이슈가 발생하기 때문에 우선은 댓글 중심으로 처리하고 그 수가 3개 이하인 케이스에 대해서 총6개가 나오도록 chatGPT에 질의하도록 하자. 또한 댓글이 0개인 케이스도 있기 때문에 미리 이 부분은 준비해야한다
현재 Task 에서 0개 또는 3개 이하인 케이스에 대해서만 추가 질의를 통해 하이라이트 구간을 추정할 수 있게 만들면 된다. 이 부분은 API 를 등록하고 테스트할 수 있게만 된다면 크게 문제는 없어 보인다. 물론 ChatGPT 4.0 기반으로 해야 편하게 가능하리라 생각된다.
위 라이브러리를 통해 자막을 통째로 가져올 수 있다. 출력 값은 다음과 같다. 물론 작동 방식이 바뀌는 순간 적용이 되지 않겠지만…
또한 출력에 대한
formatting
을 지원한다. - JSONFormatter
- PrettyPrintFormatter
- TextFormatter
- WebVTTFormatter
- SRTFormatter
1.1.2 또 다른 새로운 구간을 찾을 수 없을까?
유튜브 댓글을 보다보니, 재미있었던 영상 내 시작점을 표시하는 것을 볼 수 있었다. 이러한 데이터들은 실제 구독자들이 표시하는 구간으로써
재미있다
라는 기준점이 되는 것 같았다. 이러한 데이터를 수집하기 위해 유튜브 영상에서 댓글을 크롤링하기로 했다.핑계고 영상 기준으로 댓글 수는 1208개로 수집 시간은 대략 50초 정도 걸렸다. 이 부분을 조금 더 빠르게 해보려면 아마도 API로 변경해야할 듯 하다.
그리고 이러한 데이터를 모아서, 댓글에 언급된 시작 시간과 좋아요 수의 상관관계를 추론해보았다. 여기서 좋아요 수는 해당 댓글의 좋아요 수로써 좋아요가 높을 수록 해당 영상의 재미있는 구간으로 추론할 수 있기 때문이다.
X 축을 영상의 분, Y축을 초로 해서 해당 포인트들은 댓글에 언급된 시작 시간을 의미한다. 그리고 좋아요 수가 높을 수록 짙은 색을 띄게 된다. 여기서 가장 좋아요가 높은 구간을 살펴보면 다음과 같다.
- 32분 26초 ~ 32분 41초
- 29분 11초 ~ 29분 21초
- 26분 10초 ~ 26분 19초
3개의 구간을 얻을 수 있었다.
1.2 영상 편집이 필요하다.
단순히 영상만 추출하는게 아니다.
간단하게 영상만 추출해서 편집자들이 이러한 영상을 또 편집해야하는 문제가 있다. 그렇기 때문에 간단하게나마(?) 웹에서 편집을 할 수 있어야 한다고 생각했다. 기존
python
에서 영상 편집을 하기 위해서, opencv
를 사용해왔다. 물론 내가 만들면서 사용한 라이브러리는
moviepy
이다. python 라이브러리 중에서 그나마 동영상 편집이 편한 라이브러리 중 하나다. opencv 기반으로 동영상을 편집하는 것 보다 수월하게 편집이 가능하기 때문이다. - cuts
- concatenations
- title insertions
- compositing
등등 다양한 기능이 있다. 물론 엄청 불친절(?)한 doc이지만 그래도 그게 어딘가. 오래된 라이브러리만큼 자료들을 충분히 찾아볼 수 있었다. (현재 개발은 2020년이 최근이라 좀 그렇지만 쓸만하다.)
또한
moviepy
는 numpy, imageio, decorator, prglog, ffmpeg 등이 자동으로 설치되기 때문에 편하게 사용할 수 있다. 사실 tqdm
을 더 많이 쓰는 듯한데, proglog
는 자세한 내용까지는 모르지만 유사한 것으로 볼 수 있다. (공식 문서에서는 tqdm을 대규모 프로젝트를 빌드할 때 관리가 어렵다고 한다.) 위 예시 코드를 보면, 현재 비디오 파일을 서브클립을 생성할 수 있다. 또한 text 클립 또한 가능하고 이를 하나로 합쳐서 랜더링도 가능하다. 내가 원하는 기능이 모두 있는 셈이다.
1.2.1 동기식 요청이 아닌 비동기 요청 - Celery 사용하기
영상 인코딩을 위해 celery를 이용해 비동기 작업을 처리했다. 이번에도 동일하게 처리하기 위해 다음과 같은 celery job 을 설정하였다. 크게 전체 task 는 다음과 같다.
- 원본 영상 다운로드
- 자막 다운로드
- 댓글 가져오기(데이터 수집)
- 하이라이트 구간 계산(데이터 처리)
- 서브 클립 생성
- 영상 랜더링
영상 편집하기 전까지 처리 과정은 1~4번 과정이 필요하다. 실제로는 5개의 task가 돌아가는 것 이다. 자막은 빠르게 처리가 가능하기 때문에 따로 빼두었으나, 1,3,4번 과정이 조금 시간이 걸리게 되었다. 또한 4번 서브 클립 생성을 위해선, 1번과 3번 task가 선행되고 난 뒤 처리해야 했다.
우선 원본 영상 다운로드와 댓글 수집 관련 Task를 group화 하여 모두 완료되면,
chord
를 이용해 다음 task 인 서브 클립 생성 task를 처리했다. 다음으로 쇼츠 편집을 하고 완료된 영상 또한 별도 처리하였다. celery chord 란?
여러개의 작업을 수행하는 서브 테스크를 만든 뒤, 각 task의 return을 받아서 처리할 수 있는 방식을 의미한다. 원본 동영상과 하이라이트 댓글의 정보를 기반으로 서브 클립을 생성해야 하기 때문이다.
chain을 써보려했지만, 이러면 비동기 요청을 하는 의미가 없어지므로, group으로 묶어서 하위 작업으로 처리하고 chord를 통해 작업 결과를 받아서 최종 서브 클립을 생성하는 방식이다.
여기서 문제는 댓글 하이라이트를 가져올 때 신뢰도가 부족한 경우이다. 이때는 결과 값이 없기 때문에 서브 클립을 생성할 수 없다. 또한 하위 작업이 실패한 경우 전체 실패로 이어지기 때문에 잘 생각하고 만들어야 한다.
1.3 Docker + AWS 아키텍처 설계
Docker Compose 로 컨테이너를 구동 + AWS 아키텍처에 대해 회고하도록 한다.
CPU 연산이 많은 케이스 이기 때문에 EC2
C6
를 선택하였다. 하지만 회사 정책 상 베타테스트 수준이고, 클라우드 EC2에서 얼마나 괜찮은 성능을 내는 가에 대한 문제가 있기 때문에 현재는 t3
인스턴스로 고정하였다EC2(t3.medium) 으로 구성하였고, 내부에 5개 컨테이너를 관리하는 방식이다. Flow는 다음과 같다.
- Route53 → ALB(HTTPS:443) → EC2(HTTP:80) → NGINX(80:8000) → django(8000:gunicorn)
워크플로우 자체는 복잡해 보이긴하는데, 실상 SSL을 적용하고 관리하는 입장에서 생각해보면 위와 같은 플로우로 접근하는게 편리해보인다.
➡️ 참고 링크