sithuWiki commited on
Commit
bb6290c
·
verified ·
1 Parent(s): a8de46a

update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -139
app.py CHANGED
@@ -1,16 +1,16 @@
1
- """MineROI-Net Gradio App - Updated to use complete historical blockchain data"""
2
-
3
  import gradio as gr
4
  import pandas as pd
5
  import plotly.graph_objects as go
6
- from datetime import datetime, timedelta
7
  import os
8
- from miner_specs import MINER_SPECS, get_miner_list, ELECTRICITY_RATES
9
- from fetch_blockchain_data import get_blockchain_data_for_date, load_complete_blockchain_data
10
  from preprocessing import get_latest_sequence
11
- from electricity_prices import get_electricity_rate
12
  from predictor import MineROIPredictor
13
- from fetch_asic_prices import fetch_asic_price_for_date, FALLBACK_PRICES
 
 
 
 
14
 
15
  MODEL_PATH = "best_model_weights.pth"
16
 
@@ -26,91 +26,90 @@ def init_predictor():
26
 
27
 
28
  def init_app():
29
- """Initialize app - load complete blockchain data into memory"""
30
  print("\n" + "="*80)
31
  print("🚀 INITIALIZING MINEROI-NET APP")
32
  print("="*80)
33
-
34
- # Load complete blockchain data into memory (one-time)
35
- complete_df = load_complete_blockchain_data()
36
-
37
- if complete_df is not None:
38
- print(f"\n✅ Complete blockchain data loaded successfully!")
39
- print(f" {len(complete_df):,} days available")
40
- print(f" Date range: {complete_df['date'].min().date()} to {complete_df['date'].max().date()}")
41
- print(f"\n✅ You can now predict for ANY date in this range!")
42
- else:
43
- print(f"\n⚠️ WARNING: blockchain_data_complete.csv not found!")
44
- print(f" App will work with limited recent data only")
45
- print(f"\n📥 To enable full historical predictions:")
46
- print(f" 1. Run: python download_complete_blockchain_data.py")
47
- print(f" 2. Upload blockchain_data_complete.csv to your Gradio space")
48
-
49
  print("="*80 + "\n")
50
-
51
- # Initialize predictor
52
  init_predictor()
53
 
54
 
55
- def predict_roi(miner_name,region,prediction_date,machine_price,machine_hashrate,machine_power,machine_efficiency,electricity_rate):
56
- """Make prediction for a specific date"""
 
 
 
 
 
 
 
 
 
57
  try:
58
  window_size = 30
59
-
60
- # Convert prediction_date to datetime
61
- if isinstance(prediction_date, str):
62
- prediction_date = datetime.strptime(prediction_date, '%Y-%m-%d')
63
 
 
64
  miner_price = float(machine_price)
65
  miner_hashrate = float(machine_hashrate)
66
  machine_power = float(machine_power)
67
  machine_efficiency = float(machine_efficiency)
68
  electricity_rate = float(electricity_rate)
69
 
70
- print(f"User machine specs:")
71
  print(f" Price: {miner_price}")
72
  print(f" Hashrate (TH/s): {miner_hashrate}")
73
  print(f" Power (W): {machine_power}")
74
  print(f" Efficiency: {machine_efficiency}")
75
  print(f" Elec rate: {electricity_rate} USD/kWh")
76
-
77
- print(f"\n{'='*80}")
78
- print(f"PREDICTION REQUEST")
79
- print(f"{'='*80}")
80
- print(f"Miner: {miner_name}")
81
- print(f"Region: {region}")
82
- print(f"Date: {prediction_date.date()}")
83
- print(f"{'='*80}\n")
84
-
85
- # Get blockchain data for this specific date (30 days before + target date)
86
- print(f"📡 Fetching blockchain data for {prediction_date.date()}...")
87
- blockchain_df = get_blockchain_data_for_date(prediction_date, window_size=window_size)
88
-
 
 
 
 
 
 
 
 
 
89
  if blockchain_df is None or len(blockchain_df) < window_size:
90
  error_msg = f"""
91
  <div style='background: #e74c3c; color: white; padding: 20px; border-radius: 10px;'>
92
  <h3 style='margin: 0;'>❌ Error: Insufficient Data</h3>
93
  <p style='margin: 10px 0 0 0;'>
94
- Not enough blockchain data available for {prediction_date.date()}.
95
  Need at least {window_size} days of historical data.
96
  </p>
97
  </div>
98
  """
99
  return error_msg, error_msg, None, None
