datanerdke commited on
Commit
7f964ba
1 Parent(s): d52d92f

deploy weatherbot..........

Browse files
Files changed (5) hide show
  1. adrianjuliusaluoch.json +13 -0
  2. app.py +284 -0
  3. create_table.txt +35 -0
  4. requirements.txt +5 -0
  5. weather_data.gzip +0 -0
adrianjuliusaluoch.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "project-adrian-julius-aluoch",
4
+ "private_key_id": "b76a49d2e4ab8141c21f13addcebaa7ff1fdc3a9",
5
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDKoHac6Pf5oUW5\n+ZsrCPSje9o3ZJeYs/+gDpC1IwQucaqbdOxtcVGtdIeDgnb079JKHfizeQPChrG9\nhRCX0MKiZQTYd5eGDkqJWq4V+rygfPdzM5hJz37QQrOfRfiZXqfuRdBJWPbz+du4\nJxnu1y7DnYTbO1/j/2rUod0Ab/+4ZnJ7Jw/l3yiJIw9hP+FapKEKHCrQ1zR0m9Eq\n/q23GZspi++9ZJricWh6hAi/k5lAWSTmdTo3rC16GDINKD4X5XJYhEYBj+CE7HGi\nDoBX36Yd8HXSVYQ36CHYNKjNZyaHa3MqUqQ6Ex5Si0Cy15Sj1Sm5EFFQfOoU7g/2\nJUnEiGEVAgMBAAECggEAAqtl/n/DF11FOGY39XhhKGqxa99T+ffv4+A13VAkDrFb\nD1QaN52FPCZJERNd1U5aeVKodKXIiu+o+Asx3ZO1P9I8Wf3kIW3QO6gHJVmtb9Io\nHwt2eL54+EaYE5xN4lmMBCYKUKZMXf8KXb93Dc7XQZ0LARYaDbxswp5RTi41aNkU\nMDRZ4P8qfX6MknicNSYqkuGlBqMBeRPt8w35RAEmdNhaAGZwx4C5YE/sqJGz4Ueo\nYEQ+upn5keTyuizKJIstqZopqO73fCHOcDV18aoh4YahqfpfN0udGN4dLVEiacQY\nPgKvR+9ZDncedGDKeD6oaP4QNV1/T/Nnsr3StgkpbwKBgQD7ar4dgjBV3EUCv4n6\norCSakrX0hUnHL+BUBrEWaZ1MWesVsn+KeH4mMh6DGh4esI0cIttqtOmdGDkveOS\nVIzP8Xa20MnwltXDDrFw7ByQiHmHcyA/HjJF3SDJ/PpaTvu4sdDmUc47XgB8CQIn\njJRg6n7IkzItTqUDeUZGaMqu+wKBgQDOUgmcUHdEsr1wJSbV2wXNs2Dpc3QNkb13\n67L/aiq/M4JDYhgId8CiSVNEv8+Gv4vAcIdxr5yv+jFpAbrgwnD9CQNySbt+Lwxr\nrW2M2LN4fHbRXOHrmc0BnkfeeyudZHmUJWs5dt4QBU91ej3zh21K3ccDvMCBzInb\nZbco/I7zLwKBgD6H8fkM5FC2lEN2uC6qQBhqb2r2SWSM9eSHs+CaG5iSTSLEA0E/\n0YAvH82bQHCWt66rP0JrdnC0CVVbFTrT5KHjgI8/pro8CbaV9PQNBZ29E9zoeWC5\nde+CbCFQ1kOX2Wu6biaauhxx6NTwuKR1hoIEULw6QAScxtXyV9QzRBX5AoGAZlI9\nPe6SF9nlJVbneavTpv5NE7oUVh5vLqgP76fBZ22uLqjZbmmleVaQG0pdK2CXeGrW\nYUVMmeGk24TmH02PJ45uzSFQAPZoXIZ4DB/0cc6YRqCf0m5GQ4Ux8152dOo9eYFN\nOgR/gMaBb6ueScZiJ3zxlCLp/fVocQxy17rZUjUCgYBIBI/csQ1B5510jm6IFElc\nDhx4a4rXXQTeeUbZSjZi0mP5E52ridLFsCXF0CHOCTob67JM0r4DcVAGvEA3f62Q\nyhl/MsGlHwuhG8/1bvLcl/f75HDmLCr6ZtviTdDRCOwvpb6PRun+GDBb1rndjrnC\nw3PeIWUf/d/UFHT4PRx0QQ==\n-----END PRIVATE KEY-----\n",
6
+ "client_email": "project-adrian-julius-aluoch@project-adrian-julius-aluoch.iam.gserviceaccount.com",
7
+ "client_id": "114797938475157657864",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/project-adrian-julius-aluoch%40project-adrian-julius-aluoch.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
app.py ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Import Packages
2
+ from google.cloud import bigquery
3
+ import numpy as np
4
+ import os
5
+ import time
6
+ import datetime
7
+ import streamlit as st
8
+ import requests
9
+ import pandas as pd
10
+ import xml.etree.ElementTree as ET
11
+ import pyrebase
12
+
13
+ # Set Page Layout
14
+ st.set_page_config(page_title='Weather Data in Kenya',layout='wide')
15
+
16
+ # Set Padding
17
+ st.markdown('<style>div.block-container{padding-top:2.0rem}</style>',unsafe_allow_html=True)
18
+
19
+ # Set Page Header
20
+ title = """
21
+ <style>
22
+ .header{
23
+ font-size : 2.5rem;
24
+ font-family : sana-serif;
25
+ }
26
+ </style>
27
+ <b><center class='header'>🌤️ Open Weather Map🇰🇪</center></b>
28
+ """
29
+ st.markdown(title,unsafe_allow_html=True)
30
+
31
+ # Firebase initialization
32
+ config = {
33
+ 'apiKey': "AIzaSyAQHikJeQ7Sru-Gdy9K3YNjz0adnmTSvuQ",
34
+ 'authDomain': "disaster-tweets-manageme-72580.firebaseapp.com",
35
+ 'databaseURL': "https://disaster-tweets-manageme-72580-default-rtdb.firebaseio.com",
36
+ 'projectId': "disaster-tweets-manageme-72580",
37
+ 'storageBucket': "disaster-tweets-manageme-72580.appspot.com"
38
+ }
39
+
40
+ firebase = pyrebase.initialize_app(config)
41
+ auth = firebase.auth()
42
+
43
+ # Initialize user as None
44
+ if 'user' not in st.session_state:
45
+ st.session_state.user = None
46
+
47
+ # User registration and sign-in
48
+ if st.session_state.user is None:
49
+ tab1, tab2 = st.tabs(['Sign In','Reset Password'])
50
+
51
+ # with tab1:
52
+ # email = st.text_input("Register Email")
53
+ # password = st.text_input("Register Password", type="password")
54
+ # if st.button("Register"):
55
+ # try:
56
+ # user = auth.create_user_with_email_and_password(email, password)
57
+ # st.success(f"Successfully registered with email: {email}")
58
+ # # Send email verification
59
+ # auth.send_email_verification(user['idToken'])
60
+ # st.info("Verification email sent. Please verify your email and then sign in.")
61
+ # except Exception as e:
62
+ # st.error("Email already exists or invalid email/password format.")
63
+
64
+ with tab1:
65
+ email = st.text_input("Sign In Email")
66
+ password = st.text_input("Sign In Password", type="password")
67
+ if st.button("Sign In"):
68
+ try:
69
+ user = auth.sign_in_with_email_and_password(email, password)
70
+ if user:
71
+ st.session_state.user = user
72
+ st.success(f"Successfully signed in with email: {email}")
73
+ st.rerun() # Refresh the app to show the new section
74
+ else:
75
+ st.warning("Your email is not verified. Please check your email for a verification link.")
76
+ except Exception as e:
77
+ error_message = str(e)
78
+ if "INVALID_EMAIL" in error_message:
79
+ st.error("Invalid email. Please enter a valid email address.")
80
+ else:
81
+ st.error("Invalid password. Please check your password and try again.")
82
+
83
+ with tab2:
84
+ st.subheader("Password Reset")
85
+ reset_email = st.text_input("Email to reset password")
86
+ if st.button("Reset Password"):
87
+ try:
88
+ auth.send_password_reset_email(reset_email)
89
+ st.success("Password reset email sent. Please check your email for instructions.")
90
+ except Exception as e:
91
+ st.error(f"Error: {e}")
92
+
93
+ else:
94
+ st.success(f"Logged in as: {st.session_state.user['email']}! 🎉")
95
+
96
+ # define tabs for easy accessibility
97
+ tab1, tab2, tab3 = st.tabs(['Home','Get Data','View Data'])
98
+ with tab1:
99
+ header = """
100
+ <style>
101
+ .subheader{
102
+ font-size: 1.5rem;
103
+ font-family : sana-serif;
104
+ }
105
+ </style>
106
+ <h3 class='subheader'><b>Welcome to Open Weather Map Data Collection Site for Counties in Kenya.</b></h3>
107
+ """
108
+ st.markdown(header,unsafe_allow_html=True)
109
+ st.markdown('This Streamlit app collects weather data from various locations across Kenya using the OpenWeatherMap API.')
110
+ st.markdown("""
111
+ <b>Data Collection Steps;</b>\n
112
+ - Fetch weather data from multiple locations in Kenya.
113
+ - Append collected data to a BigQuery database for further analysis.
114
+ """, unsafe_allow_html=True)
115
+
116
+ # Initialize Environment Variable
117
+ os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'adrianjuliusaluoch.json'
118
+
119
+ # Initialize Client Variable
120
+ client = bigquery.Client()
121
+
122
+ # Function to extract text from XML element safely
123
+ def get_xml_text(parent, tag, attrib=None):
124
+ element = parent.find(tag)
125
+ if element is not None:
126
+ if attrib:
127
+ return element.get(attrib)
128
+ return element.text
129
+ return None
130
+
131
+ # create function to retrieve data from the api
132
+ def get_weather():
133
+ def get_weather(api_key, location):
134
+ base_url = "http://api.openweathermap.org/data/2.5/weather"
135
+
136
+ params = {
137
+ 'q': location,
138
+ 'appid': api_key,
139
+ 'units': 'metric', # You can use 'imperial' for Fahrenheit
140
+ }
141
+
142
+ try:
143
+ response = requests.get(base_url, params=params)
144
+ data = response.json()
145
+
146
+ # Check if the request was successful
147
+ if response.status_code == 200:
148
+
149
+ # Extract additional features from XML
150
+ xml_url = f'http://api.openweathermap.org/data/2.5/weather?q={location}&mode=xml&appid={api_key}'
151
+ xml_response = requests.get(xml_url)
152
+ xml_root = ET.fromstring(xml_response.content)
153
+
154
+ # Create a DataFrame with the relevant weather information
155
+ weather_data = {
156
+ 'City': [location],
157
+ 'Time_of_Data_Calculation': [pd.to_datetime(data['dt'], unit='s', utc=True)],
158
+ 'Coordinates': [data['coord']],
159
+ 'Weather_ID': [data['weather'][0]['id']],
160
+ 'Weather_Main': [data['weather'][0]['main']],
161
+ 'Weather_Description': [data['weather'][0]['description']],
162
+ 'Temperature': [data['main']['temp']],
163
+ 'Feels_Like': [data['main']['feels_like']],
164
+ 'Temp_Min': [data['main']['temp_min']],
165
+ 'Temp_Max': [data['main']['temp_max']],
166
+ 'Pressure': [data['main']['pressure']],
167
+ 'Humidity': [data['main']['humidity']],
168
+ 'Sea_Level': [data['main']['sea_level']] if 'sea_level' in data['main'] else None,
169
+ 'Ground_Level': [data['main']['grnd_level']] if 'grnd_level' in data['main'] else None,
170
+ 'Visibility': [data['visibility']],
171
+ 'Wind_Speed': [data['wind']['speed']],
172
+ 'Wind_Degree': [data['wind']['deg']],
173
+ 'Wind_Gust': [data['wind']['gust']] if 'gust' in data['wind'] else None,
174
+ 'Cloudiness': [data['clouds']['all']],
175
+ 'Cloudiness_Name': [get_xml_text(xml_root, 'clouds', 'name')],
176
+ 'Rain_1h': [data['rain']['1h']] if 'rain' in data and '1h' in data['rain'] else None,
177
+ 'Rain_3h': [data['rain']['3h']] if 'rain' in data and '3h' in data['rain'] else None,
178
+ 'Snow_1h': [data['snow']['1h']] if 'snow' in data and '1h' in data['snow'] else None,
179
+ 'Snow_3h': [data['snow']['3h']] if 'snow' in data and '3h' in data['snow'] else None,
180
+ 'Country_Code': [data['sys']['country']],
181
+ 'Sunrise_Time': [pd.to_datetime(data['sys']['sunrise'], unit='s', utc=True)],
182
+ 'Sunset_Time': [pd.to_datetime(data['sys']['sunset'], unit='s', utc=True)],
183
+ 'Timezone': [data['timezone']],
184
+ 'City_ID': [data['id']],
185
+ 'City_Name': [data['name']]
186
+ }
187
+
188
+
189
+ df = pd.DataFrame(weather_data)
190
+ return df
191
+ else:
192
+ print(f"{location} not found in the OpenWeatherMap DataBase.")
193
+ return None
194
+
195
+ except Exception as e:
196
+ print(f"An error occurred: {str(e)}")
197
+ return None
198
+
199
+ if __name__ == "__main__":
200
+ # Replace 'YOUR_API_KEY' with your actual OpenWeatherMap API key
201
+ api_key = '30bc8c5f44c2f641d15a7f617af532c0'
202
+
203
+ # List of locations (cities or counties) for which you want to get weather data
204
+ locations = [
205
+ 'Baringo', 'Bomet', 'Bungoma', 'Busia', 'Mandeni, KE', 'Embu, KE', 'Garissa', 'Homa Bay', 'Isiolo', 'Kajiado',
206
+ 'Kakamega', 'Kericho', 'Kiambu', 'Kilifi', 'Kerugoya', 'Kisii', 'Kisumu', 'Kitui', 'Kwale, KE', 'Nanyuki',
207
+ 'Lamu', 'Machakos', 'Makueni', 'Mandera', 'Marsabit', 'Meru', 'Migori', 'Mombasa', "Murang'a", 'Nairobi',
208
+ 'Nakuru', 'Nandi, KE', 'Narok', 'Nyamira', 'Oljoro Orok', 'Nyeri', 'Maralal', 'Siaya', 'Taveta',
209
+ 'Chogoria', 'Kitale', 'Lodwar', 'Eldoret', 'Vihiga', 'Wajir', 'Kapenguria']
210
+
211
+ # Create an empty DataFrame to store the results
212
+ all_weather_data = pd.DataFrame()
213
+
214
+ # Loop through the list of locations and concatenate DataFrames
215
+ for location in locations:
216
+ weather_data = get_weather(api_key, location)
217
+ if weather_data is not None:
218
+ all_weather_data = pd.concat([all_weather_data, weather_data], ignore_index=True)
219
+
220
+ # Print the final DataFrame
221
+ st.write(f'Data Collection Successful for all {len(all_weather_data)} Counties in Kenya.')
222
+
223
+ all_weather_data.to_parquet('weather_data.gzip',compression='gzip',index=False)
224
+ st.dataframe(all_weather_data)
225
+
226
+ # Load data into cloud database
227
+ def append_data():
228
+ dataframe = pd.read_parquet('weather_data.gzip')
229
+
230
+ table_id = 'project-adrian-julius-aluoch.central_database.openweathermap'
231
+
232
+ job = client.load_table_from_dataframe(dataframe,table_id)
233
+
234
+ while job.state != 'DONE':
235
+ time.sleep(2)
236
+ job.reload()
237
+ st.write(job.state)
238
+
239
+ with tab2:
240
+ st.markdown("""
241
+ This section allows you to retrieve weather data from various locations across Kenya using the OpenWeatherMap API.\n
242
+ To get started, simply click the "Get Data" button below.\n
243
+ The app will collect real-time weather data for all specified locations and export the data to Google Cloud BigQuery Database for Storage.
244
+ """, unsafe_allow_html=True)
245
+ # add widgets
246
+ if st.button('Get Data from API'):
247
+ with st.spinner('In progress....'):
248
+ get_weather()
249
+ append_data()
250
+ st.success('Open Weather Data Successfully Exported to Google Cloud BigQuery', icon="✅")
251
+
252
+ with tab3:
253
+ st.markdown("""
254
+ **Data Viewing and Analysis:**
255
+
256
+ Welcome to the data viewing section. Here, you can explore the collected weather data for various regions in Kenya.
257
+
258
+ Click the "View Data" button below to display the collected data in a table format. You can verify the data and ensure that all necessary information has been successfully collected.
259
+
260
+ Additionally, you can download the data as a CSV file for offline analysis or sharing with others.
261
+ """)
262
+ if st.button('View Data'):
263
+ with st.spinner('In progress....'):
264
+ sql = (
265
+ 'SELECT *'
266
+ 'FROM `central_database.openweathermap`'
267
+ )
268
+ data = client.query(sql).to_dataframe()
269
+ data = data.sort_values(by='Time_of_Data_Calculation',ascending=False).copy().reset_index(drop=True)
270
+ st.dataframe(data)
271
+ st.divider()
272
+ st.markdown('<b><u>Open Weather Map Statistics</u></b>',unsafe_allow_html=True)
273
+ st.text(f"Data Collection Began : {data['Time_of_Data_Calculation'].min()}\nLast Collection Date : {data['Time_of_Data_Calculation'].max()}\nToday's Date : {datetime.datetime.now()}")
274
+ st.text(f"Time elapsed since data collection began: {np.subtract(data['Time_of_Data_Calculation'].max(),data['Time_of_Data_Calculation'].min())}")
275
+ st.text(f"Rows : {data.shape[0]:,.0f}\nColumns : {data.shape[1]}\nCounties : {len(data['City'].unique())}")
276
+
277
+ st.download_button(label='Download as csv',data=data.to_csv().encode('utf-8'),mime='text/csv',file_name='Open Weather Data in Kenya.csv')
278
+
279
+ st.divider()
280
+
281
+ if st.button("Sign Out"):
282
+ st.session_state.user = None
283
+ st.success("User successfully logged out")
284
+ st.rerun() # Refresh the app to show the login section again
create_table.txt ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ CREATE TABLE `central_database.openweathermap` (
2
+ City STRING,
3
+ Time_of_Data_Calculation TIMESTAMP,
4
+ Coordinates STRUCT<
5
+ lat FLOAT64,
6
+ lon FLOAT64
7
+ >,
8
+ Weather_ID INT64,
9
+ Weather_Main STRING,
10
+ Weather_Description STRING,
11
+ Temperature FLOAT64,
12
+ Feels_Like FLOAT64,
13
+ Temp_Min FLOAT64,
14
+ Temp_Max FLOAT64,
15
+ Pressure FLOAT64,
16
+ Humidity INT64,
17
+ Sea_Level FLOAT64,
18
+ Ground_Level FLOAT64,
19
+ Visibility INT64,
20
+ Wind_Speed FLOAT64,
21
+ Wind_Degree FLOAT64,
22
+ Wind_Gust FLOAT64,
23
+ Cloudiness INT64,
24
+ Cloudiness_Name STRING,
25
+ Rain_1h FLOAT64,
26
+ Rain_3h FLOAT64,
27
+ Snow_1h FLOAT64,
28
+ Snow_3h FLOAT64,
29
+ Country_Code STRING,
30
+ Sunrise_Time TIMESTAMP,
31
+ Sunset_Time TIMESTAMP,
32
+ Timezone INT64,
33
+ City_ID INT64,
34
+ City_Name STRING
35
+ );
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ pyrebase4==4.7.1
2
+ setuptools
3
+ google-cloud-bigquery
4
+ streamlit
5
+ db-dtypes
weather_data.gzip ADDED
Binary file (26.6 kB). View file