본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 04. 05:03

AI 기반 미팅 플랫폼을 처음부터 구축했습니다 — 실제 작동 방식은 다음과 같습니다

요약

WebRTC, RAG, 실시간 감정 분석 기술을 결합한 AI 기반 화상 회의 플랫폼 'Hoovik'의 전체 아키텍처를 소개합니다. Node.js, Python, React를 활용하여 분산형 서비스 구조를 구축하는 과정을 다룹니다.

핵심 포인트

  • WebRTC와 Socket.IO를 이용한 실시간 통신 구현
  • RAG 기술을 적용한 회의 녹취록 기반 지능형 검색
  • FastAPI 기반의 실시간 감정 인식 및 전사 파이프라인
  • Redis와 MongoDB를 활용한 분산형 룸 관리 시스템

Hoovik에 대한 완전한 분석: WebRTC 시그널링 (signaling), Redis를 활용한 분산형 Node.js, 실시간 감정 AI, 회의 녹취록 기반의 RAG, 그리고 Python 전사 (transcription) 파이프라인 — 이 모든 것이 하나로 연결되어 있습니다.

👉 GitHub: https://github.com/AnupamKumar-1/Hoovik

🌐 라이브 데모: https://hoovik.onrender.com

🎮 인터랙티브 데모: https://app.supademo.com/demo/cmpy5ggyv95b0qmy7ccrkd3ms?utm_source=link

저는 이전에 Hoovik의 감정 분석 시스템과 WebRTC 시그널링 (signaling) 아키텍처를 포함한 개별 구성 요소들에 대해 작성한 적이 있습니다.

해당 글들은 특정 하위 시스템 (subsystems)에 집중했습니다. 이번 글은 전체 플랫폼에 초점을 맞춥니다.

Hoovik는 단일 애플리케이션이 아닙니다. 이는 함께 작동하는 서비스들의 집합체입니다: React/WebRTC 프론트엔드, 분산형 Node.js 백엔드, 전사 (transcription) 파이프라인, 실시간 감정 인식 서비스, 그리고 회의 녹취록을 기반으로 구축된 검색 증강 생성 (RAG) 시스템입니다.

이 글에서는 이러한 시스템들이 어떻게 상호작용하는지, 그 뒤에 숨겨진 아키텍처 결정 사항들, 그리고 각 구성 요소를 구축하면서 직면했던 트레이드오프 (tradeoffs)에 대해 살펴봅니다.

Hoovik의 실제 정체

Hoovik는 실시간 통신, AI 보조 분석, 그리고 녹취록 지능을 결합한 다자간 화상 회의 플랫폼입니다.

이 플랫폼은 다음을 포함합니다:

  • Socket.IO 시그널링 (signaling)을 이용한 실시간 WebRTC 화상 회의
  • 회의 참가자를 위한 실시간 얼굴 및 음성 감정 분석
  • 세그먼트 수준의 NLP 감정 태깅이 포함된 다중 화자 전사 (transcription)
  • 실시간 감정 데이터로 풍부해진 AI 생성 회의 요약
  • 회의 녹취록에 대한 검색 증강 생성 (RAG)
  • 녹취록 접근 요청 및 승인 워크플로 (workflows)
  • Redis 및 MongoDB를 기반으로 하는 분산형 룸 관리

시스템은 네 가지 주요 서비스로 구성됩니다.

네 가지 서비스

Hoovik Services

  1. React 프론트엔드 (Vite)
  2. Node.js 백엔드 (Express + Socket.IO)
  3. Python 전사 서비스 (Transcript Service, FastAPI)
  4. Python 감정 서비스 (Emotion Service, FastAPI + Socket.IO)

이 글의 나머지 부분은 미팅의 생명주기(lifecycle)를 따라 각 서비스가 어떻게 참여하는지 설명합니다.

1. Node.js 백엔드

백엔드는 다음을 담당합니다:

  • 인증 (Authentication)
  • 미팅 생성 및 관리
  • Socket.IO 시그널링 (Signaling)
  • 전사 데이터 (Transcript) 저장
  • 전사 데이터 접근 요청
  • AI 요약 생성
  • RAG 인덱싱 및 쿼리 (Indexing and querying)

