Обновить bot-tg.py
This commit is contained in:
parent
e17de635b5
commit
8cb2843fd0
1 changed files with 81 additions and 77 deletions
158
bot-tg.py
158
bot-tg.py
|
@ -6,18 +6,30 @@ import requests
|
||||||
import asyncio
|
import asyncio
|
||||||
from config import BOT_TOKEN, WEATHER_API_KEY
|
from config import BOT_TOKEN, WEATHER_API_KEY
|
||||||
|
|
||||||
# Настройка логирования
|
# настройка логирования
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Инициализация бота
|
# пасхалочка
|
||||||
|
CUSTOM_CITY_PHOTOS = {
|
||||||
|
"киев": {
|
||||||
|
"photo_url": "https://imgur.com/a/jzVHNoF",
|
||||||
|
"author": "Wikipedia"
|
||||||
|
},
|
||||||
|
"kyiv": {
|
||||||
|
"photo_url": "https://imgur.com/a/jzVHNoF",
|
||||||
|
"author": "Wikipedia"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# инициализация бота
|
||||||
bot = Bot(token=BOT_TOKEN)
|
bot = Bot(token=BOT_TOKEN)
|
||||||
dp = Dispatcher()
|
dp = Dispatcher()
|
||||||
|
|
||||||
# Клавиатура
|
# клавиатура
|
||||||
def get_keyboard():
|
def get_keyboard():
|
||||||
builder = ReplyKeyboardBuilder()
|
builder = ReplyKeyboardBuilder()
|
||||||
builder.button(text="🌤️ Узнать погоду")
|
builder.button(text="🌤️ Узнать погоду")
|
||||||
|
@ -25,10 +37,10 @@ def get_keyboard():
|
||||||
return builder.as_markup(resize_keyboard=True)
|
return builder.as_markup(resize_keyboard=True)
|
||||||
|
|
||||||
async def get_coordinates(city: str):
|
async def get_coordinates(city: str):
|
||||||
"""Получение координат города через Nominatim"""
|
"""Получение координат города"""
|
||||||
url = f"https://nominatim.openstreetmap.org/search?city={city}&format=json"
|
url = f"https://nominatim.openstreetmap.org/search?city={city}&format=json"
|
||||||
headers = {"User-Agent": "CityPhotoBot/1.0"}
|
headers = {"User-Agent": "CityPhotoBot/1.0"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, headers=headers, timeout=10)
|
response = requests.get(url, headers=headers, timeout=10)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
|
@ -45,27 +57,34 @@ async def get_coordinates(city: str):
|
||||||
async def get_weather(lat: float, lon: float, city_name: str) -> str:
|
async def get_weather(lat: float, lon: float, city_name: str) -> str:
|
||||||
"""Получение данных о погоде"""
|
"""Получение данных о погоде"""
|
||||||
url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
|
url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=10)
|
response = requests.get(url, timeout=10)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
weather_info = (
|
weather_info = (
|
||||||
f"🌆 Город: {city_name}\n"
|
f"🌆 Город: {city_name}\n"
|
||||||
f"🌡 Температура: {data['main']['temp']:.1f}°C\n"
|
f"🌡 Температура: {data['main']['temp']:.1f}°C\n"
|
||||||
f"🧭 Ощущается как: {data['main']['feels_like']:.1f}°C\n"
|
f"🧭 Ощущается как: {data['main']['feels_like']:.1f}°C\n"
|
||||||
f"💨 Ветер: {data['wind']['speed']} м/с\n"
|
f"💨 Ветер: {data['wind']['speed']} м/с\n"
|
||||||
f"☁️ Погода: {data['weather'][0]['description'].capitalize()}\n"
|
f"☁️ Погода: {data['weather'][0]['description'].capitalize()}\n"
|
||||||
f"💧 Влажность: {data['main']['humidity']}%"
|
f"💧 Влажность: {data['main']['humidity']}%"
|
||||||
)
|
)
|
||||||
return weather_info
|
return weather_info
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Weather API error: {e}")
|
logger.error(f"Weather API error: {e}")
|
||||||
return "Не удалось получить данные о погоде"
|
return "Не удалось получить данные о погоде"
|
||||||
|
|
||||||
async def get_city_photo(city: str, lat: float = None, lon: float = None):
|
async def get_city_photo(city: str):
|
||||||
"""Поиск фотографии города через Wikipedia и другие источники"""
|
"""Получение фото города с приоритетом ваших собственных фото"""
|
||||||
# 1. Попробуем Wikipedia
|
city_lower = city.lower()
|
||||||
|
|
||||||
|
# проверочка посхалки
|
||||||
|
if city_lower in CUSTOM_CITY_PHOTOS:
|
||||||
|
custom = CUSTOM_CITY_PHOTOS[city_lower]
|
||||||
|
return custom["photo_url"], custom["author"]
|
||||||
|
|
||||||
|
# генерация фото по городам
|
||||||
wikipedia_url = f"https://ru.wikipedia.org/w/api.php?action=query&prop=pageimages&titles={city}&pithumbsize=800&format=json"
|
wikipedia_url = f"https://ru.wikipedia.org/w/api.php?action=query&prop=pageimages&titles={city}&pithumbsize=800&format=json"
|
||||||
try:
|
try:
|
||||||
response = requests.get(wikipedia_url, timeout=10)
|
response = requests.get(wikipedia_url, timeout=10)
|
||||||
|
@ -78,45 +97,21 @@ async def get_city_photo(city: str, lat: float = None, lon: float = None):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Wikipedia API error: {e}")
|
logger.error(f"Wikipedia API error: {e}")
|
||||||
|
|
||||||
# 2. Попробуем Wikimedia Commons
|
|
||||||
wikimedia_url = f"https://commons.wikimedia.org/w/api.php?action=query&generator=images&titles={city}&prop=imageinfo&iiprop=url&iiurlwidth=800&format=json"
|
|
||||||
try:
|
|
||||||
response = requests.get(wikimedia_url, timeout=10)
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
pages = data.get('query', {}).get('pages', {})
|
|
||||||
for page in pages.values():
|
|
||||||
if 'imageinfo' in page:
|
|
||||||
return page['imageinfo'][0]['thumburl'], "Wikimedia Commons"
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Wikimedia API error: {e}")
|
|
||||||
|
|
||||||
# 3. Для российских городов попробуем PhotoBank RG
|
|
||||||
if "россия" in city.lower() or any(city.lower().endswith(x) for x in ["ск", "ов", "ев", "ин"]):
|
|
||||||
try:
|
|
||||||
photobank_url = f"https://rusneb.ru/api/v1/photos?query={city}&limit=1"
|
|
||||||
response = requests.get(photobank_url, timeout=10)
|
|
||||||
if response.status_code == 200:
|
|
||||||
data = response.json()
|
|
||||||
if data.get('results'):
|
|
||||||
return data['results'][0]['image_url'], "PhotoBank RG"
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"PhotoBank error: {e}")
|
|
||||||
|
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
# ответ на /start
|
||||||
|
|
||||||
@dp.message(Command("start", "help"))
|
@dp.message(Command("start", "help"))
|
||||||
async def cmd_start(message: types.Message):
|
async def cmd_start(message: types.Message):
|
||||||
await message.answer(
|
await message.answer(
|
||||||
"🏙️ Бот Погоды с фотографиями городов\n\n"
|
"🏙️ Бот Погоды с фотографиями городов\n\n"
|
||||||
"Отправьте мне название города или поделитесь геопозицией, "
|
"Отправьте мне название города или поделитесь геопозицией:",
|
||||||
"и я покажу погоду и фото города:",
|
reply_markup=get_keyboard()
|
||||||
reply_markup=get_keyboard()
|
)
|
||||||
)
|
|
||||||
|
|
||||||
@dp.message(F.text == "🌤️ Узнать погоду")
|
@dp.message(F.text == "🌤️ Узнать погоду")
|
||||||
async def weather_button(message: types.Message):
|
async def weather_button(message: types.Message):
|
||||||
await message.answer("Введите точное название города:")
|
await message.answer("Введите название города:")
|
||||||
|
|
||||||
@dp.message(F.location)
|
@dp.message(F.location)
|
||||||
async def handle_location(message: types.Message):
|
async def handle_location(message: types.Message):
|
||||||
|
@ -124,26 +119,26 @@ async def handle_location(message: types.Message):
|
||||||
try:
|
try:
|
||||||
lat = message.location.latitude
|
lat = message.location.latitude
|
||||||
lon = message.location.longitude
|
lon = message.location.longitude
|
||||||
|
|
||||||
# Получаем название города
|
# принятие названия города
|
||||||
url = f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json"
|
url = f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json"
|
||||||
headers = {"User-Agent": "CityPhotoBot/1.0"}
|
headers = {"User-Agent": "CityPhotoBot/1.0"}
|
||||||
|
|
||||||
response = requests.get(url, headers=headers, timeout=10)
|
response = requests.get(url, headers=headers, timeout=10)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
city_name = data.get('address', {}).get('city',
|
city_name = data.get('address', {}).get('city',
|
||||||
data.get('address', {}).get('town',
|
data.get('address', {}).get('town',
|
||||||
data.get('address', {}).get('village', "это место")))
|
data.get('address', {}).get('village', "это место")))
|
||||||
|
|
||||||
weather_data = await get_weather(lat, lon, city_name)
|
weather_data = await get_weather(lat, lon, city_name)
|
||||||
photo_url, source = await get_city_photo(city_name, lat, lon)
|
photo_url, author = await get_city_photo(city_name)
|
||||||
|
|
||||||
if photo_url:
|
if photo_url:
|
||||||
caption = f"{weather_data}\n\n📷 Источник: {source}" if source else weather_data
|
caption = f"{weather_data}\n\n📷 Фото: {author}" if author else weather_data
|
||||||
await message.answer_photo(photo_url, caption=caption)
|
await message.answer_photo(photo_url, caption=caption)
|
||||||
else:
|
else:
|
||||||
await message.answer(f"{weather_data}\n\n(Не удалось найти фото города)")
|
await message.answer(weather_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Location error: {e}")
|
logger.error(f"Location error: {e}")
|
||||||
await message.answer("Ошибка обработки местоположения")
|
await message.answer("Ошибка обработки местоположения")
|
||||||
|
@ -152,32 +147,40 @@ async def handle_location(message: types.Message):
|
||||||
async def city_handler(message: types.Message):
|
async def city_handler(message: types.Message):
|
||||||
"""Обработка текстовых запросов"""
|
"""Обработка текстовых запросов"""
|
||||||
city = message.text.strip()
|
city = message.text.strip()
|
||||||
|
|
||||||
if city.startswith('/'):
|
if city.startswith('/'):
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"Processing city: {city}")
|
logger.info(f"Processing city: {city}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# проверка не киев ли это
|
||||||
|
city_lower = city.lower()
|
||||||
|
if city_lower in CUSTOM_CITY_PHOTOS:
|
||||||
|
custom = CUSTOM_CITY_PHOTOS[city_lower]
|
||||||
|
weather_data = await get_weather(50.45, 30.52, "Киев") # корды киева
|
||||||
|
await message.answer_photo(
|
||||||
|
custom["photo_url"],
|
||||||
|
caption=f"{weather_data}\n\n📷 Фото: {custom['author']}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# обработка других городов
|
||||||
coords = await get_coordinates(city)
|
coords = await get_coordinates(city)
|
||||||
if not coords:
|
if not coords:
|
||||||
await message.answer("Город не найден. Попробуйте уточнить название")
|
await message.answer("Город не найден. Попробуйте уточнить название")
|
||||||
return
|
return
|
||||||
|
|
||||||
lon, lat = coords
|
lon, lat = coords
|
||||||
weather_data = await get_weather(lat, lon, city)
|
weather_data = await get_weather(lat, lon, city)
|
||||||
|
photo_url, author = await get_city_photo(city)
|
||||||
# Пробуем получить фото с 3 попытками
|
|
||||||
for attempt in range(3):
|
if photo_url:
|
||||||
photo_url, source = await get_city_photo(city, lat, lon)
|
caption = f"{weather_data}\n\n📷 Фото: {author}" if author else weather_data
|
||||||
if photo_url:
|
await message.answer_photo(photo_url, caption=caption)
|
||||||
caption = f"{weather_data}\n\n📷 Источник: {source}" if source else weather_data
|
else:
|
||||||
await message.answer_photo(photo_url, caption=caption)
|
await message.answer(weather_data)
|
||||||
return
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
|
|
||||||
await message.answer(f"{weather_data}\n\n(Не удалось найти фото города)")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"City handler error: {e}")
|
logger.error(f"City handler error: {e}")
|
||||||
await message.answer("Произошла ошибка при обработке запроса")
|
await message.answer("Произошла ошибка при обработке запроса")
|
||||||
|
@ -186,4 +189,5 @@ async def main():
|
||||||
await dp.start_polling(bot)
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue