A lightweight MLflow clone that logs ML training metrics, parameters, and artifacts directly to Discord webhooks.
Project description
DiscordFlow 🚀
The MLflow you already have open on your phone. Log ML training metrics, parameters, and artifacts directly to a Discord channel via webhooks — no server required.
✨ Features
| Feature | Description |
|---|---|
| 📈 Metric Logging | Post metrics per step/epoch with log_metrics() |
| ⚙️ Param Logging | Log hyperparameters with log_param() / log_params() |
| 🏷️ Tags | Attach arbitrary key-value tags to runs |
| 📁 Artifact Upload | Upload files (models, plots, CSVs) up to 25 MB |
| 📄 Text Artifacts | Upload text snippets as .txt file attachments |
| ▶️ Run Management | Context-manager start_run() with auto summary embed on exit |
| 🖥️ Dry-Run Mode | dry_run=True prints to stdout — no real webhook calls |
| ❌ Error Capture | Exceptions inside a start_run() block are caught and posted |
📦 Installation
pip install discordflow
Requirements: Python ≥ 3.8, requests
⚡ Quickstart
1. Get a Discord Webhook URL
In your Discord server: Server Settings → Integrations → Webhooks → New Webhook → Copy URL
2. Drop it into your training loop
from discordflow import DiscordFlow
WEBHOOK_URL = "YOUR_DISCORD_WEBHOOK_URL"
dflow = DiscordFlow(WEBHOOK_URL, experiment_name="MoE_Router_Training")
# Log hyperparameters
dflow.log_params({
"experts": 8,
"routing_strategy": "top-k",
"learning_rate": 3e-4,
})
# Training loop
for epoch in range(1, 6):
loss = 1.0 / epoch
dflow.log_metrics({
"Train Loss": round(loss, 4),
"Load Balance": round(0.8 + 0.02 * epoch, 4),
}, step=epoch)
# Upload an artifact (max 25 MB)
# dflow.log_artifact("router_weights.pt")
# dflow.log_artifact("loss_curve.png")
3. Context-manager pattern (recommended)
Use start_run() to get an automatic run-summary embed when the block exits — including elapsed time, all params, and final metrics. If your code crashes, the traceback is posted too.
with dflow.start_run("lora_rank_16") as run:
run.log_params({"lr": 2e-4, "lora_rank": 16, "epochs": 3})
run.set_tag("framework", "HuggingFace")
for epoch in range(1, 4):
run.log_metrics({
"Train Loss": round(2.5 / epoch, 4),
"Val Loss": round(2.7 / epoch, 4),
}, step=epoch)
# ✅ Run Complete embed is auto-posted here
🎨 Custom Bot Identity
Give your DiscordFlow bot a custom name and profile picture so it blends into your server:
dflow = DiscordFlow(
webhook_url = "YOUR_WEBHOOK_URL",
experiment_name= "ResNet_Training",
username = "TrainBot 🏋️", # Bot name shown in Discord
avatar_url = "https://i.imgur.com/YOUR_IMAGE.png", # Bot profile picture URL
)
| Parameter | Type | Description |
|---|---|---|
username |
str |
Display name shown on every Discord message (default: "DiscordFlow 🤖") |
avatar_url |
str |
Public URL to any image for the bot's avatar (JPEG, PNG, GIF) |
Tip: Use any publicly accessible image URL — Discord's CDN, Imgur, GitHub raw links, etc.
🧪 Local Testing (Dry Run)
No Discord server? No problem. Use dry_run=True to print all messages to stdout instead of calling the webhook:
dflow = DiscordFlow("ANY_URL", experiment_name="test", dry_run=True)
dflow.log_metrics({"loss": 0.42}, step=1)
Run the bundled demo:
python example.py
📚 API Reference
DiscordFlow(webhook_url, experiment_name, dry_run, username, avatar_url)
| Parameter | Type | Default | Description |
|---|---|---|---|
webhook_url |
str |
required | Discord webhook URL |
experiment_name |
str |
"Default Experiment" |
Shown in every embed |
dry_run |
bool |
False |
Print to stdout instead of calling webhook |
username |
str |
"DiscordFlow 🤖" |
Bot username shown in Discord |
avatar_url |
str |
None |
Custom bot avatar URL |
Logging Methods
# Single param
dflow.log_param("learning_rate", 3e-4)
# Multiple params in one embed
dflow.log_params({"lr": 3e-4, "batch_size": 128, "epochs": 10})
# Single metric
dflow.log_metric("loss", 0.42, step=5)
# Multiple metrics in one embed
dflow.log_metrics({"loss": 0.42, "acc": 0.91}, step=5)
# Arbitrary tags (purple embed)
dflow.set_tag("author", "e27")
dflow.set_tag("dataset", "openwebtext")
# Upload a file artifact (max 25 MB)
dflow.log_artifact("checkpoint.pt")
dflow.log_artifact("confusion_matrix.png")
# Upload a text snippet as a file
dflow.log_text("epoch,loss\n1,1.0\n2,0.5", filename="metrics.csv")
Run Management
# Start a named run (context manager — recommended)
with dflow.start_run("sweep_01") as run:
run.log_params({...})
run.log_metrics({...}, step=epoch)
run.set_tag("status", "grid_search")
run.log_artifact("model.pt")
# ← Auto-posts run summary embed on exit
# Or explicitly end a run
run = dflow.start_run("manual_run")
# ... do stuff ...
dflow.end_run(status="FINISHED")
🤝 Contributing
- Fork the repo
- Create your feature branch:
git checkout -b feat/my-feature - Commit your changes:
git commit -m "feat: add my feature" - Push:
git push origin feat/my-feature - Open a Pull Request
📄 License
MIT © DiscordFlow Contributors
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file discordflow-0.3.0.tar.gz.
File metadata
- Download URL: discordflow-0.3.0.tar.gz
- Upload date:
- Size: 12.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bf8090e73b68a1b06053c247d6302a20da1a6f9c82e0e229f5ce77a4782cfcc
|
|
| MD5 |
a4c7667cddf745eb24efd1c7d660b3b2
|
|
| BLAKE2b-256 |
3a0e346118e0cf528cd2c894130a8068acc6eaf93f49ccd10d24342ceb1e3255
|
File details
Details for the file discordflow-0.3.0-py3-none-any.whl.
File metadata
- Download URL: discordflow-0.3.0-py3-none-any.whl
- Upload date:
- Size: 11.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f93553d42139de0403906906c488eb163ae1ad94c4531622cc9275bd321948bd
|
|
| MD5 |
356df238f1ed7b19d6547ce62f5f1b04
|
|
| BLAKE2b-256 |
8eeead907d182bc3fadab0a94c884d67ba0b8fcdca73266fc2a51d813c4b3ee1
|