tostido's picture
Build MeshScale CPU worker template
96ef23c verified
Raw
History Blame Contribute Delete
6.86 kB
#!/usr/bin/env python3
"""
Ensemble Interface Server - HTTP API for ensemble_gen1000
Auto-generated. Do not edit directly.
Usage:
python server.py # Start on default port 8765
python server.py --port 9000 # Custom port
Double-click launch.bat to start server.
"""
import sys
import json
import argparse
from pathlib import Path
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse
# Add model directory to path
MODEL_PATH = r"F:\folder\key\children\ensemble_gen1000.py"
sys.path.insert(0, str(Path(MODEL_PATH).parent))
# Import the model
import importlib.util
spec = importlib.util.spec_from_file_location("model", MODEL_PATH)
model_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(model_module)
# Create ensemble instance
ENSEMBLE = model_module.EnsembleAgent(observe=False)
class ModelHandler(BaseHTTPRequestHandler):
"""HTTP handler for ensemble actions."""
def _send_json(self, data, status=200):
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(json.dumps(data).encode())
def do_OPTIONS(self):
"""Handle CORS preflight."""
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
def do_GET(self):
parsed = urlparse(self.path)
path = parsed.path
if path == "/manifest":
manifest = json.loads(Path("manifest.json").read_text())
self._send_json(manifest)
elif path == "/info":
self._send_json({
"ensemble_size": len(ENSEMBLE.organisms),
"best_id": ENSEMBLE.get_best()["id"],
"best_fitness": ENSEMBLE.get_best()["fitness"],
"inference_count": ENSEMBLE._inference_count,
})
elif path == "/readme":
self._send_json({"readme": ENSEMBLE.get_readme()})
elif path == "/provenance":
self._send_json(ENSEMBLE.get_full_provenance())
elif path == "/capabilities":
self._send_json({
"endpoints": [
{"path": "/forward", "method": "POST", "desc": "Run ensemble inference"},
{"path": "/export_pt", "method": "POST", "desc": "Export to PyTorch"},
{"path": "/export_onnx", "method": "POST", "desc": "Export to ONNX"},
{"path": "/bridge", "method": "POST", "desc": "Data bridging"},
{"path": "/info", "method": "GET", "desc": "Model info"},
{"path": "/provenance", "method": "GET", "desc": "Full provenance"},
]
})
elif path == "/health":
self._send_json({"status": "ok", "ensemble_size": len(ENSEMBLE.organisms)})
else:
self._send_json({"error": "Unknown endpoint"}, 404)
def do_POST(self):
parsed = urlparse(self.path)
path = parsed.path
content_length = int(self.headers.get("Content-Length", 0))
body_raw = self.rfile.read(content_length).decode() if content_length else "{}"
params = json.loads(body_raw) if body_raw else {}
try:
if path == "/forward":
result = ENSEMBLE.forward(
params.get("inputs"),
params.get("strategy", "fitness_weighted")
)
self._send_json({"result": _serialize(result)})
elif path == "/export_pt":
export_path = params.get("path", "ensemble.pt")
ENSEMBLE.export_pt(export_path)
self._send_json({"status": "ok", "path": export_path})
elif path == "/export_onnx":
export_path = params.get("path", "ensemble.onnx")
ENSEMBLE.export_onnx(export_path)
self._send_json({"status": "ok", "path": export_path})
elif path == "/bridge":
bridge = ENSEMBLE.get_bridge()
result = bridge.bridge(params["old_form"], params["new_form"])
self._send_json({"result": result})
elif path == "/hold/toggle":
# Causation Hold toggle
self._send_json({"enabled": True})
elif path == "/hold/state":
# Causation Hold state
self._send_json({"enabled": False, "paused": False})
else:
self._send_json({"error": "Unknown action"}, 404)
except Exception as e:
self._send_json({"error": str(e)}, 500)
def log_message(self, format, *args):
print(f"[Server] {args[0]}")
def _serialize(obj):
"""Make object JSON-serializable."""
import numpy as np
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, dict):
return {k: _serialize(v) for k, v in obj.items()}
if isinstance(obj, (list, tuple)):
return [_serialize(v) for v in obj]
if hasattr(obj, "item"):
return obj.item()
return obj
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--port", type=int, default=8765)
parser.add_argument("--host", default="127.0.0.1")
args = parser.parse_args()
print()
print("=" * 60)
print(f" ENSEMBLE INTERFACE SERVER - ensemble_gen1000")
print("=" * 60)
print(f" Serving on http://{args.host}:{args.port}")
print(f" Model: {MODEL_PATH}")
print()
print(" Endpoints:")
print(" GET /manifest - Model manifest")
print(" GET /info - Current state")
print(" GET /provenance - Full provenance chain")
print(" GET /health - Health check")
print(" POST /forward - Run inference")
print(" POST /export_pt - Export to PyTorch")
print(" POST /export_onnx - Export to ONNX")
print(" POST /bridge - Data bridging")
print()
print(" Press Ctrl+C to stop")
print("=" * 60)
print()
server = HTTPServer((args.host, args.port), ModelHandler)
try:
server.serve_forever()
except KeyboardInterrupt:
print("\nShutting down...")