Помогите с телеграм ботом

Ситуация такая: изучаю питон 3-ий день. Посмотрел видео курс из 5 часов. Посчитал, что можно приступить к простому, написанию телеграм бота. Я хочу, чтобы он не только ссылки писал, но и погоду. А когда прошу его написать погоду, то либо не работает команда старт, то бесконечно просит вводит города, а если введу не правильный город, то просто крашает бота. Переписывал некоторые блоки у "ютуберов", а они нихуя не объясняют и я ничего не понимаю. Можете закидать меня помидорами, но я рил не шарю, но очень хочу научиться!!! Закомментированный блок - это и есть блок с погодой, гори она в аду. Вот код:

import telebot
import pyowm
from telebot import types
owm = pyowm.OWM('мой апи', language = 'ru')
bot = telebot.TeleBot ("мой апи")
can_send_messages = True


@bot.message_handler(commands=['insta'])
def open_insta(message):
    markup1 = types.InlineKeyboardMarkup()
    btninst = types.InlineKeyboardButton("Тык сюда и ты моей инсте", url="я удалил ссылку")
    markup1.add(btninst)
    bot.send_message(message.chat.id, "Подпишись, сука", reply_markup=markup1)


@bot.message_handler(commands=['vk'])
def open_vk(message):
    markup1 = types.InlineKeyboardMarkup()
    btnvk = types.InlineKeyboardButton("Тык сюда и ты моем вк", url="я удалил ссылку")
    markup1.add(btnvk)
    bot.send_message(message.chat.id, "Подпишись, сука", reply_markup=markup1)


@bot.message_handler(commands=['stoopid'])
def open_stoopid(message):
    markup1 = types.InlineKeyboardMarkup()
    btnst = types.InlineKeyboardButton("Тык сюда и ты у самого тупого чела", url="я удалил ссылку")
    markup1.add(btnst)
    bot.send_message(message.chat.id, "Отпишись, сука", reply_markup=markup1)

@bot.message_handler(commands=['stop'])
def stop(message):
    bot.send_message(message.chat.id, "Ты вышел из раздела, жду команды!")


@bot.message_handler(commands=['menu'])
def reec(message):
    bot.send_message(message.chat.id,"""Я туповат пока что и не всегда понимаю, что ты хочешь от меня,но скоро я буду имбой 
        Тем не менее, я не могу: 
        /weather - узнать погоду (не работает сука, хз почему)
        /start снова поприветсвую тебя и спрошу кто ты
        про /menu ты уже знаешь
        /insta - узнать мою инсту 
        /vk - узнать мой вк
        /stoopid - самый тупой чел
        /stop - выход из раздела
        Пока функционал заканчивается!""")


#@bot.message_handler(content_types='text')
#def pogoda(message):
    #get_message_bot = message.text.strip().lower()
    #if get_message_bot == "weather":
        #observation = owm.weather_at_place(message.text)
        #w = observation.get_weather()
        #temp = w.get_temperature('celsius')["temp"]
        #answer1 = "В городе " + message.text + " сейчас " + w.get_detailed_status() +'\n'
        #answer1 += " Температура сейчас в районе " + str(temp) +'\n'
        #if temp < 10:
        #   answer1 +='На улице холодно, шо пиздец, оденься, как зимой!'
        #elif temp < 15:
        #   answer1 +='На улице чет холодновато, оденься теплее!'
        #elif temp < 20:
        #   answer1 += "На улице в принципе тепло, но в шортах не рекомендую выходить"
        #elif temp > 20:
        #   answer1 += "На улцие жара, шо пиздец "
        #else:
        #   answer1 += "Введи норм город или другю команду"
        #bot.send_message(message.chat.id,answer1)


@bot.message_handler(commands=['start'])
def privet(message):
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=3)
    btn1=types.KeyboardButton("/start")
    btn2=types.KeyboardButton("/menu")
    btn3=types.KeyboardButton("/vk")
    btn4=types.KeyboardButton("/insta")
    btn5=types.KeyboardButton("/stoopid")
    btn6=types.KeyboardButton("/stop")
    btn7=types.KeyboardButton("/weather")
    markup.add(btn1,btn2,btn3,btn4,btn5,btn6,btn7)
    stic = open('sticker.webp', 'rb')
    bot.send_sticker(message.chat.id, stic)
    bot.send_message(message.chat.id, "Добро пожаловать, {0.first_name}!\nЯ - <b>{1.first_name}</b>, бот созданный чтобы быть подопытным кроликом.".format(message.from_user, bot.get_me()),
    parse_mode='html', reply_markup=markup)

        #bot.send_message(message.chat.id, "Я тебя не понимаю, введи /menu , чтобы все понять!!")   
