diff --git a/bot-tg.py b/bot-tg.py new file mode 100644 index 0000000..ad7f5e8 --- /dev/null +++ b/bot-tg.py @@ -0,0 +1,122 @@ +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}")