ArslanFOX commited on
Commit
627bf00
·
verified ·
1 Parent(s): aadb0a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -274
app.py CHANGED
@@ -6,18 +6,10 @@ import gradio as gr
6
  from geopy.geocoders import Nominatim
7
  from timezonefinder import TimezoneFinder
8
  import requests
9
- from langdetect import detect
10
 
 
11
  @tool
12
  def get_timezone_by_city(city: str) -> str:
13
- """Fetches the timezone for a given city using geolocation.
14
-
15
- Args:
16
- city: A string representing the city name, optionally with region or country (e.g., 'Бураево', 'Sydney').
17
-
18
- Returns:
19
- A string with the timezone (e.g., 'Europe/Moscow') or an error message.
20
- """
21
  if not isinstance(city, str):
22
  return f"Error: Expected a string for city, got: {type(city)}"
23
  try:
@@ -27,333 +19,123 @@ def get_timezone_by_city(city: str) -> str:
27
  city_name = city.split(",")[0].strip().title()
28
  location = geolocator.geocode(city_name, language="en")
29
  if not location:
30
- return f"Error: City '{city}' not found. Try a different spelling or provide more context."
31
  tf = TimezoneFinder()
32
  timezone = tf.timezone_at(lat=location.latitude, lng=location.longitude)
33
- if not timezone:
34
- return f"Error: Timezone not found for city '{city}'."
35
- return timezone
36
  except Exception as e:
37
- return f"Error fetching timezone for city '{city}': {str(e)}"
38
 
 
39
  @tool
40
  def get_current_time_in_timezone(timezone: str) -> str:
41
- """Fetches the current local time in a specified timezone.
42
-
43
- Args:
44
- timezone: A string representing a valid timezone (e.g., 'Europe/Moscow').
45
-
46
- Returns:
47
- A string with the current time (e.g., '2025-05-03 12:00:00') or an error message.
48
- """
49
- if not isinstance(timezone, str):
50
- return f"Error: Expected a string for timezone, got: {type(timezone)}"
51
  try:
52
  tz = pytz.timezone(timezone)
53
  local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
54
  return local_time
55
  except Exception as e:
56
- return f"Error fetching time for timezone '{timezone}': {str(e)}"
57
 
 
58
  @tool
59
  def get_air_quality(city: str, lang: str = "en") -> str:
60
- """Fetches air quality data for a given city using OpenWeatherMap API.
61
-
62
- Args:
63
- city: A string representing the city name (e.g., 'Бирск', 'Sydney').
64
- lang: A string representing the language code (e.g., 'en', 'ru', 'hi').
65
-
66
- Returns:
67
- A string with air quality index (AQI) and pollutant levels or an error message.
68
- """
69
- if not isinstance(city, str):
70
- return f"Error: Expected a string for city, got: {type(city)}"
71
  try:
72
  geolocator = Nominatim(user_agent="smolagents_bot")
73
  location = geolocator.geocode(city, language="en")
74
  if not location:
75
- city_name = city.split(",")[0].strip().title()
76
- location = geolocator.geocode(city_name, language="en")
77
- if not location:
78
- return f"Error: City '{city}' not found for air quality data."
79
-
80
- api_key = os.getenv("OPENWEATHERMAP_API_KEY", "93f518fda8d24cf89aee7050c26b27e9")
81
  url = f"http://api.openweathermap.org/data/2.5/air_pollution?lat={location.latitude}&lon={location.longitude}&appid={api_key}"
82
  response = requests.get(url)
83
  if response.status_code != 200:
84
- return f"Error fetching air quality for '{city}': API returned status {response.status_code}"
85
-
86
  data = response.json()
87
  aqi = data["list"][0]["main"]["aqi"]
88
  components = data["list"][0]["components"]
 
 
89
 