@bot.message_handler(content_types='text')
def deafult(message):
    bot.send_message(message.chat.id, "Я тебя не понимаю, введи '/menu' , чтобы все понять!!")



bot.polling(none_stop=True)

Ответы (1 шт):

Автор решения: D. Violet

Если пользователь написал боту (нажал на кнопку ReplyKeyboardMarkup, которая отправляет в чат от имени пользователя "заготовку") weather - if get_message_bot == "weather": бот переходит в режим погода. Ок.

Текст сообщения пользователя, message.text передаётся в owm.weather_at_place() как место - observation = owm.weather_at_place(message.text).

Так как же бот не будет падать, если функция получения погоды пытается найти погоду в месте weather?

Почему бы не сделать для погоды отдельную команду @bot.message_handler(commands=['weather'])?

Тогда:

@bot.message_handler(commands=['weather'])
def cmd_city(message):
    send = bot.send_message(message.chat.id, 'Введи город')
    bot.register_next_step_handler(send, city)  # ожидает следующий шаг

def city(message):
    bot.send_message(message.chat.id, 'Ищу погоду в городе {city}'.format(city=message.text))
    observation = owm.weather_at_place(message.text)
    w = observation.get_weather()
    temp = w.get_temperature('celsius')["temp"]
    answer1 = "В городе " + message.text + " сейчас " + w.get_detailed_status() + '\n'
    answer1 += " Температура сейчас в районе " + str(temp) + '\n'
    if temp < 10:
        answer1 += 'На улице холодно, шо пиздец, оденься, как зимой!'
    elif temp < 15:
        answer1 += 'На улице чет холодновато, оденься теплее!'
    elif temp < 20:
        answer1 += "На улице в принципе тепло, но в шортах не рекомендую выходить"
    elif temp > 20:
        answer1 += "На улцие жара, шо пиздец "
    else:
        answer1 += "Введи норм город или другю команду"
    bot.send_message(message.chat.id, answer1)

Либо, без хэндлера на команду:

@bot.message_handler(content_types='text')
def text(message):
    if message.text == 'weather':
        send = bot.send_message(message.chat.id, 'Введи город')
        bot.register_next_step_handler(send, city)


def city(message):
    bot.send_message(message.chat.id, 'Ищу погоду в городе {city}'.format(city=message.text))
    observation = owm.weather_at_place(message.text)
    w = observation.get_weather()
    temp = w.get_temperature('celsius')["temp"]
    answer1 = "В городе " + message.text + " сейчас " + w.get_detailed_status() + '\n'
    answer1 += " Температура сейчас в районе " + str(temp) + '\n'
    if temp < 10:
        answer1 += 'На улице холодно, шо пиздец, оденься, как зимой!'
    elif temp < 15:
        answer1 += 'На улице чет холодновато, оденься теплее!'
    elif temp < 20:
        answer1 += "На улице в принципе тепло, но в шортах не рекомендую выходить"
    elif temp > 20:
        answer1 += "На улцие жара, шо пиздец "
    else:
        answer1 += "Введи норм город или другю команду"
    bot.send_message(message.chat.id, answer1)

UPD:

  1. Обработчики (Handlers) - это функции с общей подписью:

handler(request, response)

Ожидается, что обработчик будет использовать информацию из запроса (например, путь) либо для заполнения объекта ответа данными для отправки, либо для прямой записи в выходной поток через экземпляр ResponseWriter, связанный с запросом. Если обработчик выполняет запись в выходной поток, то сервер не будет пытаться выполнить дополнительную запись, т.е. выбор записи прямо в обработчик или нет - «все или ничего».

о декораторах

  1. в данном случае send = bot.send_message(message.chat.id, 'Введи город') это переменная.

  2. расположение команд не имеет значения, просто удобно видеть, например /start первым блоком кода, разве нет?

  3. bot.register_next_step_handler ожидает ввод и переходит к другому шагу передавая ему данный ввод.

  4. кнопка которая бы возвращала пользователя на этап назад - например создать функцию которая описывает главную клавиатуру и при if message.text == 'назад': вызывать данную функцию

  5. да, можно под одним хэндлером можно расположить несколько функций. 6.1 верно, сначала идёт cmd_city(), после city()
→ Ссылка