Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,126 +1,95 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
-
from
|
| 5 |
-
from PIL import Image
|
| 6 |
import datetime
|
|
|
|
| 7 |
|
| 8 |
-
# --- 2026
|
| 9 |
-
|
| 10 |
-
"
|
| 11 |
-
"
|
| 12 |
-
"
|
| 13 |
-
"
|
| 14 |
-
"
|
| 15 |
-
"
|
| 16 |
-
"bank_rate": 0.14 # 14% Solar Financing Rate
|
| 17 |
}
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
"
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
"""Simple ML model to predict peak summer load based on average units."""
|
| 27 |
-
# Dummy data: Training correlation between avg units and peak monthly units
|
| 28 |
-
X = np.array([[200], [400], [600], [800], [1000]])
|
| 29 |
-
y = np.array([[310], [580], [890], [1150], [1400]]) # Summer peaks
|
| 30 |
-
model = LinearRegression().fit(X, y)
|
| 31 |
-
prediction = model.predict([[avg_monthly_units]])
|
| 32 |
-
return float(prediction[0][0])
|
| 33 |
|
| 34 |
-
# --- MODULE
|
| 35 |
-
def
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
|
|
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
# Financials
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
|
| 54 |
|
| 55 |
-
|
| 56 |
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
# EMI (5 Year Tenure)
|
| 64 |
-
p = total_investment * 0.8 # 20% Downpayment
|
| 65 |
-
r = MARKET_DATA["bank_rate"] / 12
|
| 66 |
-
n = 60
|
| 67 |
-
emi = p * (r * (1+r)**n) / ((1+r)**n - 1)
|
| 68 |
-
|
| 69 |
-
return total_watts, required_kw, int(total_investment), round(payback, 1), int(emi)
|
| 70 |
-
|
| 71 |
-
# --- MODULE 3: ADMIN & OCR (STUBS) ---
|
| 72 |
-
def ocr_bill(image):
|
| 73 |
-
return 450 # Mocking 450 units detected from bill image
|
| 74 |
|
| 75 |
# --- GRADIO UI ---
|
| 76 |
-
with gr.Blocks(theme=gr.themes.
|
| 77 |
-
gr.Markdown("# ☀️
|
| 78 |
|
| 79 |
-
with gr.
|
| 80 |
-
with gr.
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
backup = gr.Slider(0, 12, step=1, label="Battery Backup (Hours)")
|
| 90 |
-
calc_btn = gr.Button("Generate Production Report", variant="primary")
|
| 91 |
-
|
| 92 |
-
with gr.Tab("3. Results & Financials"):
|
| 93 |
-
with gr.Row():
|
| 94 |
-
res_kw = gr.Label(label="Required System Size (kW)")
|
| 95 |
-
res_cost = gr.Label(label="Estimated Price (PKR)")
|
| 96 |
-
res_emi = gr.Label(label="Monthly EMI (Bank Alfalah/JS)")
|
| 97 |
-
|
| 98 |
-
roi_plot = gr.Markdown()
|
| 99 |
-
|
| 100 |
-
with gr.Accordion("Admin Dashboard & Installer Contact", open=False):
|
| 101 |
-
gr.Markdown("Contacting nearest AEDB Certified Installers...")
|
| 102 |
-
name = gr.Textbox(label="Full Name")
|
| 103 |
-
phone = gr.Textbox(label="WhatsApp Number")
|
| 104 |
-
gr.Button("Request Official Quote")
|
| 105 |
-
|
| 106 |
-
# Mapping Logic
|
| 107 |
-
def run_engine(img, units, apps, counts, stype, bkp):
|
| 108 |
-
if img: units = ocr_bill(img)
|
| 109 |
-
counts_list = [row[0] for row in counts]
|
| 110 |
-
load, kw, cost, roi, emi = calculate_solar_system(apps, counts_list, stype, bkp, units)
|
| 111 |
-
|
| 112 |
-
roi_report = f"""
|
| 113 |
-
### Financial Feasibility
|
| 114 |
-
* **Payback Period:** {roi} Years
|
| 115 |
-
* **Annual Energy Yield:** ~{int(kw * 1500)} Units
|
| 116 |
-
* **Monthly Savings:** PKR {int((kw * 1500 * 45)/12):,}
|
| 117 |
-
|
| 118 |
-
> **Note:** Calculations include a 20% system loss factor and 2026 Net Billing buyback rates.
|
| 119 |
-
"""
|
| 120 |
-
return f"{kw} kW", f"PKR {cost:,}", f"PKR {emi:,}/mo", roi_report
|
| 121 |
|
| 122 |
-
|
| 123 |
-
inputs=[bill_img, units_in, app_select, app_counts, sys_type, backup],
|
| 124 |
-
outputs=[res_kw, res_cost, res_emi, roi_plot])
|
| 125 |
|
| 126 |
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
+
from fpdf import FPDF
|
|
|
|
| 5 |
import datetime
|
| 6 |
+
import os
|
| 7 |
|
| 8 |
+
# --- 2026 MARKET DATA CONFIG ---
|
| 9 |
+
CONFIG = {
|
| 10 |
+
"panel_pkr_watt": 32,
|
| 11 |
+
"sun_hours": 5.2,
|
| 12 |
+
"grid_rate": 55.0,
|
| 13 |
+
"buyback_rate": 11.0,
|
| 14 |
+
"li_battery_kwh": 48000,
|
| 15 |
+
"markup": 0.15,
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
+
# --- MODULE: BANK API INTEGRATION ---
|
| 19 |
+
def fetch_bank_rates():
|
| 20 |
+
"""
|
| 21 |
+
Simulated API call to Bank Alfalah/JS Bank for 2026 Solar Financing.
|
| 22 |
+
In production, use: requests.get('https://api.bankalfalah.com/rates')
|
| 23 |
+
"""
|
| 24 |
+
return {"interest_rate": 0.14, "tenure_months": 60, "bank_name": "Bank Alfalah"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
+
# --- MODULE: PDF GENERATOR ---
|
| 27 |
+
def generate_report(load, size, cost, emi, roi):
|
| 28 |
+
pdf = FPDF()
|
| 29 |
+
pdf.add_page()
|
| 30 |
+
pdf.set_font("Arial", 'B', 16)
|
| 31 |
+
pdf.cell(200, 10, "Solar Solution Report - Pakistan 2026", ln=True, align='C')
|
| 32 |
|
| 33 |
+
pdf.set_font("Arial", size=12)
|
| 34 |
+
pdf.ln(10)
|
| 35 |
+
pdf.cell(200, 10, f"Date: {datetime.datetime.now().strftime('%Y-%m-%d')}", ln=True)
|
| 36 |
+
pdf.cell(200, 10, f"Total Connected Load: {load} Watts", ln=True)
|
| 37 |
+
pdf.cell(200, 10, f"Recommended System Size: {size} kW", ln=True)
|
| 38 |
+
pdf.cell(200, 10, f"Estimated Total Investment: PKR {cost:,}", ln=True)
|
| 39 |
+
pdf.cell(200, 10, f"Monthly EMI Plan: PKR {emi:,}/month", ln=True)
|
| 40 |
+
pdf.cell(200, 10, f"Estimated Payback Period: {roi} Years", ln=True)
|
| 41 |
+
|
| 42 |
+
report_path = "Solar_Report_PK.pdf"
|
| 43 |
+
pdf.output(report_path)
|
| 44 |
+
return report_path
|
| 45 |
|
| 46 |
+
# --- CORE LOGIC ---
|
| 47 |
+
def solar_engine(app_selection, counts, sys_type, backup_hrs):
|
| 48 |
+
# Load math (20% losses included)
|
| 49 |
+
watts_map = {"AC": 1500, "Fan": 80, "Fridge": 250, "Lights": 12}
|
| 50 |
+
total_watts = sum([watts_map[k] for k in app_selection])
|
| 51 |
+
|
| 52 |
+
daily_units = (total_watts * 10) / 1000 # Avg 10h usage
|
| 53 |
+
sys_size = round((daily_units / CONFIG["sun_hours"]) * 1.2, 1)
|
| 54 |
+
|
| 55 |
+
panel_cost = sys_size * 1000 * CONFIG["panel_pkr_watt"]
|
| 56 |
+
battery_cost = (daily_units * (backup_hrs/24) * CONFIG["li_battery_kwh"])
|
| 57 |
+
|
| 58 |
+
total_cost = int((panel_cost + battery_cost + 200000) * (1 + CONFIG["markup"]))
|
| 59 |
+
|
| 60 |
# Financials
|
| 61 |
+
bank = fetch_bank_rates()
|
| 62 |
+
p = total_cost * 0.8
|
| 63 |
+
r = bank["interest_rate"] / 12
|
| 64 |
+
n = bank["tenure_months"]
|
| 65 |
+
emi = int(p * (r * (1+r)**n) / ((1+r)**n - 1))
|
| 66 |
|
| 67 |
+
roi = round(total_cost / (daily_units * 365 * 45), 1)
|
| 68 |
|
| 69 |
+
pdf_file = generate_report(total_watts, sys_size, total_cost, emi, roi)
|
| 70 |
|
| 71 |
+
summary = f"""### 📋 System Insights
|
| 72 |
+
- **Size:** {sys_size} kW
|
| 73 |
+
- **Total Cost:** PKR {total_cost:,}
|
| 74 |
+
- **EMI:** PKR {emi:,}/mo ({bank['bank_name']})
|
| 75 |
+
"""
|
| 76 |
+
return summary, pdf_file
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
# --- GRADIO UI ---
|
| 79 |
+
with gr.Blocks(theme=gr.themes.Default()) as demo:
|
| 80 |
+
gr.Markdown("# ☀️ Solar Consultant Pro (Pakistan)")
|
| 81 |
|
| 82 |
+
with gr.Row():
|
| 83 |
+
with gr.Column():
|
| 84 |
+
apps = gr.CheckboxGroup(["AC", "Fan", "Fridge", "Lights"], label="Appliances")
|
| 85 |
+
sys = gr.Dropdown(["On-Grid", "Hybrid", "Off-Grid"], label="System Type", value="Hybrid")
|
| 86 |
+
bkp = gr.Slider(0, 12, value=4, label="Battery Backup (Hours)")
|
| 87 |
+
btn = gr.Button("Analyze & Generate PDF", variant="primary")
|
| 88 |
+
|
| 89 |
+
with gr.Column():
|
| 90 |
+
out_md = gr.Markdown()
|
| 91 |
+
out_pdf = gr.File(label="Download Full Report")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
+
btn.click(solar_engine, inputs=[apps, gr.State(1), sys, bkp], outputs=[out_md, out_pdf])
|
|
|
|
|
|
|
| 94 |
|
| 95 |
demo.launch()
|