Практические уроки

Создание веб-приложения для отслеживания настроения Flask-Heroku с использованием API Spotify

Проект A-Z для создания оценок настроения на основе песен, которые я слушаю каждый день, и соответствующего окрашивания моего онлайн-трекера настроения.

Обновление от апреля 2023 г.: Heroku больше не предоставляет бесплатный динамометр, поэтому мой веб-сайт в настоящее время не может быть загружен. Тем не менее, приведенный ниже учебник по-прежнему актуален, и если вы решите приобрести план динамометра самостоятельно, вы увидите результат!

Вот краткий обзор окончательного результата!

Ведение буллет-джорнала (или… буджо) — одно из моих главных увлечений. Просматривая сотни учетных записей bujo в Instagram, я больше всего каждый месяц жду появления шаблона трекера настроения артистов bujo. Эти красочные коллажи настроений легли в основу этого моего проекта. Когда я разрабатывал трекер настроения в следующем месяце, мне пришла в голову мысль, что было бы здорово иметь систему, которая автоматически определяет наше настроение и помогает нам заполнять ячейки каждый день.

Хорошо, и… данные?

Музыка всегда была важной составляющей моей повседневной жизни. Связь моей музыки с моим настроением, как правило, линейна: я слушаю оптимистичные песни, когда я счастлив, песни-баллады, когда мне грустно, и исцеляющие ритмы, когда я в стрессе. Таким образом, я решил использовать песни, которые я слушал на Spotify, особенно их атрибуты, предоставленные через API, такие как акустика, танцевальность и т. Д., В качестве индикаторов уровня счастья песни, а затем и моего общего настроения.

Обдумав общую идею проекта, я начал составлять чек-лист компонентов пайплайнов, выясняя порядок выполнения задач и способы решения каждой из них. Изображение ниже представляет собой документацию моего мыслительного процесса и моего плана/прогресса разработки для каждого этапа:

Героку

Heroku — это облачная платформа, которая предлагает бесплатный вариант базового хостинга веб-приложения, поэтому она подходит для небольшого личного проекта. Все, что нам нужно, это аккаунт!

После регистрации перейдите в свою личную панель управления и нажмите «Создать», чтобы создать новое приложение (мое приложение называется «Журнал настроения»). Перейдите в свое приложение и в разделе «Развертывание» выберите Heroku Git в качестве «метода развертывания» и выполните шаги, перечисленные ниже, чтобы клонировать ваш проект (в настоящее время пустой) в вашу локальную рабочую среду. Мы собираемся добавить файлы в эту папку и впоследствии внести изменения. С этим, давайте начнем работу над проектом!

Определяемся с моделью

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

Как упоминалось выше, мой уровень счастья определяется тем, насколько радостно звучит песня. Таким образом, мне нужен алгоритм, который присваивает более высокую оценку песням с более радостной атмосферой и более низкую оценку в противном случае. K-Means, неконтролируемый метод, часто используемый для анализа песен, группирует песни по их сходству, но это бесполезно для моей задачи, поскольку я уже имею в виду две категории. Модель глубокого обучения для анализа текстов также была вариантом, но предложения в песнях, как правило, короткие, повторяющиеся и имеют скрытый смысл. Кроме того, текст не является основным фактором, определяющим, когда я слушаю песню, а ритм.

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

Обучите модель логистической регрессии

Из тренировочных данных…

Особая благодарность Седжалу Дуа за подробное руководство по извлечению песен с помощью API Spotify за то, что эта задача стала проще, чем когда-либо! Программа Седжал принимает список идентификаторов списков воспроизведения Spotify и возвращает кадр данных со всеми атрибутами песен, готовый к использованию для обучения модели. Я добавил в эту функцию сделанные Spotify веселые компиляции (Mood Booster, Happy Beats и т. д.) и грустные компиляции (грустный час, жизнь — отстой и т. д.) — те, которые содержали очень репрезентативные песни этого класса. Полный набор составил около 1000 песен.

Я обучил модель с перекрестной проверкой, благодаря которой она достигла точности 0,89! Я также использовал predict_proba в личном плейлисте, содержащем как грустные, так и веселые песни, и вероятностные оценки, назначенные моделью песням, довольно хорошо отражали уровень счастья каждой из них. Затем модель была подготовлена ​​для использования в нашем приложении.

import pickle
pickle.dump(lr, open("deploy_model.sav", 'wb'))

… к предсказанию

