Skip to content

Latest commit

Β 

History

38 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Watson

Discord bot that records voice channel audio, transcribes it with faster-whisper, and optionally generates a short recap with Ollama. Saves WAV files and transcript text to disk; posts only a recap (if enabled) and links to saved files in the channel.

Add Watson to your server

Features

  • Voice recording β€” Joins a voice channel and records participants (WAV). Max length and β€œwarning before stop” are configurable.
  • Transcription β€” Speech-to-text via faster-whisper (model/device/compute_type in .env). Runs in a thread so the bot stays responsive.
  • Saved files β€” WAV and transcript .txt are written to a recordings directory (configurable). The bot does not post transcript text in the channel, only a recap (if Ollama is on) and safe references to saved files (paths relative to the recordings dir, or basenames only via env).
  • Ollama recap β€” Optional short summary (200–300 chars) after each recording: what was discussed, decisions, who’s responsible. In the same language as the dialogue. Prompt is in prompts/recap.txt.
  • Auto-stop β€” When the last human leaves the voice channel, recording stops and processing runs. Mute/deafen in the same channel is ignored (bot does not leave).
  • Config β€” All settings via .env (prefix, temp/recordings dirs, Whisper, Ollama, recap prompt path). Optional WATSON_FORCE_IPV4 if voice fails on broken IPv6; optional WATSON_LOCKDOWN_VOICE_COMMANDS and path privacy flags β€” see .env.example.

Prerequisites

  • Python 3.10–3.13 (py-cord 2.8.x RC wheels do not declare support for 3.14 yet; use 3.12 for local dev if your system Python is newer).
  • Discord bot token β€” create an application and bot; enable Message Content Intent and Server Members Intent
  • macOS (Homebrew): Opus from /opt/homebrew/lib/libopus.dylib (or set OPUS_LIB_PATH in .env)

For recap: Ollama installed and running (e.g. ollama run llama3.2). Set OLLAMA_RECAP_MODEL in .env to enable.

Adding Watson to your server

  1. Open the invite link at the top of this README.
  2. Select the server (you need Manage Server or Administrator).
  3. Click Authorize.

Then use !join, !record, !stop, !leave, !check in a text channel (see Usage).

Setup

  1. Clone and venv

    cd Watson
    python -m venv .venv
    source .venv/bin/activate   # Windows: .venv\Scripts\activate
  2. Install dependencies

    pip install -r requirements.txt

    Main deps: py-cord 2.8.0rc2 (2.8.x prerelease on PyPI with ongoing DAVE/voice fixes β€” pin to stable py-cord==2.8.0 when it appears), faster-whisper, ollama, python-dotenv, aiohttp.

  3. Configure

    cp .env.example .env

    Set at least:

    DISCORD_TOKEN=your_bot_token_here

    Optional (see .env.example):

    • BOT_COMMAND_PREFIX (default !)
    • WATSON_TEMP_DIR, WATSON_RECORDINGS_DIR (default ./temp, ./recordings)
    • RECORDING_MAX_MINUTES, WARNING_BEFORE_STOP_MINUTES
    • WHISPER_MODEL, WHISPER_DEVICE, WHISPER_COMPUTE_TYPE, TRANSCRIPT_LANGUAGE, TRANSCRIPT_BEAM_SIZE
    • OLLAMA_HOST, OLLAMA_RECAP_MODEL, RECAP_PROMPT_FILE (recap prompt path)
    • WATSON_LOCKDOWN_VOICE_COMMANDS, WATSON_ALLOWED_ROLE_IDS (restrict voice commands on public servers)
    • WATSON_DISCORD_HIDE_PATHS (show only filenames in Discord instead of relative paths)
    • WATSON_MAX_CONCURRENT_TRANSCRIPTIONS (parallel Whisper pipelines across guilds; default 1)

    Bot and invite: Developer Portal β†’ Bot β†’ enable intents β†’ OAuth2 URL Generator (scope bot, permissions: View Channels, Connect, Speak, Send Messages, Read Message History, Attach Files).

Usage

  1. Invite the bot. Required permissions: View Channels, Connect, Speak, Send Messages, Read Message History, Attach Files.

  2. In a text channel:

    Command Description
    !join Bot joins your current voice channel
    !record Start recording (max length from RECORDING_MAX_MINUTES; warning in channel before auto-stop)
    !stop Stop recording and process (transcribe + optional recap, then post recap and file links)
    !leave Bot leaves the voice channel
    !check Connection status and bot permissions (embed)
  3. After processing, the bot posts Done, then the recap (if OLLAMA_RECAP_MODEL is set), then references to saved files (relative to your recordings directory by default). No full transcript text is sent in the channel.