100
-
101
  print(f"✅ Got {len(blockchain_df)} days of data")
102
  print(f" Date range: {blockchain_df['date'].min().date()} to {blockchain_df['date'].max().date()}")
103
-
104
  price_source = "User input"
105
- print(f" Using user-provided price for {miner_name}: ${miner_price:,.2f}")
106
-
107
- # Get sequence (now uses blockchain_df which is date-specific)
108
- print(f"\n🔧 Preparing features...")
109
- sequence, _, pred_date = get_latest_sequence(
110
  blockchain_df,
111
- miner_name,
112
  miner_price,
113
- region,
114
  window_size,
115
  machine_hashrate=miner_hashrate,
116
  power=machine_power,
@@ -118,38 +117,38 @@ def predict_roi(miner_name,region,prediction_date,machine_price,machine_hashrate
118
  electricity_rate=electricity_rate,
119
  )
120
  print(f"✅ Sequence prepared: {sequence.shape}")
121
-
122
- # Predict
123
- print(f"\n🤖 Running prediction...")
124
- result = predictor.predict(sequence, region)
125
  print(f"✅ Prediction: {result['predicted_label']} ({result['confidence']:.1%})")
126
-
127
- # Create displays
128
  miner_info = create_miner_info(
129
- miner_name,
130
  miner_price,
131
- region,
132
  price_source,
133
- prediction_date,
134
  miner_hashrate,
135
  machine_power,
136
  machine_efficiency,
137
  electricity_rate,
 
138
  )
139
- prediction_html = warning_html + create_prediction_html(result, pred_date, window_size)
140
- confidence_chart = create_confidence_chart(result['probabilities'])
141
  price_chart = create_price_chart(blockchain_df, window_size)
142
-
143
- print(f"{'='*80}\n")
144
-
145
  return miner_info, prediction_html, confidence_chart, price_chart
146
-
147
  except Exception as e:
148
  import traceback
 
149
  error_details = traceback.format_exc()
150
- print(f"\n❌ ERROR:")
151
  print(error_details)
152
-
153
  error = f"""
154
  <div style='background: #e74c3c; color: white; padding: 20px; border-radius: 10px;'>
155
  <h3 style='margin: 0;'>❌ Prediction Error</h3>
@@ -159,24 +158,20 @@ def predict_roi(miner_name,region,prediction_date,machine_price,machine_hashrate
159
  return error, error, None, None
160
 
161
 
 
162
  def create_miner_info(
163
- miner_name,
164
  price,
165
- region,
166
  source,
167
- prediction_date,
168
  machine_hashrate,
169
  machine_power,
170
  machine_efficiency,
171
  electricity_rate,
 
172
  ):
173
  """
174
- Display miner info using user-provided specs (price, hashrate, power, efficiency, elec rate).
175
- We still use MINER_SPECS only to get the pretty full_name.
176
  """
177
- specs = MINER_SPECS[miner_name]
178
- full_name = specs["full_name"]
179
-
180
  elec_rate = float(electricity_rate)
181
  daily_cost = (float(machine_power) * 24.0 / 1000.0) * elec_rate
182
 
@@ -190,7 +185,7 @@ def create_miner_info(
190
 
191
  return f"""
192
  <div style="background: #1e1e1e; padding: 20px; border-radius: 10px; border: 1px solid #333; color: #ffffff;">
193
- <h3 style="color: #F7931A; margin-top: 0;">{full_name}</h3>
194
  <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
195
  <div>
196
  <p><strong>Hashrate:</strong> {machine_hashrate:.2f} TH/s</p>
@@ -199,13 +194,13 @@ def create_miner_info(
199
  </div>
200
  <div>
201
  <p>
202
- <strong>Price ({prediction_date.date()}):</strong> ${price:,.2f}
203
  <span style="background: {badge_color}; color: white; padding: 2px 8px; border-radius: 4px; font-size: 0.8em;">
204
  {source}
205
  </span>
206
  </p>
207
- <p><strong>Region:</strong> {region.title()}</p>
208
  <p><strong>Electricity rate:</strong> {elec_rate:.4f} USD/kWh</p>
 
209
  <p><strong>Estimated daily elec cost:</strong> ${daily_cost:,.2f}</p>
210
  </div>
211
  </div>
@@ -262,41 +257,21 @@ def create_price_chart(df, window):
262
 
263
 
264
  def create_interface():
265
- # Default date: today
266
- today = datetime.now().date()
267
-
268
- # Check if complete data is available to set min_date
269
- complete_df = load_complete_blockchain_data()
270
- if complete_df is not None:
271
- min_date = complete_df['date'].min().date()
272
- max_date = complete_df['date'].max().date()
273
- date_info = f"{min_date} to {max_date}"
274
- else:
275
- min_date = datetime(2018, 1, 22).date()
276
- max_date = today
277
- date_info = "⚠️ Limited (complete data not loaded)"
278
-
279
  with gr.Blocks(title="MineROI-Net") as app:
280
  gr.Markdown("# 🪙 MineROI-Net: Bitcoin Mining Hardware ROI Predictor")
281
- # gr.Markdown("### Powered by Complete Historical Blockchain Data")
282
-
 
 
 
283
  with gr.Row():
 
284
  with gr.Column(scale=1):
285
  gr.Markdown("### Configuration")
286
- miner = gr.Dropdown(choices=sorted(get_miner_list()), value='s19pro', label="ASIC Miner")
287
- region = gr.Dropdown(choices=['texas', 'china', 'ethiopia'], value='texas', label="Region")
288
-
289
- # Date picker for prediction date
290
- prediction_date = gr.Textbox(
291
- label="📅 Prediction Date",
292
- value=str(today),
293
- info=f"Format: YYYY-MM-DD (e.g., 2024-12-08)",
294
- placeholder="2024-12-08",
295
- elem_classes="date-input"
296
- )
297
  machine_price = gr.Number(
298
  label="Machine price (USD)",
299
- value=2500.0, # you can choose a nicer default
300
  precision=2,
301
  )
302
  machine_hashrate = gr.Number(
@@ -316,31 +291,26 @@ def create_interface():
316
  )
317
  electricity_rate = gr.Number(
318
  label="Electricity rate (USD/kWh)",
319
- value=ELECTRICITY_RATES["texas"], # 0.1549 by default
320
  precision=4,
321
  )
322
-
323
  btn = gr.Button("🔮 Predict ROI", variant="primary", size="lg")
324
-
325
- gr.Markdown(f"""
326
- ### About
327
- - 🔴 **Unprofitable** (ROI ≤ 0)
328
- - 🟡 **Marginal** (0 < ROI < 1)
329
- - 🟢 **Profitable** (ROI 1)
330
-
331
- **Model:** 83.7% accuracy (30-day window)
332
-
333
- **Date Range:** {date_info}
334
-
335
- **Price Source:**
336
- - 🟢 Green badge = Real API data
337
- - 🔴 Red badge = Fallback estimate
338
-
339
- **Data Source:**
340
- - Uses complete historical blockchain data
341
- - Loaded at app startup for fast predictions
342
- """)
343
-
344
  with gr.Column(scale=2):
345
  gr.Markdown("### Results")
346
  miner_info = gr.HTML()
@@ -348,13 +318,11 @@ def create_interface():
348
  with gr.Row():
349
  conf_plot = gr.Plot()
350
  price_plot = gr.Plot()
351
-
 
352
  btn.click(
353
  fn=predict_roi,
354
  inputs=[
355
- miner,
356
- region,
357
- prediction_date,
358
  machine_price,
359
  machine_hashrate,
360
  machine_power,
@@ -363,10 +331,11 @@ def create_interface():
363
  ],
364
  outputs=[miner_info, prediction, conf_plot, price_plot],
365
  )
366
-
367
  return app
368
 
369
 
 
370
  if __name__ == "__main__":
371
  # Initialize app (loads complete data into memory)
372
  init_app()
 
 
 
1
  import gradio as gr
2
  import pandas as pd
3
  import plotly.graph_objects as go
4
+ from datetime import datetime
5
  import os
6
+
 
7
  from preprocessing import get_latest_sequence
 
8
  from predictor import MineROIPredictor
9
+ from fetch_blockchain_data import get_latest_blockchain_data
10
+
11
+ # internal dummy miner used only for age_days etc. (not shown in UI)
12
+ DEFAULT_MINER_NAME = "s19pro"
13
+
14
 
15
  MODEL_PATH = "best_model_weights.pth"
16
 
 
26
 
27
 
28
  def init_app():
29
+ """Initialize app (no need for local blockchain_data_complete.csv)."""
30
  print("\n" + "="*80)
31
  print("🚀 INITIALIZING MINEROI-NET APP")
32
  print("="*80)
33
+ print("\nUsing live blockchain.com data (last 90 days).")
34
+ print("Model will use the latest 30 days for ROI prediction.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  print("="*80 + "\n")
 
 
36
  init_predictor()
37
 
38
 
39
+
40
+ def predict_roi(machine_price, machine_hashrate, machine_power, machine_efficiency, electricity_rate):
41
+ """
42
+ Real-time prediction:
43
+ - Uses latest 90 days from blockchain.com
44
+ - Model uses last 30 days
45
+ - Scaler chosen based on electricity_rate:
46
+ < 0.05 -> ethiopia scaler
47
+ 0.05-0.09 -> china scaler
48
+ > 0.09 -> texas scaler
49
+ """
50
  try:
51
  window_size = 30
 
 
 
 
52
 
53
+ # -------- parse user inputs --------
54
  miner_price = float(machine_price)
55
  miner_hashrate = float(machine_hashrate)
56
  machine_power = float(machine_power)
57
  machine_efficiency = float(machine_efficiency)
58
  electricity_rate = float(electricity_rate)
59
 
60
+ print("User machine specs:")
61
  print(f" Price: {miner_price}")
62
  print(f" Hashrate (TH/s): {miner_hashrate}")
63
  print(f" Power (W): {machine_power}")
64
  print(f" Efficiency: {machine_efficiency}")
65
  print(f" Elec rate: {electricity_rate} USD/kWh")
66
+
67
+ # -------- choose scaler region from electricity_rate --------
68
+ if electricity_rate < 0.05:
69
+ scaler_region = "ethiopia"
70
+ region_bucket = "Low-cost (< $0.05/kWh)"
71
+ elif electricity_rate <= 0.09:
72
+ scaler_region = "china"
73
+ region_bucket = "Medium-cost ($0.05–$0.09/kWh)"
74
+ else:
75
+ scaler_region = "texas"
76
+ region_bucket = "High-cost (> $0.09/kWh)"
77
+
78
+ print("\n" + "=" * 80)
79
+ print("PREDICTION REQUEST")
80
+ print("=" * 80)
81
+ print(f"Scaler region (from electricity rate): {scaler_region}")
82
+ print("=" * 80 + "\n")
83
+
84
+ # -------- fetch latest blockchain data (no date input) --------
85
+ print("📡 Fetching latest blockchain data (last 90 days)...")
86
+ blockchain_df = get_latest_blockchain_data(days=90)
87
+
88
  if blockchain_df is None or len(blockchain_df) < window_size:
89
  error_msg = f"""
90
  <div style='background: #e74c3c; color: white; padding: 20px; border-radius: 10px;'>
91
  <h3 style='margin: 0;'>❌ Error: Insufficient Data</h3>
92
  <p style='margin: 10px 0 0 0;'>
93
+ Not enough blockchain data available.
94
  Need at least {window_size} days of historical data.
95
  </p>
96
  </div>
97
  """
98
  return error_msg, error_msg, None, None
99
+
100
  print(f"✅ Got {len(blockchain_df)} days of data")
101
  print(f" Date range: {blockchain_df['date'].min().date()} to {blockchain_df['date'].max().date()}")
102
+
103
  price_source = "User input"
104
+ print(f" Using user-provided price: ${miner_price:,.2f}")
105
+
106
+ # -------- build sequence with user machine specs --------
107
+ print("\n🔧 Preparing features...")
108
+ sequence, df_window, pred_date = get_latest_sequence(
109
  blockchain_df,
110
+ DEFAULT_MINER_NAME, # internal dummy miner, not shown to user
111
  miner_price,
112
+ scaler_region,
113
  window_size,
114
  machine_hashrate=miner_hashrate,
115
  power=machine_power,
 
117
  electricity_rate=electricity_rate,
118
  )
119
  print(f"✅ Sequence prepared: {sequence.shape}")
120
+
121
+ # -------- model prediction --------
122
+ print("\n🤖 Running prediction...")
123
+ result = predictor.predict(sequence, scaler_region)
124
  print(f"✅ Prediction: {result['predicted_label']} ({result['confidence']:.1%})")
125
+
126
+ # -------- build UI outputs --------
127
  miner_info = create_miner_info(
 
128
  miner_price,
 
129
  price_source,
130
+ pred_date,
131
  miner_hashrate,
132
  machine_power,
133
  machine_efficiency,
134
  electricity_rate,
135
+ region_bucket,
136
  )
137
+ prediction_html = create_prediction_html(result, pred_date, window_size)
138
+ confidence_chart = create_confidence_chart(result["probabilities"])
139
  price_chart = create_price_chart(blockchain_df, window_size)
140
+
141
+ print("=" * 80 + "\n")
142
+
143
  return miner_info, prediction_html, confidence_chart, price_chart
144
+
145
  except Exception as e:
146
  import traceback
147
+
148
  error_details = traceback.format_exc()
149
+ print("\n❌ ERROR:")
150
  print(error_details)
151
+
152
  error = f"""
153
  <div style='background: #e74c3c; color: white; padding: 20px; border-radius: 10px;'>
154
  <h3 style='margin: 0;'>❌ Prediction Error</h3>
 
158
  return error, error, None, None
159
 
160
 
161
+
162
  def create_miner_info(
 
163
  price,
 
164
  source,
165
+ pred_date,
166
  machine_hashrate,
167
  machine_power,
168
  machine_efficiency,
169
  electricity_rate,
170
+ region_bucket,
171
  ):
172
  """
173
+ Display miner info for a user-specified machine (no ASIC dropdown).
 
174
  """
 
 
 
175
  elec_rate = float(electricity_rate)
176
  daily_cost = (float(machine_power) * 24.0 / 1000.0) * elec_rate
177
 
 
185
 
186
  return f"""
187
  <div style="background: #1e1e1e; padding: 20px; border-radius: 10px; border: 1px solid #333; color: #ffffff;">
188
+ <h3 style="color: #F7931A; margin-top: 0;">Custom ASIC Miner</h3>
189
  <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
190
  <div>
191
  <p><strong>Hashrate:</strong> {machine_hashrate:.2f} TH/s</p>
 
194
  </div>
195
  <div>
196
  <p>
197
+ <strong>Price (as of {pred_date.date()}):</strong> ${price:,.2f}
198
  <span style="background: {badge_color}; color: white; padding: 2px 8px; border-radius: 4px; font-size: 0.8em;">
199
  {source}
200
  </span>
201
  </p>
 
202
  <p><strong>Electricity rate:</strong> {elec_rate:.4f} USD/kWh</p>
203
+ <p><strong>Cost bucket:</strong> {region_bucket}</p>
204
  <p><strong>Estimated daily elec cost:</strong> ${daily_cost:,.2f}</p>
205
  </div>
206
  </div>
 
257
 
258
 
259
  def create_interface():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  with gr.Blocks(title="MineROI-Net") as app:
261
  gr.Markdown("# 🪙 MineROI-Net: Bitcoin Mining Hardware ROI Predictor")
262
+ gr.Markdown(
263
+ "Uses the **latest 30 days** of Bitcoin network data from blockchain.com "
264
+ "to classify your miner as Unprofitable / Marginal / Profitable."
265
+ )
266
+
267
  with gr.Row():
268
+ # ---- Left: inputs ----
269
  with gr.Column(scale=1):
270
  gr.Markdown("### Configuration")
271
+
 
 
 
 
 
 
 
 
 
 
272
  machine_price = gr.Number(
273
  label="Machine price (USD)",
274
+ value=2500.0,
275
  precision=2,
276
  )
277
  machine_hashrate = gr.Number(
 
291
  )
292
  electricity_rate = gr.Number(
293
  label="Electricity rate (USD/kWh)",
294
+ value=0.07, # neutral default
295
  precision=4,
296
  )
297
+
298
  btn = gr.Button("🔮 Predict ROI", variant="primary", size="lg")
299
+
300
+ gr.Markdown(
301
+ """
302
+ ### About
303
+
304
+ - 🔴 **Unprofitable** (ROI 0)
305
+ - 🟡 **Marginal** (0 < ROI < 1)
306
+ - 🟢 **Profitable** (ROI ≥ 1)
307
+
308
+ **Model:** trained on 30-day windows of Bitcoin network and miner features.
309
+ **Live mode:** whenever you click *Predict*, the app pulls the latest blockchain data.
310
+ """
311
+ )
312
+
313
+ # ---- Right: outputs ----
 
 
 
 
 
314
  with gr.Column(scale=2):
315
  gr.Markdown("### Results")
316
  miner_info = gr.HTML()
 
318
  with gr.Row():
319
  conf_plot = gr.Plot()
320
  price_plot = gr.Plot()
321
+
322
+ # Connect button to prediction function
323
  btn.click(
324
  fn=predict_roi,
325
  inputs=[
 
 
 
326
  machine_price,
327
  machine_hashrate,
328
  machine_power,
 
331
  ],
332
  outputs=[miner_info, prediction, conf_plot, price_plot],
333
  )
334
+
335
  return app
336
 
337
 
338
+
339
  if __name__ == "__main__":
340
  # Initialize app (loads complete data into memory)
341
  init_app()