145 lines
3.6 KiB
Bash
Executable File
145 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# glm-quota — Check Zhipu AI (GLM) API quota
|
|
#
|
|
# Usage:
|
|
# glm-quota # show quota
|
|
# glm-quota -v # show raw JSON response
|
|
#
|
|
# Setup API key (macOS Keychain):
|
|
# security add-generic-password -a "$USER" -s GLM_API_KEY -w "YOUR_API_KEY"
|
|
# Setup API key (Arch/Linux — libsecret):
|
|
# echo "YOUR_API_KEY" | secret-tool store --label "GLM API Key" service GLM_API_KEY
|
|
|
|
KEY_NAME="GLM_API_KEY"
|
|
URL="https://open.bigmodel.cn/api/monitor/usage/quota/limit"
|
|
|
|
# ===== OS DETECTION =====
|
|
if [ -f /etc/arch-release ]; then
|
|
OS="arch"
|
|
elif [ "$(uname -s)" = "Darwin" ]; then
|
|
OS="macos"
|
|
else
|
|
OS="linux"
|
|
fi
|
|
|
|
# ===== COLORS =====
|
|
GREEN="\033[1;32m"
|
|
CYAN="\033[1;36m"
|
|
YELLOW="\033[1;33m"
|
|
RED="\033[1;31m"
|
|
DIM="\033[2m"
|
|
RESET="\033[0m"
|
|
|
|
# ===== ARGS =====
|
|
VERBOSE=0
|
|
ONELINE=0
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-v) VERBOSE=1 ;;
|
|
-1) ONELINE=1 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# ===== LOAD TOKEN =====
|
|
case "$OS" in
|
|
macos)
|
|
API_TOKEN=$(security find-generic-password -a "$USER" -s "$KEY_NAME" -w 2>/dev/null | tr -d '\n')
|
|
;;
|
|
arch)
|
|
API_TOKEN=$(secret-tool lookup service "$KEY_NAME" 2>/dev/null | tr -d '\n')
|
|
;;
|
|
*)
|
|
API_TOKEN=$(secret-tool lookup service "$KEY_NAME" 2>/dev/null | tr -d '\n')
|
|
;;
|
|
esac
|
|
if [ -z "$API_TOKEN" ]; then
|
|
echo -e "${RED}❌ API token not found ($KEY_NAME)${RESET}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ===== CALL API =====
|
|
RESPONSE=$(curl -s -H "Authorization: $API_TOKEN" "$URL")
|
|
|
|
if [ "$VERBOSE" -eq 1 ]; then
|
|
echo -e "${YELLOW}🔧 Raw response:${RESET}"
|
|
echo "$RESPONSE" | jq .
|
|
echo ""
|
|
fi
|
|
|
|
# ===== PARSE =====
|
|
SUCCESS=$(echo "$RESPONSE" | jq -r '.success // false')
|
|
if [ "$SUCCESS" != "true" ]; then
|
|
echo -e "${RED}❌ API request failed${RESET}"
|
|
echo "$RESPONSE" | jq .
|
|
exit 1
|
|
fi
|
|
|
|
LEVEL=$(echo "$RESPONSE" | jq -r '.data.level // "unknown"')
|
|
|
|
# Extract TOKENS_LIMIT using jq in one shot
|
|
read -r T_PERCENT T_RESET T_NUM < <(echo "$RESPONSE" | jq -r '
|
|
.data.limits[] | select(.type == "TOKENS_LIMIT") |
|
|
"\(.percentage // 0) \(.nextResetTime // 0) \(.number // 5)"
|
|
')
|
|
|
|
# Extract TIME_LIMIT (web search) in one shot
|
|
read -r R_USAGE R_CURRENT R_REMAINING R_PERCENT R_RESET < <(echo "$RESPONSE" | jq -r '
|
|
.data.limits[] | select(.type == "TIME_LIMIT") |
|
|
"\(.usage // 0) \(.currentValue // 0) \(.remaining // 0) \(.percentage // 0) \(.nextResetTime // 0)"
|
|
')
|
|
|
|
# Convert millisecond timestamps to human readable
|
|
format_ms() {
|
|
local ms="$1"
|
|
if [ -n "$ms" ] && [ "$ms" -gt 0 ] 2>/dev/null; then
|
|
local sec=$((ms / 1000))
|
|
case "$OS" in
|
|
macos) date -r "$sec" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$ms" ;;
|
|
*) date -d "@$sec" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$ms" ;;
|
|
esac
|
|
else
|
|
echo "N/A"
|
|
fi
|
|
}
|
|
|
|
T_RESET_HUMAN=$(format_ms "$T_RESET")
|
|
R_RESET_HUMAN=$(format_ms "$R_RESET")
|
|
|
|
# ===== DISPLAY =====
|
|
NOW=$(date +%s)
|
|
RESET_SEC=$((T_RESET / 1000))
|
|
DIFF=$((RESET_SEC - NOW))
|
|
|
|
REMAIN=""
|
|
if [ "$DIFF" -gt 0 ]; then
|
|
H=$((DIFF / 3600))
|
|
M=$(((DIFF % 3600) / 60))
|
|
if [ "$H" -gt 0 ]; then
|
|
REMAIN=" (${H}h${M}m)"
|
|
else
|
|
REMAIN=" (${M}m)"
|
|
fi
|
|
fi
|
|
|
|
ICON=$(awk -v p="$T_PERCENT" 'BEGIN { if (p < 50) print "🟢"; else if (p > 80) print "🔴"; else print "🟡" }')
|
|
|
|
if [ "$ONELINE" -eq 1 ]; then
|
|
echo "GLM: ${T_PERCENT}%${REMAIN}${ICON}"
|
|
exit 0
|
|
fi
|
|
|
|
echo "GLM: ${T_PERCENT}%${REMAIN}${ICON}"
|
|
echo "---"
|
|
echo "✅ Account: ${LEVEL}"
|
|
echo "Token Limit: ${T_NUM}h rolling"
|
|
echo " Usage: ${T_PERCENT}%"
|
|
echo " Next Reset: $T_RESET_HUMAN"
|
|
|
|
if [ -n "$R_USAGE" ] && [ "$R_USAGE" != "0" ]; then
|
|
echo "Web Search Limit: monthly"
|
|
echo " Used: ${R_CURRENT}/${R_USAGE} (${R_PERCENT}%)"
|
|
echo " Reset: ${R_RESET_HUMAN}"
|
|
fi
|