ix-relay/ix_relay.py
2026-02-25 02:56:55 +00:00

99 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
IX Relay — Federated Inference Network
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-relay
Your idle hardware earns you compute credits.
Share compute. Earn credits. Use when you need it.
"""
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import sqlite3, json, time, os, hashlib, secrets
app = FastAPI(title="IX Relay", version="1.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"],
allow_methods=["*"], allow_headers=["*"])
DB = os.environ.get("RELAY_DB", "./relay.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, endpoint TEXT,
backend TEXT DEFAULT 'cpu', capacity INTEGER DEFAULT 1,
credits REAL DEFAULT 0, last_seen INTEGER,
status TEXT DEFAULT 'idle', version TEXT DEFAULT '1.0'
)""")
c.execute("""CREATE TABLE IF NOT EXISTS accounts (
id TEXT PRIMARY KEY, credits REAL DEFAULT 10.0, created_at INTEGER
)""")
c.execute("""CREATE TABLE IF NOT EXISTS jobs (
id TEXT PRIMARY KEY, model TEXT, node_id TEXT,
credits_cost REAL DEFAULT 0.1, status TEXT DEFAULT 'pending',
created_at INTEGER, completed_at INTEGER
)""")
c.commit()
init_db()
@app.post("/register-node")
async def register_node(request: Request):
"""Register your IX instance as a relay node."""
data = await request.json()
node_id = hashlib.sha256(
f"{data.get('endpoint','')}{secrets.token_hex(8)}".encode()
).hexdigest()[:16]
with db() as c:
c.execute("""INSERT OR REPLACE INTO nodes (id,endpoint,backend,capacity,last_seen,version)
VALUES (?,?,?,?,?,?)""",
(node_id, data.get("endpoint",""), data.get("backend","cpu"),
int(data.get("capacity",1)), int(time.time()), data.get("version","1.0")))
c.commit()
return {"node_id":node_id,
"message":"Node registered. You will receive inference jobs and earn credits.",
"initial_credits":0}
@app.get("/nodes")
async def list_nodes():
"""List active relay nodes (last 5 minutes)."""
cutoff = int(time.time()) - 300
with db() as c:
rows = c.execute("""SELECT id,backend,capacity,credits,status
FROM nodes WHERE last_seen > ? ORDER BY credits DESC""", (cutoff,)).fetchall()
return {"active_nodes":len(rows),"nodes":[dict(r) for r in rows]}
@app.get("/credits/{account_id}")
async def get_credits(account_id: str):
with db() as c:
acc = c.execute("SELECT credits FROM accounts WHERE id=?", (account_id,)).fetchone()
if not acc:
return JSONResponse({"error":"Account not found"}, status_code=404)
return {"account_id":account_id,"credits":acc["credits"]}
@app.post("/create-account")
async def create_account():
account_id = secrets.token_hex(16)
with db() as c:
c.execute("INSERT INTO accounts (id,credits,created_at) VALUES (?,?,?)",
(account_id, 10.0, int(time.time())))
c.commit()
return {"account_id":account_id,"initial_credits":10.0,
"message":"Account created. 10 free credits to start."}
@app.get("/health")
async def health():
return {"status":"ok","service":"IX Relay","author":"Salka Elmadani","version":"1.0.0"}
if __name__ == "__main__":
import uvicorn
print("IX Relay — Federated Inference Network")
print("Built in Morocco for the world.")
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT","7938")))