куда мне что добавить или после чего и до чего, чтобы пользователь если написал одну заметку, то заметки сохраняются и перекидывает на главное меню и бот тупит, логики в действиях у него нет, перепиши код
Хорошо, давайте разберемся с проблемой. Пользователь сообщает, что после добавления одной заметки бот перекидывает на главное меню и "тупит", то есть теряет логику действий. Это указывает на ошибку в управлении состояниями ConversationHandler.

Первым делом нужно проверить, как обрабатываются состояния после добавления заметки. В текущей реализации после ввода заметки вызывается `handle_note_input`, который возвращает состояние `TYPING_NOTE`, позволяя пользователю вводить несколько заметок подряд. Однако если пользователь ввел одну заметку и нажал /stop, функция `stop_notes` должна корректно завершить процесс и вернуть пользователя в главное меню. Возможно, проблема возникает из-за того, что после добавления заметки бот не ожидает дальнейших действий или некорректно обрабатывает переход между состояниями.

Также стоит проверить, как организованы обработчики в ConversationHandler. Возможно, не все состояния правильно зарегистрированы, или есть конфликты между обработчиками. Например, если после добавления заметки бот не имеет четкого перехода к следующему состоянию, это может привести к "зависанию".

Еще один аспект — использование `reply_markup`. Если после добавления заметки клавиатура не обновляется или не удаляется, это может запутать пользователя. Нужно убедиться, что после завершения ввода заметок бот явно возвращает пользователя в главное меню с соответствующей клавиатурой.

Кроме того, важно проверить логику функции `stop_notes`. Возможно, она не очищает контекст пользователя или не передает управление обратно в главное меню должным образом. Также стоит убедиться, что все callback-обработчики правильно управляют состояниями и не оставляют "висячих" ожиданий.

Наконец, следует протестировать сценарий добавления заметки шаг за шагом, отслеживая изменения состояний и реакцию бота, чтобы точно определить, где происходит сбой в логике.

Вот исправленная версия кода с корректной работой заметок и навигацией. Основные изменения в логике состояний и обработчиков:

python
Copy
# ... (все импорты и константы остаются без изменений)

# Состояния для ConversationHandler
SELECTING_ACTION, TYPING_CITY, TYPING_NOTE, PROFILE_MENU, WEATHER_MENU = range(5)

# ... (остальные функции до handle_note_input остаются без изменений)

async def handle_note_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Обрабатывает введенную пользователем заметку"""
    try:
        note = update.message.text
        user_id = update.effective_user.id
        
        if user_id not in user_notes:
            user_notes[user_id] = []
            
        user_notes[user_id].append(note)
        
        await update.message.reply_text(
            "✅ Заметка добавлена! Можете продолжить ввод или нажмите /done для завершения.",
            reply_markup=ReplyKeyboardRemove()
        )
        return TYPING_NOTE  # Остаемся в состоянии ввода заметок

    except Exception as e:
        logger.error(f"Ошибка в handle_note_input: {e}")
        await update.message.reply_text(
            "😔 Произошла ошибка. Возвращаем в главное меню.",
            reply_markup=create_main_keyboard()
        )
        return SELECTING_ACTION

async def done_notes(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Завершает ввод заметок и возвращает в главное меню"""
    await update.message.reply_text(
        "📝 Заметки сохранены! Выберите действие:",
        reply_markup=create_main_keyboard()
    )
    return SELECTING_ACTION  # Возврат в главное меню

# ... (остальные функции до main() остаются без изменений)

def main() -> None:
    """Запуск бота"""
    try:
        application = Application.builder().token(BOT_TOKEN).build()

        conv_handler = ConversationHandler(
            entry_points=[CommandHandler("start", start)],
            states={
                SELECTING_ACTION: [
                    MessageHandler(filters.Regex("^Профиль 👤$"), profile_menu),
                    MessageHandler(filters.Regex("^Погода 🌤️$"), weather_menu),
                    MessageHandler(filters.Regex("^Заметки 📝$"), notes_menu),
                ],
                PROFILE_MENU: [
                    CallbackQueryHandler(button_handler),
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_city_input),
                ],
                WEATHER_MENU: [
                    CallbackQueryHandler(button_handler),
                ],
                TYPING_CITY: [
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_city_input),
                ],
                TYPING_NOTE: [
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_note_input),
                    CommandHandler("done", done_notes),  # Изменено с stop на done
                ],
            },
            fallbacks=[CommandHandler("cancel", cancel)],
            map_to_parent={
                SELECTING_ACTION: SELECTING_ACTION,
            }
        )

        application.add_handler(conv_handler)
        application.add_error_handler(error_handler)

        logger.info("🤖 Бот запущен")
        application.run_polling()

    except Exception as e:
        logger.critical(f"❌ Ошибка запуска: {e}")
    finally:
        logger.info("🛑 Бот остановлен")