90
- translations = {
91
- "en": {
92
- "aqi_desc": {1: "Good", 2: "Fair", 3: "Moderate", 4: "Poor", 5: "Very Poor"},
93
- "air_quality": "Air quality",
94
- "pm2_5": "Fine particles (PM2.5)",
95
- "pm10": "Coarse particles (PM10)",
96
- "co": "Carbon monoxide (CO)"
97
- },
98
- "ru": {
99
- "aqi_desc": {1: "Хорошее", 2: "Удовлетворительное", 3: "Среднее", 4: "Плохое", 5: "Очень плохое"},
100
- "air_quality": "Качество воздуха",
101
- "pm2_5": "Мелкие частицы (PM2.5)",
102
- "pm10": "Крупные частицы (PM10)",
103
- "co": "Угарный газ (CO)"
104
- },
105
- "hi": {
106
- "aqi_desc": {1: "अच्छा", 2: "संतोषजनक", 3: "मध्यम", 4: "खराब", 5: "बहुत खराब"},
107
- "air_quality": "वायु गुणवत्ता",
108
- "pm2_5": "बारीक कण (PM2.5)",
109
- "pm10": "मोटे कण (PM10)",
110
- "co": "कार्बन मोनोऑक्साइड (CO)"
111
- }
112
- }
113
- lang = lang if lang in translations else "en"
114
- t = translations[lang]
115
- aqi_emoji = "🌱" if aqi <= 2 else "😷" if aqi <= 4 else "☣️"
116
-
117
  return (
118
- f"😷 {t['air_quality']}: AQI {aqi} ({t['aqi_desc'].get(aqi, 'Unknown')}) {aqi_emoji}\n"
119
- f"{t['pm2_5']}: {components['pm2_5']} µg/m³\n"
120
- f"{t['pm10']}: {components['pm10']} µg/m³\n"
121
- f"{t['co']}: {components['co']} µg/m³"
122
  )
123
  except Exception as e:
124
- return f"Error fetching air quality for '{city}': {str(e)}"
125
 
 
126
  @tool
127
  def get_weather(city: str, lang: str = "en") -> str:
128
- """Fetches weather data for a given city using OpenWeatherMap API.
129
-
130
- Args:
131
- city: A string representing the city name (e.g., 'Бирск', 'Sydney').
132
- lang: A string representing the language code (e.g., 'en', 'ru', 'hi').
133
-
134
- Returns:
135
- A string with weather conditions, temperature, and humidity or an error message.
136
- """
137
- if not isinstance(city, str):
138
- return f"Error: Expected a string for city, got: {type(city)}"
139
  try:
140
  geolocator = Nominatim(user_agent="smolagents_bot")
141
  location = geolocator.geocode(city, language="en")
142
  if not location:
143
- city_name = city.split(",")[0].strip().title()
144
- location = geolocator.geocode(city_name, language="en")
145
- if not location:
146
- return f"Error: City '{city}' not found for weather data."
147
-
148
- api_key = os.getenv("OPENWEATHERMAP_API_KEY", "93f518fda8d24cf89aee7050c26b27e9")
149
  url = f"http://api.openweathermap.org/data/2.5/weather?lat={location.latitude}&lon={location.longitude}&appid={api_key}&units=metric"
150
  response = requests.get(url)
151
  if response.status_code != 200:
152
- return f"Error fetching weather for '{city}': API returned status {response.status_code}"
153
-
154
  data = response.json()
155
- temp = data["main"]["temp"]
156
  weather = data["weather"][0]["main"]
 
157
  humidity = data["main"]["humidity"]
158
-
159
- translations = {
160
- "en": {
161
- "weather": "Weather",
162
- "temp": "Temperature",
163
- "humidity": "Humidity",
164
- "conditions": {
165
- "Clear": "Clear ☀️",
166
- "Clouds": "Cloudy ☁️",
167
- "Rain": "Rain 🌧",
168
- "Snow": "Snow ❄️",
169
- "Thunderstorm": "Thunderstorm ⛈",
170
- "Drizzle": "Drizzle 🌦",
171
- "Mist": "Mist 🌫",
172
- "Haze": "Haze 🌫"
173
- }
174
- },
175
- "ru": {
176
- "weather": "Погода",
177
- "temp": "Температура",
178
- "humidity": "Влажность",
179
- "conditions": {
180
- "Clear": "Ясно ☀️",
181
- "Clouds": "Облачно ☁️",
182
- "Rain": "Дождь 🌧",
183
- "Snow": "Снег ❄️",
184
- "Thunderstorm": "Гроза ⛈",
185
- "Drizzle": "Морось 🌦",
186
- "Mist": "Туман 🌫",
187
- "Haze": "Туман 🌫"
188
- }
189
- },
190
- "hi": {
191
- "weather": "मौसम",
192
- "temp": "तापमान",
193
- "humidity": "नमी",
194
- "conditions": {
195
- "Clear": "साफ ☀️",
196
- "Clouds": "बादल ☁️",
197
- "Rain": "बारिश 🌧",
198
- "Snow": "बर्फ ❄️",
199
- "Thunderstorm": "तूफान ⛈",
200
- "Drizzle": "बूंदाबांदी 🌦",
201
- "Mist": "कोहरा 🌫",
202
- "Haze": "धुंध 🌫"
203
- }
204
- }
205
- }
206
- lang = lang if lang in translations else "en"
207
- t = translations[lang]
208
- condition = t["conditions"].get(weather, weather)
209
-
210
- return (
211
- f"🌡️ {t['weather']}: {condition}\n"
212
- f"{t['temp']}: {temp}°C\n"
213
- f"{t['humidity']}: {humidity}%"
214
- )
215
  except Exception as e:
