Чрезмерно сложное планирование питания

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

Раньше мы использовали приложения со списками на наших телефонах для еженедельного планирования питания. Это работает, но немного неудобно. Я подумал, что самое время создать сверхинженерное техническое решение для бытовой «проблемы».

План

(Моя партнерша не умеет программировать ни на R, ни на python, но она очень талантлива в электронных таблицах. Так что google sheets может стать полезным интерфейсом для упрощения планирования питания, которым можно легко поделиться).

Вот план:

  • Создайте лист google
  • В этом гугл-листе создать рабочий лист (я думаю, так они называют эти вкладки), который будет содержать все рецепты (мастер-лист)
  • Создать рабочий лист, который будет планом на неделю, в котором мы будем ссылаться на мастер-лист
  • создать процесс, который будет забирать план на неделю, проверять его и записывать его в нужные даты в моем личном календаре.

Я собираюсь использовать dagster, потому что это то, с чем я хочу работать. Я только что установил его на запасной raspberry pi, который валялся у меня без дела, а база данных находится на моем NAS (сетевом хранилище). Эту комбинацию я называю «стеком данных Смолла» (это каламбур, основанный на «современном стеке данных», который представляет собой облачную базу данных, dbt и современные коннекторы).

Детали

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

В моем рабочем листе для планирования на неделю есть колонка для дня недели (потому что я ужасно люблю даты без контекста), колонка даты и колонка ID. Есть также столбцы для названия, описания, ссылки и т.д. из основного списка, но они указывают обратно на основной список.

Идеализированный дизайн

Итак, на практике история пользователя выглядит следующим образом:

Как ___, я хочу ____ по ___, чтобы

Будучи технически подкованным инженером данных, у которого слишком много свободного времени, я хочу оптимизировать свою стратегию планирования питания, выбирая блюда из основного списка и добавляя эти идентификаторы в столбец, чтобы блюда появлялись в моем домашнем календаре.

Я думал, что это будет просто, если я буду использовать комбинацию ID дат для планирования блюд.

Совершенство — враг добра, поэтому позвольте мне набросать минимальный жизнеспособный продукт (MVP), дальнейшие улучшения и продвинутую версию. Это важно, потому что уже то, что минимальная вещь работает, экономит мне время и приносит радость. В своей работе я фокусируюсь на бизнес-ценности MVP, на таких вещах, как: «это экономит нам деньги», «это экономит нам время», «это делает то, что мы не могли сделать раньше».

Минимальный жизнеспособный продукт: Я заполняю даты и идентификаторы: дата: 2022-04-27, ID: 32 (допустим, 32 относится к блюду: pannenkoeken).

В отдельном календаре google ‘meals’ будет новое событие в 1830 2022-04-27 с названием ‘pannenkoeken’ В этом минимальном жизнеспособном продукте задание будет выполняться каждый день и не будет делать никаких проверок.

Более надежный продукт : будет проверять каждый день, был ли изменен рабочий лист, будет проверять даты, сравнивать с текущей датой и выполнять модификацию только для дат, начиная с сегодняшней, и, возможно, только на 2 недели вперед. Защита от идентификаторов, которые ссылаются на несуществующие рецепты. Проверяет, действительно ли даты относятся к дням недель, которые я указал слева от них.

Еще более продвинутая версия Суммирует недельные пищевые ценности (но для этого мне нужно заполнить все значения). Сравнивает недельные значения питательных веществ с целями. Может делать предложения по питанию. Может быть, еще одна работа по обновлению мастер-листа?

Фактический дизайн

  • Ежедневное задание dagster, которое забирает значения из листа.
  • Календарь google (отдельный календарь, чтобы я не мог уничтожить другие календари)
  • лист google

Вот как я использую это в работе.

([0] sensor for changes in sheet?) => [1] download planningsheet values, turn into dataframe
[1] => [2] check values and cleanup
[2] => [3] write individual events to calendar
[2] => [4] write to table in database

Вход в полноэкранный режим Выйти из полноэкранного режима
  • [0] — опционально, было бы неплохо в будущем, чтобы задание срабатывало только при необходимости, а не каждый день и не каждый день.
  • [1] подключаемся к API google sheets и получаем все значения из листа еженедельного планирования, превращаем в dataframe
  • [2] проверка значений в датафрейме, очистка данных
  • [3] запись в календарь
  • [4] запись в базу данных (опционально)

Соображения по дизайну

У меня любовь-ненависть с google sheets или excel файлами, они очень гибкие, но также дают много возможностей. Но я предвижу, что буду больше использовать google sheets. Поэтому может быть полезно сделать более общий оператор для google sheets и выполнять конкретные задачи с полученным датафреймом.

