Spaces:
AZK53
/
Sleeping

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()