# app.py # # Hugging Face Space – Live U.S. Debt Clock # • Pulls the last 40 Treasury “Debt to the Penny” points # • Derives a $/sec rate from point-0 and point-30 (or falls back to the last # two distinct points when needed) # • Projects the current debt from the timestamp (00:01 UTC) of the latest # record all the way to *now*—no 12-hour guard # # Endpoints # / – simple text “running” check # /api/debt – JSON { startingDebt, ratePerSecond, asOf } # /api/ping – lightweight uptime probe # # ──────────────────────────────────────────────────────────── import os, time, threading, requests from flask import Flask, jsonify app = Flask(__name__) # ─────────────────── runtime state ──────────────────── DEBT_STATE = { "debt_at_record": 0.0, # value at latest record date "record_time": 0.0, # epoch seconds for that record date (00:01 UTC) "rate_per_sec": 0.0, # $/s derived from chosen points "last_refresh": 0.0 } # ─────────────────── config ─────────────────────────── HORIZON = 30 # how many records back to measure the slope API = ( "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/" "accounting/od/debt_to_penny" f"?fields=record_date,tot_pub_debt_out_amt&sort=-record_date&page[size]={HORIZON+10}" # 10 extra records just in case identical values need skipping ) # ─────────────────── helpers ────────────────────────── def load_debt_records(): r = requests.get(API, timeout=15) r.raise_for_status() return [ (item["record_date"], float(item["tot_pub_debt_out_amt"])) for item in r.json()["data"] ] # newest first def epoch_0001utc(date_str: str) -> float: """Convert YYYY-MM-DD to seconds since epoch at 00:01 UTC of that day.""" tm = time.strptime(date_str, "%Y-%m-%d") return time.mktime(tm) + 60 # add 60 s → 00:01 UTC # ─────────────────── background refresher ──────────── def refresher(): while True: try: recs = load_debt_records() # newest first (d0_date, d0_val) = recs[0] # attempt the long-horizon slope candidate = recs[HORIZON] if len(recs) > HORIZON else None if candidate and candidate[1] != d0_val: (dk_date, dk_val) = candidate # point-30 else: # fall back to previous distinct point dk_date, dk_val = next( (d for d in recs[1:] if d[1] != d0_val), (None, None) ) if dk_date is None: raise ValueError("Could not find two distinct points") t0, tk = epoch_0001utc(d0_date), epoch_0001utc(dk_date) rate = (d0_val - dk_val) / (t0 - tk) # $/s (may be negative) DEBT_STATE.update( debt_at_record = d0_val, record_time = t0, rate_per_sec = rate, last_refresh = time.time() ) print( f"[refresh] latest={d0_date} debt={d0_val:,.2f} " f"rate={rate:,.2f}$/s horizon={t0 - tk:.0f}s" ) except Exception as e: print("Debt refresh error:", e) time.sleep(300) # five-minute cycle threading.Thread(target=refresher, daemon=True).start() # ─────────────────── routes ────────────────────────── @app.route("/") def root(): return "✅ Debt clock running", 200 @app.route("/api/debt") def api_debt(): now = time.time() elapsed = max(0.0, now - DEBT_STATE["record_time"]) # **no 12-h guard** current = DEBT_STATE["debt_at_record"] + DEBT_STATE["rate_per_sec"] * elapsed return jsonify( startingDebt = current, ratePerSecond = DEBT_STATE["rate_per_sec"], asOf = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(now)) ) @app.route("/api/ping") def api_ping(): return {"status": "ok"}, 200 # ─────────────────── main ──────────────────────────── if __name__ == "__main__": port = int(os.environ.get("PORT", 7860)) app.run(host="0.0.0.0", port=port)