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를 같이 올림

실행

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

사용 흐름

  1. 봇을 서버에 초대하고 음성 권한을 부여합니다.
  2. 음성 채널에 들어갑니다.
  3. 텍스트 채널에서 /join 실행
  4. 말을 하면 봇이 발화 단위로 인식하고 음성으로 짧게 답합니다.
  5. 다시 말하면 현재 읽고 있던 TTS는 즉시 중단됩니다.

로컬 테스트:

  1. bun run audio:devices 로 source/sink id 또는 이름 확인
  2. ollama pull qwen3:0.6b
  3. 필요하면 .envLOCAL_AUDIO_SOURCE, LOCAL_AUDIO_SINK, OLLAMA_MODEL 설정
  4. bun run start:local
  5. 마이크로 바로 말해서 응답 확인

설계 메모

  • 입력은 유저별 병렬 처리
  • 출력은 길드 세션당 단일 큐
  • 로컬 모드는 단일 화자 입력 기준
  • 화자 구분은 speaker_id, speaker_name을 LLM 프롬프트에 항상 포함
  • 현재 기본 LLM은 qwen3:0.6b 이며 속도 우선 설정이라 답변 품질이 약하면 qwen3:1.7b 또는 qwen3:4b 로 올리는 것을 권장합니다.
  • STT/TTS는 아직 ElevenLabs API를 사용하므로 프로젝트 전체가 완전 무과금은 아닙니다.
Description
No description provided
Readme 561 KiB
Languages
TypeScript 87.3%
Python 11.6%
Dockerfile 0.8%
Batchfile 0.3%