5d636e8619d64a5901aee9354cc6f21a4f484106
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_KEYELEVENLABS_VOICE_ID
Discord 모드에서만 필수:
DISCORD_BOT_TOKENDISCORD_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_SOURCEpw-record --target에 넣을 PipeWire source id 또는 node name
LOCAL_AUDIO_SINKpw-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_EVENTStrue면 명령을 실행한 텍스트 채널에 transcript/reply를 같이 올림
실행
bun install
Ollama 준비:
ollama pull qwen3:0.6b
속도보다 품질이 더 중요하면:
ollama pull qwen3:1.7b
# 또는
ollama pull qwen3:4b
디스코드 모드:
bun run start:discord
로컬 장치 목록:
bun run audio:devices
로컬 테스트 모드:
bun run start:local
타입 체크:
bun run check
사용 흐름
- 봇을 서버에 초대하고 음성 권한을 부여합니다.
- 음성 채널에 들어갑니다.
- 텍스트 채널에서
/join실행 - 말을 하면 봇이 발화 단위로 인식하고 음성으로 짧게 답합니다.
- 다시 말하면 현재 읽고 있던 TTS는 즉시 중단됩니다.
로컬 테스트:
bun run audio:devices로 source/sink id 또는 이름 확인ollama pull qwen3:0.6b- 필요하면
.env에LOCAL_AUDIO_SOURCE,LOCAL_AUDIO_SINK,OLLAMA_MODEL설정 bun run start:local- 마이크로 바로 말해서 응답 확인
설계 메모
- 입력은 유저별 병렬 처리
- 출력은 길드 세션당 단일 큐
- 로컬 모드는 단일 화자 입력 기준
- 화자 구분은
speaker_id,speaker_name을 LLM 프롬프트에 항상 포함 - 현재 기본 LLM은
qwen3:0.6b이며 속도 우선 설정이라 답변 품질이 약하면qwen3:1.7b또는qwen3:4b로 올리는 것을 권장합니다. - STT/TTS는 아직 ElevenLabs API를 사용하므로 프로젝트 전체가 완전 무과금은 아닙니다.
Description
Languages
TypeScript
87.3%
Python
11.6%
Dockerfile
0.8%
Batchfile
0.3%