Widget desktop 224x224 che mostra: - residuo sessione (5h) e settimanale (7d) con barre colorate - conteggio richieste, costo 4 settimane, modello top - timer di reset stimati (calibrati al primo reset osservato) - backend bash che chiama https://ollama.com/api/usage - legge la chiave API da ~/.pi/agent/auth.json (provider ollama-cloud)
98 lines
4.6 KiB
Bash
Executable File
98 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Backend del plasmoide Ollama Cloud Usage.
|
|
# L'API /api/usage non fornisce reset_at: manteniamo una stima locale e la
|
|
# ricalibriamo quando usage/conteggi scendono (reset effettivamente osservato).
|
|
set -u
|
|
|
|
AUTH_JSON="${OLLAMA_AUTH_JSON:-$HOME/.pi/agent/auth.json}"
|
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/ollama-cloud-usage"
|
|
STATE_FILE="$STATE_DIR/reset-state.json"
|
|
KEY=""
|
|
|
|
if [ -f "$AUTH_JSON" ]; then
|
|
KEY="$(jq -r '.["ollama-cloud"].key // empty' "$AUTH_JSON" 2>/dev/null)"
|
|
fi
|
|
[ -n "$KEY" ] || KEY="${OLLAMA_API_KEY:-}"
|
|
|
|
if [ -z "$KEY" ]; then
|
|
printf '{"ok":false,"error":"no_api_key","detail":"nessuna chiave Ollama Cloud configurata"}\n'
|
|
exit 0
|
|
fi
|
|
|
|
RESP="$(curl -sS --max-time 15 https://ollama.com/api/usage -H "Authorization: Bearer $KEY" 2>/dev/null)"
|
|
CURL_RC=$?
|
|
if [ "$CURL_RC" -ne 0 ] || [ -z "$RESP" ]; then
|
|
printf '{"ok":false,"error":"fetch_failed","detail":"curl exit %s"}\n' "$CURL_RC"
|
|
exit 0
|
|
fi
|
|
|
|
if ! printf '%s' "$RESP" | jq -e '(.limits.session.usage | type == "number") and (.limits.weekly.usage | type == "number")' >/dev/null 2>&1; then
|
|
printf '{"ok":false,"error":"bad_json","detail":"risposta non valida da /api/usage"}\n'
|
|
exit 0
|
|
fi
|
|
|
|
NOW="$(date +%s)"
|
|
SESSION_USAGE="$(printf '%s' "$RESP" | jq -c '.limits.session.usage')"
|
|
WEEKLY_USAGE="$(printf '%s' "$RESP" | jq -c '.limits.weekly.usage')"
|
|
SESSION_REQ="$(printf '%s' "$RESP" | jq -c '[.limits.session.models[]?.request_count] | add // 0')"
|
|
WEEKLY_REQ="$(printf '%s' "$RESP" | jq -c '[.limits.weekly.models[]?.request_count] | add // 0')"
|
|
|
|
mkdir -p "$STATE_DIR" 2>/dev/null || true
|
|
STATE_JSON='{}'
|
|
[ -f "$STATE_FILE" ] && STATE_JSON="$(<"$STATE_FILE")"
|
|
|
|
# $1 nome finestra, $2 durata sec, $3 usage, $4 richieste.
|
|
# Esporta RESET_AT e CALIBRATED; calibrated=true solo dopo reset osservato.
|
|
calculate_reset() {
|
|
local name="$1" duration="$2" current_usage="$3" current_req="$4"
|
|
local previous_usage previous_req previous_reset previous_calibrated detected periods
|
|
|
|
previous_usage="$(printf '%s' "$STATE_JSON" | jq -c --arg n "$name" '.[$n].last_usage // null')"
|
|
previous_req="$(printf '%s' "$STATE_JSON" | jq -c --arg n "$name" '.[$n].last_requests // null')"
|
|
previous_reset="$(printf '%s' "$STATE_JSON" | jq -r --arg n "$name" '.[$n].reset_at // 0')"
|
|
previous_calibrated="$(printf '%s' "$STATE_JSON" | jq -r --arg n "$name" '.[$n].calibrated // false')"
|
|
detected="$(jq -n --argjson old "$previous_usage" --argjson new "$current_usage" --argjson oldreq "$previous_req" --argjson newreq "$current_req" '($old != null and (($new < ($old - 0.02)) or ($newreq < $oldreq)))')"
|
|
|
|
if [ "$previous_reset" -le 0 ]; then
|
|
RESET_AT=$((NOW + duration))
|
|
CALIBRATED=false
|
|
elif [ "$detected" = true ]; then
|
|
RESET_AT=$((NOW + duration))
|
|
CALIBRATED=true
|
|
else
|
|
RESET_AT="$previous_reset"
|
|
CALIBRATED="$previous_calibrated"
|
|
# Una stima scaduta viene avanzata; resta STIMA finché non osserviamo il reset.
|
|
if [ "$NOW" -ge "$RESET_AT" ]; then
|
|
periods=$(((NOW - RESET_AT) / duration + 1))
|
|
RESET_AT=$((RESET_AT + periods * duration))
|
|
fi
|
|
fi
|
|
}
|
|
|
|
calculate_reset session 18000 "$SESSION_USAGE" "$SESSION_REQ"
|
|
SESSION_RESET="$RESET_AT"
|
|
SESSION_CALIBRATED="$CALIBRATED"
|
|
calculate_reset weekly 604800 "$WEEKLY_USAGE" "$WEEKLY_REQ"
|
|
WEEKLY_RESET="$RESET_AT"
|
|
WEEKLY_CALIBRATED="$CALIBRATED"
|
|
|
|
# Stato 0600: non contiene segreti, ma resta privato al profilo utente.
|
|
umask 077
|
|
TMP_STATE="$(mktemp "$STATE_DIR/.reset-state.XXXXXX" 2>/dev/null || true)"
|
|
if [ -n "$TMP_STATE" ]; then
|
|
jq -n \
|
|
--argjson now "$NOW" \
|
|
--argjson su "$SESSION_USAGE" --argjson sr "$SESSION_REQ" --argjson sat "$SESSION_RESET" --argjson sc "$SESSION_CALIBRATED" \
|
|
--argjson wu "$WEEKLY_USAGE" --argjson wr "$WEEKLY_REQ" --argjson wat "$WEEKLY_RESET" --argjson wc "$WEEKLY_CALIBRATED" \
|
|
'{updated_at:$now,session:{last_usage:$su,last_requests:$sr,reset_at:$sat,calibrated:$sc},weekly:{last_usage:$wu,last_requests:$wr,reset_at:$wat,calibrated:$wc}}' >"$TMP_STATE" && mv "$TMP_STATE" "$STATE_FILE"
|
|
fi
|
|
|
|
printf '%s' "$RESP" | jq -c \
|
|
--argjson fetched "$NOW" \
|
|
--argjson session_at "$SESSION_RESET" --argjson session_cal "$SESSION_CALIBRATED" \
|
|
--argjson weekly_at "$WEEKLY_RESET" --argjson weekly_cal "$WEEKLY_CALIBRATED" \
|
|
'{ok:true,session:{remaining:(1-.limits.session.usage),used:.limits.session.usage,models:.limits.session.models},weekly:{remaining:(1-.limits.weekly.usage),used:.limits.weekly.usage,models:.limits.weekly.models},activity:.activity,fetched_at:$fetched,resets:{session:{at:$session_at,estimated:($session_cal|not)},weekly:{at:$weekly_at,estimated:($weekly_cal|not)}}}' \
|
|
2>/dev/null || printf '{"ok":false,"error":"bad_json","detail":"impossibile elaborare la risposta"}\n'
|
|
|
|
exit 0 |