배포는 다음과 같은 요소들을 통해 연결된 여러 개의 PM2 프로세스로 실행됩니다:

  • 영속성 (Persistence)을 위한 MongoDB
  • 공유 상태 (Shared state)를 위한 Redis
  • 프로세스 간 이벤트 전달을 위한 Socket.IO Redis 어댑터 (Redis Adapter)

공유 룸 상태 (Shared Room State)

여러 Node.js 인스턴스가 요청을 처리할 때, 룸 상태를 프로세스 메모리에 안전하게 보관할 수 없습니다.

대신, 변경 가능한 미팅 상태는 Redis에 저장됩니다.

참가자들은 Redis 해시 (Hash)에 저장됩니다:

meeting:participants:

각 필드는 직렬화된(serialized) 참가자 객체를 포함합니다.

이 설계는 다음과 같은 이점을 제공합니다:

  • 입장(join) 시 특정 필드에 대한 HSET 업데이트
  • 퇴장(leave) 시 특정 필드에 대한 HDEL 업데이트
  • 모든 백엔드 프로세스 간의 공유 상태 유지
  • 직렬화 오버헤드(serialization overhead) 감소

입장 순서는 별도로 저장되며, WebRTC 역할 할당(role assignment)에 사용됩니다.

분산 입장 잠금 (Distributed Join Locking)

룸에 입장하는 것은 공유 상태를 수정합니다.

경쟁 상태 (Race conditions)를 방지하기 위해, 룸 입장은 Redis 기반의 분산 잠금 (Distributed lock)을 사용하여 직렬화됩니다.

await withRoomLock(meetingCode, async () => {
  // 입장 로직 (join logic)
});

잠금은 다음을 사용합니다:

  • SET NX PX 획득
  • 토큰 기반 소유권 (Token-based ownership)
  • Lua 스크립트를 이용한 비교 및 삭제 해제 (compare-and-delete release)

이를 통해 한 번에 하나의 입장 작업만이 룸 상태를 변경하도록 보장합니다.

인증 (Authentication)

인증은 JWT 액세스 토큰 (Access tokens)과 리프레시 토큰 로테이션 (Refresh token rotation)을 사용합니다.

로그인 이슈:

  • 짧은 수명의 JWT 액세스 토큰 (Access token)
  • HttpOnly 쿠키에만 저장되는 불투명 리프레시 토큰 (Opaque refresh token)

리프레시 토큰은 모든 리프레시 요청 시 로테이션 (Rotation)되어, 사용자 세션을 유지하면서도 재전송 공격 (Replay risk) 위험을 줄입니다.

2. 프론트엔드 (The Frontend)

프론트엔드는 독립적인 서브시스템을 관리하는 특화된 훅 (Hooks)을 중심으로 구축된 React 애플리케이션입니다.

주요 책임은 다음과 같습니다:

  • WebRTC 피어 연결 (Peer connection) 관리
  • Socket.IO 시그널링 (Signaling)
  • 채팅 (Chat)
  • 활성 화자 감지 (Active speaker detection)
  • 감정 포착 (Emotion capture)
  • 녹화 (Recording)
  • 전사 내용 보기 (Transcript viewing)
  • RAG 상호작용 (RAG interaction)

WebRTC

피어 연결은 전용 React 훅을 통해 관리되며, 퍼펙트 네고시에이션 (Perfect negotiation) 패턴을 구현합니다.

애플리케이션은 다음을 지원합니다:

  • 다자간 비디오 (Multi-party video)
  • ICE 재시작 (ICE restarts)
  • 화면 공유 (Screen sharing)
  • 원격 참가자 관리 (Remote participant management)

활성 화자 감지 (Active Speaker Detection)

두 가지 독립적인 감지 경로가 존재합니다.

SSRC 경로

사용 가능한 경우:

js RTCRtpReceiver.getSynchronizationSources()

를 사용하여 RTP 오디오 레벨을 직접 가져옵니다.

RMS 폴백 (RMS Fallback)

SSRC를 지원하지 않는 브라우저는 다음을 사용합니다:

  • Web Audio API
  • AnalyserNode
  • RMS 에너지 계산 (RMS energy calculations)

애플리케이션은 적절한 방법을 동적으로 선택합니다.

