Group models by vendor, auto-pick latest version, filter junk — for anyone using 9Router or a multi-provider OpenAI-compatible API.
9Router /v1/models returns all models from all providers in one flat list. For example, 41 models from BAi + Nvidia + Alibaba etc — mixed up, hard to choose, can't tell which vendor each is from, which version is the latest, or which are just free trials.
This picker:
- Group by vendor — BAi, Nvidia, etc. are automatically separated by model id prefix
- Auto-pick — just say
pick("glm")→ instantly getbai/glm-5.2(latest version) - Skip free/junk — models with "free" substring are auto-filtered
- Registered filter — only show models you have access to (manual curation)
- Version-aware sort —
gpt-5.6>gpt-5.5>gpt-5.4>gpt-5-mini - 5-minute cache — doesn't spam 9Router on every render
git clone https://github.com/Mftrferdinand/NineRouter-Picker
cd ninerouter-picker
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
cp .env.example .env
# Edit .env → fill in YOUR 9Router URL & key
./venv/bin/python picker.py list # view your models
./venv/bin/python picker.py pick glm # auto-pick latest glmEdit .env:
NINEROUTER_URL=https://api.groq.com/openai/v1
NINEROUTER_KEY=gsk_YOUR_KEY_HEREPicker automatically uses that endpoint.
./venv/bin/python picker.py list # picker (filter registered)
./venv/bin/python picker.py list-all # all models
./venv/bin/python picker.py show # current model
./venv/bin/python picker.py test # test current (ping)
./venv/bin/python picker.py register bai/glm-5.2
./venv/bin/python picker.py unregister bai/glm-5.2
./venv/bin/python picker.py use bai/glm-5.2 # set current + test
./venv/bin/python picker.py pick glm # auto-pick by preference
./venv/bin/python picker.py pick # auto-pick (priority default)
./venv/bin/python picker.py refresh # bust cache + renderfrom picker import pick, list_registered, current, set_current, render, add_registered
# Auto-pick
pick() # → first match from PICK_PRIORITY (e.g. 'bai/minimax-m3')
pick("glm") # → latest glm (e.g. 'bai/glm-5.2')
pick("kimi") # → latest kimi
pick("gpt") # → latest gpt
pick("claude") # → latest claude
# Curation
list_registered() # → ['bai/glm-5.2', 'bai/minimax-m3', ...]
add_registered('bai/qwen3.6-27b')
set_current('bai/glm-5.2')
current() # → 'bai/minimax-m3' or None
# Render markdown
print(render("model")) # grouped, filter registered
print(render("register")) # grouped, all models
print(render("full")) # current + registered + grouped- Pool =
list_registered()if available, else all non-free models. - If
preferenceis passed:- exact match (full id or tail) → return immediately
- substring match → sort by version DESC (latest wins)
- Else: rank by
PICK_PRIORITYlist (exact tail > prefix > substring), return top.
Version sort: flatten all numeric runs in the tail, padded to 6 segments.
gpt-5.6-sol > gpt-5.5 > gpt-5.4-pro > gpt-5.4 > gpt-5-mini
Edit picker.py:
# Label vendor (default: capitalize prefix)
VENDOR_LABELS = {"bai": "BAi", "nvidia": "Nvidia", "alibaba": "Aliyun"}
# Label model (default: tail of id)
MODEL_LABELS = {"bai/glm-5.2": "Glm-5.2 (Premium)"}
# Priority fallback (default + curation)
PICK_PRIORITY = ["minimax-m3", "glm-5.2", "kimi-k2.6", ...].env(contains YOUR real URL & key) is git-ignored — never pushed.env.exampleon GitHub is just a dummy template (CHANGE_ME)- Each user uses THEIR OWN 9Router/endpoint — no key sharing
localhost= only your device can access
ninerouter-picker/
├── picker.py # core lib + CLI (single file)
├── requirements.txt # httpx only
├── .env.example # template (don't fill with real key)
├── .env # your real key (gitignored!)
├── .gitignore
├── registered.json # models you selected (auto-generated)
├── current.json # active model (auto-generated)
└── README.md
MIT