From a45e5434f4ddc6a08b1a9759f677a2c5140eacac Mon Sep 17 00:00:00 2001 From: lachtan Date: Mon, 14 Sep 2026 21:07:56 +0200 Subject: [PATCH] =?UTF-8?q?nanobot:=202026-09-14=2021:07:55=20=E2=80=94=20?= =?UTF-8?q?usage:=20resets=20countdown=20+=20per-model=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- skills/usage/SKILL.md | 20 +++++++--- skills/usage/scripts/ollama_usage.py | 55 +++++++++++++++++++++------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/skills/usage/SKILL.md b/skills/usage/SKILL.md index a4c502e..2efcd58 100644 --- a/skills/usage/SKILL.md +++ b/skills/usage/SKILL.md @@ -21,17 +21,25 @@ Pokud chybí nebo klíč nefunguje (401/403), řekni to uživateli — nescrapuj ## Výstup -Text v češtině, stručně: +Text v češtině, přesně tento formát: -- **Session**: použité % + per-model requesty -- **Weekly**: použité % + per-model requesty -- **Aktivita**: `activity.cost` (skutečné dolary) za poslední 4 týdny +- `Session: %, resets in X hours — (), …` +- `Weekly: %, resets in Y days — (), …` +- `Modely (počet požadavků, weekly okno):` — seznam modelů s requesty -`limits.*.usage` je zlomek limitu plánu (× 100 = % jako na dashboardu). -Vypisuj % jako API/dashboard; `$` jen u `activity.cost`. +## Reset časy — odvození, ne API + +`/api/usage` **neobsahuje reset timestamps** (ty existují jen v HTML UI). +Skript je počítá: session = do další celé hodiny UTC (dashboard ukazuje +„Resets in 1 hour"), weekly = do nejbližšího pondělí 00:00 UTC. +Důvod: session usage šel v testu nahoru během pár minut (rolling okno), +weekly se mění pomalu, konzistentní s hodinovým/týdenním oknem. +Kdyby se ukázalo, že okno není kalendářové, uprav `until_next_*`. ## Poznámky - Endpoint: `GET https://ollama.com/api/usage`, hlavička `Authorization: Bearer ` (ověřeno 2026-09, issue #15132 je zastaralá). +- `limits.*.usage` je zlomek limitu plánu (× 100 = % jako na dashboardu). +- `activity.cost` u Pro plánu vrací $0.00000 — nefunkční, ve výstupu vynechán. - Klíč z `~/.ollama/id_ed25519` nefunguje — jen API key z ollama.com. \ No newline at end of file diff --git a/skills/usage/scripts/ollama_usage.py b/skills/usage/scripts/ollama_usage.py index 5775016..caabec7 100644 --- a/skills/usage/scripts/ollama_usage.py +++ b/skills/usage/scripts/ollama_usage.py @@ -8,6 +8,7 @@ import os import sys import urllib.error import urllib.request +from datetime import datetime, timedelta, timezone from pathlib import Path API_URL = "https://ollama.com/api/usage" @@ -30,8 +31,31 @@ def load_api_key() -> str: def fmt_models(models: list[dict]) -> str: if not models: return "" - parts = [f'{m["name"]} ({m["request_count"]} req)' for m in models] - return ", ".join(parts) + return ", ".join(f'{m["name"]} ({m["request_count"]})' for m in models) + + +def until_next_full_hour(now: datetime) -> timedelta: + nxt = (now.replace(minute=0, second=0, microsecond=0) + + timedelta(hours=1)) + return nxt - now + + +def until_next_monday(now: datetime) -> timedelta: + # days until Monday (weekday(): Mon == 0) + days = (7 - now.weekday()) % 7 or 7 + nxt = (now.replace(hour=0, minute=0, second=0, microsecond=0) + + timedelta(days=days)) + return nxt - now + + +def fmt_delta_short(td: timedelta) -> str: + """Human countdown, dashboard style: '1 hour', '55 minutes', '6 days'.""" + total = td.total_seconds() + if total >= 86400: + return f"{int(total // 86400)} days" + if total >= 3600: + return f"{round(total / 3600)} hours" + return f"{max(1, round(total / 60))} minutes" def main() -> None: @@ -50,22 +74,27 @@ def main() -> None: limits = data.get("limits", {}) session = limits.get("session", {}) weekly = limits.get("weekly", {}) + now = datetime.now(timezone.utc) print("Ollama Cloud — spotřeba") s_models = fmt_models(session.get("models", [])) - print(f'Session: {session.get("usage", 0) * 100:.1f} %' + (f" — {s_models}" if s_models else "")) + print( + f'Session: {session.get("usage", 0) * 100:.1f} %, ' + f'resets in {fmt_delta_short(until_next_full_hour(now))}' + + (f" — {s_models}" if s_models else "") + ) w_models = fmt_models(weekly.get("models", [])) - print(f'Weekly: {weekly.get("usage", 0) * 100:.1f} %' + (f" — {w_models}" if w_models else "")) + print( + f'Weekly: {weekly.get("usage", 0) * 100:.1f} %, ' + f'resets in {fmt_delta_short(until_next_monday(now))}' + + (f" — {w_models}" if w_models else "") + ) - activity = data.get("activity", {}) - cost = activity.get("cost") - if cost is not None: - period = activity.get("period", {}) - print( - f'Aktivita: ${float(cost):.5f}' - f' ({period.get("type", "?")} {period.get("starting_at", "")[:10]}' - f' → {period.get("ending_at", "")[:10]})' - ) + models = weekly.get("models", []) + if models: + print("Modely (počet požadavků, weekly okno):") + for m in models: + print(f' {m["name"]}: {m["request_count"]}') if __name__ == "__main__":