감정 포착 (Emotion Capture)

호스트는 다음을 포착합니다:

  • 원격 참가자의 비디오 프레임 (Video frames)
  • 원격 참가자 스트림의 오디오 청크 (Audio chunks)

포착된 미디어는 전용 Socket.IO 연결을 사용하여 감정 서비스 (Emotion service)로 직접 전송됩니다.

각 참가자는 독립적인 감정 서비스 연결을 받으므로, 참가자 수준의 미디어 상태 추적 및 백프레셔 제어 (Backpressure control)가 가능합니다.

감정 서비스는 서버 상태 및 백프레셔 이벤트를 통해 프론트엔드에 포착 속도를 조정하도록 지시할 수 있습니다.

감정 인지 요약 (Emotion-Aware Summaries)

회의 중에 수집된 감정 이벤트는 로컬에 저장되며, 이후 AI 요약을 생성할 때 제출됩니다.

백엔드는 다음을 결합합니다:

  • 전사 내용에서 파생된 감정 정보 (Transcript-derived emotion information)
  • 실시간으로 포착된 감정 이력 (Live captured emotion history)

이를 통해 AI 요약(AI summaries)은 발화 내용과 관찰된 참가자의 감정 사이의 주목할 만한 불일치를 강조할 수 있습니다.

3. 전사 서비스 (The Transcript Service)

전사 서비스는 FastAPI로 구현되었습니다.

주요 책임은 다음과 같습니다:

  • 오디오 처리 (Audio processing)
  • 음성 인식 (Speech recognition)
  • 화자 분할 (Speaker segmentation)
  • 세그먼트 수준의 NLP 감정 분류 (Segment-level NLP emotion classification)

이 서비스는 전사와 감정 태깅을 위해 다음을 사용합니다:

  • Whisper
  • DistilRoBERTa

비동기 처리 (Asynchronous Processing)

회의 녹화본은 회의가 종료된 후 업로드됩니다.

서비스는 즉시 다음을 반환합니다:

http 202 Accepted

그리고 백그라운드 작업(background task)에서 처리를 수행합니다.

처리 파이프라인은 다음과 같습니다:

오디오 업로드 (Audio Upload) ↓ FFmpeg 변환 (FFmpeg Conversion) ↓ Whisper 전사 (Whisper Transcription) ↓ 세그먼트 병합 (Segment Merging) ↓ NLP 감정 분류 (NLP Emotion Classification (DistilRoBERTa)) ↓ Node 백엔드로 전사 콜백 (Transcript Callback To Node Backend)

전사 데이터 전달 (Transcript Delivery)

처리가 완료되면, 전사 서비스는 구조화된 전사 데이터를 Node.js 백엔드로 다시 보냅니다.

일시적인 백엔드 장애 발생 시 신뢰성을 높이기 위해 재시도 로직(Retry logic)이 사용됩니다.

4. 감정 서비스 (The Emotion Service)

감정 서비스는 참가자의 미디어 스트림(media streams)에 대해 실시간 추론(real-time inference)을 수행합니다.

프론트엔드는 다음을 서비스로 직접 전송합니다:

  • emotion.frame 이벤트
  • audio_chunk 이벤트

서비스는 다음을 사용하여 추론을 수행합니다:

  • Wav2Vec2
  • MediaPipe
  • XGBoost 앙상블 모델 (XGBoost ensemble models)

그리고 프론트엔드로 다음 이벤트를 다시 방출(emit)합니다:

text emotion.result 이벤트

양식 인식 처리 (Modality-Aware Processing)

참가자가 하나의 양식(modality)을 비활성화하더라도 추론은 계속됩니다.

예시:

  • 카메라 활성화, 마이크 비활성화 → 비디오 전용 모드 (video-only mode)
  • 마이크 활성화, 카메라 비활성화 → 오디오 전용 모드 (audio-only mode)

이를 통해 두 가지 미디어 스트림이 모두 필요하지 않아도 감정 추적을 계속할 수 있습니다.

백프레셔 지원 (Backpressure Support)

서비스는 또한 다음 이벤트를 방출합니다:

  • server.status
  • backpressure

이를 통해 프론트엔드가 캡처 속도(capture rates)를 동적으로 조정하고 부하를 줄일 수 있습니다.