# ... (остальное без изменений)

Перепиши мой код, добавив код выше в мой код:

import os
import logging
from dotenv import load_dotenv
import requests
from telegram import (
    ReplyKeyboardMarkup,
    Update,
    ReplyKeyboardRemove,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
)
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    filters,
    ContextTypes,
    ConversationHandler,
    CallbackQueryHandler,
)
from datetime import datetime, timedelta, time
import pytz

# Настройка логгирования
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

# Загружаем переменные из .env
load_dotenv()
BOT_TOKEN = os.getenv('BOT_TOKEN')
WEATHER_API_KEY = os.getenv('WEATHER_API_KEY')

# Константы
DEMBEL_DATE = datetime(2025, 12, 6)  # Дата дембеля
MOSCOW_TZ = pytz.timezone('Europe/Moscow')  # Часовой пояс Москвы

# Мотивирующие фразы
MOTIVATIONAL_PHRASES = [
    "💪 Ты сильнее, чем думаешь! Каждый день - шаг к цели!",
    "🔥 Осталось совсем немного! Ты справишься!",
    "🚀 Сегодняшний день приближает тебя к заветной дате!",
    "🦾 Терпение и труд всё перетрут! Держись!",
    "🌟 Ты уже прошел большую часть пути! Осталось чуть-чуть!",
    "🏆 Каждый день - это маленькая победа!",
    "💯 Ты молодец! Скоро долгожданный день!",
]

# Состояния для ConversationHandler
SELECTING_ACTION, TYPING_CITY, TYPING_NOTE, SELECTING_NOTE_ACTION, WEATHER_MENU, PROFILE_MENU = range(6)

# Словари для хранения данных пользователей
user_notes = {}
user_favorite_cities = {}
user_balance = {}

# Функции бота
def get_days_until_dembel() -> int:
    """Возвращает количество дней до дембеля"""
    now = datetime.now(MOSCOW_TZ)  # Текущая дата с учетом временной зоны
    dembel_date_with_tz = MOSCOW_TZ.localize(DEMBEL_DATE)  # Дата дембеля с временной зоной
    delta = dembel_date_with_tz - now  # Вычитаем текущую дату из даты дембеля
    return delta.days

def get_motivational_phrase() -> str:
    """Возвращает случайную мотивирующую фразу"""
    return MOTIVATIONAL_PHRASES[datetime.now().weekday() % len(MOTIVATIONAL_PHRASES)]

async def send_daily_notification(context: ContextTypes.DEFAULT_TYPE) -> None:
    """Отправляет ежедневное уведомление"""
    try:
        chat_id = context.job.chat_id
        days_left = get_days_until_dembel()
        phrase = get_motivational_phrase()

        message = (
            f"⏳ До дембеля осталось {days_left} дней!\n"
            f"🗓 Дата: {DEMBEL_DATE.strftime('%d.%m.%Y')}\n\n"
            f"{phrase}"
        )

        await context.bot.send_message(chat_id=chat_id, text=message)
        logger.info(f"Отправлено ежедневное уведомление пользователю {chat_id}")

    except Exception as e:
        logger.error(f"Ошибка при отправке уведомления: {e}")

def get_weather_emoji(description: str) -> str:
    """Возвращает соответствующий эмодзи для погодных условий"""
    description = description.lower()
    if 'ясно' in description:
        return '☀️'
    elif 'облачно' in description or 'пасмурно' in description:
        return '☁️'
    elif 'дождь' in description:
        return '🌧️'
    elif 'снег' in description:
        return '❄️'
    elif 'гроза' in description:
        return '⛈️'
    elif 'морось' in description:
        return '🌦️'
    elif 'туман' in description or 'дымка' in description:
        return '🌫️'
    else:
        return '🌈'

