File size: 10,776 Bytes
c8eb3d2 f56f009 f51e482 f56f009 f667f58 c8eb3d2 7c447dd f56f009 5c1befb f56f009 5c1befb cd62afd 5c2605b cd62afd 5c2605b 114f421 5c2605b 7c447dd 5c2605b 114f421 5c2605b 695d8e1 7c447dd 695d8e1 5c2605b 695d8e1 5c2605b 695d8e1 7c447dd 114f421 7c447dd 114f421 7c447dd 114f421 7c447dd 114f421 7c447dd 114f421 7c447dd 114f421 7c447dd 114f421 afc637b 686a5a1 7c447dd 114f421 cd62afd 686a5a1 cd62afd f51e482 114f421 6c6f4c1 5c2605b 6c6f4c1 5c2605b 6c6f4c1 5c2605b 6c6f4c1 5c2605b 114f421 5c2605b 114f421 5c2605b 114f421 5c2605b 114f421 7c447dd 6c6f4c1 114f421 5c2605b cd62afd 695d8e1 7c447dd 5c2605b 114f421 695d8e1 114f421 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
import streamlit as st
import fitz # PyMuPDF
from PIL import Image
import pytesseract
import folium
from streamlit_folium import st_folium
import re
import tempfile
import requests
# Helper Functions
def extract_pdf_text(file):
"""Extract text from PDF."""
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
temp_file.write(file.read())
temp_path = temp_file.name
doc = fitz.open(temp_path)
text = ""
for page in doc:
text += page.get_text()
return text
def extract_image_text(file):
"""Extract text from image."""
img = Image.open(file)
return pytesseract.image_to_string(img)
def extract_sanction_load_from_text(text):
"""Extract sanction load from the bill text."""
match = re.search(r"load[:\-]?\s*(\d+)", text, re.IGNORECASE)
return int(match.group(1)) if match else None
def extract_location_from_pdf(text):
"""Extract location from the second line of the PDF text."""
lines = text.split('\n')
if len(lines) >= 2:
location = lines[1].strip()
return location
return None
def clean_address(address):
"""Clean the extracted address text to remove unnecessary characters."""
if address:
address = address.replace('\n', ' ').strip()
address = re.sub(r'\s+', ' ', address) # Replace multiple spaces with one
return address
return None
def extract_values_from_lines(text, start_line=53, end_line=60):
"""Extract numeric values from a specified range of lines in the text."""
lines = text.split('\n')
# Extract lines 53 to 60 (0-indexed, so 52 to 59 in the list)
relevant_lines = lines[start_line-1:end_line]
values = []
for line in relevant_lines:
match = re.search(r"(\d+\.?\d*)", line) # Match numeric values (including decimals)
if match:
values.append(float(match.group(1))) # Convert matched value to float
return values
def get_suggested_solar_size(values):
"""Suggest the solar size based on the maximum value found."""
if values:
max_value = max(values)
# Divide the maximum value by 360 to get the suggested solar size in kW
suggested_size = max_value / 360
return round(suggested_size, 2) # Round to 2 decimal places for kW
return None
def geocode_address_nominatim(address):
"""Convert address to latitude and longitude using Nominatim API."""
if not address:
return None, None
url = f"https://nominatim.openstreetmap.org/search?format=json&q={address}"
headers = {'User-Agent': 'EasySun-Solar-Planner/1.0 (your-email@example.com)'}
try:
response = requests.get(url, headers=headers)
if response.status_code != 200:
st.error(f"Failed to get a valid response from Nominatim API. Status Code: {response.status_code}")
return None, None
result = response.json()
if result:
lat = float(result[0]['lat'])
lon = float(result[0]['lon'])
st.write(f"Found location: Latitude {lat}, Longitude {lon}")
return lat, lon
else:
st.error(f"No results found for address: {address}")
return None, None
except requests.exceptions.RequestException as e:
st.error(f"Error connecting to Nominatim API: {e}")
return None, None
def calculate_solar_system(area_sqft, panel_rating, inverter_type, backup_time=0):
"""Calculate solar system size and components for the Pakistan region."""
panel_area_sqft = 20
system_capacity_kw = (panel_rating / 1000) * (area_sqft / panel_area_sqft) # Convert panel rating to kW
num_panels = area_sqft // panel_area_sqft
inverter_type = inverter_type.lower()
# Default parameters
battery_capacity = 0
cable_length = system_capacity_kw * 1.5
breaker_rating = system_capacity_kw * 1.25
earthing = system_capacity_kw * 0.75
# Inverter type based logic
if inverter_type == "off-grid" or inverter_type == "hybrid":
# Calculate battery capacity based on backup time (for Off-Grid and Hybrid only)
if backup_time > 0:
battery_capacity = system_capacity_kw * backup_time # Assuming 1 hour of battery per kW system size
else:
st.warning("Please provide backup time for Off-Grid or Hybrid inverter type.")
inverter_type = "Hybrid" if inverter_type == "hybrid" else "Off-Grid" if inverter_type == "off-grid" else "On-Grid"
# Panels in series and strings in parallel calculations
panels_in_series = 3
strings_in_parallel = num_panels // panels_in_series
return {
"System Size (kW)": round(system_capacity_kw, 2),
"Number of Panels": round(num_panels),
"Inverter Type": inverter_type.capitalize(),
"Battery Capacity (kWh)": round(battery_capacity, 2),
"Cable Length (meters)": round(cable_length, 2),
"Breaker Rating (Amps)": round(breaker_rating, 2),
"Earthing (meters)": round(earthing, 2),
"Panels in Series": panels_in_series,
"Strings in Parallel": strings_in_parallel,
}
# Streamlit UI
def main():
st.set_page_config(page_title="π EasySun: Solar Planner for All", layout="wide")
# Header Section
st.markdown(
"""
<h1 style="text-align:center; color: #4CAF50;">π EasySun: AI Solar Planner for All</h1>
<p style="text-align:center; font-size: 18px;">Simplified Solar Planning for Pakistan</p>
""", unsafe_allow_html=True)
# File Upload Section
st.markdown("### Step 1: Upload Your Electricity Bill")
uploaded_file = st.file_uploader("Upload your electricity bill (PDF/JPG)", type=["pdf", "jpg", "jpeg"])
sanction_load = None
location = None
city = None
lat, lon = None, None
if uploaded_file:
with st.spinner("Extracting information from the uploaded file..."):
if uploaded_file.type == "application/pdf":
bill_text = extract_pdf_text(uploaded_file)
else:
bill_text = extract_image_text(uploaded_file)
st.text_area("Extracted Text", bill_text)
sanction_load = extract_sanction_load_from_text(bill_text)
if sanction_load:
st.success(f"Sanction Load Extracted: {sanction_load} kW")
else:
st.error("Unable to extract sanction load.")
location = extract_location_from_pdf(bill_text)
if location:
location = clean_address(location)
st.success(f"Location Extracted: {location}")
else:
st.error("Unable to extract location.")
# City Input Section
st.markdown("### Step 2: Enter the City Information")
city = st.text_input("Enter the city of your location (required):")
if not city:
st.warning("City is required to proceed.")
return
# Full Address Generation
full_address = f"{location}, {city}, Pakistan" if location else f"{city}, Pakistan"
# Geocode Address Section
st.markdown("### Step 3: Geolocation of Your Address")
lat, lon = geocode_address_nominatim(full_address)
if lat and lon:
st.success(f"Location Found: Latitude {lat}, Longitude {lon}")
map_ = folium.Map(location=[lat, lon], zoom_start=12)
folium.Marker([lat, lon], popup=f"Location: {full_address}").add_to(map_)
st_folium(map_, width=700, height=500)
else:
st.error(f"Unable to find the location: {full_address}.")
# Extract Values and Suggested Solar Size Section
st.markdown("### Step 4: Extract Solar Size from Bill")
values = extract_values_from_lines(bill_text, start_line=53, end_line=60)
if values:
suggested_solar_size = get_suggested_solar_size(values)
if suggested_solar_size:
st.success(f"Suggested Solar System Size as per Utilization: {suggested_solar_size} kW")
else:
st.error("Unable to determine suggested solar size from the extracted values.")
else:
st.error("No numeric values found in lines 53-60.")
# Solar System Calculation Section
st.markdown("### Step 5: Solar System Calculation")
panel_rating = st.number_input("Enter Panel Rating (in W):", min_value=1, step=1)
inverter_type = st.selectbox("Select Inverter Type", ["On-Grid", "Off-Grid", "Hybrid"])
backup_time = 0
if inverter_type in ["Off-Grid", "Hybrid"]:
backup_time = st.number_input("Enter Backup Time (hours):", min_value=1, step=1)
area_sqft = st.number_input("Enter roof area (square feet):", min_value=1, step=1)
if st.button("Calculate Solar System"):
if area_sqft > 0 and panel_rating > 0:
results = calculate_solar_system(area_sqft, panel_rating, inverter_type, backup_time)
st.write("### Solar System Sizing Results")
for key, value in results.items():
st.write(f"- **{key}**: {value}")
st.markdown("### Solar Panel Layout")
for _ in range(results["Strings in Parallel"]):
st.text("β".join(["π"] * results["Panels in Series"]))
else:
st.error("Please provide valid inputs for panel rating, roof area, and inverter type.")
# ROI Calculation Section
st.markdown("### Step 6: ROI Calculation")
total_installation_cost = st.number_input("Enter total installation cost (in PKR):", min_value=1, step=1000)
electricity_charges = st.number_input("Enter electricity charges (in PKR per kWh):", min_value=1, step=1)
# Assuming monthly solar generation (this value can be adjusted based on location or other factors)
solar_generation_per_month_kWh = st.number_input("Enter solar generation per month (in kWh):", min_value=1, step=10)
if st.button("Calculate ROI"):
if total_installation_cost > 0 and electricity_charges > 0 and solar_generation_per_month_kWh > 0:
# Calculate monthly savings (based on solar generation and electricity charges)
monthly_savings = solar_generation_per_month_kWh * electricity_charges
# Calculate the ROI in months and years
roi_months = total_installation_cost / monthly_savings
roi_years = roi_months / 12
st.write("### ROI Calculation Results")
st.write(f"- **Monthly Savings**: {monthly_savings} PKR")
st.write(f"- **ROI (Months)**: {roi_months:.2f} months")
st.write(f"- **ROI (Years)**: {roi_years:.2f} years")
else:
st.error("Please provide valid inputs for installation cost, electricity charges, and solar generation.")
if __name__ == "__main__":
main() |