Вчерашняя задача - это яркий пример полиморфизма в ООП. Суть в том, что мы создаём "класс-потомок" и изменяем его поведение относительно наследуемого класса, но обо всём по порядку.
В викторине приняли участие 31 человек из них верно ответили всего 5. Большая часть сошлись во мнении, что должна выйти ошибка
Код задачи:
Разберём задачу.
Начнём с класса. Мы создали класс
В нашем вновь созданном классе мы переопределяем три метода:
- Конструктор класса
-
-
После класса идёт ряд действий:
1. В переменную
2. К списку добавляется число
3. В переменную
4. Последним шагом выводим значение словаря передав объект из переменной
Почему удалось добавить список как ключ?
Тут всё достаточно просто. Действительно, словарь не даёт делать ключом нехэшируемые объекты, и на то есть свои причины: списки и другие изменяемые типы данных не хэшируются, поскольку изменение приводило бы к изменению их хэша, а словари хранят ключи в хэш-таблице. Таким образом, записав значение по одному ключу, который в последствии изменится, мы не сможем получить записанные данные.
Что касается нашего случая, то когда мы переопределили
Почему в выводе 3?
И тут ответ "на поверхности". Когда для вывода объектов используется функция
Заключение.
Вот такая задачка у нас вышла. В задаче показан пример полиморфизма в действии, когда класс
В викторине приняли участие 31 человек из них верно ответили всего 5. Большая часть сошлись во мнении, что должна выйти ошибка
TypeError. Вторым популярным ответом стал [0, 1, 2], означающий, что должен вывестись весь список.Код задачи:
class MyList(list):
def __init__(self, *args):
super().__init__()
for i in args:
self.append(i)
def __hash__(self):
return 1
def __str__(self):
return str(self.__len__())
lst = MyList(0, 1)
lst.append(2)
dct = {lst: lst}
print(dct[lst])
Разберём задачу.
Начнём с класса. Мы создали класс
MyList и унаследовали его от встроенного в Python класса list. Этот класс, экземпляры хорошо известной нам структуры данных - списка.В нашем вновь созданном классе мы переопределяем три метода:
- Конструктор класса
__init__ – в этом методе инициализируем super-класс, т.е. вызываем метод __init__ из родительского класса. Далее в цикле добавляем все переданные позиционные аргументы в список, используя метод append, который мы унаследовали из родительского класса привычного нам списка.-
dunder-метод __hash__ – данный метод возвращает хэш-значение объекта класса. Если тип данных не хэшируется (как, например, типа данных список), то возвращается None. В нашем случае мы возвращаем значение 1, что соответствует True.-
dunder-метод __str__ – данный метод возвращает строковое представление объекта класса. Для списков это - "[1, 2, 3]", в нашем случае возвращается строка с указанием длинны списка (за это отвечает dunder-метод __len__).После класса идёт ряд действий:
1. В переменную
lst помещается объект созданного нами только что класса MyList с аргументами (0, 1). Тем самым формируется список [0, 1] (здесь и дальше мы будем употреблять слово "список" условно, называя так объекты нашего авторского класса, унаследованного от списка).2. К списку добавляется число
2, получается следующий список - [0, 1, 2].3. В переменную
dct помещаем словарь, в котором ключ и значение - это значение, записанное в переменную lst (то есть объект нашего авторского класса со списком [0, 1, 2]).4. Последним шагом выводим значение словаря передав объект из переменной
lst как ключ.Почему удалось добавить список как ключ?
Тут всё достаточно просто. Действительно, словарь не даёт делать ключом нехэшируемые объекты, и на то есть свои причины: списки и другие изменяемые типы данных не хэшируются, поскольку изменение приводило бы к изменению их хэша, а словари хранят ключи в хэш-таблице. Таким образом, записав значение по одному ключу, который в последствии изменится, мы не сможем получить записанные данные.
Что касается нашего случая, то когда мы переопределили
dunder-метод __hash__, мы изменили поведение класса list, сделав его хэшируемым. Именно это позволило использовать переменную со списком в качестве ключа.Почему в выводе 3?
И тут ответ "на поверхности". Когда для вывода объектов используется функция
print, вызывается dunder-метод __str__. Мы переопределили его, возвращая вместо стандартного строкового представления списка – его длину.Заключение.
Вот такая задачка у нас вышла. В задаче показан пример полиморфизма в действии, когда класс
list изменяет своё поведение, будучи унаследован пользовательским классом.🔥9🤯1
AIOgram3 16. Перевод голосовых сообщений в текст
Автор: Иван Ашихмин
Голосовые сообщения – весьма спорная тема. Кто-то без них жить не может, а кто-то ненавидит их всей душой. Если опустить прения на эту тему, то у голосовых сообщений есть одна проблема: их банально не всегда удобно слушать. Чаще всего голосовые сообщения – это "информация в моменте", и, когда появляется возможность прослушать их, они теряют свою актуальность.
У нас в чате любят слать голосовые, и, чтобы все могли оставаться "в теме", даже когда не у каждого есть возможность прослушать их, мы решили научить бота переводить голосовые в текст.
Нейронных сетей, заточенных под распознавание голоса, свыше десятка, но они требуют серьёзных вычислительных мощностей, чего мой не самый мощный сервер не может предоставить.
Автор: Иван Ашихмин
Голосовые сообщения – весьма спорная тема. Кто-то без них жить не может, а кто-то ненавидит их всей душой. Если опустить прения на эту тему, то у голосовых сообщений есть одна проблема: их банально не всегда удобно слушать. Чаще всего голосовые сообщения – это "информация в моменте", и, когда появляется возможность прослушать их, они теряют свою актуальность.
У нас в чате любят слать голосовые, и, чтобы все могли оставаться "в теме", даже когда не у каждого есть возможность прослушать их, мы решили научить бота переводить голосовые в текст.
Нейронных сетей, заточенных под распознавание голоса, свыше десятка, но они требуют серьёзных вычислительных мощностей, чего мой не самый мощный сервер не может предоставить.
🔥5😁1😱1
Готовые сервисы тоже есть, но практически все - платные. Не беря в расчёт "пробные периоды" из бесплатных (вернее с бесплатным лимитом в месяц) есть два сервиса:
- Google Cloud - думаю не стоит рассказывать о Google. Они предлагают бесплатный тариф - 60 минут в месяц.
- SpeechFlow - сервис, позиционирующий себя как "лидера рынка". Поддерживают транскрипцию с 14-ти языков. Предлагают бесплатный тариф: 30 минут онлайн-распознавания (на сайте) и пять часов по API в месяц.
Сервис от Google нам не подходит: 60 минут на целый месяц слишком мало, поэтому выбор был сделан в пользу SpeechFlow. Пять часов в месяц – тоже не то чтобы много, но с этим уже можно работать. Ну, и будет интересно посмотреть статистику длительности голосовых и их количества.
Регистрация и получение API-ключа.
Переходим на сайт сервиса: https://speechflow.io/ru/
Регистрация максимально проста, особенно если заходить через Google-аккаунт.
После регистрации попадаем в личный кабинет. Там в левой панели выбираем раздел "API".
На открывшейся странице нажимаем кнопку "Сгенерировать ключ API".
В появившемся окне будет две строки:
-
-
ВНИМАНИЕ! Ключ отображается всего один раз! Сохраните его в удобном для вас месте.
Также на этой странице есть примеры кода на различных языках, включая и Python. Пример для Python избыточный. Мы возьмём его за основу и упростим для нашей задачи.
Отслеживание и расшифровка голосовых сообщений.
В посте "AIOgram3 14. Фильтруем запрещённые слова" мы писали обработку для проверки сообщений на запрещённые слова. В этом посте мы дополним ее функционалом проверки голосовых сообщений.
Но сперва добавим ключи в класс
Откроем файл
В значение полей вставьте полученные от SpeechFlow данные доступа.
Обработка голосовых сообщений.
Откройте файл
Тут у нас уже есть функция
Добавим его ниже, использовав
Сперва нам необходимо скачать голосовое сообщение с сервера Telegram. Для этого выполним несколько шагов:
1. Создадим переменную
2. Создадим переменную
3. Создадим переменную
4. Создадим переменную
5. Асинхронно выполним команду скачивания файла.
Получается вот такой блок кода:
Создаём четыре переменные, которые понадобятся далее в коде:
1.
2.
- Google Cloud - думаю не стоит рассказывать о Google. Они предлагают бесплатный тариф - 60 минут в месяц.
- SpeechFlow - сервис, позиционирующий себя как "лидера рынка". Поддерживают транскрипцию с 14-ти языков. Предлагают бесплатный тариф: 30 минут онлайн-распознавания (на сайте) и пять часов по API в месяц.
Сервис от Google нам не подходит: 60 минут на целый месяц слишком мало, поэтому выбор был сделан в пользу SpeechFlow. Пять часов в месяц – тоже не то чтобы много, но с этим уже можно работать. Ну, и будет интересно посмотреть статистику длительности голосовых и их количества.
Регистрация и получение API-ключа.
Переходим на сайт сервиса: https://speechflow.io/ru/
Регистрация максимально проста, особенно если заходить через Google-аккаунт.
После регистрации попадаем в личный кабинет. Там в левой панели выбираем раздел "API".
На открывшейся странице нажимаем кнопку "Сгенерировать ключ API".
В появившемся окне будет две строки:
-
KeyId - идентификатор ключа-
KeySecret - секретный ключВНИМАНИЕ! Ключ отображается всего один раз! Сохраните его в удобном для вас месте.
Также на этой странице есть примеры кода на различных языках, включая и Python. Пример для Python избыточный. Мы возьмём его за основу и упростим для нашей задачи.
Отслеживание и расшифровка голосовых сообщений.
В посте "AIOgram3 14. Фильтруем запрещённые слова" мы писали обработку для проверки сообщений на запрещённые слова. В этом посте мы дополним ее функционалом проверки голосовых сообщений.
Но сперва добавим ключи в класс
Secrets.Откроем файл
settings.py и в классе Secrets добавим две строки:audio_key_id: str = "ваш_KeyId"
audio_key_secret: str = "ваш_KeySecret"
В значение полей вставьте полученные от SpeechFlow данные доступа.
Обработка голосовых сообщений.
Откройте файл
filter_words.py.Тут у нас уже есть функция
check_message с условием if message.text. Для того, чтобы "отлавливать" голосовые сообщения, нужно другое условие - if message.voice.Добавим его ниже, использовав
elif.Сперва нам необходимо скачать голосовое сообщение с сервера Telegram. Для этого выполним несколько шагов:
1. Создадим переменную
file_id, в которую получим идентификатор голосового сообщения.2. Создадим переменную
file, в которую асинхронно получим информацию о файле голосового сообщения.3. Создадим переменную
file_path, в которую получим путь до файла.4. Создадим переменную
file_name, в которой укажем путь и имя сохраняемого файла на нашем сервере. Убедитесь, что директория, в которой вы собираетесь сохранять файл, существует.5. Асинхронно выполним команду скачивания файла.
Получается вот такой блок кода:
file_id = message.voice.file_id
file = await bot.get_file(file_id)
file_path = file.file_path
file_name = f"files/audio{file_id}.mp3"
await bot.download_file(file_path, file_name)
Создаём четыре переменные, которые понадобятся далее в коде:
1.
headers – в этой переменной создаём словарь с ключами keyId и keySecret, в которые передаём значения соответствующих полей из класса Secrets.2.
create_url – в этой переменной определяем URL-адрес, на который отправляем файл для транскрипции. Обратите внимание на query-параметр lang: в нём указываем язык голосового сообщения.👍3🔥1😱1
3.
4.
Блок кода:
Далее отправляем
Если статус-код ответа равен статус-коду 200, проваливаемся внутрь условия. Иначе завершаем выполнение обработки.
Внутри условия в переменную
Затем к переменной
Всего есть четыре значения
1. Тип результата по умолчанию: формат JSON для предложений и слов с указанием начального и конечного времени.
2. Формат JSON для сгенерированных субтитров с указанием начального и конечного времени.
3. Формат SRT для сгенерированных субтитров с указанием начального и конечного времени.
4. Чистый текстовый формат для результатов транскрипции без указания начального и конечного времени.
Для ответа в чате лучше всего подходит 4-й вариант.
Блок кода:
Запускаем бесконечный цикл.
Внутри цикла отправляем
Если статус-код ответа равен 200, проваливаемся внутрь условия. Иначе прерываем цикл и завершаем выполнение обработки.
В переменную
Далее у нас два условия:
Если в
Проваливаемся внутрь условия.
Проверяем, что в
В переменную
Асинхронно отправляем ответ на голосовое сообщение.
Удаляем файл с сервера.
Прерываем цикл.
Иначе-если (
Выставляем сон на три секунды и переходим к следующей итерации цикла.
Если оба условия не были удовлетворены, то мы прерываем цикл.
Полный код:
query_url – в этой переменной определяем URL-адрес, на который будем обращаться для получения результата транскрипции.4.
files – в этой переменной создаём словарь с ключом file, в значение которого помещаем открытый аудиофайл.Блок кода:
headers = {"keyId": Secrets.audio_key_id, "keySecret": Secrets.audio_key_secret}
create_url = "https://api.speechflow.io/asr/file/v1/create?lang=ru"
query_url = "https://api.speechflow.io/asr/file/v1/query?taskId="
files = {"file": open(file_name, "rb")}Далее отправляем
POST-запрос на адрес create_url и записываем ответ в переменную response.Если статус-код ответа равен статус-коду 200, проваливаемся внутрь условия. Иначе завершаем выполнение обработки.
Внутри условия в переменную
create_result получаем JSON ответа.Затем к переменной
query_url добавляем идентификатор задачи из create_result и query-параметр resultType.Всего есть четыре значения
resultType:1. Тип результата по умолчанию: формат JSON для предложений и слов с указанием начального и конечного времени.
2. Формат JSON для сгенерированных субтитров с указанием начального и конечного времени.
3. Формат SRT для сгенерированных субтитров с указанием начального и конечного времени.
4. Чистый текстовый формат для результатов транскрипции без указания начального и конечного времени.
Для ответа в чате лучше всего подходит 4-й вариант.
Блок кода:
response = requests.post(create_url, headers=headers, files=files)
if response.status_code 200:
create_result = response.json()
query_url += create_result["taskId"] + "&resultType=4"
Запускаем бесконечный цикл.
Внутри цикла отправляем
GET-запрос на адрес query_url и сохраняем ответ в переменную response.Если статус-код ответа равен 200, проваливаемся внутрь условия. Иначе прерываем цикл и завершаем выполнение обработки.
В переменную
query_result получаем JSON ответа.Далее у нас два условия:
Если в
query_result по ключу code лежит значение 11000, значит, транскрипция завершена.Проваливаемся внутрь условия.
Проверяем, что в
query_result по ключу result есть данные, иначе прерываем цикл. Такое может произойти, когда сервису не удалось распознать речь на голосовом или если оно было без речи вовсе.В переменную
result получаем значение ключа result из query_result. Для удобства можно дополнительно применить метод .replace(), чтобы заменить два переноса строки, например, на пробел.Асинхронно отправляем ответ на голосовое сообщение.
Удаляем файл с сервера.
Прерываем цикл.
Иначе-если (
elif) в query_result по ключу code лежит значение 11001, значит транскрипция ещё не завершена и стоит попробовать чуточку позже.Выставляем сон на три секунды и переходим к следующей итерации цикла.
Если оба условия не были удовлетворены, то мы прерываем цикл.
Полный код:
🔥4😱1
import os
import requests
import time
from botlogic.settings import bot, Secrets
elif message.voice:
file_id = message.voice.file_id
file = await bot.get_file(file_id)
file_path = file.file_path
file_name = f"/code/pressanybutton_bot/files/audio{file_id}.mp3"
await bot.download_file(file_path, file_name)
headers = {"keyId": Secrets.audio_key_id, "keySecret": Secrets.audio_key_secret}
create_url = "https://api.speechflow.io/asr/file/v1/create?lang=ru"
query_url = "https://api.speechflow.io/asr/file/v1/query?taskId="
files = {"file": open(file_name, "rb")}
response = requests.post(create_url, headers=headers, files=files)
if response.status_code 200:
create_result = response.json()
query_url += create_result["taskId"] + "&resultType=4"
while True:
response = requests.get(query_url, headers=headers)
if response.status_code 200:
query_result = response.json()
if query_result["code"] 11000:
if query_result["result"]:
result = query_result["result"].replace("\n\n", " ")
await message.reply(f"<pre><code>{result}</code></pre>")
os.remove(file_name)
break
elif query_result["code"] 11001:
time.sleep(3)
continue
else:
break
else:
break
Заключение.
Качество распознавания не всегда хорошее. Тот же
WhisperAI на модели small выдавал куда лучший результат, но он требователен к железу. Интересно, как быстро кончится лимит в 5 часов.Файлы к посту, можно получить в боте по коду: 790636
Пост на сайте
Поддержать проект
#Python #Гайды #Telegram #AIOgram #Telegram_бот #AIOgram3 #бот #нейронные_сети #whisper #SpeechFlow #транскрипция #голосовые_сообщения
🔥5👍1😱1
Приветствую вас, друзья, в этот волшебный вечер пятницы!
А волшебен он именно тем, что впереди два дня свободы от трудовых будней, начальства и всяческой рутины. И выходные лучше всего начать с просмотра хорошего фильма.
Фильм: Семь
Год: 1995
Детектив Уильям Сомерсет - ветеран уголовного розыска, мечтающий уйти на пенсию и уехать подальше от города и грешных обитателей. За 7 дней до пенсии на Сомерсета сваливаются две неприятности: молодой напарник Миллс и особо изощренное убийство. Острый ум опытного сыщика сразу определяет, что за этим преступлением, скорее всего, последуют другие. Новости подтверждают его догадку. Поняв, что убийца наказывает свои жертвы за совершенные ими смертные грехи, детектив встает перед выбором: вернуться к работе либо уйти и передать дело своему менее опытному напарнику?
https://www.sspoisk.ru/film/377/?utm_referrer=www.google.com
Хорошего просмотра)
А волшебен он именно тем, что впереди два дня свободы от трудовых будней, начальства и всяческой рутины. И выходные лучше всего начать с просмотра хорошего фильма.
Фильм: Семь
Год: 1995
Детектив Уильям Сомерсет - ветеран уголовного розыска, мечтающий уйти на пенсию и уехать подальше от города и грешных обитателей. За 7 дней до пенсии на Сомерсета сваливаются две неприятности: молодой напарник Миллс и особо изощренное убийство. Острый ум опытного сыщика сразу определяет, что за этим преступлением, скорее всего, последуют другие. Новости подтверждают его догадку. Поняв, что убийца наказывает свои жертвы за совершенные ими смертные грехи, детектив встает перед выбором: вернуться к работе либо уйти и передать дело своему менее опытному напарнику?
https://www.sspoisk.ru/film/377/?utm_referrer=www.google.com
Хорошего просмотра)
🔥6
Что выведет код с изображения ниже?
Anonymous Quiz
36%
[[1, 2, 3, 4], [1, 2], [1, 2, 3, 5]]
14%
[[1, 2, 3, 5], [1, 2, 3, 5], [1, 2, 3, 5]]
12%
[[1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
39%
Ничего из перечисленного выше
👍1🔥1
Вчера мы задали простую, но весьма хитрую задачку. Суть задачи заключается в понимании типов данных Python, а именно того, как работают изменяемые типы данных. Перед чтением разбора рекомендуем прочитать наш пост "Питон на измене".
В викторине приняли участие 44 человека! Верных ответов, правда, набралось всего 8, что равно 18-ти процентам... Самым популярным вариантом, оказался "Ничего из перечисленного выше", набрав 39%, следом за ним идёт первый вариант с 32% ответов.
Код задачи:
Разберём задачу.
Создаём переменную
Далее производим ряд действий над элементами списка:
1. В нулевой элемент списка добавляем цифру 4.
2. Из первого элемента списка вынимаем последнюю цифру.
3. Во второй элемент списка добавляем цифру 5.
4. Выводим весь список на экран.
В итоге мы ожидаем получить
Почему тогда верный ответ `[[1, 2, 3, 5], [1, 2, 3, 5], [1, 2, 3, 5]]`?
Вспоминаем, каким типом данных является список? Верно, изменяемым. Ещё такие типы данных именуют "ссылочными".
Всё дело в том, что когда мы в самом начале умножали список
Это легко проверить, запустив следующий код:
Как видим, все три элемента списка ссылаются на одну и ту же ячейку памяти, т.е. на один и тот же список.
В связи с этим, изменяя один элемент списка, мы изменяем и остальные.
Заключение.
Вот так вот простейший с виду код может обмануть программиста.
В викторине приняли участие 44 человека! Верных ответов, правда, набралось всего 8, что равно 18-ти процентам... Самым популярным вариантом, оказался "Ничего из перечисленного выше", набрав 39%, следом за ним идёт первый вариант с 32% ответов.
Код задачи:
my_list = [[1, 2, 3]] * 3
my_list[0].append(4)
my_list[1].pop()
my_list[2].append(5)
print(my_list)
Разберём задачу.
Создаём переменную
my_list в которой умножаем список [[1, 2, 3]] на три. Получаем следующий список: [[1, 2, 3], [1, 2, 3], [1, 2, 3]].Далее производим ряд действий над элементами списка:
1. В нулевой элемент списка добавляем цифру 4.
2. Из первого элемента списка вынимаем последнюю цифру.
3. Во второй элемент списка добавляем цифру 5.
4. Выводим весь список на экран.
В итоге мы ожидаем получить
[[1, 2, 3, 4], [1, 2], [1, 2, 3, 5]].Почему тогда верный ответ `[[1, 2, 3, 5], [1, 2, 3, 5], [1, 2, 3, 5]]`?
Вспоминаем, каким типом данных является список? Верно, изменяемым. Ещё такие типы данных именуют "ссылочными".
Всё дело в том, что когда мы в самом начале умножали список
[[1, 2, 3]] на три, мы по сути создали список из трех ссылок на один и тот же список.Это легко проверить, запустив следующий код:
my_list = [[1, 2, 3]] * 3
print(id(my_list))
print(id(my_list[0]), id(my_list[1]), id(my_list[2]))
>>> 2239539514496
>>> 2239534636480 2239534636480 2239534636480
Как видим, все три элемента списка ссылаются на одну и ту же ячейку памяти, т.е. на один и тот же список.
В связи с этим, изменяя один элемент списка, мы изменяем и остальные.
Заключение.
Вот так вот простейший с виду код может обмануть программиста.
🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
Мы ещё дипломы не получили, а ГБ уже предлагает сменить профессию...
Видео записал одногруппник/подписчик @mssw_wssm
Видео записал одногруппник/подписчик @mssw_wssm
😁7🤡2👀1
AIOgram3 17. Подготовка к разворачиванию на сервере
Автор: Иван Ашихмин
В одном из следующих постов в цикле "Применение Docker" мы с вами будем разворачивать бота на сервере, но перед этим необходимо кое-что подготовить.
Когда мы прописывали токен бота в посте "AIOgram3 3. Основная функция", я упомянул, что хранение в коде секретных данных небезопасно. В данном посте мы исправим это, и я покажу, как правильно передавать секреты в бота.
Переменные окружения.
Автор: Иван Ашихмин
В одном из следующих постов в цикле "Применение Docker" мы с вами будем разворачивать бота на сервере, но перед этим необходимо кое-что подготовить.
Когда мы прописывали токен бота в посте "AIOgram3 3. Основная функция", я упомянул, что хранение в коде секретных данных небезопасно. В данном посте мы исправим это, и я покажу, как правильно передавать секреты в бота.
Переменные окружения.
🔥3👍1
Переменные окружения (environment variables) – это механизм хранения данных, который позволяет хранить конфигурационные параметры вне кода. Они обычно используются для хранения секретной информации, такой, как ключи API, пароли и токены, а также для хранения прочих параметров (пути к файлам, настройки приложения и т.п.).
Для хранения переменных окружения с их значениями мы будем использовать специальный, "скрытый"
Обратите внимание. В системе может быть выключено отображение скрытых файлов.
Для получения данных из переменных окружения в коде будем использовать модуль
Файл .env.
В корневой директории проекта, там, где файл
Откройте рядом файл
Если вы повторяли все посты, то у вас должно быть шесть полей в этом классе:
Создадим в
Должно получиться вот так:
Если вы используете git, то обязательно внесите .env-файл в .gitignore!
Получение данных из окружения и .env-файла.
Когда мы будем разворачивать бота на сервере, все данные из
Это можно сделать вручную, открыв файл и записав значения в словарь, но мне этот подход не нравится. К тому же всё написано до нас. Для чтения локального файла будем использовать библиотеку
Для установки библиотеки необходимо выполнить команду:
После этого добавляем её в файл
Вернёмся к файлу
В самом начале файла, сразу после импортов, вызываем функцию
Переходим к классу
В нём нам необходимо заменить все значения полей на
Обратите внимание! Если тип поля, например, int, то и значение полученное из переменной окружения нужно приводить к этому типу.
Получается так:
Завершение.
На этом подготовка закончена. Теперь на локальной машине секретные данные будут браться из
Для хранения переменных окружения с их значениями мы будем использовать специальный, "скрытый"
.env файл. Название файла именно так и пишется <точка>env, без каких либо расширений. Самый известный пример подобных "скрытых" файлов, это .gitignore.Обратите внимание. В системе может быть выключено отображение скрытых файлов.
Для получения данных из переменных окружения в коде будем использовать модуль
environ из встроенной в Python библиотеки os.Файл .env.
В корневой директории проекта, там, где файл
main.py, создадим .env-файл и откроем его.Откройте рядом файл
settings.py и найдите класс Secrets.Если вы повторяли все посты, то у вас должно быть шесть полей в этом классе:
token, admin_id, group_id, weather_key, audio_key_id, audio_key_secret.Создадим в
.env-файле такие же строки, но в верхнем регистре, т.к. переменные окружения принято прописывать заглавными буквами. После каждой переменной ставим равно = и копируем значение из класса Secrets. Без кавычек.Должно получиться вот так:
TOKEN=ваш_токен
ADMIN_ID=id_администратора
GROUP_ID=id_группы
WEATHER_KEY=токен_погоды
AUDIO_KEY_ID=id_распознавания_голоса
AUDIO_KEY_SECRET=токен_распознавания_голоса
Если вы используете git, то обязательно внесите .env-файл в .gitignore!
Получение данных из окружения и .env-файла.
Когда мы будем разворачивать бота на сервере, все данные из
.env-файла будут переданы внутрь контейнера, а самого его там не будет в целях безопасности. Однако, для работы с .env-файлом на локальной машине, необходимо его прочесть и получить из него данные.Это можно сделать вручную, открыв файл и записав значения в словарь, но мне этот подход не нравится. К тому же всё написано до нас. Для чтения локального файла будем использовать библиотеку
dotenv.Для установки библиотеки необходимо выполнить команду:
pip install python-dotenv
После этого добавляем её в файл
requirements.txt. Он нам понадобится во время разворачивания проекта на сервере.python-dotenv1.0.1
Вернёмся к файлу
settings.py.В самом начале файла, сразу после импортов, вызываем функцию
load_dotenv() для чтения .env-файла.from dotenv import load_dotenv
load_dotenv()
Переходим к классу
Secrets. В нём нам необходимо заменить все значения полей на
os.environ.get(""), где в кавычках указывается переменная окружения.Обратите внимание! Если тип поля, например, int, то и значение полученное из переменной окружения нужно приводить к этому типу.
Получается так:
@dataclass
class Secrets:
token: str = os.environ.get("TOKEN")
admin_id: int = int(os.environ.get("ADMIN_ID"))
group_id: int = int(os.environ.get("GROUP_ID"))
weather_key: str = os.environ.get("WEATHER_KEY")
audio_key_id: str = os.environ.get("AUDIO_KEY_ID")
audio_key_secret: str = os.environ.get("AUDIO_KEY_SECRET")
Завершение.
На этом подготовка закончена. Теперь на локальной машине секретные данные будут браться из
.env-файла, а о том, как это будет работать на сервере, узнаете в следующих постах.👍3🔥3
Файлы к посту, можно получить в боте по коду: 735906
Пост на сайте
Поддержать проект
#Python #Гайды #Telegram #AIOgram #AIOgram3 #бот #Telegram_бот #env #развёртывание #dotenv #environment #deploy
Пост на сайте
Поддержать проект
#Python #Гайды #Telegram #AIOgram #AIOgram3 #бот #Telegram_бот #env #развёртывание #dotenv #environment #deploy
🔥4❤1
Приветствую!
В длинных постах можно запутаться поэтому, собираю воедино всё, что есть на данный момент.
Оглавления:
Для удобства навигации есть посты с оглавлениями по темам:
"Сайт на Django"
"Telegram-бот на AIOgram3"
"Применение Docker"
"Полезные инструменты"
"Путь в IT."
"Код в мешке"
"Boosty эксклюзив"
Ресурсы канала:
Уютный и немного безумный чат канала.
Бот с материалами к постам
Сайт со всеми постами
Канал в Dzen
Сообщество в VK
Поддержка.
Если вам нравится канал и выходящий материал, поделитесь ссылкой с людьми, кому это тоже может быть интересно.
Также поддержать канал можно на Boosty.
Или внеся сайт в исключения вашего блокировщика рекламы.
В длинных постах можно запутаться поэтому, собираю воедино всё, что есть на данный момент.
Оглавления:
Для удобства навигации есть посты с оглавлениями по темам:
"Сайт на Django"
"Telegram-бот на AIOgram3"
"Применение Docker"
"Полезные инструменты"
"Путь в IT."
"Код в мешке"
"Boosty эксклюзив"
Ресурсы канала:
Уютный и немного безумный чат канала.
Бот с материалами к постам
Сайт со всеми постами
Канал в Dzen
Сообщество в VK
Поддержка.
Если вам нравится канал и выходящий материал, поделитесь ссылкой с людьми, кому это тоже может быть интересно.
Также поддержать канал можно на Boosty.
Или внеся сайт в исключения вашего блокировщика рекламы.
🔥3
Разворачивание Django-проекта на PythonAnyWhere
Автор: Иван Ашихмин
Есть несколько сервисов, которые позволяют бесплатно развернуть проекты на Django (и не только).
Их немного и в каждом есть свои ограничения, но они порой бывают полезны, когда собственного сервера нет, но нужно, например, показать результат работы заказчику.
В этом посте мы развернём проект на сервисе PythonAnyWhere.
Адрес сервиса: https://www.pythonanywhere.com
Регистрация в сервисе достаточно простая, нет смысла её описывать. В процессе регистрации осознанно выбирайте
После регистрации обязательно подтвердите электронную почту.
Подготовка проекта.
Перед тем, как приступить к работе с сервисом, необходимо подготовить проект для работы.
Автор: Иван Ашихмин
Есть несколько сервисов, которые позволяют бесплатно развернуть проекты на Django (и не только).
Их немного и в каждом есть свои ограничения, но они порой бывают полезны, когда собственного сервера нет, но нужно, например, показать результат работы заказчику.
В этом посте мы развернём проект на сервисе PythonAnyWhere.
Адрес сервиса: https://www.pythonanywhere.com
Регистрация в сервисе достаточно простая, нет смысла её описывать. В процессе регистрации осознанно выбирайте
username, поскольку именно он будет адресом сайта в интернете.После регистрации обязательно подтвердите электронную почту.
Подготовка проекта.
Перед тем, как приступить к работе с сервисом, необходимо подготовить проект для работы.
👍2❤1🔥1
В корне проекта, рядом с файлом
Также можно воспользоваться командой
Также в корне проекта создайте
Подробнее об этом файле рассказано в посте "AIOgram3 17. Подготовка к разворачиванию на сервере".
Для получения данных из
Установим её командой
Конфигурация настроек.
Откроем файл
В самом начале файла, сразу после импортов, добавляем вызов функции
После переменной
Они нужны для повышения безопасности проекта.
В переменную
Далее перейдём к блоку
Для поддержки
Убедитесь, что STATIC и MEDIA пути у вас верно указаны:
Далее нам нужны следующие переменные:
Заменяем в них значения на
Переменную
Создадим соответствующие переменные в
База данных.
Откроем на сайте раздел
Придумываем пароль и сразу вписываем его в
manage.py, создайте файл requirements.txt, если его нет. Добавьте туда используемые в вашем проекте библиотеки в формате <название_библиотеки><версия>, например, Django5.0.1.Также можно воспользоваться командой
pip freeze > requirements.txt которая соберёт все установленные библиотеки и запишет их в файл.Также в корне проекта создайте
.env-файл. В нём будут храниться секретные данные, такие, как секретный ключ Django, данные для подключения к БД и т.д. Всё, что не следует хранить в коде.Подробнее об этом файле рассказано в посте "AIOgram3 17. Подготовка к разворачиванию на сервере".
Для получения данных из
.env-файла нам потребуется библиотека python-dotenv.Установим её командой
pip install python-dotenv и добавим в requirements.txt.Конфигурация настроек.
Откроем файл
settings.py.В самом начале файла, сразу после импортов, добавляем вызов функции
load_dotenv().from dotenv import load_dotenv
load_dotenv()
После переменной
DEBUG добавим две переменные:SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Они нужны для повышения безопасности проекта.
В переменную
ALLOWED_HOSTS добавляем два адреса: один локальный, второй адрес будущей страницы на сервисе – ["127.0.0.1", "username.pythonanywhere.com"], где вместо username необходимо указать ваш логин в сервисе. Далее перейдём к блоку
DATABASES и заменим его с настроек для sqlite на mysql:DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.getenv("MYSQL_DBNAME"),
"USER": os.getenv("MYSQL_USER"),
"PASSWORD": os.getenv("MYSQL_PASSWORD"),
"HOST": os.getenv("MYSQL_HOST"),
"OPTIONS": {
"init_command": "SET NAMES 'utf8mb4';SET sql_mode = 'STRICT_TRANS_TABLES'",
"charset": "utf8mb4",
},
}
}Для поддержки
MySQL установим библиотеку mysqlclient, выполнив команду pip install mysqlclient. И сразу добавим её в requirements.txt.Убедитесь, что STATIC и MEDIA пути у вас верно указаны:
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "static/"
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media/"
Далее нам нужны следующие переменные:
SECRET_KEY, DEBUG, NAME, USER, PASSWORD, HOST.Заменяем в них значения на
os.environ.get(""), где в кавычках "" указываем имя переменной окружения.Переменную
DEBUG оборачиваем в if-else конструкцию.SECRET_KEY = os.environ.get("SECRET_KEY")
if os.environ.get("DEBUG") == "False":
DEBUG = False
else:
DEBUG = TrueСоздадим соответствующие переменные в
.env-файле в виде <имя_переменной>=<значение>, без кавычек.SECRET_KEY=...
DEBUG=False
MYSQL_DBNAME=...
MYSQL_USER=...
MYSQL_PASSWORD=...
MYSQL_HOST=...
База данных.
Откроем на сайте раздел
Databases. Нам сразу предлагают ввести пароль базы данных. Он должен отличаться от пароля к личному кабинету сервиса.Придумываем пароль и сразу вписываем его в
.env-файл в переменную MYSQL_PASSWORD.👍2🔥1
После того, как будет сконфигурирована БД, откроется страница, на которой в блоке
Ниже в блоке
Далее необходимо изменить кодировку БД с латинской на кириллическую. Для этого в блоке
Должно вывести:
Выходим из консоли, набрав команду
Загрузка файлов на сервер.
Загрузить файлы на сервер можно разными способами, например, опубликовать проект в GitHub или загрузить архив и распаковать его.
Я выбрал вариант с репозиторием на GitHub.
После того, как проект опубликован, на странице раздела
Вводим команду:
Когда скачаются файлы, вводим команду для перехода в директорию проекта:
Создаём и затем активируем виртуальное окружение Python:
Устанавливаем зависимости:
Настройка веб-приложения.
Переходим в раздел
На экране выбора веб-фреймворка нажимаем
После создания веб-приложения мы попадаем на страницу настройки.
Находим раздел
Находим раздел
Раскомментируем все строки, начинающиеся с одного символа решётки
Сразу после импортов добавляем загрузку
Далее в переменной
В месте, где указываем файл настроек проекта
Мой код файла:
Connecting будет две строки: Database host address и Username. Вписываем их в .env-файл в переменные MYSQL_HOST и MYSQL_USER, соответственно.Ниже в блоке
Your databases будет указано имя базы данных в формате <username>$<default>. Копируем и вписываем в переменную MYSQL_DBNAME.Далее необходимо изменить кодировку БД с латинской на кириллическую. Для этого в блоке
Your databases кликаем по имени базы данных и в открывшейся MySQL-консоли вводим, заменив username$default на имя базы данных:ALTER DATABASE username$default CHARACTER SET utf8 COLLATE utf8_general_ci;
Должно вывести:
Query OK, 1 row affected, 2 warnings (0.03 sec)
Выходим из консоли, набрав команду
exit.Загрузка файлов на сервер.
Загрузить файлы на сервер можно разными способами, например, опубликовать проект в GitHub или загрузить архив и распаковать его.
Я выбрал вариант с репозиторием на GitHub.
После того, как проект опубликован, на странице раздела
Consoles выбираем Bash для создания нового терминала.Вводим команду:
git clone <ссылка_на_репозиторий>
Когда скачаются файлы, вводим команду для перехода в директорию проекта:
cd <имя_проекта>
Создаём и затем активируем виртуальное окружение Python:
python3 -m venv venv
source venv/bin/activate
Устанавливаем зависимости:
pip install -r requirements.txt
Настройка веб-приложения.
Переходим в раздел
Web и нажимаем кнопку Add a new web app.На экране выбора веб-фреймворка нажимаем
Manual configuration (including virtualenvs). Далее Python 3.10.После создания веб-приложения мы попадаем на страницу настройки.
Находим раздел
Virtualenv и указываем путь к директории с виртуальным окружением. Если вы в точности повторяли всё, что было указано выше, то он будет таким: /home/<имя_пользователя>/<имя_проекта>/venv.Находим раздел
Code и в нём строку WSGI configuration file. Кликаем по ссылке и попадаем в окно редактирования WSGI-файла. Находим блок # +++++++++++ DJANGO +++++++++++ и удаляем всё, что находится до и после него.Раскомментируем все строки, начинающиеся с одного символа решётки
#.Сразу после импортов добавляем загрузку
.env-файла. Обратите внимание, в этой директории должен находиться .env-файл:from dotenv import load_dotenv
project_folder = os.path.expanduser('~/<имя_проекта>')
load_dotenv(os.path.join(project_folder, '.env'))
Далее в переменной
path указываем полный путь до директории проекта. Обратите внимание, в этой директории должен находиться файл manage.py:path = '/home/<имя_пользователя>/<имя_проекта>'
if path not in sys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE'] = '<имя_проекта>.settings'
## then:
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
В месте, где указываем файл настроек проекта
<имя_проекта>.settings, прописывайте его так, как он указан в вашем файле settings.py в переменной WSGI_APPLICATION - <имя_проекта>.wsgi.application.Мой код файла:
👍2🔥2
# +++++++++++ DJANGO +++++++++++
# To use your own django app use code like this:
import os
import sys
from dotenv import load_dotenv
project_folder = os.path.expanduser('~/temp_project')
load_dotenv(os.path.join(project_folder, '.env'))
path = '/home/proDream/temp_project'
if path not in sys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'pressanybutton.settings'
## then:
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Миграции и статика.
Вернёмся в консоль с активированным виртуальным окружением. Его можно найти в разделе
Consoles. Если закрыли, то откройте снова и активируйте
venv, либо на странице веб-приложения, в разделе Virtualenv нажмите Start a console in this virtualenv.Убеждаемся, что мы находимся в той же директории, что и файл
manage.py, выполнив команду ls. Если нет, то перейдите в нужную директорию командой cd.Выполним команду миграции базы данных:
python manage.py migrate
Создаём суперпользователя командой:
python manage.py createsuperuser
И следом выполняем команду сбора статических файлов:
python manage.py collectstatic
В результате выполнения третьей команды все статические файлы проекта будут собраны в одно место. В консоли будет отображен полный путь до директории со статическими файлами.
Скопируйте его.
На странице веб-приложения находим раздел
Static files.В блок
URL вводим /static/, а в блок Directory - скопированный ранее путь.Если в вашем проекте помимо статики используется ещё и media, укажите директорию и путь.
Завершение.
Остался последний шаг.
В самом верху страницы есть блок
Reload с большой зелёной кнопкой. Нажимаем на неё и ждём несколько секунд.После чего переходим по адресу, указанному над кнопкой
Configuration for ....В результате должна отобразиться главная страница сайта.
Поздравляю, ваш сайт доступен всему интернету по этому адресу.
Файлы к посту, можно получить в боте по коду: 687020
Пост на сайте
Поддержать проект
#Python #Django #Гайды #Разворачивание #Deploy #бесплатный_хостинг #PythonAnyWhere
👍3🔥2
Всем добрейшего вечерочка пятницы!
На связи ваша любимая рубрика "Пятничный кинорелакс". Пришло время отвлечься от дел и немного отдохнуть за просмотром очередного пятничного фильма. В этот раз запасаться вкусняшками советовать не буду. Фильм хоть и комедия, однако в нём есть не очень приятные (на мой взгляд) сцены😁
Фильм: Тяжёлая поездка
Год: 2018
В небольшом финском городке четыре патлатых друга играют тяжелую музыку в подвале дома и по совместительству оленьей фермы одного из них, да так, что олени готовы покончить с собой. Когда проезжавший мимо иностранец оказывается промоутером крупного норвежского метал-фестиваля, и ребята дают ему свою демо-запись, то вся деревня решает, что они — настоящие рок-звёзды. Теперь и гопники, дразнившие наших героев, предлагают вместе выпить.
https://www.kinopoisk.ru/film/1094255/
https://www.sspoisk.ru/film/1094255/
Приятного просмотра
На связи ваша любимая рубрика "Пятничный кинорелакс". Пришло время отвлечься от дел и немного отдохнуть за просмотром очередного пятничного фильма. В этот раз запасаться вкусняшками советовать не буду. Фильм хоть и комедия, однако в нём есть не очень приятные (на мой взгляд) сцены😁
Фильм: Тяжёлая поездка
Год: 2018
В небольшом финском городке четыре патлатых друга играют тяжелую музыку в подвале дома и по совместительству оленьей фермы одного из них, да так, что олени готовы покончить с собой. Когда проезжавший мимо иностранец оказывается промоутером крупного норвежского метал-фестиваля, и ребята дают ему свою демо-запись, то вся деревня решает, что они — настоящие рок-звёзды. Теперь и гопники, дразнившие наших героев, предлагают вместе выпить.
https://www.kinopoisk.ru/film/1094255/
https://www.sspoisk.ru/film/1094255/
Приятного просмотра
🔥2👍1