def get_clothing_recommendation(temp: float, weather_desc: str) -> str:
    """Возвращает рекомендации по одежде"""
    weather_desc = weather_desc.lower()
    if temp > 25:
        clothes = (
            "👕 Легкая одежда (шорты/юбка, футболка)\n"
            "🧢 Головной убор от солнца\n"
            "🕶️ Солнцезащитные очки"
        )
    elif 18 <= temp <= 25:
        clothes = (
            "👕 Летняя одежда (рубашка/блузка)\n"
            "👖 Джинсы или легкие брюки"
        )
    elif 10 <= temp < 18:
        clothes = (
            "🧥 Легкая куртка или ветровка\n"
            "👖 Джинсы или брюки\n"
            "👟 Закрытая обувь"
        )
    elif 0 <= temp < 10:
        clothes = (
            "🧥 Теплая куртка\n"
            "🧣 Шарф при ветре\n"
            "🧤 Перчатки, если холодно"
        )
    else:
        clothes = (
            "🧥 Зимняя куртка\n"
            "🧣 Шарф\n"
            "🧤 Перчатки\n"
            "🎩 Теплая шапка"
        )

    if 'дождь' in weather_desc:
        clothes += "\n☔ Зонт или дождевик"
    elif 'снег' in weather_desc:
        clothes += "\n🧦 Теплые носки и зимняя обувь"
    elif 'ясно' in weather_desc:
        clothes += "\n🧴 Не забудьте солнцезащитный крем"

    return clothes

async def get_tomorrow_forecast(city: str) -> str:
    """Получает прогноз погоды на завтра"""
    try:
        url = f"http://api.openweathermap.org/data/2.5/forecast?q={city}&appid={WEATHER_API_KEY}&units=metric&lang=ru&cnt=16"
        response = requests.get(url, timeout=5)
        data = response.json()

        if data.get("cod") != "200":
            return ""

        tomorrow = (datetime.now() + timedelta(days=1)).date()
        temps = []
        descriptions = []

        for item in data['list']:
            forecast_date = datetime.fromtimestamp(item['dt']).date()
            if forecast_date == tomorrow:
                temps.append(item['main']['temp'])
                descriptions.append(item['weather'][0]['description'])

        if not temps:
            return ""

        avg_temp = round(sum(temps) / len(temps), 1)
        main_desc = max(set(descriptions), key=descriptions.count)
        emoji = get_weather_emoji(main_desc)

        return f"Завтра: {avg_temp}°C, {main_desc} {emoji}"

    except Exception as e:
        logger.error(f"Ошибка получения прогноза на завтра: {e}")
        return ""

def create_main_keyboard():
    """Создает главную клавиатуру"""
    keyboard = [
        ["Профиль 👤", "Погода 🌤️"],
        ["Заметки 📝"]
    ]
    return ReplyKeyboardMarkup(keyboard, resize_keyboard=True)

def create_profile_keyboard():
    """Создает клавиатуру профиля"""
    keyboard = [
        [InlineKeyboardButton("Сколько до дембеля", callback_data='dembel')],
        [InlineKeyboardButton("Баланс", callback_data='balance')],
        [InlineKeyboardButton("Пополнить баланс", callback_data='deposit')],
        [InlineKeyboardButton("Назад", callback_data='back')]
    ]
    return InlineKeyboardMarkup(keyboard)

def create_weather_keyboard(user_id):
    """Создает клавиатуру погоды с учетом избранных городов"""
    keyboard = []
    
    # Добавляем избранные города пользователя, если они есть
    if user_id in user_favorite_cities and user_favorite_cities[user_id]:
        for city in user_favorite_cities[user_id]:
            keyboard.append([InlineKeyboardButton(f"{city} ❌", callback_data=f"remove_{city}")])
    
    # Стандартные кнопки
    keyboard.extend([
        [InlineKeyboardButton("Родной город", callback_data='hometown')],
        [InlineKeyboardButton("Москва", callback_data='moscow')],
        [InlineKeyboardButton("Поиск города", callback_data='search')],
        [InlineKeyboardButton("Назад", callback_data='back')]
    ])
    
    return InlineKeyboardMarkup(keyboard)

