ix-scout/ix_scout.py
2026-02-25 00:53:30 +00:00

110 lines
4.0 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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")))