5. RAG 파이프라인 (The RAG Pipeline)

전사 데이터가 저장된 후, 의미론적 검색(semantic retrieval)을 위해 인덱싱될 수 있습니다.

인덱싱 파이프라인(indexing pipeline)은 다음과 같이 구성됩니다:

  1. 청킹 (Chunking)
  2. 임베딩 생성 (Embedding generation)
  3. 백그라운드 인덱싱 (Background indexing)
  4. 벡터 검색 (Vector retrieval)
  5. LLM 답변 생성 (LLM answer generation)

청킹 (Chunking)

화자 세그먼트(speaker segments)를 사용할 수 있는 경우, 청크(chunks)는 다음을 보존합니다:

  • 화자 할당 (Speaker attribution)
  • 타임스탬프 (Timestamps)
  • 전사 구조 (Transcript structure)

그렇지 않은 경우, 슬라이딩 윈도우(sliding-window) 청킹 전략이 사용됩니다.

임베딩 (Embeddings)

임베딩은 다음을 사용하여 생성됩니다:

text nomic-embed-text-v1.5

중복 계산을 방지하기 위해 임베딩 결과는 Redis에 캐싱됩니다.

인덱싱 (Indexing)

전사(Transcript) 인덱싱은 BullMQ 워커(workers)를 통해 비동기적으로 실행됩니다.

이를 통해 시간이 오래 걸리는 임베딩 작업이 API 요청을 차단하는 것을 방지합니다.

검색 (Retrieval)

검색은 다음을 결합합니다:

  • MongoDB 벡터 검색 (MongoDB Vector Search)
  • 최대 한계 관련성 (Maximum Marginal Relevance, MMR)

이를 통해 관련성(relevance)과 다양성(diversity)의 균형을 맞춥니다.

답변 생성 (Answer Generation)

검색된 컨텍스트(context)는 Groq에서 호스팅되는 언어 모델(language models)로 전달되어 답변을 생성합니다.

회의 데이터에 대한 멀티턴 대화(multi-turn conversations)를 지원하기 위해 세션 히스토리(Session history)가 유지됩니다.

액세스 제어(Access control)는 전사 액세스와 동일한 권한 부여 모델을 따릅니다:

  • 전사 소유자 (Transcript owner)
  • 승인된 전사 요청 (Approved transcript request)
  • 소유권 메타데이터가 없는 레거시 전사 (Legacy transcripts without ownership metadata)

트레이드오프 및 향후 개선 사항 (Tradeoffs And Future Improvements)

현재 아키텍처에는 몇 가지 알려진 트레이드오프(tradeoffs)가 남아 있습니다.

  • 회의 정리 작업(Meeting cleanup jobs)이 각 백엔드 프로세스에서 독립적으로 실행됩니다.
  • BullMQ 워커는 현재 전용 워커 프로세스가 아닌 애플리케이션 서버와 함께 실행됩니다.
  • 전사 서비스(transcript service)는 아직 중앙 집중식 작업 큐(job queue)를 사용하지 않습니다.
  • Safari 미디어 미리보기 우회 작업(Safari media preview workarounds)을 포함하여 일부 브라우저별 처리가 여전히 필요합니다.

이러한 결정은 플랫폼의 현재 규모에서는 수용 가능한 수준이었으나, 전용 워커와 큐 기반 처리(queue-based processing)가 자연스러운 다음 단계가 될 것입니다.

모든 것을 통합한 후 (After Putting It All Together)

Hoovik은 단순한 비디오 미팅 애플리케이션에서 WebRTC, 실시간 머신러닝(real-time machine learning), 전사 지능(transcript intelligence), 그리고 검색 증강 검색(retrieval-augmented search)을 결합한 분산 플랫폼으로 진화했습니다.

이 프로젝트에서 가장 흥미로웠던 부분은 단일 기술 그 자체가 아니었습니다. 서비스 간의 경계를 설계하고, 실제 환경의 제약 조건 하에서 서비스들이 안정적으로 함께 작동하도록 만드는 과정이었습니다.

구현 내용을 살펴보고 싶다면, 인터랙티브 데모(interactive demo)를 시도해 보거나 GitHub에서 소스 코드(source code)를 확인해 보세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0