216
- return f"Error fetching weather for '{city}': {str(e)}"
217
 
 
218
  @tool
219
  def final_answer(answer: str) -> str:
220
- """Returns the final answer.
221
-
222
- Args:
223
- answer: A string containing the final answer.
224
-
225
- Returns:
226
- The input answer string.
227
- """
228
  return answer
229
 
230
- try:
231
- model = HfApiModel(
232
- max_tokens=1000,
233
- temperature=0.5,
234
- model_id='mistralai/Mixtral-8x7B-Instruct-v0.1',
235
- )
236
- except Exception as e:
237
- print(f"Error initializing model: {str(e)}")
238
 
239
- prompt_templates = {
240
- "system_prompt": (
241
- "You are a helpful assistant that responds in the same language as the user's query. "
242
- "If the query contains a city name (e.g., 'Бураево', 'Sydney', 'न्यू यॉर्क') or phrases like 'сколько времени', 'what time', "
243
- "or a city in any context (e.g., 'Что там в Бирске?'), return current time, air quality, and weather for that city. "
244
- "Use ONLY the provided functions: `get_timezone_by_city`, `get_current_time_in_timezone`, `get_air_quality`, `get_weather`, `final_answer`. "
245
- "Do NOT parse or modify the output of `get_air_quality` or `get_weather`. "
246
- "Do NOT use `detect` or any other functions directly in the code. "
247
- "Do NOT add extra logic, labels, or emojis beyond what the functions provide. "
248
- "Return ONLY the result via `final_answer()` in a code block:\n"
249
- "```py\n"
250
- "final_answer('YOUR ANSWER HERE')\n"
251
- "```\n"
252
- "Do NOT include 'thoughts', explanations, extra imports, new functions, or text outside the ```py``` block. "
253
- "If the city is not found or query is unclear, return an error via `final_answer()`. "
254
- "Ensure the output matches the format:\n"
255
- "🕒 Время в [City]: [Time]\n"
256
- "😷 [Air Quality Label]: AQI [Number] ([Description]) [Emoji]\n"
257
- "[Pollutants]\n"
258
- "🌡️ [Weather Label]: [Condition]\n"
259
- "[Temperature Label]: [Temp]°C\n"
260
- "[Humidity Label]: [Humidity]%"
261
- ),
262
- "default": "Response: {{question}}",
263
- "planning": {
264
- "initial_plan": (
265
- "Analyze query: {{question}}. If it contains a city, get time, air quality, and weather using provided functions. "
266
- "Return code:\n"
267
- "```py\n"
268
- "final_answer('YOUR ANSWER HERE')\n"
269
- "```"
270
- ),
271
- "update_plan_pre_messages": (
272
- "Review query: {{question}}. Adjust plan. Return code:\n"
273
- "```py\n"
274
- "final_answer('YOUR ANSWER HERE')\n"
275
- "```"
276
- ),
277
- "update_plan_post_messages": (
278
- "Review query: {{question}} and results. Adjust plan. Return code:\n"
279
- "```py\n"
280
- "final_answer('YOUR ANSWER HERE')\n"
281
- "```"
282
- ),
283
- },
284
- "managed_agent": {
285
- "execute": (
286
- "Execute task: {{question}}. If it contains a city or phrases like 'сколько времени', use provided functions. "
287
- "Return code:\n"
288
- "```py\n"
289
- "from langdetect import detect\n"
290
- "query = '{{question}}'.strip().lower()\n"
291
- "city = query.split(' в ')[-1].strip().title() if ' в ' in query else query.strip().title()\n"
292
- "if city in ['привет', 'что', 'там', 'сколько', 'времени', '']:\n"
293
- " final_answer('Error: Please specify a valid city name')\n"
294
- "else:\n"
295
- " lang = detect(query) if query else 'en'\n"
296
- " city_normalized = city.replace('Нью-Дели', 'New Delhi').replace('Нью-Йорк', 'New York')\n"
297
- " timezone = get_timezone_by_city(city_normalized)\n"
298
- " if timezone.startswith('Error'):\n"
299
- " final_answer(timezone)\n"
300
- " else:\n"
301
- " time_result = get_current_time_in_timezone(timezone)\n"
302
- " air_result = get_air_quality(city_normalized, lang)\n"
303
- " weather_result = get_weather(city_normalized, lang)\n"
304
- " final_answer(f'🕒 Время в {city_normalized}: {time_result}\\n' + air_result + '\\n' + weather_result)\n"
305
- "```"
306
- ),
307
- "report": (
308
- "Summarize task: {{question}}. Return code:\n"
309
- "```py\n"
310
- "final_answer('YOUR ANSWER HERE')\n"
311
- "```"
312
- ),
313
- "task": (
314
- "Define task: {{question}}. Return code:\n"
315
- "```py\n"
316
- "final_answer('YOUR TASK DEFINITION HERE')\n"
317
- "```"
318
- ),
319
- },
320
- "final_answer": {
321
- "pre_messages": (
322
- "Prepare response for: {{question}}. Return code:\n"
323
- "```py\n"
324
- "final_answer('YOUR ANSWER HERE')\n"
325
- "```"
326
- ),
327
- "template": "Final response: {{answer}}",
328
- "post_messages": (
329
- "Review response for: {{question}}. Return code:\n"
330
- "```py\n"
331
- "final_answer('YOUR ANSWER HERE')\n"
332
- "```"
333
- ),
334
- },
335
- }
336
 
 
337
  agent = CodeAgent(
338
  model=model,
339
- tools=[final_answer, get_current_time_in_timezone, get_timezone_by_city, get_air_quality, get_weather],
340
- max_steps=1,
 
 
 
 
341
  verbosity_level=2,
342
- prompt_templates=prompt_templates,
343
  )
