# realtime_voice_bot 디스코드 음성 채널 또는 로컬 PC 마이크/스피커에서 한국어 음성을 인식하고, 로컬 LLM 응답을 생성한 뒤 ElevenLabs TTS로 다시 읽어주는 최소 프로토타입입니다. ## 현재 구현 범위 - Discord slash command 기반 제어: `/join`, `/leave`, `/status`, `/reset`, `/say` - 로컬 테스트 모드: `pw-record` 입력, `pw-play` 출력 - `@discordjs/voice` 기반 음성 채널 입장 및 유저별 오디오 수신 - 48k stereo PCM을 16k mono로 내려서 유저별 VAD 처리 - Silero 계열 VAD(`avr-vad`)로 발화 시작/종료 감지 - ElevenLabs Scribe Realtime WebSocket으로 발화 단위 STT - Ollama 로컬 LLM으로 짧은 한국어 답변 생성 - ElevenLabs Flash v2.5 스트리밍 TTS - 채널 단위 단일 재생 큐 - 사용자 발화 시작 시 현재 TTS와 대기열 중단(barge-in) ## 권장 환경 - Bun `1.3+` - Node.js `22.12+` - Ollama - Discord bot with Voice permissions - ElevenLabs API key + 사용할 Voice ID ## 환경 변수 `.env.example`를 참고해서 `.env`를 채우면 됩니다. 필수: - `ELEVENLABS_API_KEY` - `ELEVENLABS_VOICE_ID` Discord 모드에서만 필수: - `DISCORD_BOT_TOKEN` - `DISCORD_APPLICATION_ID` 선택: - `DISCORD_COMMAND_GUILD_ID` - 테스트 서버에만 slash command를 즉시 반영하려면 설정 - `OLLAMA_BASE_URL` - 기본값: `http://localhost:11434` - `OLLAMA_MODEL` - 기본값: `qwen3:0.6b` - 가장 빠른 무료 오픈웨이트 로컬 기본값 - `OLLAMA_KEEP_ALIVE` - 기본값: `5m` - `OLLAMA_NUM_CTX` - 기본값: `4096` - `LOCAL_AUDIO_SOURCE` - `pw-record --target` 에 넣을 PipeWire source id 또는 node name - `LOCAL_AUDIO_SINK` - `pw-play --target` 에 넣을 PipeWire sink id 또는 node name - `LOCAL_SPEAKER_NAME` - 로컬 테스트에서 프롬프트에 넣을 화자 이름 - `ELEVENLABS_STT_MODEL` - 기본값: `scribe_v2_realtime` - `ELEVENLABS_TTS_MODEL` - 기본값: `eleven_flash_v2_5` - `DEBUG_TEXT_EVENTS` - `true`면 명령을 실행한 텍스트 채널에 transcript/reply를 같이 올림 ## 실행 ```bash bun install ``` Ollama 준비: ```bash ollama pull qwen3:0.6b ``` 속도보다 품질이 더 중요하면: ```bash ollama pull qwen3:1.7b # 또는 ollama pull qwen3:4b ``` 디스코드 모드: ```bash bun run start:discord ``` 로컬 장치 목록: ```bash bun run audio:devices ``` 로컬 테스트 모드: ```bash bun run start:local ``` 타입 체크: ```bash bun run check ``` ## 사용 흐름 1. 봇을 서버에 초대하고 음성 권한을 부여합니다. 2. 음성 채널에 들어갑니다. 3. 텍스트 채널에서 `/join` 실행 4. 말을 하면 봇이 발화 단위로 인식하고 음성으로 짧게 답합니다. 5. 다시 말하면 현재 읽고 있던 TTS는 즉시 중단됩니다. 로컬 테스트: 1. `bun run audio:devices` 로 source/sink id 또는 이름 확인 2. `ollama pull qwen3:0.6b` 3. 필요하면 `.env` 에 `LOCAL_AUDIO_SOURCE`, `LOCAL_AUDIO_SINK`, `OLLAMA_MODEL` 설정 3. `bun run start:local` 4. 마이크로 바로 말해서 응답 확인 ## 설계 메모 - 입력은 유저별 병렬 처리 - 출력은 길드 세션당 단일 큐 - 로컬 모드는 단일 화자 입력 기준 - 화자 구분은 `speaker_id`, `speaker_name`을 LLM 프롬프트에 항상 포함 - 현재 기본 LLM은 `qwen3:0.6b` 이며 속도 우선 설정이라 답변 품질이 약하면 `qwen3:1.7b` 또는 `qwen3:4b` 로 올리는 것을 권장합니다. - STT/TTS는 아직 ElevenLabs API를 사용하므로 프로젝트 전체가 완전 무과금은 아닙니다.