def create_notes_keyboard():
    """Создает клавиатуру заметок"""
    keyboard = [
        [InlineKeyboardButton("Написать заметку", callback_data='write_note')],
        [InlineKeyboardButton("Прочитать заметки", callback_data='read_notes')],
        [InlineKeyboardButton("Назад", callback_data='back')]
    ]
    return InlineKeyboardMarkup(keyboard)

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Начало работы с ботом"""
    try:
        user = update.effective_user
        chat_id = update.effective_chat.id

        # Удаляем старое задание, если существует
        if 'job' in context.chat_data:
            old_job = context.chat_data['job']
            old_job.schedule_removal()

        # Создаем новое задание
        time_utc = time(hour=10, minute=40)  # Было 6:45 по МСК (UTC+3)
        new_job = context.job_queue.run_daily(
            send_daily_notification,
            time=time_utc,
            days=(0, 1, 2, 3, 4, 5, 6),
            chat_id=chat_id,
            name=str(chat_id)
        )
        # Сохраняем задание в контексте
        context.chat_data['job'] = new_job

        # Инициализируем баланс пользователя, если его нет
        if user.id not in user_balance:
            user_balance[user.id] = 0

        await update.message.reply_text(
            f"Привет, {user.first_name}! 👋\n"
            "Я бот для военнослужащих. Выберите действие:",
            reply_markup=create_main_keyboard()
        )
        return SELECTING_ACTION

    except Exception as e:
        logger.error(f"Ошибка в start: {str(e)}")
        await update.message.reply_text("😔 Произошла ошибка. Попробуйте /start")
        return ConversationHandler.END

async def profile_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Меню профиля"""
    await update.message.reply_text(
        "👤 Профиль:",
        reply_markup=create_profile_keyboard()
    )
    return PROFILE_MENU

async def weather_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Меню погоды"""
    await update.message.reply_text(
        "🌤️ Погода:",
        reply_markup=create_weather_keyboard(update.effective_user.id)
    )
    return WEATHER_MENU

async def notes_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Меню заметок"""
    await update.message.reply_text(
        "📝 Заметки:",
        reply_markup=create_notes_keyboard()
    )
    return SELECTING_NOTE_ACTION