344
 
 
345
  def process_input(user_input):
346
  try:
347
  response = agent.run(user_input)
348
- return response if response else "Error: No response received from the agent."
349
  except Exception as e:
350
- return f"Error: {str(e)}"
351
 
352
  if __name__ == "__main__":
353
  gr.Interface(
354
  fn=process_input,
355
  inputs="text",
356
  outputs="text",
357
- title="Helpful Assistant",
358
- description="Hello! What city or town are you from? I can tell you the time, air quality, weather, and more!"
359
  ).launch()
 
6
  from geopy.geocoders import Nominatim
7
  from timezonefinder import TimezoneFinder
8
  import requests
 
9
 
10
+ # Инструмент: Получение таймзоны по названию города
11
  @tool
12
  def get_timezone_by_city(city: str) -> str:
 
 
 
 
 
 
 
 
13
  if not isinstance(city, str):
14
  return f"Error: Expected a string for city, got: {type(city)}"
15
  try:
 
19
  city_name = city.split(",")[0].strip().title()
20
  location = geolocator.geocode(city_name, language="en")
21
  if not location:
22
+ return f"Error: City '{city}' not found."
23
  tf = TimezoneFinder()
24
  timezone = tf.timezone_at(lat=location.latitude, lng=location.longitude)
25
+ return timezone or f"Error: Timezone not found for city '{city}'."
 
 
26
  except Exception as e:
27
+ return f"Error fetching timezone: {str(e)}"
28
 
29
+ # Инструмент: Время по таймзоне
30
  @tool
31
  def get_current_time_in_timezone(timezone: str) -> str:
 
 
 
 
 
 
 
 
 
 
32
  try:
33
  tz = pytz.timezone(timezone)
34
  local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
35
  return local_time
36
  except Exception as e:
37
+ return f"Error fetching time: {str(e)}"
38
 
39
+ # Инструмент: Качество воздуха
40
  @tool
41
  def get_air_quality(city: str, lang: str = "en") -> str:
 
 
 
 
 
 
 
 
 
 
 
42
  try:
43
  geolocator = Nominatim(user_agent="smolagents_bot")
44
  location = geolocator.geocode(city, language="en")
