Вот один из вариантов такого бота:

```
import os
import logging
import aiohttp.client
from aiogram.types import Location
import urllib
import asyncio
from aiogram import Bot, Dispatcher, executor, types
from aiogram.types import InlineQuery, InlineQueryResultArticle, InputTextMessageContent



API_TOKEN = os.getenv('TELEGRAM_API_TOKEN')
PROXY_URL = os.getenv('TELEGRAM_PROXY_URL')
PROXY_AUTH = os.getenv('TELEGRAM_PROXY_AUTH')
WEATHER_RETRIEVAL_FAILED_MESSAGE = get_message('weather_for_location_retrieval_failed')


logging.basicConfig(level=logging.INFO)


bot = Bot(token=API_TOKEN, proxy=PROXY_URL, proxy_auth=PROXY_AUTH)
dp = Dispatcher(bot)


MESSAGES = {
    'weather_for_location_retrieval_failed': 'Не получилось узнать погоду в этой локации 😞,' +
    'предлагаем посмотреть, какая погода за окном. \n\n /help - инструкция по использованию бота.',

    'general_failure': 'Я такое не умею 😞.\n\n /help - инструкция по использованию бота.',

    'weather_in_city_message': 'Погода в городе {}:\n{}\nтемпература: {:.1f}°C.',

    'weather_in_location_message': 'Погода в указанной локации:\n{}\nтемпература: {:.1f}°C.',

    'help': 'Я умею показывать погоду в вашем городе, введите название города или отправьте местоположение.'
}


def get_message(message_key: str):
    return MESSAGES[message_key]


WEATHER_SERVICE_API_KEY = os.getenv('WEATHER_SERVICE_API_KEY')


class WeatherServiceException(BaseException):
    pass


class WeatherInfo:

    def __init__(self, temperature, status, is_kelvin=True):
        self.temperature = kelvin_to_celsius(
            temperature) if is_kelvin else temperature
        self.status = status


async def get_weather_for_city(city_name: str) -> WeatherInfo:
    return await make_weather_service_query(get_city_query_url(city_name))


async def get_weather_for_location(location: Location) -> WeatherInfo:
    return await make_weather_service_query(get_location_query_url(location))


def get_city_query_url(city_name: str):
    return f'http://api.openweathermap.org/data/2.5/weather?q={urllib.parse.quote(city_name)}&appid={WEATHER_SERVICE_API_KEY}&lang=ru'


def get_location_query_url(location: Location):
    return f'http://api.openweathermap.org/data/2.5/weather?lat={location.latitude}&lon={location.longitude}&appid={WEATHER_SERVICE_API_KEY}&lang=ru'


async def make_weather_service_query(url: str) -> WeatherInfo:
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            if resp.status == 200:
                return get_weather_from_response(await resp.json())

    raise WeatherServiceException()


def get_weather_from_response(json):
    return WeatherInfo(json['main']['temp'], json['weather'][0]['description'])


def kelvin_to_celsius(degrees):
    KELVIN_0 = 273.15
    return degrees - KELVIN_0


temperature_rules = [
    (-10, 'Очень холодно. Одевайте все самое теплое.'),
    (0, 'Холодно, стоит взять теплую куртку и шарф.'),
    (10, 'Прохладно, стоит одеться потеплее.'),
    (15, 'Приятная погода, но куртка не помешает.'),
    (20, 'Тепло. Легкая кофта подойдет.'),
    (27, 'Очень тепло. Футболка и шорты - то, что нужно.'),
    (50, 'Очень жарко, держитесь в тени и возьмите с собой воды.'),
    (5000, 'Скорее всего, вы на солнце.')
]


def get_temperature_advice(temperature: int) -> str:
    for rule, advice in temperature_rules:
        if temperature < rule:
            return advice

    return ''


def get_status_advice(weather: str) -> str:
    if 'дожд' in weather:
        return 'Возьмите зонтик.'
    return ''


def get_advice(weather: WeatherInfo) -> str:
    advice = get_temperature_advice(weather.temperature)
    advice += '\n'
    advice += get_status_advice(weather.status)
    return advice

@dp.message_handler(commands=['start', 'help'])
async def start(message: types.Message):
    await message.reply(get_message('help'), reply=False)


@dp.message_handler(content_types=['text'])
async def get_weather_in_city(message: types.Message):
    try:
        weather: WeatherInfo = await get_weather_for_city(message.text)
    except WeatherServiceException:
        await message.reply(WEATHER_RETRIEVAL_FAILED_MESSAGE)
        return

    response = get_message('weather_in_city_message') \
        .format(message.text, weather.status, weather.temperature)+ '\n\n' + \
        get_advice(weather)

    await message.reply(response)


@dp.message_handler()
async def default_response(message: types.Message):
    await message.reply(get_message('general_failure'))


@dp.message_handler(content_types=['location'])
async def get_weather_in_location(message: types.Message):
    if message.location:
        try:
            weather = await get_weather_for_location(message.location)
        except WeatherServiceException:
            await message.reply(WEATHER_RETRIEVAL_FAILED_MESSAGE)
            return

        response = get_message('weather_in_location_message') \
            .format(weather.status, weather.temperature) + '\n\n' + \
            get_advice(weather)

        await message.reply(response)
        return
            
    await message.reply(WEATHER_RETRIEVAL_FAILED_MESSAGE)


if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)
```
spam fails_task lang_mismatch pii not_appropriate hate_speech sexual_content quality toxicity humor helpfulness creativity violence