thisisdev commited on
Commit
fce7679
·
verified ·
1 Parent(s): 5ed943d

final: changelog

Browse files
Files changed (1) hide show
  1. app.py +261 -0
app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import requests
4
+ import gradio as gr
5
+ from agno.agent import Agent
6
+ from dotenv import load_dotenv
7
+ from dataclasses import dataclass
8
+ from typing import Dict, Optional
9
+ from firecrawl import FirecrawlApp
10
+ from pydantic import BaseModel, Field
11
+ from agno.models.openai import OpenAIChat
12
+
13
+ load_dotenv()
14
+
15
+ class AQIResponse(BaseModel):
16
+ success: bool
17
+ data: Dict[str, float]
18
+ status: str
19
+ expiresAt: str
20
+
21
+ class ExtractSchema(BaseModel):
22
+ aqi: float = Field(description = "Air Quality Index")
23
+ temperature: float = Field(description = "Temperature in Degree Celsius")
24
+ humidity: float = Field(description = "Humidity Percentage")
25
+ wind_speed: float = Field(description = "")
26
+ pm25:float = Field(description = "Particulate Matter 2.5 micrometers")
27
+ pm10:float = Field(description = "Particulate Matter 10 micrometers")
28
+ co: float = Field(description = "Carbon Monoxide Level")
29
+
30
+ @dataclass
31
+ class UserInput:
32
+ city: str
33
+ state: str
34
+ country: str
35
+ medical_conditions: Optional[str]
36
+ planned_activity: str
37
+
38
+ class AQIAnalyzer:
39
+
40
+ def __init__(self, firecrawl_key : str) -> None:
41
+ self.firecrawl = FirecrawlApp(api_key = firecrawl_key)
42
+
43
+ def _format_url(self, country : str, state: str, city: str) -> str:
44
+ """Format URLs based on location, handling cases with and without state
45
+ """
46
+ country_clean = country.lower().replace(" ", "-")
47
+ city_clean = city.lower().replace(" ", "-")
48
+
49
+ if not state or state.lower().replace(" ","-"):
50
+ return f"https://www.aqi.in/dashboard/{country_clean}/{city_clean}"
51
+
52
+ state_clean = state.lower().replace(" ", "-")
53
+ return f"https://www.aqi.in/dashboard/{country_clean}/{state_clean}/{city_clean}"
54
+
55
+
56
+ def fetch_aqi_data(self, city: str, state: str, country: str) -> tuple[Dict[str, float], str]:
57
+ """Fetch API data using Firecrawl"""
58
+ try:
59
+ url = self._format_url(country, state, city)
60
+ info_msg = f"Accessing URL: {url}"
61
+
62
+ resp = self.firecrawl.extract(
63
+ urls = [f"{url}/*"],
64
+ params = {
65
+ "prompt" : "Extract the current real-time AQI, temperature, humidity, wind speed, PM2.5, PM10 and CO Levels from the page. Also extract the timestamp of the data.",
66
+ "schema": ExtractSchema.model_json_schema()
67
+ }
68
+ )
69
+
70
+ aqi_response = AQIResponse(**resp)
71
+
72
+ if not aqi_response.success:
73
+ raise requests.HTTPError(f"Failed to fetch AQI Data: {aqi_response.status}")
74
+
75
+ return aqi_response.data, info_msg
76
+
77
+ except Exception as e:
78
+ error_msg = f"Error Fetching AQI Data: {str(e)}"
79
+ return {
80
+ "api": 0,
81
+ "temperature": 0,
82
+ "humidity": 0,
83
+ "wind_speed": 0,
84
+ "pm25": 0,
85
+ "pm10": 0,
86
+ "co": 0
87
+ }, error_msg
88
+
89
+ class HealthRecommendationAgent:
90
+
91
+ def __init__(self, openai_key: str) -> Agent:
92
+ self.agent = Agent(
93
+ model = OpenAIChat(
94
+ id = "gpt-4.1-nano",
95
+ name = "Health Recommendation Agent",
96
+ api_key = openai_key
97
+ )
98
+ )
99
+
100
+ def _create_prompt(self, aqi_data: Dict[str, float], user_input: UserInput) -> str:
101
+ return f"""
102
+ Based on the following air quality condition in {user_input.city}, {user_input.state}, {user_input.country}:
103
+ - Overall AQI: {aqi_data["aqi"]}
104
+ - PM2.5 Level: {aqi_data["pm25"]} µg/m³
105
+ - PM10 Level: {aqi_data["pm10"]} µg/m³
106
+ - CO Level: {aqi_data["co"]} ppb
107
+
108
+ Weather Conditions:
109
+ - Temperature: {aqi_data["temperature"]}°C
110
+ - Humidity: {aqi_data["humidity"]}%
111
+ - Wind Speed: {aqi_data["co"]} ppb
112
+ """
113
+
114
+ def get_recommendation(self, aqi_data: Dict[str, float], user_input: UserInput) -> str:
115
+ prompt = self._create_prompt(prompt)
116
+ resp = self.agent.run(prompt)
117
+
118
+ return resp.content
119
+
120
+ def analyze_conditions(city: str, state: str, country: str, medical_condition: str, planned_activity: str, firecrawl_key: str, openai_key: str) -> tuple[str, str, str, str]:
121
+ """Analyze condition and return AQI data, recommendation, and status messages"""
122
+ try:
123
+ # initialize the analyzer
124
+ aqi_analyzer = AQIAnalyzer(firecrawl_key=firecrawl_key)
125
+ health_agent = HealthRecommendationAgent(openai_key = openai_key)
126
+
127
+ # Create user input
128
+ user_input = UserInput(
129
+ city = city,
130
+ state = state,
131
+ country = country,
132
+ medical_conditions = medical_condition,
133
+ planned_activity = planned_activity
134
+ )
135
+
136
+ # Get AQI Data
137
+ aqi_data, info_msg = aqi_analyzer.fetch_aqi_data(
138
+ city = user_input.city,
139
+ state = user_input.state,
140
+ country = user_input.country
141
+ )
142
+
143
+ # Format AQI data for display
144
+ aqi_json = json.dumps({
145
+ "Air Quality Index (AQI): ": aqi_data["aqi"],
146
+ "PM2.5: ":f"{aqi_data["pm25"]} µg/m³",
147
+ "PM10: ": f"{aqi_data["pm10"]} µg/m³",
148
+ "Carbon Monoxide (CO): " : f"{aqi_data["co"]} ppb",
149
+ "Temperature": f"{aqi_data['temperature']}°C",
150
+ "Humidity": f"{aqi_data['humidity']}%",
151
+ "Wind Speed": f"{aqi_data['wind_speed']} km/h"
152
+ }, indent=2)
153
+
154
+ # Get Recommendations
155
+ recommendations = health_agent.get_recommendation(aqi_data, user_input)
156
+
157
+ warning_msg = """
158
+ Note: The data shown may not match real-time values on the website.
159
+ This could be due to:
160
+ - Cached data in Firecrawl
161
+ - Rate Limiting
162
+ - Website updates not being captured
163
+
164
+ Consider refreshing or checking the website directly for real-time values
165
+ """
166
+
167
+ return aqi_json, recommendations, info_msg, warning_msg
168
+
169
+ except Exception as e:
170
+ error_msg = f"Error Occured: {str(e)}"
171
+ return "", "Analysis Failed", error_msg, ""
172
+
173
+ def create_demo() -> gr.Blocks:
174
+ """Create and configure the gradio interface"""
175
+
176
+ with gr.Blocks(title = "AQL Analysis and Recommendation Agent") as Demo:
177
+ gr.Markdown(
178
+ """
179
+ AQI Analysis Agent
180
+ Get personalized health recommendations based on air quality conditions.
181
+ """
182
+ )
183
+
184
+ # API Configurations
185
+ with gr.Accordion("API Configuration", open=False):
186
+ firecrawl_key = gr.Textbox(
187
+ label="Firecrawl API Key",
188
+ type="password",
189
+ placeholder="Enter your Firecrawl API Key"
190
+ )
191
+
192
+ openai_key = gr.Textbox(
193
+ label="OpenAI API Key",
194
+ type = "password",
195
+ placeholder="Enter your OpenAI API Key"
196
+ )
197
+
198
+ # Location Details
199
+ with gr.Row():
200
+ with gr.Column():
201
+ city = gr.Textbox(label="City", placeholder="eg. Mumbai")
202
+ state = gr.Textbox(
203
+ label="State",
204
+ placeholder="Leave blank for UT or US Cities",
205
+ value = ""
206
+ )
207
+ country = gr.Textbox(label="Country", value = "India")
208
+ # Personal Details
209
+ with gr.Row():
210
+ with gr.Column():
211
+ medical_conditions = gr.Textbox(
212
+ label="Medical Conditions (optional)",
213
+ placeholder="e.g., asthma, allergies",
214
+ lines=2
215
+ )
216
+ planned_activity = gr.Textbox(
217
+ label="Planned Activity",
218
+ placeholder="e.g., morning jog for 2 hours",
219
+ lines=2
220
+ )
221
+
222
+ # Status Messages
223
+ info_box = gr.Textbox(label="ℹ️ Status", interactive=False)
224
+ warning_box = gr.Textbox(label="⚠️ Warning", interactive=False)
225
+
226
+ # Output Areas
227
+ aqi_data_json = gr.JSON(label="Current Air Quality Data")
228
+ recommendations = gr.Markdown(label="Health Recommendations")
229
+
230
+ # Analyze Button
231
+ analyze_btn = gr.Button("🔍 Analyze & Get Recommendations", variant="primary")
232
+ analyze_btn.click(
233
+ fn=analyze_conditions,
234
+ inputs=[
235
+ city,
236
+ state,
237
+ country,
238
+ medical_conditions,
239
+ planned_activity,
240
+ firecrawl_key,
241
+ openai_key
242
+ ],
243
+ outputs=[aqi_data_json, recommendations, info_box, warning_box]
244
+ )
245
+
246
+ # Examples
247
+ gr.Examples(
248
+ examples=[
249
+ ["Mumbai", "Maharashtra", "India", "asthma", "morning walk for 30 minutes"],
250
+ ["Delhi", "", "India", "", "outdoor yoga session"],
251
+ ["New York", "", "United States", "allergies", "afternoon run"],
252
+ ["Kakinada", "Andhra Pradesh", "India", "none", "Tennis for 2 hours"]
253
+ ],
254
+ inputs=[city, state, country, medical_conditions, planned_activity]
255
+ )
256
+
257
+ return demo
258
+
259
+ if __name__ == "__main__":
260
+ demo = create_demo()
261
+ demo.launch(share=True)