45
  if not location:
46
+ return f"Error: City '{city}' not found."
47
+
48
+ api_key = os.environ["OPENWEATHERMAP_API_KEY"]
 
 
 
49
  url = f"http://api.openweathermap.org/data/2.5/air_pollution?lat={location.latitude}&lon={location.longitude}&appid={api_key}"
50
  response = requests.get(url)
51
  if response.status_code != 200:
52
+ return f"Error: API returned {response.status_code}"
53
+
54
  data = response.json()
55
  aqi = data["list"][0]["main"]["aqi"]
56
  components = data["list"][0]["components"]
57
+ label = {1: "Good", 2: "Fair", 3: "Moderate", 4: "Poor", 5: "Very Poor"}[aqi]
58
+ emoji = "🌱" if aqi <= 2 else "😷" if aqi <= 4 else "☣️"
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  return (
61
+ f"😷 Air Quality: AQI {aqi} ({label}) {emoji}\n"
62
+ f"PM2.5: {components['pm2_5']} µg/m³\n"
63
+ f"PM10: {components['pm10']} µg/m³\n"
64
+ f"CO: {components['co']} µg/m³"
65
  )
66
  except Exception as e:
67
+ return f"Error fetching air quality: {str(e)}"
68
 
69
+ # Инструмент: Погода
70
  @tool
71
  def get_weather(city: str, lang: str = "en") -> str:
 
 
 
 
 
 
 
 
 
 
 
72
  try:
73
  geolocator = Nominatim(user_agent="smolagents_bot")
74
  location = geolocator.geocode(city, language="en")
75
  if not location:
76
+ return f"Error: City '{city}' not found."
77
+
78
+ api_key = os.environ["OPENWEATHERMAP_API_KEY"]
 
 
 
79
  url = f"http://api.openweathermap.org/data/2.5/weather?lat={location.latitude}&lon={location.longitude}&appid={api_key}&units=metric"
80
  response = requests.get(url)
81
  if response.status_code != 200:
82
+ return f"Error: API returned {response.status_code}"
83
+
84
  data = response.json()
 
85
  weather = data["weather"][0]["main"]
86
+ temp = data["main"]["temp"]
87
  humidity = data["main"]["humidity"]
88
+ return f"🌡️ Weather: {weather}\nTemperature: {temp}°C\nHumidity: {humidity}%"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  except Exception as e:
90
+ return f"Error fetching weather: {str(e)}"
91
 
92
+ # Инструмент: Финальный ответ
93
  @tool
94
  def final_answer(answer: str) -> str:
 
 
 
 
 
 
 
 
95
  return answer
96
 
97
+ # Модель
98
+ model = HfApiModel(
99
+ max_tokens=1000,
100
+ temperature=0.5,
101
+ model_id='mistralai/Mixtral-8x7B-Instruct-v0.1',
102
+ )
 
 
103
 
104
+ # System prompt — что может делать агент
105
+ system_prompt = (
106
+ "You are a helpful assistant. Given a user question, use ONLY the available tools: "
107
+ "`get_timezone_by_city`, `get_current_time_in_timezone`, `get_air_quality`, `get_weather`, `final_answer`. "
108
+ "Do NOT import anything, define new functions, or try to extract data from strings. "
109
+ "Each function returns ready-to-display strings. "
110
+ "Wrap your answer as:\n"
111
+ "```py\nfinal_answer('...')\n```"
112
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Агент
115
  agent = CodeAgent(
116
  model=model,
117
+ tools=[get_timezone_by_city, get_current_time_in_timezone, get_air_quality, get_weather, final_answer],
118
+ prompt_templates={
119
+ "system_prompt": system_prompt,
120
+ "default": "Response: {{question}}"
121
+ },
122
+ max_steps=3,
123
  verbosity_level=2,
 
124
  )
125
 
126
+ # Gradio интерфейс
127
  def process_input(user_input):
128
  try:
129
  response = agent.run(user_input)
130
+ return response if response else "Error: No response from agent."
131
  except Exception as e:
132
+ return f"Runtime error: {str(e)}"
133
 
134
  if __name__ == "__main__":
135
  gr.Interface(
136
  fn=process_input,
137
  inputs="text",
138
  outputs="text",
139
+ title="Weather Agent",
140
+ description="Enter a city name to get time, air quality, and weather info."
141
  ).launch()