Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blueprint: generate an Ingredient database #135

Open
Mannshoch opened this issue Jan 10, 2020 · 16 comments
Open

Blueprint: generate an Ingredient database #135

Mannshoch opened this issue Jan 10, 2020 · 16 comments
Labels
enhancement New feature or request

Comments

@Mannshoch
Copy link

Mannshoch commented Jan 10, 2020

Generate an Ingredient Database based on the recipe. Allow to enhance the Data about the Ingredient.

eg.
Toast Hawaii -> Ingredient: Toast, Ananas, Ham

Now you could enhance it with Data.

  • Toast:
    • Brand: XX
      • Barcode: xxx
      • Price: XX.XX
      • split: 12
        • weight of 1: XXg
  • Pineapple:
    • Also known as: Ananas
    • Brand: XX
      • Description: One whole Pineapple
      • Barcode: xxx
      • Price: XX.XX
      • split: 10 / manual
      • weight: XXg
  • Boiled Ham
    • Brand: XX
      • Barcode: xxx
      • Price: XX.XX
      • split: 7
        • weight of 1: XXg

At the end you could calculate the material cost per meal. #116
You may connect to https://world.openfoodfacts.org/data to get additional Data.
You may search a meal by Ingredients or filter by allergies.
You may send a set of Ingredients to Nextcloud Tasks for a Shopping-list #127 #11

@gruessung
Copy link

+1

@mrzapp
Copy link
Contributor

mrzapp commented Jan 27, 2020

I support this. We could use the HowToSupply model, if I'm reading it right.

@mrzapp mrzapp self-assigned this Jan 27, 2020
@mrzapp mrzapp added the enhancement New feature or request label Jan 27, 2020
@mrzapp mrzapp added this to To do in NextCloud app via automation Jan 27, 2020
@mrzapp mrzapp added this to the v0.7.0 milestone Jan 27, 2020
@mrzapp mrzapp modified the milestones: v0.7.0, v0.8.0 Mar 27, 2020
@mrzapp mrzapp moved this from To do to Backlog in NextCloud app May 4, 2020
@mrzapp mrzapp moved this from Backlog to To do in NextCloud app Jun 7, 2020
@mrzapp mrzapp moved this from To do to Backlog in NextCloud app Jul 3, 2020
@obbardc
Copy link

obbardc commented Jul 23, 2020

meal planning and a shopping list would be great :-)

@seyfeb
Copy link
Collaborator

seyfeb commented Aug 26, 2020

I’m not sure if such a detailed database is necessary (like differentiating between different brands selling pineapples). But I’d really like to have some auto-fill option / maybe searchable dropdown list for ingredients for (a) faster editing and (b) a unified ingredient style.

@Mannshoch
Copy link
Author

Necessary may not in every case. And the development in this direction would need some time, I know.

It would be great if the developers could hold this idea in mind while they develop this great app.They have her an app with a great potential.

@christianlupus
Copy link
Collaborator

Ok, let's be a bit fancy here. I get your point when typing in the recipes manually.

How would you want the app to behave when importing a URL? The URL will have something like 100g of ham in its ingredient list. How should we map that to the database?
Or do you suggest just to add the ham to the database now and wait for the user to supply the reminding information like description, barcode, ...?

In the recipes we cannot link it back to the ingredients. The recipes are stored in a JSON file that is compatible with the standard form given by https://schema.org/Recipe. It would therefore not be 100% compatible.

Do not get me wrong here: I am not saying this is impossible at all to create a database but first we/I need to know what you have in your mind and then check if this is realizable and what are the cost of if (in terms of functionality).

@Mannshoch
Copy link
Author

Or do you suggest just to add the ham to the database now and wait for the user to supply the reminding information like description, barcode, ...?
yes.

If someone creates an ingredient with the name or alias "ham" cookbook should detect the word and recognize it as ingredient "ham".

The recipes are stored in a JSON file that is compatible with the standard form...

If I understand it right, this JSON are the database and not an export of the database stored in Nextcloud?

In my mind I see also/alternatively the possibility to edit a recipe, select a word like "ham", and get a dropdown list of ingredients and have, either the possibility to create a new one or replace it with one in the database.

