148 lines
7.2 KiB
Markdown
148 lines
7.2 KiB
Markdown
# Model Radar
|
|
|
|
[](https://github.com/oiupoyt/model-radar/actions)
|
|
[](LICENSE)
|
|
|
|
A lightweight, crash-resilient Discord bot built in Rust with [poise](https://github.com/serenity-rs/poise) and [serenity](https://github.com/serenity-rs/serenity). Model Radar monitors [OpenRouter](https://openrouter.ai)'s live model catalog for free LLMs (`:free` and exact $0 pricing) and dispatches real-time catalog release alerts and live auto-updating dashboards directly to Discord servers.
|
|
|
|
A live instance is running 24/7. You can see the bot in action and test commands here:
|
|
**[Join the Live Discord Server](https://discord.gg/dJ5MhVCGh)**
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Automated OpenRouter Monitoring:** Periodically polls the public OpenRouter models API (`/api/v1/models`) with configurable intervals.
|
|
- **Accurate Zero-Price Detection:** String-based decimal parsing identifies genuine free-tier models (including scientific notation like `0e-9999`) while rejecting precision artifacts, non-zero pricing, and tiered overrides.
|
|
- **Live Auto-Updating Dashboard:** Running `/watch` posts a persistent public dashboard embed in your channel that automatically refreshes every poll interval (`POLL_SECONDS`), featuring new drops at the top and active stealth/experimental models directly on the first page.
|
|
- **Interactive Component Buttons:** Multi-page `/free-models` and `/status` views include interactive `[◀ Prev]` and `[Next ▶]` buttons with automatic timeout disabling.
|
|
- **Model ID Autocomplete:** Live slash command autocomplete for `/model <id>` to instantly find any model in the catalog as you type.
|
|
- **Direct OpenRouter Links:** Embed titles link directly to the model's page on OpenRouter for quick browser inspection.
|
|
- **Pricing per 1M Tokens:** Model inspection computes readable rates per 1 Million tokens (e.g. `$0.15 / 1M tokens`).
|
|
- **Flexible Subscription Filters:**
|
|
- `free_only`: Target free models or watch all new catalog entries.
|
|
- `search`: Filter releases by model identifier or name (e.g., `qwen`, `llama`, `coder`).
|
|
- `min_context`: Ignore models with context windows below a given token threshold (e.g. `32,768`).
|
|
- `compact`: Dense notification rows for high-volume channels.
|
|
- **Opt-In Role Pings:** Server-level ping configuration supporting custom roles as well as `@everyone`.
|
|
- **Crash-Resilient State:** Subscriptions and catalog states are stored atomically (`.tmp` write followed by atomic filesystem rename) to guarantee state integrity across crashes and container reboots.
|
|
- **Queue Bounds:** Unreachable alert channels (e.g., deleted channel or revoked permissions) are capped at 50 queued events, preventing unbounded state growth.
|
|
- **Discord API Safety:** Strict UTF-16 character limit enforcement and markdown character escaping prevent broken embeds or Discord 400 Bad Request rejections.
|
|
- **Dry-Run Diagnostic Mode:** Test public catalog availability and parsing without needing a Discord token (`--check`).
|
|
|
|
---
|
|
|
|
## Slash Commands
|
|
|
|
| Command | Scope | Description |
|
|
| :--- | :--- | :--- |
|
|
| `/free-models [search] [page]` | Public / Ephemeral | Browse all currently available free models in OpenRouter's catalog with interactive `[◀ Prev]` / `[Next ▶]` buttons and search filter. |
|
|
| `/status [free_only] [search] [min_context] [page] [page_size] [compact] [public]` | Configurable | View a catalog freshness snapshot with model counts, interactive pagination, and token constraints. |
|
|
| `/model <id> [compact] [show_pricing] [public]` | Configurable | Inspect detailed specifications with live model ID autocomplete, cost per 1M tokens, and direct clickable links to OpenRouter. |
|
|
| `/watch [ping_role] [free_only] [search] [min_context] [ping_enabled] [compact] [clear_role]` | Manage Server | Posts a public live auto-updating dashboard in the channel and configures drop alerts. Supports any role or `@everyone`. |
|
|
| `/unwatch` | Manage Server | Remove the server's subscription and delete all queued pending alerts. |
|
|
| `/stats` | Ephemeral | View catalog freshness, last successful fetch timestamp, polling interval, and complete server subscription settings. |
|
|
| `/testping` | Manage Server | Dispatch a labeled test notification to verify channel permissions and role mentionability without modifying catalog state. |
|
|
| `/about` | Ephemeral | Display bot information, command guide, poll interval, and optional operator support link. |
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
### 1. Create a Discord Bot Application
|
|
|
|
1. Open the [Discord Developer Portal](https://discord.com/developers/applications) and create a **New Application**.
|
|
2. Navigate to the **Bot** tab:
|
|
- Click **Reset Token** to generate a bot token for your `DISCORD_TOKEN` environment variable.
|
|
- *Note:* No Privileged Gateway Intents are required (Model Radar does not require Message Content, Server Members, or Presence intents).
|
|
3. Navigate to **OAuth2 → URL Generator**:
|
|
- **Scopes:** Select `bot` and `applications.commands`.
|
|
- **Bot Permissions:** Select `View Channels`, `Send Messages`, and `Embed Links`.
|
|
4. Open the generated invite URL in your browser to invite the bot to your server.
|
|
|
|
---
|
|
|
|
### 2. Configuration & Environment Variables
|
|
|
|
| Variable | Required | Default | Description |
|
|
| :--- | :---: | :---: | :--- |
|
|
| `DISCORD_TOKEN` | Yes | — | Discord Bot Token from the Developer Portal. |
|
|
| `POLL_SECONDS` | No | `600` | Catalog polling interval in seconds (allowed: `60` to `86400`). |
|
|
| `STATE_PATH` | No | `state.json` | Path where subscription settings and catalog state are stored. |
|
|
| `SUPPORT_URL` | No | — | Optional HTTPS URL (e.g. Ko-fi, GitHub Sponsors) shown in `/about`. |
|
|
| `DISCORD_GUILD_ID` | No | — | Guild ID for instant slash command registration during testing (global registration takes up to an hour). |
|
|
|
|
---
|
|
|
|
### 3. Deployment Options
|
|
|
|
#### Option A: Docker Compose (Recommended)
|
|
|
|
1. Clone the repository:
|
|
```bash
|
|
git clone https://github.com/oiupoyt/model-radar.git
|
|
cd model-radar
|
|
```
|
|
|
|
2. Create `.env` from example:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
Edit `.env` and set `DISCORD_TOKEN`.
|
|
|
|
3. Launch the container:
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
State persists in `./data`.
|
|
|
|
#### Option B: Native Cargo Run
|
|
|
|
Prerequisites: [Rust 1.85+ (Edition 2024)](https://rustup.rs/)
|
|
|
|
```bash
|
|
# Verify catalog connection and parsing (no token required)
|
|
cargo run --locked -- --check
|
|
|
|
# Run the bot
|
|
export DISCORD_TOKEN="your_bot_token"
|
|
export POLL_SECONDS=600
|
|
cargo run --release --locked
|
|
```
|
|
|
|
---
|
|
|
|
## Setting Up Alerts in Discord
|
|
|
|
1. Pick a role for notifications (e.g. `@ModelAlerts`, `@everyone`, or any custom role).
|
|
2. In the channel where alerts should be posted, run:
|
|
```text
|
|
/watch ping_role:@ModelAlerts ping_enabled:true
|
|
```
|
|
*(Or `/watch ping_role:@everyone ping_enabled:true` to notify everyone).*
|
|
3. Verify the setup by running:
|
|
```text
|
|
/testping
|
|
```
|
|
4. Check your active server configuration at any time with `/stats`.
|
|
|
|
---
|
|
|
|
## Development & Testing
|
|
|
|
```bash
|
|
# Run unit and integration tests
|
|
cargo test --locked
|
|
|
|
# Run linter
|
|
cargo clippy --all-targets -- -D warnings
|
|
|
|
# Check code formatting
|
|
cargo fmt --check
|
|
```
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
This project is licensed under the [MIT License](LICENSE).
|