|
|
| """
|
| 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
|
|
|
|
|
| MODEL_PATH = r"F:\folder\key\children\ensemble_gen1000.py"
|
| sys.path.insert(0, str(Path(MODEL_PATH).parent))
|
|
|
|
|
| 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)
|
|
|
|
|
| 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":
|
|
|
| self._send_json({"enabled": True})
|
|
|
| elif path == "/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...")
|
|
|