#!/usr/bin/env python3 """ Simple GPU Miner Client for AITBC - simulates GPU work """ import json import time import httpx import logging import sys import subprocess from datetime import datetime # Configuration COORDINATOR_URL = "http://127.0.0.1:8000" MINER_ID = "localhost-gpu-miner" AUTH_TOKEN = "REDACTED_MINER_KEY" HEARTBEAT_INTERVAL = 15 MAX_RETRIES = 10 RETRY_DELAY = 30 # Setup logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # GPU capabilities (simulated) GPU_CAPABILITIES = { "gpu": { "model": "NVIDIA GeForce RTX 4060 Ti", "memory_gb": 16, "cuda_version": "12.4", "platform": "CUDA", "supported_tasks": ["inference", "training", "stable-diffusion", "llama"], "max_concurrent_jobs": 1 } } def simulate_gpu_work(prompt, duration=3): """Simulate GPU processing work""" logger.info(f"Simulating GPU work for: '{prompt}'") # Simulate processing time time.sleep(duration) # Generate a simple response based on the prompt if "hello" in prompt.lower(): response = "Hello! I'm an AI assistant running on the AITBC network. Your request was processed by a GPU miner." elif "ai" in prompt.lower(): response = "AI (Artificial Intelligence) is the simulation of human intelligence in machines that are programmed to think and learn." elif "blockchain" in prompt.lower(): response = "Blockchain is a distributed ledger technology that maintains a secure and decentralized record of transactions." else: response = f"Processed request: {prompt}. This is a simulated GPU response from the AITBC network." return response def wait_for_coordinator(): """Wait for coordinator to be available""" for i in range(MAX_RETRIES): try: response = httpx.get(f"{COORDINATOR_URL}/v1/health", timeout=5) if response.status_code == 200: logger.info("Coordinator is available!") return True except: pass logger.info(f"Waiting for coordinator... ({i+1}/{MAX_RETRIES})") time.sleep(RETRY_DELAY) logger.error("Coordinator not available after max retries") return False def register_miner(): """Register the miner with the coordinator""" register_data = { "capabilities": GPU_CAPABILITIES, "concurrency": 1, "region": "localhost" } headers = { "X-Api-Key": AUTH_TOKEN, "Content-Type": "application/json" } try: response = httpx.post( f"{COORDINATOR_URL}/v1/miners/register?miner_id={MINER_ID}", json=register_data, headers=headers, timeout=10 ) if response.status_code == 200: data = response.json() logger.info(f"Successfully registered miner: {data}") return data.get("session_token", "demo-token") else: logger.error(f"Registration failed: {response.status_code} - {response.text}") return None except Exception as e: logger.error(f"Registration error: {e}") return None def send_heartbeat(): """Send heartbeat to coordinator""" heartbeat_data = { "status": "active", "current_jobs": 0, "last_seen": datetime.utcnow().isoformat(), "gpu_utilization": 45, # Simulated "memory_used": 8192, # Simulated } headers = { "X-Api-Key": AUTH_TOKEN, "Content-Type": "application/json" } try: response = httpx.post( f"{COORDINATOR_URL}/v1/miners/heartbeat?miner_id={MINER_ID}", json=heartbeat_data, headers=headers, timeout=5 ) if response.status_code == 200: logger.info("Heartbeat sent successfully") else: logger.error(f"Heartbeat failed: {response.status_code} - {response.text}") except Exception as e: logger.error(f"Heartbeat error: {e}") def execute_job(job): """Execute a job using simulated GPU processing""" job_id = job.get('job_id') payload = job.get('payload', {}) logger.info(f"Executing job {job_id}: {payload}") try: if payload.get('type') == 'inference': # Get the prompt prompt = payload.get('prompt', '') # Simulate GPU processing logger.info(f"Processing with GPU...") result_text = simulate_gpu_work(prompt, duration=3) # Submit result back to coordinator submit_result(job_id, { "result": { "status": "completed", "output": result_text, "model": "simulated-gpu", "tokens_processed": len(result_text.split()), "execution_time": 3.0, "gpu_used": True }, "metrics": { "gpu_utilization": 85, "memory_used": 2048, "power_consumption": 250 } }) logger.info(f"Job {job_id} completed successfully") return True else: # Unsupported job type logger.error(f"Unsupported job type: {payload.get('type')}") submit_result(job_id, { "result": { "status": "failed", "error": f"Unsupported job type: {payload.get('type')}" } }) return False except Exception as e: logger.error(f"Job execution error: {e}") submit_result(job_id, { "result": { "status": "failed", "error": str(e) } }) return False def submit_result(job_id, result): """Submit job result to coordinator""" headers = { "X-Api-Key": AUTH_TOKEN, "Content-Type": "application/json" } try: response = httpx.post( f"{COORDINATOR_URL}/v1/miners/{job_id}/result", json=result, headers=headers, timeout=10 ) if response.status_code == 200: logger.info(f"Result submitted for job {job_id}") else: logger.error(f"Result submission failed: {response.status_code} - {response.text}") except Exception as e: logger.error(f"Result submission error: {e}") def poll_for_jobs(): """Poll for available jobs""" poll_data = { "miner_id": MINER_ID, "capabilities": GPU_CAPABILITIES, "max_wait_seconds": 5 } headers = { "X-Api-Key": AUTH_TOKEN, "Content-Type": "application/json" } try: response = httpx.post( f"{COORDINATOR_URL}/v1/miners/poll", json=poll_data, headers=headers, timeout=10 ) if response.status_code == 200: job = response.json() logger.info(f"Received job: {job}") return job elif response.status_code == 204: logger.info("No jobs available") return None else: logger.error(f"Poll failed: {response.status_code} - {response.text}") return None except Exception as e: logger.error(f"Error polling for jobs: {e}") return None def main(): """Main miner loop""" logger.info("Starting Simple GPU Miner Client...") # Wait for coordinator if not wait_for_coordinator(): sys.exit(1) # Register with coordinator session_token = register_miner() if not session_token: logger.error("Failed to register, exiting") sys.exit(1) logger.info("Miner registered successfully, starting main loop...") # Main loop last_heartbeat = 0 last_poll = 0 try: while True: current_time = time.time() # Send heartbeat if current_time - last_heartbeat >= HEARTBEAT_INTERVAL: send_heartbeat() last_heartbeat = current_time # Poll for jobs if current_time - last_poll >= 3: job = poll_for_jobs() if job: # Execute the job execute_job(job) last_poll = current_time time.sleep(1) except KeyboardInterrupt: logger.info("Shutting down miner...") except Exception as e: logger.error(f"Error in main loop: {e}") sys.exit(1) if __name__ == "__main__": main()