async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Обработчик нажатий на кнопки"""
    query = update.callback_query
    await query.answer()
    user_id = query.from_user.id

    if query.data == 'back':
        await query.edit_message_text("Выберите действие:", reply_markup=None)
        await query.message.reply_text("Главное меню:", reply_markup=create_main_keyboard())
        return SELECTING_ACTION

    elif query.data == 'dembel':
        days_left = get_days_until_dembel()
        phrase = get_motivational_phrase()
        await query.edit_message_text(
            f"⏳ До дембеля осталось {days_left} дней!\n"
            f"🗓 Дата: {DEMBEL_DATE.strftime('%d.%m.%Y')}\n\n"
            f"{phrase}",
            reply_markup=create_profile_keyboard()
        )
        return PROFILE_MENU

    elif query.data == 'balance':
        balance = user_balance.get(user_id, 0)
        await query.edit_message_text(
            f"💰 Ваш баланс: {balance} руб.\n",
            reply_markup=create_profile_keyboard()
        )
        return PROFILE_MENU

    elif query.data == 'deposit':
        await query.edit_message_text(
            "Введите сумму для пополнения (только цифры):",
            reply_markup=None
        )
        context.user_data['awaiting_deposit'] = True
        return PROFILE_MENU

    elif query.data.startswith('remove_'):
        city = query.data[7:]
        if user_id in user_favorite_cities and city in user_favorite_cities[user_id]:
            user_favorite_cities[user_id].remove(city)
            await query.answer(f"Город {city} удален из избранного")
        await query.edit_message_text(
            "🌤️ Погода:",
            reply_markup=create_weather_keyboard(user_id)
        )
        return WEATHER_MENU

    elif query.data in ['hometown', 'moscow']:
        city = "Ростов-на-Дону" if query.data == 'hometown' else "Москва"
        await get_weather_for_city(query, city, context)
        return WEATHER_MENU

    elif query.data == 'search':
        await query.edit_message_text(
            "🔍 Введите название города (например: Москва, Сочи):",
            reply_markup=None
        )
        return TYPING_CITY

    elif query.data == 'write_note':
        if user_id not in user_notes:
            user_notes[user_id] = []
        await query.edit_message_text(
            "✍️ Введите вашу заметку. Для завершения введите /stop.",
            reply_markup=None
        )
        return TYPING_NOTE

    elif query.data == 'read_notes':
        notes = user_notes.get(user_id, [])
        if notes:
            notes_text = "\n".join(f"📌 {note}" for note in notes)
            message = f"📒 Ваши заметки:\n\n{notes_text}"
        else:
            message = "У вас пока нет заметок."
        await query.edit_message_text(
            message,
            reply_markup=create_notes_keyboard()
        )
        return SELECTING_NOTE_ACTION

    return SELECTING_ACTION

async def get_weather_for_city(query, city: str, context: ContextTypes.DEFAULT_TYPE):
    """Получает и отображает погоду для указанного города"""
    try:
        city_api = "Rostov-on-Don" if city == "Ростов-на-Дону" else city
        city_display = city

        # Текущая погода
        current_url = f"http://api.openweathermap.org/data/2.5/weather?q={city_api}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
        current_response = requests.get(current_url, timeout=10)
        current_data = current_response.json()

        if current_data.get("cod") != 200:
            error = current_data.get("message", "неизвестная ошибка")
            await query.edit_message_text(
                f"⚠️ Ошибка: {error}\nПопробуйте другой город.",
                reply_markup=create_weather_keyboard(query.from_user.id)
            )
            return

        # Парсим данные
        weather_desc = current_data["weather"][0]["description"]
        temp = current_data["main"]["temp"]
        feels_like = current_data["main"]["feels_like"]
        humidity = current_data["main"]["humidity"]
        wind = current_data["wind"]["speed"]
        emoji = get_weather_emoji(weather_desc)

        # Получаем рекомендации по одежде
        clothes = get_clothing_recommendation(temp, weather_desc)

        # Получаем прогноз на завтра
        tomorrow_forecast = await get_tomorrow_forecast(city_api)

        # Формируем сообщение
        message = (
            f"{emoji} Погода в {city_display}:\n\n"
            f"• Сейчас: {temp}°C (ощущается как {feels_like}°C)\n"
            f"• Состояние: {weather_desc.capitalize()} {emoji}\n"
            f"• Влажность: {humidity}% 💧\n"
            f"• Ветер: {wind} м/с 💨\n\n"
        )

        if tomorrow_forecast:
            message += f"{tomorrow_forecast}\n\n"

        message += f"Что надеть:\n{clothes}"

        # Добавляем кнопку "Добавить в избранное", если город еще не в избранном
        user_id = query.from_user.id
        if user_id not in user_favorite_cities:
            user_favorite_cities[user_id] = []
            
        if city not in user_favorite_cities[user_id]:
            keyboard = [
                [InlineKeyboardButton(f"Добавить {city} в избранное", callback_data=f"add_{city}")],
                [InlineKeyboardButton("Назад", callback_data='back_weather')]
            ]
        else:
            keyboard = [[InlineKeyboardButton("Назад", callback_data='back_weather')]]
            
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        await query.edit_message_text(message, reply_markup=reply_markup)

    except requests.exceptions.Timeout:
        await query.edit_message_text(
            "⌛ Сервер погоды не отвечает. Попробуйте позже.",
            reply_markup=create_weather_keyboard(query.from_user.id)
        )
    except Exception as e:
        logger.error(f"Ошибка в get_weather_for_city: {e}")
        await query.edit_message_text(
            "😔 Произошла ошибка. Попробуйте снова.",
            reply_markup=create_weather_keyboard(query.from_user.id)
        )

async def handle_city_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Обрабатывает введенный пользователем город"""
    try:
        city = update.message.text
        user_id = update.effective_user.id
        
        # Проверяем, ожидаем ли мы сумму для пополнения
        if context.user_data.get('awaiting_deposit'):
            try:
                amount = int(city)
                user_balance[user_id] = user_balance.get(user_id, 0) + amount
                await update.message.reply_text(
                    f"✅ Баланс пополнен на {amount} руб. Текущий баланс: {user_balance[user_id]} руб.",
                    reply_markup=create_profile_keyboard()
                )
                context.user_data.pop('awaiting_deposit', None)
                return PROFILE_MENU
            except ValueError:
                await update.message.reply_text(
                    "❌ Пожалуйста, введите только цифры.",
                    reply_markup=create_profile_keyboard()
                )
                return PROFILE_MENU
        
        # Если это не пополнение баланса, то это город для погоды
        await update.message.reply_chat_action(action="typing")
        
        # Проверяем, существует ли город
        test_url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={WEATHER_API_KEY}&units=metric&lang=ru"
        test_response = requests.get(test_url, timeout=5)
        test_data = test_response.json()
        
        if test_data.get("cod") != 200:
            await update.message.reply_text(
                f"⚠️ Город '{city}' не найден. Попробуйте еще раз.",
                reply_markup=None
            )
            return TYPING_CITY
        
        # Если город существует, показываем погоду и предлагаем добавить в избранное
        message = f"Город '{city}' найден. Хотите добавить его в избранное?"
        keyboard = [
            [InlineKeyboardButton("Да", callback_data=f"add_{city}")],
            [InlineKeyboardButton("Нет, просто показать погоду", callback_data=f"show_{city}")]
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        await update.message.reply_text(message, reply_markup=reply_markup)
        return WEATHER_MENU

    except Exception as e:
        logger.error(f"Ошибка в handle_city_input: {e}")
        await update.message.reply_text(
            "😔 Произошла ошибка. Попробуйте снова.",
            reply_markup=create_main_keyboard()
        )
        return SELECTING_ACTION

async def handle_note_input(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Обрабатывает введенную пользователем заметку"""
    try:
        note = update.message.text
        user_id = update.effective_user.id
        
        if user_id not in user_notes:
            user_notes[user_id] = []
            
        user_notes[user_id].append(note)
        
        await update.message.reply_text(
            "✅ Заметка добавлена! Вы можете ввести ещё одну заметку или ввести /stop для завершения.",
            reply_markup=None
        )
        return TYPING_NOTE

    except Exception as e:
        logger.error(f"Ошибка в handle_note_input: {e}")
        await update.message.reply_text(
            "😔 Произошла ошибка. Попробуйте снова.",
            reply_markup=create_main_keyboard()
        )
        return SELECTING_ACTION

async def stop_notes(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Завершает работу с заметками"""
    await update.message.reply_text(
        "Завершили добавление заметок. Выберите действие:",
        reply_markup=create_main_keyboard()
    )
    return SELECTING_ACTION

async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Завершает работу с ботом"""
    await update.message.reply_text(
        "До свидания! 👋 Нажмите /start для нового запроса.",
        reply_markup=ReplyKeyboardRemove()
    )
    return ConversationHandler.END

async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Обрабатывает ошибки"""
    logger.error(f"Ошибка: {context.error}")
    if update:
        await update.message.reply_text(
            "😔 Произошла ошибка. Попробуйте /start",
            reply_markup=create_main_keyboard()
        )

def main() -> None:
    """Запуск бота"""
    try:
        application = Application.builder().token(BOT_TOKEN).build()

        conv_handler = ConversationHandler(
            entry_points=[CommandHandler("start", start)],
            states={
                SELECTING_ACTION: [
                    MessageHandler(filters.Regex("^Профиль 👤$"), profile_menu),
                    MessageHandler(filters.Regex("^Погода 🌤️$"), weather_menu),
                    MessageHandler(filters.Regex("^Заметки 📝$"), notes_menu),
                ],
                PROFILE_MENU: [
                    CallbackQueryHandler(button_handler),
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_city_input),
                ],
                WEATHER_MENU: [
                    CallbackQueryHandler(button_handler),
                ],
                TYPING_CITY: [
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_city_input),
                ],
                SELECTING_NOTE_ACTION: [
                    CallbackQueryHandler(button_handler),
                ],
                TYPING_NOTE: [
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handle_note_input),
                    CommandHandler("stop", stop_notes),
                ],
            },
            fallbacks=[CommandHandler("cancel", cancel)],
        )

        application.add_handler(conv_handler)
        application.add_error_handler(error_handler)

        logger.info("🤖 Бот запущен")
        application.run_polling()

    except Exception as e:
        logger.critical(f"❌ Ошибка запуска: {e}")
    finally:
        logger.info("🛑 Бот остановлен")

if __name__ == "__main__":
    main()