Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -7,18 +7,26 @@ from langdetect import detect
|
|
| 7 |
from geopy.geocoders import Nominatim
|
| 8 |
from timezonefinder import TimezoneFinder
|
| 9 |
import gradio as gr
|
|
|
|
| 10 |
|
| 11 |
load_dotenv()
|
| 12 |
|
| 13 |
-
def geocode_city(city: str):
|
|
|
|
|
|
|
|
|
|
| 14 |
geolocator = Nominatim(user_agent="weather_assistant")
|
| 15 |
-
location = geolocator.geocode(city, language=
|
| 16 |
if not location:
|
|
|
|
| 17 |
simple = city.split()[0]
|
| 18 |
-
location = geolocator.geocode(simple, language=
|
| 19 |
return location
|
| 20 |
|
| 21 |
def get_timezone_by_city(city: str) -> str:
|
|
|
|
|
|
|
|
|
|
| 22 |
location = geocode_city(city)
|
| 23 |
if not location:
|
| 24 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
@@ -28,6 +36,9 @@ def get_timezone_by_city(city: str) -> str:
|
|
| 28 |
return tz
|
| 29 |
|
| 30 |
def get_current_time_in_timezone(timezone: str) -> str:
|
|
|
|
|
|
|
|
|
|
| 31 |
try:
|
| 32 |
now = datetime.datetime.now(pytz.timezone(timezone))
|
| 33 |
return now.strftime("%Y-%m-%d %H:%M:%S")
|
|
@@ -35,6 +46,9 @@ def get_current_time_in_timezone(timezone: str) -> str:
|
|
| 35 |
return f"❌ Ошибка получения времени: {e}"
|
| 36 |
|
| 37 |
def get_air_quality(city: str, lang: str = "en") -> str:
|
|
|
|
|
|
|
|
|
|
| 38 |
location = geocode_city(city)
|
| 39 |
if not location:
|
| 40 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
@@ -73,6 +87,34 @@ def get_air_quality(city: str, lang: str = "en") -> str:
|
|
| 73 |
"pm10": "मोटे कण (PM10)",
|
| 74 |
"co": "कार्बन मोनोऑक्साइड (CO)",
|
| 75 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
}
|
| 77 |
t = translations.get(lang, translations["en"])
|
| 78 |
emoji = "🌱" if aqi <= 2 else "😷" if aqi <= 4 else "☣️"
|
|
@@ -84,6 +126,9 @@ def get_air_quality(city: str, lang: str = "en") -> str:
|
|
| 84 |
)
|
| 85 |
|
| 86 |
def get_weather(city: str, lang: str = "en") -> str:
|
|
|
|
|
|
|
|
|
|
| 87 |
location = geocode_city(city)
|
| 88 |
if not location:
|
| 89 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
@@ -131,6 +176,46 @@ def get_weather(city: str, lang: str = "en") -> str:
|
|
| 131 |
"Mist": "कोहरा 🌫", "Haze": "धुंध 🌫"
|
| 132 |
}
|
| 133 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
}
|
| 135 |
t = translations.get(lang, translations["en"])
|
| 136 |
desc = t["conditions"].get(cond, cond)
|
|
@@ -141,18 +226,59 @@ def get_weather(city: str, lang: str = "en") -> str:
|
|
| 141 |
)
|
| 142 |
|
| 143 |
def process_input(user_input: str) -> str:
|
|
|
|
| 144 |
lang = detect(user_input)
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
city = user_input.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
tz = get_timezone_by_city(city)
|
| 148 |
if tz.startswith("❌"):
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
| 153 |
aq = get_air_quality(city, lang)
|
| 154 |
w = get_weather(city, lang)
|
| 155 |
-
|
|
|
|
| 156 |
|
| 157 |
if __name__ == "__main__":
|
| 158 |
gr.Interface(
|
|
|
|
| 7 |
from geopy.geocoders import Nominatim
|
| 8 |
from timezonefinder import TimezoneFinder
|
| 9 |
import gradio as gr
|
| 10 |
+
import re
|
| 11 |
|
| 12 |
load_dotenv()
|
| 13 |
|
| 14 |
+
def geocode_city(city: str, lang: str = "en"):
|
| 15 |
+
"""
|
| 16 |
+
Geocode city with fallback to simpler name and language.
|
| 17 |
+
"""
|
| 18 |
geolocator = Nominatim(user_agent="weather_assistant")
|
| 19 |
+
location = geolocator.geocode(city, language=lang)
|
| 20 |
if not location:
|
| 21 |
+
# fallback: first word
|
| 22 |
simple = city.split()[0]
|
| 23 |
+
location = geolocator.geocode(simple, language=lang)
|
| 24 |
return location
|
| 25 |
|
| 26 |
def get_timezone_by_city(city: str) -> str:
|
| 27 |
+
"""
|
| 28 |
+
Get timezone for a city.
|
| 29 |
+
"""
|
| 30 |
location = geocode_city(city)
|
| 31 |
if not location:
|
| 32 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
|
|
| 36 |
return tz
|
| 37 |
|
| 38 |
def get_current_time_in_timezone(timezone: str) -> str:
|
| 39 |
+
"""
|
| 40 |
+
Get local current time in a timezone.
|
| 41 |
+
"""
|
| 42 |
try:
|
| 43 |
now = datetime.datetime.now(pytz.timezone(timezone))
|
| 44 |
return now.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
| 46 |
return f"❌ Ошибка получения времени: {e}"
|
| 47 |
|
| 48 |
def get_air_quality(city: str, lang: str = "en") -> str:
|
| 49 |
+
"""
|
| 50 |
+
Get translated air quality info.
|
| 51 |
+
"""
|
| 52 |
location = geocode_city(city)
|
| 53 |
if not location:
|
| 54 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
|
|
| 87 |
"pm10": "मोटे कण (PM10)",
|
| 88 |
"co": "कार्बन मोनोऑक्साइड (CO)",
|
| 89 |
},
|
| 90 |
+
"zh": {
|
| 91 |
+
"title": "😷 空气质量",
|
| 92 |
+
"aqi_desc": {1: "良好", 2: "一般", 3: "中等", 4: "较差", 5: "很差"},
|
| 93 |
+
"pm2_5": "细颗粒物 (PM2.5)",
|
| 94 |
+
"pm10": "可吸入颗粒物 (PM10)",
|
| 95 |
+
"co": "一氧化碳 (CO)",
|
| 96 |
+
},
|
| 97 |
+
"es": {
|
| 98 |
+
"title": "😷 Calidad del aire",
|
| 99 |
+
"aqi_desc": {1: "Buena", 2: "Aceptable", 3: "Moderada", 4: "Pobre", 5: "Muy mala"},
|
| 100 |
+
"pm2_5": "Partículas finas (PM2.5)",
|
| 101 |
+
"pm10": "Partículas gruesas (PM10)",
|
| 102 |
+
"co": "Monóxido de carbono (CO)",
|
| 103 |
+
},
|
| 104 |
+
"fr": {
|
| 105 |
+
"title": "😷 Qualité de l'air",
|
| 106 |
+
"aqi_desc": {1: "Bonne", 2: "Passable", 3: "Moyenne", 4: "Mauvaise", 5: "Très mauvaise"},
|
| 107 |
+
"pm2_5": "Particules fines (PM2.5)",
|
| 108 |
+
"pm10": "Particules grossières (PM10)",
|
| 109 |
+
"co": "Monoxyde de carbone (CO)",
|
| 110 |
+
},
|
| 111 |
+
"ko": {
|
| 112 |
+
"title": "😷 대기질",
|
| 113 |
+
"aqi_desc": {1: "좋음", 2: "보통", 3: "보통 이상", 4: "나쁨", 5: "매우 나쁨"},
|
| 114 |
+
"pm2_5": "미세먼지 (PM2.5)",
|
| 115 |
+
"pm10": "먼지 (PM10)",
|
| 116 |
+
"co": "일산화탄소 (CO)",
|
| 117 |
+
},
|
| 118 |
}
|
| 119 |
t = translations.get(lang, translations["en"])
|
| 120 |
emoji = "🌱" if aqi <= 2 else "😷" if aqi <= 4 else "☣️"
|
|
|
|
| 126 |
)
|
| 127 |
|
| 128 |
def get_weather(city: str, lang: str = "en") -> str:
|
| 129 |
+
"""
|
| 130 |
+
Get translated weather info.
|
| 131 |
+
"""
|
| 132 |
location = geocode_city(city)
|
| 133 |
if not location:
|
| 134 |
return f"❌ Не удалось найти населенный пункт '{city}'."
|
|
|
|
| 176 |
"Mist": "कोहरा 🌫", "Haze": "धुंध 🌫"
|
| 177 |
}
|
| 178 |
},
|
| 179 |
+
"zh": {
|
| 180 |
+
"title": "🌡️ 天气",
|
| 181 |
+
"temp": "温度",
|
| 182 |
+
"humidity": "湿度",
|
| 183 |
+
"conditions": {
|
| 184 |
+
"Clear": "晴 ☀️", "Clouds": "多云 ☁️", "Rain": "雨 🌧",
|
| 185 |
+
"Snow": "雪 ❄️", "Thunderstorm": "雷暴 ⛈", "Drizzle": "毛毛雨 🌦",
|
| 186 |
+
"Mist": "雾 🌫", "Haze": "霾 🌫"
|
| 187 |
+
}
|
| 188 |
+
},
|
| 189 |
+
"es": {
|
| 190 |
+
"title": "🌡️ Clima",
|
| 191 |
+
"temp": "Temperatura",
|
| 192 |
+
"humidity": "Humedad",
|
| 193 |
+
"conditions": {
|
| 194 |
+
"Clear": "Despejado ☀️", "Clouds": "Nublado ☁️", "Rain": "Lluvia 🌧",
|
| 195 |
+
"Snow": "Nieve ❄️", "Thunderstorm": "Tormenta ⛈", "Drizzle": "Llovizna 🌦",
|
| 196 |
+
"Mist": "Niebla 🌫", "Haze": "Calina 🌫"
|
| 197 |
+
}
|
| 198 |
+
},
|
| 199 |
+
"fr": {
|
| 200 |
+
"title": "🌡️ Météo",
|
| 201 |
+
"temp": "Température",
|
| 202 |
+
"humidity": "Humidité",
|
| 203 |
+
"conditions": {
|
| 204 |
+
"Clear": "Dégagé ☀️", "Clouds": "Nuageux ☁️", "Rain": "Pluie 🌧",
|
| 205 |
+
"Snow": "Neige ❄️", "Thunderstorm": "Orage ⛈", "Drizzle": "Bruine 🌦",
|
| 206 |
+
"Mist": "Brume 🌫", "Haze": "Brume légère 🌫"
|
| 207 |
+
}
|
| 208 |
+
},
|
| 209 |
+
"ko": {
|
| 210 |
+
"title": "🌡️ 날씨",
|
| 211 |
+
"temp": "온도",
|
| 212 |
+
"humidity": "습도",
|
| 213 |
+
"conditions": {
|
| 214 |
+
"Clear": "맑음 ☀️", "Clouds": "흐림 ☁️", "Rain": "비 🌧",
|
| 215 |
+
"Snow": "눈 ❄️", "Thunderstorm": "뇌우 ⛈", "Drizzle": "이슬비 🌦",
|
| 216 |
+
"Mist": "안개 🌫", "Haze": "실안개 🌫"
|
| 217 |
+
}
|
| 218 |
+
},
|
| 219 |
}
|
| 220 |
t = translations.get(lang, translations["en"])
|
| 221 |
desc = t["conditions"].get(cond, cond)
|
|
|
|
| 226 |
)
|
| 227 |
|
| 228 |
def process_input(user_input: str) -> str:
|
| 229 |
+
|
| 230 |
lang = detect(user_input)
|
| 231 |
+
if lang not in ["en","ru","hi","zh","es","fr","ko"]:
|
| 232 |
+
if re.search(r'[\u0400-\u04FF]', user_input):
|
| 233 |
+
lang = "ru"
|
| 234 |
+
else:
|
| 235 |
+
lang = "en"
|
| 236 |
city = user_input.strip()
|
| 237 |
+
|
| 238 |
+
loc_disp = geocode_city(city, lang)
|
| 239 |
+
if not loc_disp:
|
| 240 |
+
return f"❌ Не удалось найти населенный пункт '{city}'."
|
| 241 |
+
parts = loc_disp.raw.get("display_name", "").split(", ")
|
| 242 |
+
city_disp = parts[0]
|
| 243 |
+
region_disp = parts[1] if len(parts) > 2 else ""
|
| 244 |
+
country_disp = parts[-1] if parts else ""
|
| 245 |
+
|
| 246 |
+
location_labels = {
|
| 247 |
+
"en": "📍 Location",
|
| 248 |
+
"ru": "📍 Местоположение",
|
| 249 |
+
"hi": "📍 स्थान",
|
| 250 |
+
"zh": "📍 位置",
|
| 251 |
+
"es": "📍 Ubicación",
|
| 252 |
+
"fr": "📍 Emplacement",
|
| 253 |
+
"ko": "📍 위치",
|
| 254 |
+
}
|
| 255 |
+
time_labels = {
|
| 256 |
+
"en": "🕒 Time",
|
| 257 |
+
"ru": "🕒 Время",
|
| 258 |
+
"hi": "🕒 समय",
|
| 259 |
+
"zh": "🕒 时间",
|
| 260 |
+
"es": "🕒 Hora",
|
| 261 |
+
"fr": "🕒 Heure",
|
| 262 |
+
"ko": "🕒 시간",
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
location_line = f"{location_labels.get(lang,'📍 Location')}: {city_disp}"
|
| 266 |
+
if region_disp:
|
| 267 |
+
location_line += f", {region_disp}"
|
| 268 |
+
if country_disp:
|
| 269 |
+
location_line += f", {country_disp}"
|
| 270 |
+
|
| 271 |
tz = get_timezone_by_city(city)
|
| 272 |
if tz.startswith("❌"):
|
| 273 |
+
time_line = tz
|
| 274 |
+
else:
|
| 275 |
+
ct = get_current_time_in_timezone(tz)
|
| 276 |
+
time_line = f"{time_labels.get(lang,'🕒 Time')}: {ct}"
|
| 277 |
+
|
| 278 |
aq = get_air_quality(city, lang)
|
| 279 |
w = get_weather(city, lang)
|
| 280 |
+
|
| 281 |
+
return f"{location_line}\n\n{time_line}\n\n{aq}\n\n{w}"
|
| 282 |
|
| 283 |
if __name__ == "__main__":
|
| 284 |
gr.Interface(
|