1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
# Senator Sperma (Rust)
A Discord bot rebuilt in Rust from the original Python implementation. Music
playback via songbird, AI chat via OpenRouter or anything OpenAI compatible (ollama.cpp and such), TTS, web/file search
scheduled jobs, per-server triggers, QR codes, media conversion, and misc utilities.
Built on poise 0.6 + serenity 0.12 + songbird 0.6, with async SQLite (sqlx 0.9)
for persistence.
## Setup
### 1. Clone
```bash
git clone https://codeberg.org/salmonik/senator-sperma
cd senator-sperma
```
### 2. System Dependencies
The following binaries must be available on `PATH`:
- `ffmpeg` — audio decoding/encoding for playback, conversion, and compression
- `qalc` (Qalculate) — used by `/math` to evaluate expressions
- `yt-dlp` (optional) — used by `/download`
- `piper` (optional) — local TTS for `/tts` and `/senator ... tts_vc`; falls back to Google Translate TTS if unavailable
Unlike the Python version, QR encode/decode is handled by the pure-Rust
`qrcode`/`rxing` crates — no `zbar` system library required.
### 3. Build
Requires a recent Rust toolchain (edition 2024).
```bash
cargo build --release
```
### 4. Configure Environment
Create a `.env` in the project root
look at `.env.example` on what to put there
On launch, missing variables are reported via tracing (`error!` for required,
`warn!` for optional with defaults). The database and schema migrations are
created automatically on first run.
For local TTS, set `TTS_MODEL_PATH` to a Piper `.onnx` model file (or a
directory of models, in which case `TTS_VOICE` selects the model, defaulting to
`pl_PL-bass-high`). When `TTS_MODEL_PATH` is unset or Piper is unavailable, the
bot falls back to Google Translate TTS.
### 5. Run
```bash
cargo run --release
```
## Commands
Slash commands are autoregistered globally on startup. Some are registered
under their original Polish verb names to match the UI expected by existing
servers.
### AI
- `/senator` — chat with the OpenRouter model
### Music (songbird)
- `/music grajcuj` — play from Copyparty search, a direct URL, or an uploaded file; optional `position` (`now`, `next`, `last`, default `last`)
- `/music queue` — show the current track followed by the pending queue
- `/music skip` — stop the current track and play the next queued one
- `/music stop` — stop playback, clear the queue, and leave voice
- `/music join` — join the caller's voice channel
### TTS
- `/tts` — local Piper TTS (Polish, Google Translate fallback), sent as a file or played in voice
### Search & Web
- `/web` — DuckDuckGo HTML scrape (soon to use 4get)
- `/search` — search Copyparty and return a direct download URL
- `/download` — fetch media from any yt-dlp-supported URL
### Media Tools
- `/compress` (alias `kompresja`) — compress a media attachment to low quality
- `/convert` (alias `konwersja`) — convert media between formats
### Utilities
- `/upload` — push Discord attachments into Copyparty
- `/say` — repeat the given text as the bot
- `/math` — evaluate an ASCII math expression through `qalc`
- `/qr generowanie` / `/qr dekodowanie` — QR encode / decode
### Triggers
- `/trigger create` — new trigger group
- `/trigger add` — add keywords/responses to a group
- `/trigger remove` — remove a keyword/response
- `/trigger delete` — delete a group
- `/trigger list` — list a group's keywords and responses
- `/trigger help` — usage info
### Cron
- `/cron dodaj_audio` — schedule audio playback
- `/cron dodaj_wiadomość` — schedule a periodic message
- `/cron pokaż` — list all cron jobs
- `/cron usuń` — remove a cron job
- `/cron pauza` — pause a job
- `/cron wznów` — resume a job
### Message Context Menu
- "Wyślij załączniki" (right-click message) — upload attachments to Copyparty
- "kompresja" (right-click message) — compress all attachments
## Architecture
The runtime is organised around a shared `Data` struct (poise `user_data`)
that holds the DB pool, HTTP client, Copyparty client, voice manager, the
in-memory trigger cache, autocomplete cache, and per-guild music queue.
- `src/main.rs` — boot: tracing, dotenvy, Config, DB pool, framework, cron task
- `src/config.rs` — env-driven `Config` + variable validation
- `src/commands/` — one module per command group
- `src/copyparty/` — Copyparty search/upload client
- `src/openrouter/` — OpenRouter chat client
- `src/database/` — sqlx pool, migrations, query helpers (6 tables)
- `src/voice/` — `VoiceManager`, mp3 → songbird input
- `src/events/` — `handle_ready`, voice-state, message (trigger matching)
- `src/tasks/` — 30s cron scheduler poll loop
- `src/lang.rs` — user-facing Polish strings
All temporary files go through `crate::config::TEMP_PATH`
(`/tmp/senator_sperma`).
|