import gradio as gr import time import logging from parallel_miner_v3 import ParallelMiner import threading import json from datetime import datetime import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots # Global variables for mining state miner_instance = None mining_thread = None is_mining = False stats_history = { "timestamps": [], "hashrates": [], "total_hashes": [], "blocks_found": [] } def update_stats_history(hashrate, total_hashes, blocks): """Update historical stats for plotting""" current_time = datetime.now().strftime("%H:%M:%S") stats_history["timestamps"].append(current_time) stats_history["hashrates"].append(hashrate) stats_history["total_hashes"].append(total_hashes) stats_history["blocks_found"].append(blocks) # Keep only last 100 data points max_points = 100 if len(stats_history["timestamps"]) > max_points: stats_history["timestamps"] = stats_history["timestamps"][-max_points:] stats_history["hashrates"] = stats_history["hashrates"][-max_points:] stats_history["total_hashes"] = stats_history["total_hashes"][-max_points:] stats_history["blocks_found"] = stats_history["blocks_found"][-max_points:] def create_performance_plots(): """Create performance visualization plots""" fig = make_subplots( rows=2, cols=1, subplot_titles=("Mining Hashrate (KH/s)", "Total Hashes"), vertical_spacing=0.12 ) # Hashrate plot fig.add_trace( go.Scatter(x=stats_history["timestamps"], y=[h/1000 for h in stats_history["hashrates"]], mode='lines+markers', name='Hashrate', line=dict(color='#2ecc71')), row=1, col=1 ) # Total hashes plot fig.add_trace( go.Scatter(x=stats_history["timestamps"], y=stats_history["total_hashes"], mode='lines', name='Total Hashes', line=dict(color='#3498db')), row=2, col=1 ) fig.update_layout( height=600, showlegend=True, title_text="Mining Performance Metrics", template="plotly_dark" ) return fig def start_mining(): """Start the mining process""" global miner_instance, mining_thread, is_mining if is_mining: return "Mining is already running!" try: miner_instance = ParallelMiner(num_cores=5) miner_instance.mining = True is_mining = True # Start mining in background thread mining_thread = threading.Thread( target=miner_instance.start_mining, kwargs={"duration": None} ) mining_thread.daemon = True mining_thread.start() return "Mining started successfully! Monitor the stats below." except Exception as e: return f"Error starting mining: {str(e)}" def stop_mining(): """Stop the mining process""" global miner_instance, is_mining if not is_mining: return "Mining is not running!" try: if miner_instance: # Log final stats before stopping logging.info("\n=== Final Mining Statistics ===") grand_total = 0 for core_idx, core in enumerate(miner_instance.cores): core_total = core.total_hashes grand_total += core_total logging.info(f"Core {core_idx}: {core_total:,} hashes") logging.info(f"Grand Total: {grand_total:,} hashes") logging.info(f"Overall Hashrate: {miner_instance.current_hashrate/1000:.2f} KH/s") logging.info(f"Blocks Found: {miner_instance.blocks_found}") logging.info("============================\n") miner_instance.mining = False is_mining = False return "Mining stopped successfully! Check logs for final statistics." return "No active mining instance found." except Exception as e: return f"Error stopping mining: {str(e)}" def get_mining_stats(): """Get current mining statistics""" global miner_instance, is_mining if not miner_instance or not is_mining: return { "status": "Stopped", "hashrate": "0 H/s", "total_hashes": "0", "blocks_found": "0", "best_hash": "None", "difficulty": "0" } # Update historical stats update_stats_history( miner_instance.current_hashrate, miner_instance.total_hashes, miner_instance.blocks_found ) # Create performance plot performance_plot = create_performance_plots() return { "status": "Running" if is_mining else "Stopped", "hashrate": f"{miner_instance.current_hashrate/1000:.2f} KH/s", "total_hashes": f"{miner_instance.total_hashes:,}", "blocks_found": str(miner_instance.blocks_found), "best_hash": miner_instance.best_hash.hex() if miner_instance.best_hash else "None", "difficulty": f"{miner_instance.best_hash_difficulty:,}", "performance_plot": performance_plot } # Create the Gradio interface with gr.Blocks(theme=gr.themes.Monochrome()) as app: gr.Markdown("# ⛏️ Bitcoin Mining Dashboard") with gr.Row(): start_btn = gr.Button("▶️ Start Mining", variant="primary") stop_btn = gr.Button("⏹️ Stop Mining", variant="secondary") with gr.Row(): with gr.Column(): status_label = gr.Label(label="Status") hashrate_label = gr.Label(label="Current Hashrate") total_hashes_label = gr.Label(label="Total Hashes") blocks_label = gr.Label(label="Blocks Found") best_hash_label = gr.Label(label="Best Hash") difficulty_label = gr.Label(label="Best Difficulty") with gr.Row(): plot_output = gr.Plot(label="Performance Metrics") # Setup event handlers start_btn.click( fn=start_mining, outputs=[status_label] ) stop_btn.click( fn=stop_mining, outputs=[status_label] ) # Instead of automatic updates, add a refresh button refresh_btn = gr.Button("🔄 Refresh Stats") refresh_btn.click( fn=get_mining_stats, outputs=[ status_label, hashrate_label, total_hashes_label, blocks_label, best_hash_label, difficulty_label, plot_output ] ) if __name__ == "__main__": app.launch( share=True, # Enable sharing server_name="0.0.0.0", server_port=7862 # Using different port to avoid conflicts )