# Streaming Avatar 개발기 - v3: 핵심 기술 스택 선정 ## 개요 v2에서 설계한 아키텍처를 구현하기 위한 구체적인 기술 스택을 선정합니다. 비용 효율성과 성능의 균형을 고려합니다. ## 기술 선정 기준 1. **성능**: 실시간 처리 가능 여부 2. **비용**: 운영 비용 및 라이선스 3. **확장성**: 동시 접속자 처리 4. **유지보수**: 커뮤니티 및 문서화 5. **통합성**: 다른 컴포넌트와의 호환성 ## 1. 프론트엔드 스택 ### 선정: Next.js 14 + React 18 ```typescript // package.json { "dependencies": { "next": "^14.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "@livekit/components-react": "^1.4.0", // WebRTC 라이브러리 "zustand": "^4.4.0", // 상태 관리 "tailwindcss": "^3.3.0" // 스타일링 } } ``` **선정 이유:** - Server Components로 초기 로딩 최적화 - Edge Runtime 지원 (Vercel/Cloudflare) - LiveKit 컴포넌트와 좋은 호환성 - 풍부한 생태계 ### WebRTC 라이브러리 비교 | 라이브러리 | 특징 | 비용 | 선택 | |-----------|------|------|------| | **LiveKit** | 풀스택 솔루션, 오픈소스 | Free (Self-hosted) | ✓ | | Daily.co | 쉬운 통합 | $0.004/min | | | Twilio | 안정적, 대규모 | $0.004/min | | | agora.io | 글로벌 인프라 | $0.99/1000min | | **LiveKit 선정 이유:** - 오픈소스 (Apache 2.0) - Self-hosted 가능 (비용 절감) - Simulcast, Dynacast 지원 - 우수한 Python SDK ## 2. 백엔드 스택 ### 선정: FastAPI + Python 3.11 ```python # requirements.txt fastapi==0.104.0 uvicorn[standard]==0.24.0 python-multipart==0.0.6 websockets==12.0 aiortc==1.6.0 livekit==0.11.0 redis==5.0.0 celery==5.3.4 ``` **선정 이유:** - 비동기 처리 (async/await) - 자동 API 문서화 (OpenAPI) - AI/ML 라이브러리와 호환성 - Type hints 지원 ### 태스크 큐: Celery + Redis ```python # tasks/pipeline.py from celery import Celery app = Celery('streaming_avatar', broker='redis://localhost:6379') @app.task def process_speech_to_avatar(session_id: str, audio_data: bytes): """음성 → 아바타 파이프라인 처리""" # 1. STT text = transcribe_audio(audio_data) # 2. LLM response = generate_response(session_id, text) # 3. TTS + Lip Sync video_stream = generate_avatar_video(response) # 4. 스트리밍 전송 stream_to_client(session_id, video_stream) ``` ## 3. AI 컴포넌트 ### 3.1 STT (Speech-to-Text) | 서비스 | 지연 | 정확도 | 비용 | 선택 | |--------|------|--------|------|------| | **Faster-Whisper** | ~100ms | 높음 | Free | ✓ (Self-hosted) | | Deepgram | ~50ms | 높음 | $0.0043/min | 백업 | | Google STT | ~200ms | 높음 | $0.006/min | | | Azure STT | ~150ms | 높음 | $0.016/min | | ```python # stt/whisper_engine.py from faster_whisper import WhisperModel class WhisperSTT: def __init__(self): self.model = WhisperModel( "small", # small 모델 (244M params) device="cuda", compute_type="float16" ) async def transcribe_stream(self, audio_stream): """실시간 음성 인식""" async for chunk in audio_stream: segments, _ = self.model.transcribe( chunk, beam_size=1, # 속도 우선 language="ko", vad_filter=True ) for segment in segments: yield segment.text ``` ### 3.2 LLM (Large Language Model) | 모델 | 지연 (첫 토큰) | 품질 | 비용/1M tokens | 선택 | |------|---------------|------|----------------|------| | **Gemini 2.0 Flash** | ~200ms | 우수 | $0.075 | ✓ | | GPT-4o mini | ~300ms | 우수 | $0.150 | 백업 | | Claude Haiku | ~250ms | 우수 | $0.250 | | | Llama 3 (Self) | ~100ms | 양호 | Free | | ```python # llm/gemini_client.py import google.generativeai as genai class GeminiLLM: def __init__(self, api_key: str): genai.configure(api_key=api_key) self.model = genai.GenerativeModel( 'gemini-2.0-flash-exp', system_instruction="""당신은 친절하고 도움이 되는 AI 어시스턴트입니다. 응답은 자연스러운 대화체로, 2-3문장 이내로 간결하게 답변하세요.""" ) async def generate_stream(self, messages: list) -> AsyncIterator[str]: """스트리밍 응답 생성""" response = await self.model.generate_content_async( messages, stream=True, generation_config={ "max_output_tokens": 150, "temperature": 0.7 } ) async for chunk in response: if chunk.text: yield chunk.text ``` ### 3.3 TTS (Text-to-Speech) | 서비스 | 지연 | 품질 | 비용/1M chars | 선택 | |--------|------|------|---------------|------| | **Google TTS** | ~100ms | 양호 | $4.00 | ✓ (기본) | | **ElevenLabs** | ~150ms | 최고 | $15.00 | ✓ (프리미엄) | | Coqui XTTS | ~200ms | 양호 | Free | 백업 | | Azure TTS | ~120ms | 우수 | $4.00 | | ```python # tts/hybrid_engine.py from google.cloud import texttospeech from elevenlabs import generate, stream class HybridTTS: def __init__(self, use_premium: bool = False): self.use_premium = use_premium # Google TTS (기본) self.google_client = texttospeech.TextToSpeechClient() # ElevenLabs (프리미엄) self.elevenlabs_voice = "21m00Tcm4TlvDq8ikWAM" # Rachel async def synthesize_stream(self, text: str): """실시간 음성 합성""" if self.use_premium: # ElevenLabs 스트리밍 audio_stream = generate( text=text, voice=self.elevenlabs_voice, model="eleven_turbo_v2", stream=True ) async for chunk in audio_stream: yield chunk else: # Google TTS synthesis_input = texttospeech.SynthesisInput(text=text) voice = texttospeech.VoiceSelectionParams( language_code="ko-KR", name="ko-KR-Neural2-A" ) audio_config = texttospeech.AudioConfig( audio_encoding=texttospeech.AudioEncoding.LINEAR16 ) response = self.google_client.synthesize_speech( input=synthesis_input, voice=voice, audio_config=audio_config ) yield response.audio_content ``` ### 3.4 Lip Sync | 모델 | 실시간 | 품질 | GPU 요구 | 선택 | |------|--------|------|----------|------| | **MuseTalk** | ✓ | 높음 | RTX 3060+ | ✓ | | Wav2Lip | △ | 중간 | RTX 2060+ | 백업 | | SadTalker | ✗ | 높음 | RTX 3080+ | | | LivePortrait | △ | 최고 | RTX 4080+ | | ```python # lipsync/musetalk_engine.py import torch from musetalk.inference import MuseTalkInference class MuseTalkEngine: def __init__(self, avatar_path: str): self.model = MuseTalkInference( device="cuda", model_path="musetalk_v1.5" ) self.avatar = self.model.load_avatar(avatar_path) def generate_frames(self, audio_features: torch.Tensor): """오디오 특징으로 프레임 생성""" for features in audio_features.chunk(25): # 25fps frame = self.model.generate( avatar=self.avatar, audio_features=features ) yield frame ``` ## 4. 인프라 스택 ### 4.1 컴퓨팅 | 용도 | 사양 | 예상 비용/월 | |------|------|-------------| | API Server | 4 vCPU, 8GB RAM | $40 | | GPU Server | RTX 4090 x1 | $200 | | Redis | 2GB | $15 | | **합계** | | **~$255** | ### 4.2 클라우드 서비스 비교 | 서비스 | GPU | 시간당 비용 | 선택 | |--------|-----|------------|------| | **RunPod** | RTX 4090 | $0.44 | ✓ | | Lambda Labs | A100 | $1.29 | | | AWS | A10G | $1.00 | | | GCP | T4 | $0.35 | 백업 | ## 5. 최종 기술 스택 ```yaml # docker-compose.yml 미리보기 services: frontend: build: ./frontend ports: - "3000:3000" environment: - NEXT_PUBLIC_API_URL=http://api:8000 - NEXT_PUBLIC_LIVEKIT_URL=wss://livekit:7880 api: build: ./backend ports: - "8000:8000" depends_on: - redis - livekit deploy: resources: reservations: devices: - capabilities: [gpu] livekit: image: livekit/livekit-server ports: - "7880:7880" - "7881:7881" volumes: - ./livekit.yaml:/livekit.yaml redis: image: redis:7-alpine ports: - "6379:6379" ``` ## 비용 추정 (월간) | 항목 | 비용 | |------|------| | GPU 서버 (RunPod) | $200 | | API 서버 | $40 | | Gemini API (100K req) | $7.50 | | Google TTS (1M chars) | $4.00 | | 도메인 + SSL | $10 | | **총 비용** | **~$261/월** | ## 다음 단계 (v4) MuseTalk을 설치하고 실시간 립싱크 파이프라인을 구현합니다. --- *이 시리즈는 총 10개의 포스트로 구성되어 있습니다.*