Compare commits
6 Commits
319db74bce
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| aeeb4042eb | |||
| 8e974f01bb | |||
| 42d9758ecc | |||
| b34d5b1d97 | |||
| ff86eeff4b | |||
| ff30800337 |
@@ -61,7 +61,7 @@
|
|||||||
"margin-bottom": 16,
|
"margin-bottom": 16,
|
||||||
"margin-left": 16,
|
"margin-left": 16,
|
||||||
"margin-right": 16,
|
"margin-right": 16,
|
||||||
"modules-left": ["gamemode", "battery", "temperature", "cpu", "memory", "network", "custom/codex-primary", "custom/codex-secondary"],
|
"modules-left": ["gamemode", "battery", "temperature", "cpu", "memory", "custom/codex-primary", "custom/codex-secondary", "network"],
|
||||||
"modules-center": [],
|
"modules-center": [],
|
||||||
"modules-right": ["mpris", "pulseaudio", "custom/output-device", "backlight", "idle_inhibitor", "clock"],
|
"modules-right": ["mpris", "pulseaudio", "custom/output-device", "backlight", "idle_inhibitor", "clock"],
|
||||||
"clock": {
|
"clock": {
|
||||||
@@ -160,6 +160,7 @@
|
|||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window primary",
|
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window primary",
|
||||||
"exec-if": "test -r ~/.codex/auth.json",
|
"exec-if": "test -r ~/.codex/auth.json",
|
||||||
|
"escape": false,
|
||||||
"format": " {}"
|
"format": " {}"
|
||||||
},
|
},
|
||||||
"custom/codex-secondary": {
|
"custom/codex-secondary": {
|
||||||
@@ -167,6 +168,7 @@
|
|||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window secondary",
|
"exec": "$HOME/.config/waybar/scripts/openai-rate.py --window secondary",
|
||||||
"exec-if": "test -r ~/.codex/auth.json",
|
"exec-if": "test -r ~/.codex/auth.json",
|
||||||
|
"escape": false,
|
||||||
"format": " {}"
|
"format": " {}"
|
||||||
},
|
},
|
||||||
"custom/backup": {
|
"custom/backup": {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
__pycache__
|
||||||
@@ -17,6 +17,10 @@ def waybar(text, klass="good", tooltip=None):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def unknown(tooltip):
|
||||||
|
waybar('unk <span font-size="7pt">--</span>', "good", tooltip)
|
||||||
|
|
||||||
|
|
||||||
def load_auth():
|
def load_auth():
|
||||||
auth_path = Path(os.environ.get("OPENAI_AUTH_FILE", "~/.codex/auth.json")).expanduser()
|
auth_path = Path(os.environ.get("OPENAI_AUTH_FILE", "~/.codex/auth.json")).expanduser()
|
||||||
auth = {}
|
auth = {}
|
||||||
@@ -69,11 +73,11 @@ def fetch_usage(token, account_id):
|
|||||||
return json.load(res)
|
return json.load(res)
|
||||||
except urllib.error.HTTPError as exc:
|
except urllib.error.HTTPError as exc:
|
||||||
detail = exc.read().decode("utf-8", "replace")[:240]
|
detail = exc.read().decode("utf-8", "replace")[:240]
|
||||||
waybar("AI rate failed", "critical", f"Usage endpoint returned HTTP {exc.code}\n{detail}")
|
unknown(f"Usage endpoint returned HTTP {exc.code}\n{detail}")
|
||||||
except (OSError, TimeoutError) as exc:
|
except (OSError, TimeoutError) as exc:
|
||||||
waybar("AI rate failed", "critical", f"Could not reach Codex usage endpoint\n{exc}")
|
unknown(f"Could not reach Codex usage endpoint\n{exc}")
|
||||||
except json.JSONDecodeError as exc:
|
except json.JSONDecodeError as exc:
|
||||||
waybar("AI rate unreadable", "critical", f"Usage endpoint returned invalid JSON\n{exc}")
|
unknown(f"Usage endpoint returned invalid JSON\n{exc}")
|
||||||
|
|
||||||
|
|
||||||
def window_label(seconds):
|
def window_label(seconds):
|
||||||
@@ -135,48 +139,14 @@ def format_window(name, window):
|
|||||||
tooltip += f", resets in {reset}"
|
tooltip += f", resets in {reset}"
|
||||||
return {
|
return {
|
||||||
"label": label,
|
"label": label,
|
||||||
|
"reset": reset or "--",
|
||||||
"left": left,
|
"left": left,
|
||||||
"text": f"{left}% {label}",
|
|
||||||
"used": used,
|
"used": used,
|
||||||
"tooltip": tooltip,
|
"tooltip": tooltip,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def credit_text(credits):
|
def output_window(data, source, selector):
|
||||||
if not isinstance(credits, dict) or not credits.get("has_credits"):
|
|
||||||
return None
|
|
||||||
if credits.get("unlimited"):
|
|
||||||
return "credits unlimited"
|
|
||||||
balance = credits.get("balance")
|
|
||||||
if balance is None:
|
|
||||||
return "credits enabled"
|
|
||||||
try:
|
|
||||||
return f"credits {round(float(balance))}"
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return f"credits {balance}"
|
|
||||||
|
|
||||||
|
|
||||||
def spend_control_text(spend_control):
|
|
||||||
limit = (spend_control or {}).get("individual_limit")
|
|
||||||
if not isinstance(limit, dict):
|
|
||||||
return None
|
|
||||||
|
|
||||||
remaining = limit.get("remaining_percent")
|
|
||||||
used = limit.get("used")
|
|
||||||
cap = limit.get("limit")
|
|
||||||
reset = reset_text(limit.get("reset_after_seconds"))
|
|
||||||
if not isinstance(remaining, int):
|
|
||||||
return None
|
|
||||||
|
|
||||||
text = f"monthly credits: {100 - remaining}% used"
|
|
||||||
if used and cap:
|
|
||||||
text += f" ({used}/{cap})"
|
|
||||||
if reset:
|
|
||||||
text += f", resets in {reset}"
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def selected_window_output(data, source, selector):
|
|
||||||
rate_limit = data.get("rate_limit") or {}
|
rate_limit = data.get("rate_limit") or {}
|
||||||
window = format_window(selector, rate_limit.get(f"{selector}_window"))
|
window = format_window(selector, rate_limit.get(f"{selector}_window"))
|
||||||
if not window:
|
if not window:
|
||||||
@@ -184,45 +154,15 @@ def selected_window_output(data, source, selector):
|
|||||||
|
|
||||||
klass = usage_class(window["used"], rate_limit.get("limit_reached"))
|
klass = usage_class(window["used"], rate_limit.get("limit_reached"))
|
||||||
tooltip = [window["tooltip"], f"{window['left']}% remaining", f"source: {source}"]
|
tooltip = [window["tooltip"], f"{window['left']}% remaining", f"source: {source}"]
|
||||||
waybar(f"{window['left']}% {window['label']}", klass, "\n".join(tooltip))
|
waybar(f"{window['left']}% <span font-size=\"7pt\">{window['reset']}</span>", klass, "\n".join(tooltip))
|
||||||
|
|
||||||
|
|
||||||
def combined_output(data, source):
|
|
||||||
rate_limit = data.get("rate_limit") or {}
|
|
||||||
windows = [
|
|
||||||
format_window("primary", rate_limit.get("primary_window")),
|
|
||||||
format_window("secondary", rate_limit.get("secondary_window")),
|
|
||||||
]
|
|
||||||
windows = [window for window in windows if window]
|
|
||||||
|
|
||||||
parts = [window["text"] for window in windows]
|
|
||||||
credits = credit_text(data.get("credits"))
|
|
||||||
if credits:
|
|
||||||
parts.append(credits)
|
|
||||||
|
|
||||||
if not parts:
|
|
||||||
waybar("AI n/a", "warning", f"No displayable usage data\nsource: {source}")
|
|
||||||
|
|
||||||
worst_used = max(window["used"] for window in windows) if windows else 0
|
|
||||||
klass = usage_class(worst_used, rate_limit.get("limit_reached"))
|
|
||||||
|
|
||||||
tooltip = [window["tooltip"] for window in windows]
|
|
||||||
spend = spend_control_text(data.get("spend_control"))
|
|
||||||
if credits:
|
|
||||||
tooltip.append(credits)
|
|
||||||
if spend:
|
|
||||||
tooltip.append(spend)
|
|
||||||
tooltip.append(f"source: {source}")
|
|
||||||
|
|
||||||
waybar(f"AI {' '.join(parts)}", klass, "\n".join(tooltip))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
parser = ArgumentParser(description="Waybar Codex rate-limit widget")
|
parser = ArgumentParser(description="Waybar Codex rate-limit widget")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--window",
|
"--window",
|
||||||
choices=("primary", "secondary", "all"),
|
choices=("primary", "secondary"),
|
||||||
default="all",
|
required=True,
|
||||||
help="usage window to display",
|
help="usage window to display",
|
||||||
)
|
)
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
@@ -232,11 +172,7 @@ def main():
|
|||||||
args = parse_args()
|
args = parse_args()
|
||||||
token, account_id, source = load_auth()
|
token, account_id, source = load_auth()
|
||||||
data = fetch_usage(token, account_id)
|
data = fetch_usage(token, account_id)
|
||||||
|
output_window(data, source, args.window)
|
||||||
if args.window == "all":
|
|
||||||
combined_output(data, source)
|
|
||||||
else:
|
|
||||||
selected_window_output(data, source, args.window)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -253,7 +253,5 @@ window#waybar.fullscreen #window {
|
|||||||
}
|
}
|
||||||
#custom-codex-primary.critical,
|
#custom-codex-primary.critical,
|
||||||
#custom-codex-secondary.critical {
|
#custom-codex-secondary.critical {
|
||||||
color: #282828;
|
color: #fb4934;
|
||||||
background: #fb4934;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user