Чтобы делать прогнозы, мне нужно было получить все песни, которые я слушаю за день. Из всех функций, предлагаемых API Spotify, функция current_user_recent_played наиболее близка к достижению наших целевых результатов. Однако он ограничен возвратом последних 50 песен за один вызов. Так что мне пришлось написать небольшую программу для очистки всех песен за последние 24 часа (иллюстрацию того, как это работает, можно также найти в моей рукописной заметке).

Всякий раз, когда я вызывал эту функцию, помимо всех треков, она также возвращала курсор, который сообщал мне временную метку 50-й песни, которую я прослушал (в миллисекундах). Например, если я прослушал 120 песен за последние 24 часа, то 50-я самая последняя песня была, скажем, 5 часов назад. Идея заключалась в том, чтобы получить пакет из 50 песен за раз, извлечь этот курсор, установить начальную точку для этого курсора и начать сначала, чтобы получить следующие 50 песен. Процесс остановился, как только курсор пакета, который я получил, превысил 24-часовую отметку. В этот момент мне пришлось бы вызывать функцию get_right_limit(), которая определяла количество песен, которые я прослушал с момента последнего курсора, не прошедшего 24-часовую отметку. Фрагмент кода ниже:

Функция получения лимита выглядит следующим образом:

После того, как я получил все песни, осталось извлечь особенности этих песен, точно так же, как я сделал это в предыдущем разделе. После этого я загрузил маринованную модель с помощью pickle.load() и использовал predict_proba для получения оценок, которые я добавлял к нашему фрейму данных в виде столбца под названием «предсказание». ”:

mixed = get_features_for_playlist2(mixed, curr_time, curr_time - 86400000) # 86400000 is 1 day in millis
lr = pickle.load(open('models/deploy_model.sav', 'rb'))
vnpred = lr.predict_proba(mixed.drop(['name', 'artist','track_URI'], axis=1))[:,1]
mixed.insert(3, 'prediction', vnpred)
# take the median score
day_median = float(median(mixed['prediction']))

Сохранение результатов

Мне также требовалось средство хранения, которое обновлялось бы при запуске вышеуказанной программы и из которого приложение Flask могло бы легко извлекать и использовать результаты. Здесь я использовал таблицу SQL. Код для хранения и обновления результатов каждый день:

Стоит отметить, что мне пришлось создать таблицу с 31 строкой, так как приложение Flask будет извлекать все 31 значение для поиска цветов для графика. Все значения в таблице были инициализированы 0. Всякий раз, когда мы переходили к новому месяцу, таблица сбрасывалась: все старые значения очищались и заменялись 0.

На Flask и Heroku!

Среда колбы

Если вы раньше не использовали Flask, вот краткое и полезное руководство по установке и началу работы! Список всех необходимых файлов для нашего фляжного приложения можно найти в моем планировщике выше.

Кроме того, чтобы отправить ваше приложение на Heroku, я предлагаю использовать pipenv — инструмент для создания виртуальной среды — поскольку он хорошо справляется с блокировкой всех необходимых зависимых библиотек для вашего приложения (и доставляет мне меньше проблем, чем использование файла requirements.txt). !). Чтобы использовать его, используйте pip install pipenv, затем введите оболочку pipenv, чтобы активировать среду. В этой среде выполните pipenv install [list of package_name], чтобы установить пакеты, необходимые для вашей программы. Наконец, заблокируйте конвейер после установки, чтобы заблокировать все эти требования для своего приложения. Вам нужно будет ввести эту команду еще раз, если вы устанавливаете какие-либо дополнительные пакеты, прежде чем отправлять приложение в Heroku, иначе развертывание выдаст вам ошибки, говорящие о том, что таких модулей нет.

SQL ‹-› Flask (app.py)

Теперь, когда у меня были готовые результаты, сохраненные в schema.sql, я начал загружать их в свое приложение Flask. В app.py для легкого извлечения информации из таблицы я использовал пакет под названием Flask-SQLAlchemy. Прежде всего, мне нужно было создать движок и объявить модель со следующим синтаксисом:

app.py ‹-› main.html ‹-› javascript

