У меня есть такой код, добавь кнопку "Заметки" (Можно писать заметки и они будут сохраняться у себя в профиле) сделай рабочее состояние. У меня нет прав администратора для базы данных:

import os
import logging
from dotenv import load_dotenv
import requests
from telegram import ReplyKeyboardMarkup, Update, ReplyKeyboardRemove
from telegram.ext import (
    Application,
    CommandHandler,
    MessageHandler,
    filters,
    ContextTypes,
    ConversationHandler,
)
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 = range(2)

# Клавиатура с городами
reply_keyboard = [
    ["Ростов-на-Дону 🌊", "Анапа 🏖️"],
    ["Поиск 🔍"],
]
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True, resize_keyboard=True)

# Функции бота
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 ""

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

        days_left = get_days_until_dembel()
        phrase = get_motivational_phrase()

        await update.message.reply_text(
            f"Привет, {user.first_name}! 👋\n"
            f"⏳ До дембеля осталось {days_left} дней!\n"
            f"🗓 Дата: {DEMBEL_DATE.strftime('%d.%m.%Y')}\n\n"
            f"{phrase}\n\n"
            "Я бот, который покажет тебе текущую погоду и подскажет, что надеть.\n"
            "Выбери город из списка или найди другой:",
            reply_markup=markup
        )
        return SELECTING_ACTION

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

async def get_weather(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Получает погоду для выбранного города"""
    try:
        city = update.message.text

        if city == "Поиск 🔍":
            await update.message.reply_text(
                "🔍 Введите название города (например: Москва, Сочи):",
                reply_markup=ReplyKeyboardRemove(),
            )
            return TYPING_CITY

        if "Ростов" in city:
            city_api = "Rostov-on-Don"
            city_display = "Ростове-на-Дону 🌊"
        elif "Анапа" in city:
            city_api = "Anapa"
            city_display = "Анапе 🏖️"
        else:
            city_api = city
            city_display = city

        await update.message.reply_chat_action(action="typing")

        # Текущая погода
        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 update.message.reply_text(
                f"⚠️ Ошибка: {error}\nПопробуйте другой город.",
                reply_markup=markup
            )
            return SELECTING_ACTION

        # Парсим данные
        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}\n\n"
            f"Хотите узнать погоду в другом месте? Выберите город:"
        )

        await update.message.reply_text(message, reply_markup=markup)
        return SELECTING_ACTION

    except requests.exceptions.Timeout:
        await update.message.reply_text(
            "⌛ Сервер погоды не отвечает. Попробуйте позже.",
            reply_markup=markup
        )
        return SELECTING_ACTION
    except Exception as e:
        logger.error(f"Ошибка в get_weather: {e}")
        await update.message.reply_text(
            "😔 Произошла ошибка. Попробуйте /start",
            reply_markup=markup
        )
        return SELECTING_ACTION

async def search_city(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
    """Обрабатывает введенный пользователем город"""
    try:
        city = update.message.text
        return await get_weather(update, context)
    except Exception as e:
        logger.error(f"Ошибка в search_city: {e}")
        await update.message.reply_text(
            "😔 Ошибка обработки города. Попробуйте /start",
            reply_markup=markup
        )
        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=markup
        )

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("^(Ростов-на-Дону|Анапа)"), get_weather),
                    MessageHandler(filters.Regex("^Поиск 🔍$"), get_weather),
                ],
                TYPING_CITY: [
                    MessageHandler(filters.TEXT & ~filters.COMMAND, search_city),
                ],
            },
            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()