Files

86 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Track Firecrawl API credit usage for portal dashboard."""
import json, os, time
from datetime import datetime, timezone
BASE = os.path.expanduser("~/.hermes/scripts")
LOG = os.path.join(BASE, "firecrawl-usage.json")
LIMIT = 1000 # Current tier
def _defaults():
return {"total_used": 0, "calls": [], "monthly": {}, "last_reset": str(datetime.now(timezone.utc))}
def load():
"""Load usage data, merging in any missing top-level keys.
Older state files were written without the `monthly` / `calls` keys,
which caused KeyError crashes in summary(). Merging defaults makes the
loader forward/backward compatible with partial state files.
"""
data = _defaults()
if os.path.exists(LOG):
try:
with open(LOG) as f:
loaded = json.load(f)
if isinstance(loaded, dict):
data.update(loaded)
except (json.JSONDecodeError, OSError):
pass # Corrupt/unreadable state — fall back to defaults
# Guarantee required keys/types even if the file had them as null/wrong type
if not isinstance(data.get("monthly"), dict):
data["monthly"] = {}
if not isinstance(data.get("calls"), list):
data["calls"] = []
if not isinstance(data.get("total_used"), (int, float)):
data["total_used"] = 0
return data
def save(data):
with open(LOG, "w") as f:
json.dump(data, f, indent=2)
def record(credits_used, endpoint, url=""):
data = load()
now = datetime.now(timezone.utc)
month_key = now.strftime("%Y-%m")
# Track total
data["total_used"] += credits_used
# Track monthly
if month_key not in data["monthly"]:
data["monthly"][month_key] = 0
data["monthly"][month_key] += credits_used
# Log individual call
data["calls"].append({
"ts": now.isoformat(),
"endpoint": endpoint,
"url": url[:100],
"credits": credits_used
})
# Trim call log to last 1000
data["calls"] = data["calls"][-1000:]
save(data)
def summary():
data = load()
month_key = datetime.now(timezone.utc).strftime("%Y-%m")
month_used = data["monthly"].get(month_key, 0)
return {
"total_used": data["total_used"],
"month_used": month_used,
"month_limit": LIMIT,
"month_remaining": max(0, LIMIT - month_used),
"month_pct": round(month_used / LIMIT * 100, 1),
"recent_calls": data["calls"][-10:]
}
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "summary":
print(json.dumps(summary(), indent=2))
else:
print(f"Credits: {summary()['month_used']}/{LIMIT} used this month")