Файл main.html в папке templates используется нашим приложением Flask для создания интерфейса веб-сайта. Но чтобы рисовать фигуры и настраивать цвета, нам нужны Javascript и CSS. Flask требует, чтобы мы помещали файлы .js и .css в другую папку, называемую статической. Я использовал Canvas API Javascript и пакет rainbowVis для создания рисунков. На этом этапе потребовалось много проб и ошибок, прежде чем были получены конечные продукты, но это была и самая интересная часть. Пакет RainbowVis предоставляет инструмент для создания массива шестнадцатеричных чисел, представляющих градиент из 1000 цветов от синего (= печальный) до зеленого (= нейтральный) и желтого (= счастливый). Идея состоит в том, чтобы округлить оценки настроения до 3 знаков после запятой, умножить их на 1000 и получить шестнадцатеричный цвет в этом индексе.

Поэтому мне пришлось передавать баллы из app.py в html-файл в javascript-файл. После раунда гугления я придумал решение:

  • Чтобы передать оценки из app.py в main.html, я использовал функции Flask-SQLAlchemy для запроса оценки или столбца «результаты» и передал их в html в виде массива через рендер_шаблон(). Я поместил эту функцию в маршрут по умолчанию, так как хотел, чтобы рисунки отображались сразу, когда мы посещаем главную страницу.
@app.route('/', methods=['GET'])
def main():
    table = Mood.query.with_entities(Mood.results).all()
    table = [r for r, in table]
    # table is currently storing the mood scores
    return render_template('main.html', results = table)
  • Счета теперь хранятся в html в массиве под названием results. Чтобы получить информацию в массиве, мы должны использовать двойные фигурные скобки. Мы можем использовать console.log({{results}}), чтобы убедиться, что массив успешно передан.
  • Чтобы передать результаты из main.html в canvas.js, я обернул коды из canvas.js в функцию с именем draw(), которая принимала один аргумент: массив значений. Внутри HTML я вызвал функцию draw() и передал ей таблицу оценок настроения. Код выглядит следующим образом. Обратите внимание, что синтаксис HTML-файла для Flask немного отличается от обычного HTML-файла для включения src и href.
  • Теперь внутри canvas.js вы можете получить доступ к значениям в результатах с помощью обычной индексации массива!

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

Фляга ‹-› Героку

Следуя следующим шагам в разделе Развертывание, добавьте, зафиксируйте и отправьте наши файлы в Heroku (не забудьте заблокировать pipenv перед выполнением этого шага). Ваш терминал должен показать что-то вроде этого:

И если вы перейдете по URL-адресу, он должен показать точное состояние, которое было видно в приложении Flask, размещенном локально на вашем компьютере, когда вы запускаете flask. Вуаля!

График работы каждый день:

Самый последний шаг — автоматизировать программу, чтобы она запускалась в конце каждого дня, и соответствующим образом обновлять график. Для этого я написал скрипт crontab, который запускал clock.py каждую ночь в 23:59, чтобы обновить таблицу SQL с новой оценкой за этот день, а затем повторно отправил весь проект в Heroku.

Обратите внимание, что для правильной работы crontab в macOS вам необходимо разрешить ему использование ваших локальных папок. Перейдите в «Системные настройки» -> «Безопасность и конфиденциальность» -> «Полный доступ к диску». Нажмите на замок ниже, чтобы разрешить внесение изменений. Нажмите на знак «+», затем перейдите по пути «/usr/sbin/cron». Установите флажок для cron, снова нажмите на замок, чтобы зафиксировать изменения. И все готово.

Введите crontab -e, чтобы начать запись сценария crontab:

59 23 * * * cd /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling && /opt/anaconda3/bin/python /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling/clock.py && /usr/local/bin/git add /Users/irenechang/Desktop/PORTFOLIO/Fall2021/mood-journaling/. && /usr/local/bin/git commit -m "commits" && /usr/local/bin/git push heroku HEAD:master

Готово! Наша программа настроена на ежедневное обновление!

Выводы:

Это был забавный и интересный проект ML от идеи до развертывания, который я начал с целью получить практический опыт работы с Heroku и Flask, а также ознакомиться с работой над конвейером AZ модели науки о данных. Надеюсь, вам понравится понимание вашего повседневного настроения, которое этот онлайн-журнал раскрывает так же много, как и я. Кроме того, я надеюсь, что это даст вам полезное руководство для вашего личного проекта, особенно когда речь идет о развертывании модели и выяснении связей между несколькими различными элементами.

Большое спасибо за чтение! Мои коды можно найти в этом репозитории! Не стесняйтесь обращаться ко мне за любыми идеями или отзывами через мой LinkedIn, я буду рад связаться!

Использованная литература: