110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
IX Scout — Global Hardware Node Registry
|
|
Part of the Inference-X Ecosystem
|
|
# SALKA ELMADANI | inference-x.com | BSL-1.1
|
|
Copyright (C) 2024-2026 Salka Elmadani. BSL-1.1.
|
|
https://git.inference-x.com/inference-x-community/ix-scout
|
|
|
|
Real-time map of every IX node on Earth.
|
|
Anonymous. Voluntary. Community-powered.
|
|
"""
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.responses import JSONResponse, HTMLResponse
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
import sqlite3, json, time, os, hashlib
|
|
|
|
app = FastAPI(title="IX Scout", version="1.0.0",
|
|
description="Real-time global map of every Inference-X node.")
|
|
app.add_middleware(CORSMiddleware, allow_origins=["*"],
|
|
allow_methods=["*"], allow_headers=["*"])
|
|
|
|
DB = os.environ.get("SCOUT_DB", "./scout.db")
|
|
|
|
def db():
|
|
conn = sqlite3.connect(DB)
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
def init_db():
|
|
with db() as c:
|
|
c.execute("""CREATE TABLE IF NOT EXISTS nodes (
|
|
id TEXT PRIMARY KEY,
|
|
backend TEXT NOT NULL,
|
|
model TEXT,
|
|
tokens_per_sec REAL DEFAULT 0,
|
|
ram_gb REAL DEFAULT 0,
|
|
country TEXT DEFAULT '',
|
|
version TEXT DEFAULT '1.0',
|
|
reported_at INTEGER,
|
|
load_pct REAL DEFAULT 0
|
|
)""")
|
|
c.commit()
|
|
|
|
@app.on_event("startup")
|
|
async def startup(): init_db()
|
|
|
|
@app.post("/report")
|
|
async def report_node(request: Request):
|
|
"""IX Engine nodes report telemetry here (opt-in via --scout flag)."""
|
|
try:
|
|
data = await request.json()
|
|
node_id = hashlib.sha256(
|
|
f"{data.get('backend','')}{data.get('ram_gb',0)}".encode()
|
|
).hexdigest()[:16]
|
|
with db() as c:
|
|
c.execute("""INSERT OR REPLACE INTO nodes
|
|
(id,backend,model,tokens_per_sec,ram_gb,country,version,reported_at,load_pct)
|
|
VALUES (?,?,?,?,?,?,?,?,?)""",
|
|
(node_id, data.get("backend","cpu"), data.get("model",""),
|
|
float(data.get("tokens_per_sec",0)), float(data.get("ram_gb",0)),
|
|
data.get("country",""), data.get("version","1.0"),
|
|
int(time.time()), float(data.get("load_pct",0))))
|
|
c.commit()
|
|
return {"status":"ok","node_id":node_id}
|
|
except Exception as e:
|
|
return JSONResponse({"error":str(e)}, status_code=400)
|
|
|
|
@app.get("/stats")
|
|
async def stats():
|
|
"""Aggregated network stats — last 24 hours."""
|
|
cutoff = int(time.time()) - 86400
|
|
with db() as c:
|
|
backends = c.execute("""
|
|
SELECT backend, COUNT(*) as nodes,
|
|
AVG(tokens_per_sec) as avg_tps,
|
|
AVG(ram_gb) as avg_ram,
|
|
AVG(load_pct) as avg_load
|
|
FROM nodes WHERE reported_at > ?
|
|
GROUP BY backend ORDER BY nodes DESC
|
|
""", (cutoff,)).fetchall()
|
|
total = c.execute("SELECT COUNT(*) as t FROM nodes WHERE reported_at > ?",
|
|
(cutoff,)).fetchone()
|
|
return {
|
|
"total_nodes": total["t"] if total else 0,
|
|
"window": "24h",
|
|
"backends": [dict(b) for b in backends]
|
|
}
|
|
|
|
@app.get("/nodes")
|
|
async def list_nodes(limit: int = 100):
|
|
"""List recent nodes (anonymized)."""
|
|
cutoff = int(time.time()) - 3600
|
|
with db() as c:
|
|
rows = c.execute("""
|
|
SELECT backend, model, tokens_per_sec, ram_gb, country, version
|
|
FROM nodes WHERE reported_at > ? ORDER BY reported_at DESC LIMIT ?
|
|
""", (cutoff, limit)).fetchall()
|
|
return {"nodes": [dict(r) for r in rows], "count": len(rows)}
|
|
|
|
@app.get("/health")
|
|
async def health():
|
|
return {"status":"ok","service":"IX Scout","author":"Salka Elmadani","version":"1.0.0"}
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
print("IX Scout — Global Hardware Node Registry")
|
|
print("Anonymous. Voluntary. Real.")
|
|
print("Built in Morocco for the world.")
|
|
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT","7936")))
|