@christianlupus
Copy link
Collaborator

If someone creates an ingredient with the name or alias "ham" cookbook should detect the word and recognize it as ingredient "ham".

The recognize is the tricky part. I have read people use machine learning to extract that from the text.... We will see what we can do about it.

If I understand it right, this JSON are the database and not an export of the database stored in Nextcloud?

Not really.
The recipes are formatted such that a "special pattern" is inside the HTML. This pattern is invisible to the user (only some attributes) but a parser can make sense of it (see semantic web).

The JSON is just an except of this meta information that is easily parsable for a machine. Each recipe is saved as a single file withing the nextcloud. Additional files like images are downloaded as well and everything is packed up and stored in one folder.

So far there was no database involved (except for the management of the NC's files). To allow for quick search and organization, these JSON files are once more parsed and cached in the main database. This allows to use the database whenever a quick operation is needed (page reload) but the whole data is saved in the JSON files. So if you just throw away the database and reread the JSON files from a backup everything is back on track.

In my mind I see also/alternatively the possibility to edit a recipe, select a word like "ham", and get a dropdown list of ingredients and have, either the possibility to create a new one or replace it with one in the database.

For the manual inserting I am full with you. There a dropdown of something similar might be very useful. The biggest problem is the automatic import from a URL (which is most probably the more common case btw).

@mrzapp mrzapp removed their assignment Sep 24, 2020
@Mannshoch
Copy link
Author

If someone creates an ingredient with the name or alias "ham" cookbook should detect the word and recognize it as ingredient "ham".

The recognize is the tricky part. I have read people use machine learning to extract that from the text.... We will see what we can do about it.

I'm not sure If I understand it right. Why do you see a need for machine learning to be able to recognizing e.g. "ham" in a Text?

Why do you not save the recipes into the NC Database if the JSON is a limitation for some enhancement?

@christianlupus
Copy link
Collaborator

I'm not sure If I understand it right. Why do you see a need for machine learning to be able to recognizing e.g. "ham" in a Text?

Because the text in the imported (!) JSON is not structured. It could read like 100g of roasted ham (cold from fridge) or bacon or a knive's tip of salt. We have to split the amount (or your ingredient db would have entries for all amounts you could think of) and potentially parse the text further.

If it was structured this was much easier in the first step because the amount would be clear at least. Still, this is not well-defined due to synonyms, trademarks in the ingredient's name or other semantic. A human can understand this easily but parsing requires quite some work. I just want to outline this comment that describes a shortcoming of schema.org standard and the concrete usage of a neuronal network to parse exactly that sort of data.

Why do you not save the recipes into the NC Database if the JSON is a limitation for some enhancement?

This has multiple reasons:

  1. The JSON file is sort of a backup.
  2. The data is not thereat all when importing. Once we can parse it, we can save it but use it as well.

@fab920
Copy link

fab920 commented Sep 24, 2020

@christianlupus
Copy link
Collaborator

christianlupus commented Sep 25, 2020

Just as pointed out in the section takeaway of the first link you provided:

The recipe parser, which combines machine learning with our huge archive of labeled data, takes a first step towards solving this important problem [of extracting structured information].

Unfortunately, the two provided projects run in python and a bit of ruby which is not PHP as we use in NC. Also we have no training data at the moment (which would be highly language-dependent). All in all I see the problem to solve the parsing as a whole separate point that might need to be addressed later.

For now I see the priority to have a UI representation (especially for the editing part) and a backend storage implementation. To stick with the credo of JSON files as data storage and DB as cache, I see multiple ways:

  1. We get the schema.org standard to be changed to allow more structured definitions for the ingredients. There are similar issues with Support for ingredient grouping #311. Then we can save the data at least partly in the json file itself.
  2. Adding a mapping file into each recipe folder. This would map between each ingredient and the corresponding structured represenation.
    The list of possible ingredients could be DB only (better performance) or in a JSON (?) file in the root of the recipe folder. That would stick with the credo but require to handle a JSON database potentially. Maybe other structures might be working as well.

Here I am open for discussion. Once we have the backend store the data and the frontend show the data, we can consider how to insert it (last resort: manual typing).

@Luegengladiator
Copy link

There is an "old" project phprecipebook (https://github.com/nazgul26/PHPRecipebook) with a "self-filling" ingredient database on the background. It's not that detailed, but for the recipe it doesn't matter whether the ham is from trader a or b. This information is only neccessary for shoping.

@christianlupus christianlupus modified the milestones: v0.8.0, v0.9.0 Feb 14, 2021
@CyberFoxar
Copy link

I feel like an ingredient database could be generated if the https://schema.org/Recipe actually uses the supply and https://schema.org/HowToSupply from the parent object.

Cookbook might then try to convert recipeIngredient to proper HowToSupply. The issue is in parsing correctly the free-form text field.

The UI might offer this functionality, maybe offer a button to "convert" a field from a free-form to structured field. This would replace the free-form input with a set of inputs pre-filled with the information a parser would have extracted from it. The user can then easily correct errors.

Cookbook could maintain a database of "known HowToSupply", but stored as a list of https://schema.org/Thing. This database can then be referenced when a user add a recipe, so that the same "thing" is referenced. A UI element like a searchable dropdown would be a good candidate.

@christianlupus christianlupus added this to To do in UI rework via automation Oct 31, 2023
@seyfeb
Copy link
Collaborator

seyfeb commented Nov 2, 2023

Let me try to summarize and extend on the ideas in this thread and add an example of how it might be done.

I think we agreed on the fact that it might be helpful to have structured ingredients (amount, unit, name, ...) for the ingredients. As mentioned in schemaorg/schemaorg#882 one idea to give ingredients more structure is to use HowToSupply objects in the supply property of the Recipe. HowToSupply can have a QuantitativeValue for indicating the amount of an ingredient and a name, etc.

The schema.org properties I have in mind are listed below. Properties which I think should be stored with the recipe as a fallback but should be overwritten with data from the database when the JSON is delivered from the API. This would ensure names and prices getting updated in the database to cover all ingredients with the same identifier.

HowToSupply

  • identifier: A unique id for the ingredient
  • estimatedCost*: Can be used for calculating the total cost of a recipe.
  • requiredQuantity: The amount required for the recipe
  • position: Indicates the position in the list ingredients
  • name*: The name of the ingredient in singular ("tomato", "Oyster sauce", "salt")
  • description: An additional description of the ingredient for the particular recipe ("in dices", "minced", "heated to 70 °C")

QuantitativeValue

Units

I have the feeling that a database for the units might be necessary as well, but I'm not clear on that, yet. I would suggest to add some units commonly used in recipes by default, such as those listed below (to be extended or reduced). With a database one could define conversions between units (where available), and add new units that are not available by default. An easier solution would be to fall back to the unitText property such as for the clove of garlic as in the JSON example at the end.

Weight

  • mg, g, kg
  • pound (lb)
  • ounce (oz)

Volume

  • ml, cl, dl, l
  • cup
  • tablespoons (tbsp) and teaspoons (tsp)
  • fl oz (??)
  • dash
  • pinch

Amount

  • package
  • pieces/units?
  • sprig
  • clove
  • head
  • leaf
  • sheet
  • slice
  • cube

User flow for importing a recipe

Case: No supply field set or empty

In this case the ingredients will be available as the recipeIngredient property.

  1. Start import
  2. Ask User if he wants to map ingredients from the database
    3.a Case "yes":
    3.a.1 Show suggestions for database ingredients* based on the recipeIngredient elements in an autofill element
    3.a.2 User can choose to update wrong elements
    3.a.3 If ingredient is not in database, user may create new ingredient or leave it as a text item which is not available in database
    3.b Case "no":
    3.b.1 Ingredients are kept as text elements with no reference to database items

Case: supply field set

  1. Start import
  2. Ask User if he wants to map ingredients from the database
    3.a Case "yes":
    3.a.1 Show suggestions for database ingredients based on the supply and recipeIngredient elements in an autofill element
    3.a.2 User can choose to update wrong elements
    3.a.3 If ingredient is not in database, user may create new ingredient or leave it as a text item which is not available in database
    3.b Case "no":
    3.b.1 Ingredients are kept as text elements with no reference to database items but in the supply property. recipeIngredient is empty.

* Matching the ingredients

To match ingredients of a recipe with database ingredients I would suggest to look at the amount, unit, ingredient name, and any description separately.

  1. Add any number to value field (amount)
  2. Do some fuzzy matching for the unit with known units (and their alternative names)
  3. Do some fuzzy matching for the ingredient name with ingredients available in the database
  4. Compare commonly used terms for description
  5. Leave checking and correcting to the user

Managing ingredients

There should be a dedicated user interface to manage all ingredients. This should allow renaming and updating prices. Things to consider could be sth. like setting allowed units and checking if any recipes use the ingredient before allowing to delete it.

The base ingredients should be stored in the database for fast access. They should be referenced by their id from the respective recipes. When the data (name, etc.) is stored in the recipes' JSON, the files act as a backup of the ingredient database. It might be necessary then to update the JSON files with the current state of the database, e.g., each time the recipe is requested and store an additinal property for the last changed timestamp to know which was the last state of the database when restoring the database from files.

Example JSON

In the example below I show a non-complete (in the sense that you should not try to cook it) recipe for a lasagna as an example for the ideas above. I left out the dates, nutrition, etc. which are not important for the ideas here, but should obviously still be supported. I'm reusing the one I also had in #1874 .

I used the supply property for listing ingredients, as proposed here schemaorg/schemaorg#882.

Short version of JSON
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "Recipe",
  "name": "Delicious Lasagna",
  // ...
  "recipeIngredient": [],
  "supply": [
    {
      "@type": "HowToSupply",
      "identifier": "37d8e801-13fe-4ce9-ba93-6b8a35e6646f",
      "name": "ground beef",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "kilogram",
        "unitCode": "KGM"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "887ab19e-97be-43b1-bf20-b423b38eda5a",
      "name": "onion",
      "description": "diced",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "cup",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "5bea667a-344a-44e9-a842-b6187e95b702",
      "description": "minced",
      "name": "garlic",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 2,
        "unitText": "clove"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "f0a77778-5292-4bf4-8be2-4541a1cbd6ee",
      "name": "ricotta cheese",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 2,
        "unitText": "cups",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "ce0388ac-617f-4a15-9273-9ba805bf7523",
      "name": "shredded mozzarella cheese",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "cup",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "4563b9e4-460b-4325-96f2-9fc5ef349e81",
      "name": "salt",
      "description": "to taste"
    },
    {
      "@type": "HowToSupply",
      "identifier": "6811be83-8282-4851-bb88-749b3be727af",
      "name": "pepper",
      "description": "to taste"
    },
    {
      "@type": "HowToSupply",
      "identifier": "f16704c8-9b3f-4009-b6d1-1ec843e416f3",
      "name": "lasagne noodles",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 12,
        "unitText": "piece",
        "unitCode": "C62"
      }
    }
  ],
  "recipeInstructions": [
    {
      "@type": "HowToSection",
      "position": 1,
      "name": "Prepare the Meat Sauce",
      // ...
      "itemListElement": [
        {
          "@type": "HowToDirection",
          // ...
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "37d8e801-13fe-4ce9-ba93-6b8a35e6646f",
              "name": "ground beef",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "kilogram",
                "unitCode": "KGM"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "887ab19e-97be-43b1-bf20-b423b38eda5a",
              "name": "onion",
              "description": "diced",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "cup",
                "unitCode": "CU"
              }
            }
          ],
          // ...
        },
        {
          "@type": "HowToDirection",
          // ...
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "5bea667a-344a-44e9-a842-b6187e95b702",
              "description": "minced",
              "name": "garlic",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 2,
                "unitText": "clove"
              }
            }
          ],
          // ...
        }
      ]
    },
    {
      "@type": "HowToSection",
      // ...
      "itemListElement": [
        {
          "@type": "HowToDirection",
          // ...
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "f0a77778-5292-4bf4-8be2-4541a1cbd6ee",
              "name": "ricotta cheese",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 2,
                "unitText": "cups",
                "unitCode": "CU"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "ce0388ac-617f-4a15-9273-9ba805bf7523",
              "name": "shredded mozzarella cheese",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "cup",
                "unitCode": "CU"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "4563b9e4-460b-4325-96f2-9fc5ef349e81",
              "name": "salt",
              "description": "to taste"
            },
            {
              "@type": "HowToSupply",
              "identifier": "6811be83-8282-4851-bb88-749b3be727af",
              "name": "pepper",
              "description": "to taste"
            }
          ],
          // ...
        }
      ]
    },
    // ...

    {
      "@type": "HowToDirection",
      "position": 3,
      // ...      
      "supply": [
        {
          "@type": "HowToSupply",
          "identifier": "f16704c8-9b3f-4009-b6d1-1ec843e416f3",
          "name": "lasagne noodles",
          "description": "",
          "requiredQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitText": "piece",
            "unitCode": "C62"
          }
        },
        {
          "@type": "HowToSupply",
          "name": "meat sauce",
        },
        {
          "@type": "HowToSupply",
          "name": "cheese filling",
        }
      ],
      // ...        
    }
  ]
}
</script>
Full JSON
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "Recipe",
  "name": "Delicious Lasagna",
  "totalTime": "PT1H30M",
  "cookTime": "PT40min",
  "recipeIngredient": [],
  "supply": [
    {
      "@type": "HowToSupply",
      "identifier": "37d8e801-13fe-4ce9-ba93-6b8a35e6646f",
      "name": "ground beef",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "kilogram",
        "unitCode": "KGM"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "887ab19e-97be-43b1-bf20-b423b38eda5a",
      "name": "onion",
      "description": "diced",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "cup",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "5bea667a-344a-44e9-a842-b6187e95b702",
      "description": "minced",
      "name": "garlic",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 2,
        "unitText": "clove"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "f0a77778-5292-4bf4-8be2-4541a1cbd6ee",
      "name": "ricotta cheese",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 2,
        "unitText": "cups",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "ce0388ac-617f-4a15-9273-9ba805bf7523",
      "name": "shredded mozzarella cheese",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 0.5,
        "unitText": "cup",
        "unitCode": "CU"
      }
    },
    {
      "@type": "HowToSupply",
      "identifier": "4563b9e4-460b-4325-96f2-9fc5ef349e81",
      "name": "salt",
      "description": "to taste"
    },
    {
      "@type": "HowToSupply",
      "identifier": "6811be83-8282-4851-bb88-749b3be727af",
      "name": "pepper",
      "description": "to taste"
    },
    {
      "@type": "HowToSupply",
      "identifier": "f16704c8-9b3f-4009-b6d1-1ec843e416f3",
      "name": "lasagne noodles",
      "description": "",
      "requiredQuantity": {
        "@type": "QuantitativeValue",
        "value": 12,
        "unitText": "piece",
        "unitCode": "C62"
      }
    }
  ],
  "recipeInstructions": [
    {
      "@type": "HowToSection",
      "position": 1,
      "name": "Prepare the Meat Sauce",
      "description": "First the meat sauce needs to be prepared. Be aware that this will take a lot of time to get the best result.",
      "image": [
        "meat_sauce_1.jpg",
        "meat_sauce_2.jpg"
      ],
      "thumbnailUrl": [
        "meat_sauce_1_thumb.jpg",
        "meat_sauce_2_thumb.jpg"
      ],
      "itemListElement": [
        {
          "@type": "HowToDirection",
          "position": 1,
          "image": ["ground_beef_in_pan.jpg"],
          "thumbnailUrl": ["ground_beef_in_pan_thumb.jpg"],
          "timeRequired": ["PT6M"],
          "text": "In a large skillet, brown the ground beef and the onions.",
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "37d8e801-13fe-4ce9-ba93-6b8a35e6646f",
              "name": "ground beef",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "kilogram",
                "unitCode": "KGM"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "887ab19e-97be-43b1-bf20-b423b38eda5a",
              "name": "onion",
              "description": "diced",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "cup",
                "unitCode": "CU"
              }
            }
          ],
          "tool": [
            {
              "@type": "HowToTool",
              "identifier": "b3c0d2ff-009c-423e-89e8-e0245d027006",
              "name": "large skillet",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 1,
                "unitText": "unit",
                "unitCode": "C62"
              }
            }
          ]
        },
        {
          "@type": "HowToDirection",
          "position": 2,
          "image": [],
          "thumbnailUrl": [],
          "timeRequired": ["PT4M"],
          "text": "Add minced garlic and sauté for a few minutes.",
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "5bea667a-344a-44e9-a842-b6187e95b702",
              "description": "minced",
              "name": "garlic",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 2,
                "unitText": "clove"
              }
            }
          ],
          "tool": []
        }
      ]
    },
    {
      "@type": "HowToSection",
      "position": 2,
      "name": "Prepare the Cheese Filling",
      "description": "Get ready for the cheesy part...",
      "image": [],
      "thumbnailUrl": [],
      "itemListElement": [
        {
          "@type": "HowToDirection",
          "position": 1,
          "image": ["cheese_in_a_bowl.jpg"],
          "thumbnailUrl": ["cheese_in_a_bowl_thumb.jpg"],
          "timeRequired": ["PT2M"],
          "text": "In a bowl, combine ricotta cheese, mozzarella cheese, salt, and pepper.",
          "supply": [
            {
              "@type": "HowToSupply",
              "identifier": "f0a77778-5292-4bf4-8be2-4541a1cbd6ee",
              "name": "ricotta cheese",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 2,
                "unitText": "cups",
                "unitCode": "CU"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "ce0388ac-617f-4a15-9273-9ba805bf7523",
              "name": "shredded mozzarella cheese",
              "description": "",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 0.5,
                "unitText": "cup",
                "unitCode": "CU"
              }
            },
            {
              "@type": "HowToSupply",
              "identifier": "4563b9e4-460b-4325-96f2-9fc5ef349e81",
              "name": "salt",
              "description": "to taste"
            },
            {
              "@type": "HowToSupply",
              "identifier": "6811be83-8282-4851-bb88-749b3be727af",
              "name": "pepper",
              "description": "to taste"
            }
          ],
          "tool": [
            {
              "@type": "HowToTool",
              "identifier": "b3c0d2ff-009c-423e-89e8-e0245d027006",
              "name": "bowl",
              "description": "ca. 500 ml",
              "requiredQuantity": {
                "@type": "QuantitativeValue",
                "value": 1,
                "unitText": "unit",
                "unitCode": "C62"
              }
            }
          ]
        }
      ]
    },
    {
      "@type": "HowToDirection",
      "position": 3,
      "image": ["lasagna_layer.jpg"],
      "thumbnailUrl": ["lasagna_layer_thumb.jpg"],
      "timeRequired": ["PT10M"],
      "text": "In a baking dish, layer lasagna noodles, meat sauce, and cheese filling.",
      "supply": [
        {
          "@type": "HowToSupply",
          "identifier": "f16704c8-9b3f-4009-b6d1-1ec843e416f3",
          "name": "lasagne noodles",
          "description": "",
          "requiredQuantity": {
            "@type": "QuantitativeValue",
            "value": 12,
            "unitText": "piece",
            "unitCode": "C62"
          }
        },
        {
          "@type": "HowToSupply",
          "name": "meat sauce",
        },
        {
          "@type": "HowToSupply",
          "name": "cheese filling",
        }
      ],
      "tool": [
        {
          "@type": "HowToTool",
          "identifier": "e015a3fb-ca67-4890-9ec7-05359828fa0c",
          "name": "baking dish",
          "requiredQuantity": {
            "@type": "QuantitativeValue",
            "value": 1,
            "unitText": "unit",
            "unitCode": "C62"
          }
        }
      ]
    }
  ]
}
</script>

UI

Obviously UI for managing the ingredients, the import, etc. is needed. But first the basic functionality should be mapped out and probed for any problems that might occur.

That said - do you spot any issues or have an opinion on this? :)

@sunjam
Copy link

sunjam commented Jan 14, 2024

I could see this sort of thing becoming extremely useful when combined with sharing between users.

UserA has 3 ingredients for the recipe
UserB has the remaining ingredients for the recipe.

Might be a wild idea, but would be awesome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
NextCloud app
  
Backlog
Development

No branches or pull requests

10 participants