Также о листах: из-за их гибкости вам действительно следует проверять данные, прежде чем что-то с ними делать! Интеграция Pandera в dagster действительно хороша для такой проверки (но я не могу заставить ее работать на этой машине).

Я также предвижу, что буду чаще использовать календарь google, поэтому более общие операторы здесь тоже хорошая идея.

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

Фактическая работа

продвижение задания в git-снимках:

  • ссылка на файл задания в момент создания
  • ссылка на файл с проверкой pandera и работающей записью в google календарь
# import dagster stuff
# import operator for reading sheets
# import functions for writing to gcalender
# operator that cleans dataframe of sheetdata
# operator that can write events to gcalendar
# jobconfig for operators
# actual job

Вход в полноэкранный режим Выход из полноэкранного режима

Я не сделал скриншот, когда задание было в таком состоянии, но вот дальнейшее развитие задания, видимое в gui:

фактический код на python

# this looks much better on my own site, it seems DEV messes up the indentation, kind of important for python...
import pandas as pd
from dagster import op, job, Out
from ops.gsheets import get_sheet_data
from ops.gcalendar import insert_event, create_event_dict
import zoneinfo
import datetime
@op
def cleanup_recipes(df: pd.DataFrame) -> pd.DataFrame:
    """A helper operator to clean up this sheet.
    The get_sheet_data operator is generic and doesn't care
    about what it gets. But I know the design of this sheet         and so
 I can do some cleaning.
 Because google sheets can change I think it is wise to check
 the schema after modification."""
    # first row in this case is names.
    df.columns = df.iloc[0]
    # drop the first row (is already the header).
    df = df.iloc[1:, :]
    # drop rows without a date filled in (it is not NA (missing) but empty)
    df = df[df.datum != ""]
    # drop rows without ID
    df = df[df.ID != ""]
    # set the datum row to dates -type?
    # TODO: guard against changes in the past
    # TODO: guard against changes more than 14 days in the future
    return df

@op(config_schema={"calendar_id":str})
def insert_recipes_into_gcal(context,df:pd.DataFrame) -> None:
    """Parse dataframe and send every recipe as event to google calendar"""
    # take 'datum' and make that into start and end datetime
    # fix time at 18:30-19:30
    tz=zoneinfo.ZoneInfo('Europe/Amsterdam')
    #
    for row in df.itertuples(index=False):
        context.log.info(f"writing {row.datum}")
        date_ = datetime.date.fromisoformat(row.datum)
        startdatetime=datetime.datetime.combine(
date_, datetime.time(18,30,tzinfo=tz),
        )
    enddatetime=datetime.datetime.combine(
    date_, datetime.time(19,30,tzinfo=tz),
    )
    dict = create_event_dict(
        startdatetime=startdatetime,
        enddatetime=enddatetime,
        title=row.maaltijdnaam,
        description=f"{row.omschrijving}, type: {row.type}, link {row.link} ",
        )
        insert_event(calendar_id=context.op_config["calendar_id"],event_dict=dict)

@job(
    config={
        "ops": {
    "get_sheet_data": {
    "config": {
    "sheetid": "1bTFbQTY6869y52kyr48DlcHsN7FnUWyxBfuL5XLVRWI",
    "sheetnumber": 0,
    }
    },
    "insert_recipes_into_gcal":{
    "config":{
    "calendar_id" :     "447883an888q1ldagsqe9pj7ts@group.calendar.google.com"
    }
    }
    }
    }
)
def recept_2_calender():
"""Read recepten from google sheet and write to calender"""
    future_recipes_df = get_sheet_data()
    cleaned_recipes = cleanup_recipes(future_recipes_df)
    insert_recipes_into_gcal(cleaned_recipes)

Вход в полноэкранный режим Выход из полноэкранного режима

Заключение

И вот он, чрезмерно сложный, чрезмерно продуманный технический MVP для решения бытовой задачи.

Замечания и недочеты

  • служебные аккаунты и календари в google — это все выделенные адреса электронной почты.

функциональность календаря google

Чтобы понять, как записать событие в календарь, потребовалось довольно много времени. Есть несколько руководств, но, как всегда в случае с google docs, не всегда можно найти то, что ищешь.

Попытки

  • необходимо включить google calendar в console.google.com
  • Логика аутентификации с помощью учетной записи службы не показана в кратком руководстве.
  • необходимо включить доступ к календарю в консоли
  • необходимо пригласить учетную запись службы в календарь google (иначе учетная запись не будет видеть календари).

Google листы

Проблемы

  • необходимо включить доступ к Google sheets в console.google.com
  • необходимо предоставить общий доступ к листу служебной учетной записи
  • значения в листах могут иметь лишние пробелы до и после, поэтому обязательно обрезайте их перед дальнейшей обработкой

Оцените статью
Procodings.ru
Добавить комментарий