tg-bot/bot-tg.py

122 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
from logging.handlers import RotatingFileHandler
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command
from aiogram.utils.keyboard import ReplyKeyboardBuilder
import requests
import asyncio
# настройка логов
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# логирование в файл, максимум 5мб по 3 бэкапа
file_handler = RotatingFileHandler(
'weather_bot.log',
maxBytes=5*1024*1024,
backupCount=3,
encoding='utf-8'
)
file_handler.setFormatter(formatter)
# вывод в консоль
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(console_handler)
# конфиг
try:
from config import BOT_TOKEN, WEATHER_API_KEY
except ImportError:
logging.critical("Ошибка: Создайте файл config.py с BOT_TOKEN и WEATHER_API_KEY!")
exit(1)
# инициализация бота
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
# клавиатура
builder = ReplyKeyboardBuilder()
builder.button(text="Узнать погоду")
builder.button(text="Помощь")
keyboard = builder.as_markup(resize_keyboard=True)
# обработка команд
@dp.message(Command("start", "help"))
async def cmd_start(message: types.Message):
logging.info(f"Новый пользователь: {message.from_user.id}")
await message.answer(
"Бот Погоды\n\n"
"Отправьте мне название города, и я пришлю текущую погоду.\n"
"Или нажмите кнопку ниже:",
reply_markup=keyboard
)
@dp.message(lambda message: message.text in ["Узнать погоду", "Помощь"])
async def button_handler(message: types.Message):
if message.text == "Узнать погоду":
await message.answer("Введите название города:")
else:
await cmd_start(message)
@dp.message()
async def get_weather(message: types.Message):
city = message.text.strip()
if not city:
return
logging.info(f"Запрос погоды для: {city} (от {message.from_user.id})")
try:
# запрос к API
url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
response = requests.get(url, timeout=10)
logging.debug(f"API Response: {response.status_code} {response.text[:200]}...")
if response.status_code != 200:
error_msg = response.json().get('message', 'Unknown error')
logging.error(f"API Error for {city}: {response.status_code} - {error_msg}")
await message.answer(f"Ошибка: {error_msg.capitalize()}")
return
data = response.json()
# формирование ответа
weather_report = (
f"Город: {data['name']}\n"
f"Температура: {data['main']['temp']:.1f}°C\n"
f"Ощущается как: {data['main']['feels_like']:.1f}°C\n"
f"Ветер: {data['wind']['speed']} м/с\n"
f"Погода: {data['weather'][0]['description'].capitalize()}\n"
f"Влажность: {data['main']['humidity']}%"
)
logging.info(f"Успешный ответ для {city}")
await message.answer(weather_report)
except requests.exceptions.Timeout:
logging.error(f"Таймаут запроса для {city}")
await message.answer("Сервер погоды не отвечает. Попробуйте позже.")
except Exception as e:
logging.exception(f"Ошибка для {city}:")
await message.answer("⚠️ Произошла внутренняя ошибка. Попробуйте другой город.")
# запуск бота
async def main():
logging.info("Starting bot...")
await dp.start_polling(bot)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logging.info("Bot stopped by user")
except Exception as e:
logging.critical(f"Fatal error: {e}")