For public servers, enable WATSON_LOCKDOWN_VOICE_COMMANDS so only moderators (Manage Server / Administrator / configured roles) can use !join, !record, !stop, and !leave. !check stays available for diagnostics.

Saved transcript file format: first line = header (date, time, guild name, channel name); blank line; recap (if any); blank line; transcript body.

Docker

  • Ollama runs as a separate service; the bot connects to it via OLLAMA_HOST.
  • Recordings directory in the container is mounted from the host so files persist.
docker compose up -d

Then pull a model for recap (if you use it):

docker compose exec ollama ollama pull llama3.2

In .env set OLLAMA_RECAP_MODEL=llama3.2 (and optionally override OLLAMA_HOST; compose sets OLLAMA_HOST=http://ollama:11434).

On a remote host, mount your host folders in docker-compose.yml, e.g.:

volumes:
  - /data/watson/recordings:/app/recordings
  - /data/watson/temp:/app/temp

Troubleshooting

  • Bot left when I muted β€” Fixed: the bot only leaves when someone actually leaves the channel; mute/deafen in the same channel is ignored.
  • High memory β€” Use WHISPER_DEVICE=cpu and WHISPER_COMPUTE_TYPE=int8; prefer smaller Whisper models if needed.
  • Voice works better over IPv4 β€” Some networks break Discord UDP over IPv6; set WATSON_FORCE_IPV4=1 in .env.
  • Voice 4017 / DAVE (E2EE) β€” If Discord closes the voice websocket with ConnectionClosed code 4017, the gateway rejected the handshake because DAVE (mandatory Discord voice end‑to‑end encryption) negotiation failed. Py-cord may not yet satisfy DAVE on your shards; Watson only surfaces the failure in chat/logs β€” fix requires a Py-cord release with DAVE‑compatible voice (or another supported client). See pycord#3135.
  • Slow transcription β€” Use GPU: WHISPER_DEVICE=cuda, WHISPER_COMPUTE_TYPE=float16 (and install CUDA deps).
  • Heavy load from multiple guilds β€” Default WATSON_MAX_CONCURRENT_TRANSCRIPTIONS=1 serializes Whisper work across servers; increase only if CPU/GPU allows.
  • No recap β€” Ensure Ollama is running and OLLAMA_RECAP_MODEL is set; in Docker, OLLAMA_HOST=http://ollama:11434 is set by compose.
  • Bot doesn’t respond β€” Enable Message Content Intent (and Server Members Intent) in the Developer Portal.
  • "Error occurred while decoding opus frame" β€” Usually a single bad voice packet; recording often continues. If it’s frequent, install libopus (e.g. brew install opus on macOS, apt install libopus0 on Debian) and set OPUS_LIB_PATH in .env to the library path (see .env.example).

Testing

Discord and faster-whisper are mocked; no token or model needed:

pytest tests/ -v

See tests/README.md for testing concurrent recordings (mocks and manual).

Project structure

watson/
β”œβ”€β”€ __init__.py
β”œβ”€β”€ bootstrap.py         # Logging, dirs, env check, bot.run
β”œβ”€β”€ config.py            # Env-backed Settings
β”œβ”€β”€ discord_patches.py   # Optional IPv4, Opus, VoiceClient shutdown patch
β”œβ”€β”€ env_check.py         # Writable dirs + optional Ollama probe
β”œβ”€β”€ handlers.py          # Commands, listeners, recording pipeline
β”œβ”€β”€ paths.py             # Safe path strings for Discord messages
β”œβ”€β”€ permissions.py       # Optional lockdown for voice commands
β”œβ”€β”€ recap.py             # Ollama recap (blocking helper)
β”œβ”€β”€ state.py             # Bot instance + transcribing guild set
β”œβ”€β”€ transcribe.py        # Lazy Whisper + transcript formatting
main.py                  # Entry: dotenv, IPv4 patch, run_bot()
prompts/
β”œβ”€β”€ recap.txt            # Prompt for recap ({{TRANSCRIPT}} placeholder)
scripts/
β”œβ”€β”€ discord_voice_smoke.py   # Standalone voice gateway diagnostic
tests/
β”œβ”€β”€ conftest.py          # Mocks for handlers/transcribe imports
β”œβ”€β”€ test_main.py         # Helpers, config, command behaviour
└── README.md            # Concurrent recording notes
Dockerfile
docker-compose.yml
.env.example
requirements.txt
README.md

License

Use and modify as you like.

About

πŸ€– Discord bot that records voice channels and transcribes audio in real-time using Faster-Whisper. Features auto-stop and timestamped transcripts.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages