bhardwaj08sarthak commited on
Commit
520323c
·
verified ·
1 Parent(s): d7f1ea8

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -0
app.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dotenv import load_dotenv
2
+ import os
3
+ import googlemaps
4
+ import re
5
+ import gradio as gr
6
+ from datetime import datetime
7
+ import requests
8
+ from geopy.geocoders import Nominatim
9
+ from datetime import datetime, date, timedelta
10
+ import pandas as pd
11
+ import json
12
+ from pathlib import Path
13
+
14
+ dotenv_path = os.getenv('DOTENV_PATH', None)
15
+ if dotenv_path:
16
+ load_dotenv(dotenv_path)
17
+ else:
18
+ load_dotenv()
19
+
20
+ api_key = os.getenv("GOOGLE_API_KEY")
21
+ if not api_key:
22
+ raise EnvironmentError("GOOGLE_API_KEY not found in environment variables.")
23
+ gmaps = googlemaps.Client(key=api_key)
24
+ def get_directions(
25
+ source: str,
26
+ destination: str,
27
+ mode: str,
28
+ departure_time: str):
29
+ """
30
+ Returns a Markdown-formatted string with step-by-step directions and a static map URL.
31
+
32
+ Args:
33
+ source: Starting address or place name.
34
+ destination: Ending address or place name.
35
+ mode: Transport mode: driving, walking, bicycling, or transit.
36
+ departure_time: Trip start time in "YYYY-MM-DD HH:MM" format.
37
+ waypoints: Optional comma-separated list of waypoints.
38
+
39
+ Returns:
40
+ A single Markdown string summarizing the route or an error message.
41
+ """
42
+ # Parse departure time
43
+ try:
44
+ dt = datetime.strptime(departure_time.strip(), "%Y-%m-%d %H:%M")
45
+ except ValueError:
46
+ return (
47
+ "**⚠️ Invalid time format.** Please enter departure time as YYYY-MM-DD HH:MM."
48
+ )
49
+
50
+ # Build waypoints list
51
+ wp_list = None
52
+
53
+ # Call Directions API
54
+ directions = gmaps.directions(
55
+ origin=source,
56
+ destination=destination,
57
+ mode=mode.lower(),
58
+ departure_time=dt,
59
+ waypoints=wp_list,
60
+ optimize_waypoints=True,
61
+ )
62
+
63
+ if not directions:
64
+ return "**No route found.**"
65
+
66
+ # Use first route & leg
67
+ route = directions[0]
68
+ leg = route["legs"][0]
69
+
70
+ # Build summary
71
+ summary = f"**Trip from '{leg['start_address']}' to '{leg['end_address']}'**\n"
72
+ summary += f"- Total distance: {leg['distance']['text']}\n"
73
+ summary += f"- Estimated duration: {leg['duration']['text']}\n\n"
74
+ summary += "### Step-by-Step Directions:\n"
75
+
76
+ for i, step in enumerate(leg["steps"], start=1):
77
+ travel_mode = step.get("travel_mode", "").upper()
78
+ if travel_mode == "TRANSIT":
79
+ details = step.get("transit_details", {})
80
+ line = details.get("line", {})
81
+ vehicle = line.get("vehicle", {}).get("type", "Transit")
82
+ line_name = line.get("short_name") or line.get("name", "")
83
+ dep = details.get("departure_stop", {}).get("name", "")
84
+ arr = details.get("arrival_stop", {}).get("name", "")
85
+ stops = details.get("num_stops", "")
86
+ instr = f"Take {vehicle} {line_name} from {dep} to {arr} ({stops} stops)"
87
+ dist = step.get("distance", {}).get("text", "")
88
+ dur = details.get("departure_time",{}).get("text","")
89
+ else:
90
+ raw = step.get("html_instructions", "")
91
+ instr = re.sub(r"<[^>]+>", "", raw)
92
+ dist = step.get("distance", {}).get("text", "")
93
+ dur = step.get("departure_time",{}).get("text","")
94
+
95
+ summary += f"{i}. {instr} ({dist},{dur})\n"
96
+
97
+ # Static map snapshot
98
+ poly = route.get("overview_polyline", {}).get("points")
99
+ if poly:
100
+ static_map_url = (
101
+ "https://maps.googleapis.com/maps/api/staticmap"
102
+ f"?size=600x400&path=enc:{poly}&key={api_key}"
103
+ )
104
+ summary += "\n---\n"
105
+ summary += ("Here’s a **static map snapshot** of this route:\n" + static_map_url)
106
+
107
+ return summary
108
+
109
+ WEATHER_CODES = {
110
+ 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
111
+ 45: "Fog", 48: "Depositing rime fog", 51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle",
112
+ 61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain", 71: "Slight snowfall", 73: "Moderate snowfall",
113
+ 75: "Heavy snowfall", 80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers",
114
+ 95: "Thunderstorm", 96: "Thunderstorm with hail"
115
+ }
116
+
117
+
118
+ def get_weather_forecast_range(location_name, start_date, end_date):
119
+ try:
120
+ if isinstance(start_date, str):
121
+ start_date = datetime.strptime(start_date, "%Y-%m-%d").date()
122
+ if isinstance(end_date, str):
123
+ end_date = datetime.strptime(end_date, "%Y-%m-%d").date()
124
+
125
+ today = date.today()
126
+ days_ahead = (end_date - today).days
127
+
128
+ if days_ahead > 15:
129
+ return {"error": "Weather data only available up to 15 days from today."}
130
+
131
+ geolocator = Nominatim(user_agent="weather_api")
132
+ location = geolocator.geocode(location_name)
133
+ if not location:
134
+ return {"error": f"Could not find coordinates for '{location_name}'."}
135
+ lat, lon = location.latitude, location.longitude
136
+
137
+ include_hourly = days_ahead <= 6
138
+
139
+ url = "https://api.open-meteo.com/v1/forecast"
140
+ params = {
141
+ "latitude": lat,
142
+ "longitude": lon,
143
+ "daily": "sunrise,sunset,uv_index_max,temperature_2m_max,temperature_2m_min,weather_code",
144
+ "temperature_unit": "celsius",
145
+ "windspeed_unit": "kmh",
146
+ "timeformat": "iso8601",
147
+ "timezone": "auto",
148
+ "start_date": start_date.isoformat(),
149
+ "end_date": end_date.isoformat()
150
+ }
151
+
152
+ if include_hourly:
153
+ params["hourly"] = "temperature_2m,weather_code,uv_index,visibility"
154
+
155
+ response = requests.get(url, params=params)
156
+ if response.status_code != 200:
157
+ return {"error": f"API error {response.status_code}: {response.text}"}
158
+ raw = response.json()
159
+
160
+ forecasts = []
161
+ for idx, d in enumerate(raw["daily"]["time"]):
162
+ day_result = {
163
+ "date": d,
164
+ "sunrise": raw["daily"]["sunrise"][idx].split("T")[1],
165
+ "sunset": raw["daily"]["sunset"][idx].split("T")[1],
166
+ "uv_max": round(raw["daily"]["uv_index_max"][idx], 1),
167
+ "temp_min": round(raw["daily"]["temperature_2m_min"][idx]),
168
+ "temp_max": round(raw["daily"]["temperature_2m_max"][idx]),
169
+ "weather": WEATHER_CODES.get(int(raw["daily"]["weather_code"][idx]), "Unknown")
170
+ }
171
+
172
+ if include_hourly and "hourly" in raw:
173
+ hourly_df = pd.DataFrame({
174
+ "time": raw["hourly"]["time"],
175
+ "temp": raw["hourly"]["temperature_2m"],
176
+ "code": raw["hourly"]["weather_code"],
177
+ "uv": raw["hourly"]["uv_index"],
178
+ "visibility": [v / 1000 for v in raw["hourly"]["visibility"]]
179
+ })
180
+
181
+ hourly_df["time"] = pd.to_datetime(hourly_df["time"])
182
+ target_date = datetime.strptime(d, "%Y-%m-%d").date()
183
+ df_day = hourly_df[hourly_df["time"].dt.date == target_date]
184
+
185
+ df_day["weather"] = df_day["code"].apply(lambda c: WEATHER_CODES.get(int(c), "Unknown"))
186
+
187
+ day_result["hourly"] = [
188
+ {
189
+ "time": t.strftime("%Y-%m-%d %H:%M"),
190
+ "temp": f"{round(temp)}°C",
191
+ "weather": w,
192
+ "uv": round(uv, 1),
193
+ "visibility": f"{round(vis, 1)} km"
194
+ }
195
+ for t, temp, w, uv, vis in zip(
196
+ df_day["time"], df_day["temp"], df_day["weather"],
197
+ df_day["uv"], df_day["visibility"]
198
+ )
199
+ ]
200
+ else:
201
+ day_result["note"] = "Hourly weather data is only available for the next 7 days."
202
+
203
+ forecasts.append(day_result)
204
+
205
+ return forecasts
206
+
207
+ except Exception as e:
208
+ return {"error": str(e)}
209
+
210
+ def get_weather_forecast_range_ui(location_name, start_date, end_date):
211
+ result = get_weather_forecast_range(location_name, start_date, end_date)
212
+
213
+ if "error" in result:
214
+ return f"**⚠️ Error:** {result['error']}"
215
+
216
+ # Save JSON silently
217
+ save_dir = Path("logs")
218
+ save_dir.mkdir(exist_ok=True)
219
+ save_path = save_dir / f"weather_{location_name}_{start_date}_to_{end_date}.json"
220
+ with open(save_path, "w", encoding="utf-8") as f:
221
+ json.dump(result, f, indent=2)
222
+
223
+ # Generate Markdown summary
224
+ md = f"## Weather Forecast for {location_name}\n\n"
225
+ for day in result:
226
+ md += f"### 📅 {day['date']}\n"
227
+ md += f"- 🌅 Sunrise: {day['sunrise']}\n"
228
+ md += f"- 🌇 Sunset: {day['sunset']}\n"
229
+ md += f"- 🌡️ Temp: {day['temp_min']}°C – {day['temp_max']}°C\n"
230
+ md += f"- 🌤️ Weather: {day['weather']}\n"
231
+ md += f"- ☀️ UV Index Max: {day['uv_max']}\n"
232
+
233
+ if "hourly" in day:
234
+ md += f"**Hourly Forecast:**\n"
235
+ for h in day["hourly"]:
236
+ md += f" - {h['time']}: {h['temp']}, {h['weather']}, UV {h['uv']}, Visibility {h['visibility']}\n"
237
+ elif "note" in day:
238
+ md += f"_{day['note']}_\n"
239
+ md += "\n"
240
+
241
+ return md
242
+
243
+ demo = gr.TabbedInterface(
244
+ [
245
+ gr.Interface(
246
+ fn=get_directions,
247
+ inputs=[
248
+ gr.Textbox(label="Source Location", placeholder="e.g. New York City"),
249
+ gr.Textbox(label="Destination Location", placeholder="e.g. Los Angeles"),
250
+ gr.Radio(["driving", "walking", "bicycling", "transit"], label="Travel Mode", value="driving"),
251
+ gr.Textbox(label="Departure Time (YYYY-MM-DD HH:MM)", placeholder="e.g. 2025-06-08 14:30"),
252
+ ],
253
+ outputs=gr.Markdown(label="Directions Summary"),
254
+ api_name="get direction"
255
+ ),
256
+ gr.Interface(
257
+ fn=get_weather_forecast_range_ui,
258
+ inputs=[
259
+ gr.Textbox(label="Location Name", placeholder="Enter a city or place name"),
260
+ gr.Textbox(label="Start Date (YYYY-MM-DD)", value=date.today()),
261
+ gr.Textbox(label="End Date (YYYY-MM-DD)", value=date.today() + timedelta(days=6)),
262
+ ],
263
+ outputs=gr.Markdown(label="Readable Forecast"),
264
+ api_name="get weather forecast"
265
+ )
266
+ ],
267
+ tab_names=["Google Maps Directions", "Weather Forecast"]
268
+ )
269
+
270
+ if __name__ == "__main__":
271
+ demo.launch()