converted ingredient parser to class and added automation beta hint
This commit is contained in:
parent
ecd300d2db
commit
a7dc23194e
@ -5,7 +5,26 @@ import unicodedata
|
||||
from cookbook.models import Unit, Food
|
||||
|
||||
|
||||
def parse_fraction(x):
|
||||
class IngredientParser:
|
||||
request = None
|
||||
ignore_rules = False
|
||||
food_aliases = []
|
||||
unit_aliases = []
|
||||
|
||||
def __init__(self, request, cache_mode, ignore_automations=False):
|
||||
"""
|
||||
Initialize ingredient parser
|
||||
:param request: request context (to control caching, rule ownership, etc.)
|
||||
:param cache_mode: defines if all rules should be loaded on initialization (good when parser is used many times) or if they should be retrieved every time (good when parser is not used many times in a row)
|
||||
:param ignore_automations: ignore automation rules, allows to use ingredient parser without database access/request (request can be None)
|
||||
"""
|
||||
self.request = request
|
||||
self.ignore_rules = ignore_automations
|
||||
if cache_mode:
|
||||
self.food_aliases = []
|
||||
self.unit_aliases = []
|
||||
|
||||
def parse_fraction(self, x):
|
||||
if len(x) == 1 and 'fraction' in unicodedata.decomposition(x):
|
||||
frac_split = unicodedata.decomposition(x[-1:]).split()
|
||||
return (float((frac_split[1]).replace('003', ''))
|
||||
@ -19,8 +38,7 @@ def parse_fraction(x):
|
||||
except ZeroDivisionError:
|
||||
raise ValueError
|
||||
|
||||
|
||||
def parse_amount(x):
|
||||
def parse_amount(self, x):
|
||||
amount = 0
|
||||
unit = ''
|
||||
note = ''
|
||||
@ -36,11 +54,11 @@ def parse_amount(x):
|
||||
end += 1
|
||||
if end > 0:
|
||||
if "/" in x[:end]:
|
||||
amount = parse_fraction(x[:end])
|
||||
amount = self.parse_fraction(x[:end])
|
||||
else:
|
||||
amount = float(x[:end].replace(',', '.'))
|
||||
else:
|
||||
amount = parse_fraction(x[0])
|
||||
amount = self.parse_fraction(x[0])
|
||||
end += 1
|
||||
did_check_frac = True
|
||||
if end < len(x):
|
||||
@ -48,7 +66,7 @@ def parse_amount(x):
|
||||
unit = x[end:]
|
||||
else:
|
||||
try:
|
||||
amount += parse_fraction(x[end])
|
||||
amount += self.parse_fraction(x[end])
|
||||
unit = x[end + 1:]
|
||||
except ValueError:
|
||||
unit = x[end:]
|
||||
@ -58,8 +76,7 @@ def parse_amount(x):
|
||||
note = x
|
||||
return amount, unit, note
|
||||
|
||||
|
||||
def parse_ingredient_with_comma(tokens):
|
||||
def parse_ingredient_with_comma(self, tokens):
|
||||
ingredient = ''
|
||||
note = ''
|
||||
start = 0
|
||||
@ -74,14 +91,13 @@ def parse_ingredient_with_comma(tokens):
|
||||
note = ' '.join(tokens[start + 1:])
|
||||
return ingredient, note
|
||||
|
||||
|
||||
def parse_ingredient(tokens):
|
||||
def parse_ingredient(self, tokens):
|
||||
ingredient = ''
|
||||
note = ''
|
||||
if tokens[-1].endswith(')'):
|
||||
# Check if the matching opening bracket is in the same token
|
||||
if (not tokens[-1].startswith('(')) and ('(' in tokens[-1]):
|
||||
return parse_ingredient_with_comma(tokens)
|
||||
return self.parse_ingredient_with_comma(tokens)
|
||||
# last argument ends with closing bracket -> look for opening bracket
|
||||
start = len(tokens) - 1
|
||||
while not tokens[start].startswith('(') and not start == 0:
|
||||
@ -91,17 +107,16 @@ def parse_ingredient(tokens):
|
||||
raise ValueError
|
||||
elif start < 0:
|
||||
# no opening bracket anywhere -> just ignore the last bracket
|
||||
ingredient, note = parse_ingredient_with_comma(tokens)
|
||||
ingredient, note = self.parse_ingredient_with_comma(tokens)
|
||||
else:
|
||||
# opening bracket found -> split in ingredient and note, remove brackets from note # noqa: E501
|
||||
note = ' '.join(tokens[start:])[1:-1]
|
||||
ingredient = ' '.join(tokens[:start])
|
||||
else:
|
||||
ingredient, note = parse_ingredient_with_comma(tokens)
|
||||
ingredient, note = self.parse_ingredient_with_comma(tokens)
|
||||
return ingredient, note
|
||||
|
||||
|
||||
def parse(x):
|
||||
def parse(self, x):
|
||||
# initialize default values
|
||||
amount = 0
|
||||
unit = ''
|
||||
@ -122,7 +137,7 @@ def parse(x):
|
||||
else:
|
||||
try:
|
||||
# try to parse first argument as amount
|
||||
amount, unit, unit_note = parse_amount(tokens[0])
|
||||
amount, unit, unit_note = self.parse_amount(tokens[0])
|
||||
# only try to parse second argument as amount if there are at least
|
||||
# three arguments if it already has a unit there can't be
|
||||
# a fraction for the amount
|
||||
@ -133,31 +148,31 @@ def parse(x):
|
||||
# probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except # noqa: E501
|
||||
raise ValueError
|
||||
# try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½'
|
||||
amount += parse_fraction(tokens[1])
|
||||
amount += self.parse_fraction(tokens[1])
|
||||
# assume that units can't end with a comma
|
||||
if len(tokens) > 3 and not tokens[2].endswith(','):
|
||||
# try to use third argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
|
||||
try:
|
||||
ingredient, note = parse_ingredient(tokens[3:])
|
||||
ingredient, note = self.parse_ingredient(tokens[3:])
|
||||
unit = tokens[2]
|
||||
except ValueError:
|
||||
ingredient, note = parse_ingredient(tokens[2:])
|
||||
ingredient, note = self.parse_ingredient(tokens[2:])
|
||||
else:
|
||||
ingredient, note = parse_ingredient(tokens[2:])
|
||||
ingredient, note = self.parse_ingredient(tokens[2:])
|
||||
except ValueError:
|
||||
# assume that units can't end with a comma
|
||||
if not tokens[1].endswith(','):
|
||||
# try to use second argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
|
||||
try:
|
||||
ingredient, note = parse_ingredient(tokens[2:])
|
||||
ingredient, note = self.parse_ingredient(tokens[2:])
|
||||
if unit == '':
|
||||
unit = tokens[1]
|
||||
else:
|
||||
note = tokens[1]
|
||||
except ValueError:
|
||||
ingredient, note = parse_ingredient(tokens[1:])
|
||||
ingredient, note = self.parse_ingredient(tokens[1:])
|
||||
else:
|
||||
ingredient, note = parse_ingredient(tokens[1:])
|
||||
ingredient, note = self.parse_ingredient(tokens[1:])
|
||||
else:
|
||||
# only two arguments, first one is the amount
|
||||
# which means this is the ingredient
|
||||
@ -166,7 +181,7 @@ def parse(x):
|
||||
try:
|
||||
# can't parse first argument as amount
|
||||
# -> no unit -> parse everything as ingredient
|
||||
ingredient, note = parse_ingredient(tokens)
|
||||
ingredient, note = self.parse_ingredient(tokens)
|
||||
except ValueError:
|
||||
ingredient = ' '.join(tokens[1:])
|
||||
|
||||
@ -174,21 +189,28 @@ def parse(x):
|
||||
note += ' ' + unit_note
|
||||
return amount, unit.strip(), ingredient.strip(), note.strip()
|
||||
|
||||
|
||||
# small utility functions to prevent emtpy unit/food creation
|
||||
def get_unit(unit, space):
|
||||
def get_unit(self, unit):
|
||||
"""
|
||||
Get or create a unit for given space respecting possible automations
|
||||
:param unit: string unit
|
||||
:return: None if unit passed is invalid, Unit object otherwise
|
||||
"""
|
||||
if not unit:
|
||||
return None
|
||||
if len(unit) > 0:
|
||||
u, created = Unit.objects.get_or_create(name=unit, space=space)
|
||||
u, created = Unit.objects.get_or_create(name=unit, space=self.request.space)
|
||||
return u
|
||||
return None
|
||||
|
||||
|
||||
def get_food(food, space):
|
||||
def get_food(self, food):
|
||||
"""
|
||||
Get or create a food for given space respecting possible automations
|
||||
:param food: string food
|
||||
:return: None if food passed is invalid, Food object otherwise
|
||||
"""
|
||||
if not food:
|
||||
return None
|
||||
if len(food) > 0:
|
||||
f, created = Food.objects.get_or_create(name=food, space=space)
|
||||
f, created = Food.objects.get_or_create(name=food, space=self.request.space)
|
||||
return f
|
||||
return None
|
||||
|
@ -10,7 +10,7 @@ from recipe_scrapers._utils import get_host_name, normalize_string
|
||||
from urllib.parse import unquote
|
||||
|
||||
|
||||
def get_recipe_from_source(text, url, space):
|
||||
def get_recipe_from_source(text, url, request):
|
||||
def build_node(k, v):
|
||||
if isinstance(v, dict):
|
||||
node = {
|
||||
@ -103,7 +103,7 @@ def get_recipe_from_source(text, url, space):
|
||||
parse_list.append(el)
|
||||
scrape = text_scraper(text, url=url)
|
||||
|
||||
recipe_json = helper.get_from_scraper(scrape, space)
|
||||
recipe_json = helper.get_from_scraper(scrape, request)
|
||||
|
||||
for el in parse_list:
|
||||
temp_tree = []
|
||||
|
@ -3,14 +3,14 @@ import re
|
||||
from isodate import parse_duration as iso_parse_duration
|
||||
from isodate.isoerror import ISO8601Error
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse as parse_single_ingredient
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.models import Keyword
|
||||
from django.utils.dateparse import parse_duration
|
||||
from html import unescape
|
||||
from recipe_scrapers._utils import get_minutes
|
||||
|
||||
|
||||
def get_from_scraper(scrape, space):
|
||||
def get_from_scraper(scrape, request):
|
||||
# converting the scrape_me object to the existing json format based on ld+json
|
||||
recipe_json = {}
|
||||
try:
|
||||
@ -91,15 +91,16 @@ def get_from_scraper(scrape, space):
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), space)
|
||||
recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), request.space)
|
||||
except AttributeError:
|
||||
recipe_json['keywords'] = keywords
|
||||
|
||||
ingredient_parser = IngredientParser(request, True)
|
||||
try:
|
||||
ingredients = []
|
||||
for x in scrape.ingredients():
|
||||
try:
|
||||
amount, unit, ingredient, note = parse_single_ingredient(x)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(x)
|
||||
ingredients.append(
|
||||
{
|
||||
'amount': amount,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import re
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -42,11 +42,12 @@ class ChefTap(Integration):
|
||||
step.instruction += '\n' + source_url
|
||||
step.save()
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -3,7 +3,7 @@ from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
|
||||
@ -58,10 +58,11 @@ class Chowdown(Integration):
|
||||
instruction='\n'.join(directions) + '\n\n' + '\n'.join(descriptions), space=self.request.space,
|
||||
)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -6,7 +6,7 @@ from io import BytesIO
|
||||
|
||||
import yaml
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
from gettext import gettext as _
|
||||
@ -53,11 +53,12 @@ class CookBookApp(Integration):
|
||||
step.save()
|
||||
recipe.steps.add(step)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in recipe_yml['ingredients'].split('\n'):
|
||||
if ingredient.strip() != '':
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -2,7 +2,7 @@ import base64
|
||||
import json
|
||||
from io import BytesIO
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -34,11 +34,12 @@ class Domestica(Integration):
|
||||
if file['source'] != '':
|
||||
step.instruction += '\n' + file['source']
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in file['ingredients'].split('\n'):
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -4,7 +4,7 @@ from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -37,17 +37,18 @@ class Mealie(Integration):
|
||||
if len(recipe_json['description'].strip()) > 500:
|
||||
step.instruction = recipe_json['description'].strip() + '\n\n' + step.instruction
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in recipe_json['recipe_ingredient']:
|
||||
try:
|
||||
if ingredient['food']:
|
||||
f = get_food(ingredient['food'], self.request.space)
|
||||
u = get_unit(ingredient['unit'], self.request.space)
|
||||
f = ingredient_parser.get_food(ingredient['food'])
|
||||
u = ingredient_parser.get_unit(ingredient['unit'])
|
||||
amount = ingredient['quantity']
|
||||
note = ingredient['note']
|
||||
else:
|
||||
amount, unit, ingredient, note = parse(ingredient['note'])
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient['note'])
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -1,6 +1,6 @@
|
||||
import re
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
|
||||
@ -42,11 +42,12 @@ class MealMaster(Integration):
|
||||
instruction='\n'.join(directions) + '\n\n', space=self.request.space,
|
||||
)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -4,7 +4,7 @@ from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -39,6 +39,7 @@ class NextcloudCookbook(Integration):
|
||||
|
||||
ingredients_added = True
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in recipe_json['recipeIngredient']:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import json
|
||||
|
||||
from cookbook.helper.ingredient_parser import get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -23,9 +23,10 @@ class OpenEats(Integration):
|
||||
|
||||
step = Step.objects.create(instruction=instructions, space=self.request.space,)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in file['ingredients']:
|
||||
f = get_food(ingredient['food'], self.request.space)
|
||||
u = get_unit(ingredient['unit'], self.request.space)
|
||||
f = ingredient_parser.get_food(ingredient['food'])
|
||||
u = ingredient_parser.get_unit(ingredient['unit'])
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=ingredient['amount'], space=self.request.space,
|
||||
))
|
||||
|
@ -4,7 +4,7 @@ import json
|
||||
import re
|
||||
from io import BytesIO
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
from gettext import gettext as _
|
||||
@ -66,12 +66,13 @@ class Paprika(Integration):
|
||||
keyword, created = Keyword.objects.get_or_create(name=c.strip(), space=self.request.space)
|
||||
recipe.keywords.add(keyword)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
try:
|
||||
for ingredient in recipe_json['ingredients'].split('\n'):
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -38,11 +38,12 @@ class Pepperplate(Integration):
|
||||
instruction='\n'.join(directions) + '\n\n', space=self.request.space,
|
||||
)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -2,7 +2,7 @@ from io import BytesIO
|
||||
|
||||
import requests
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
|
||||
@ -53,11 +53,12 @@ class Plantoeat(Integration):
|
||||
keyword, created = Keyword.objects.get_or_create(name=k.strip(), space=self.request.space)
|
||||
recipe.keywords.add(keyword)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -6,7 +6,7 @@ from zipfile import ZipFile
|
||||
import imghdr
|
||||
|
||||
from cookbook.helper.image_processing import get_filetype
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
|
||||
@ -55,11 +55,12 @@ class RecetteTek(Integration):
|
||||
|
||||
try:
|
||||
# Process the ingredients. Assumes 1 ingredient per line.
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in file['ingredients'].split('\n'):
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -3,7 +3,7 @@ from bs4 import BeautifulSoup
|
||||
from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.recipe_url_import import parse_servings, iso_duration_to_minutes
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
@ -41,12 +41,13 @@ class RecipeKeeper(Integration):
|
||||
|
||||
step = Step.objects.create(instruction='', space=self.request.space,)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in file.find("div", {"itemprop": "recipeIngredients"}).findChildren("p"):
|
||||
if ingredient.text == "":
|
||||
continue
|
||||
amount, unit, ingredient, note = parse(ingredient.text.strip())
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient.text.strip())
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -3,7 +3,7 @@ from io import BytesIO
|
||||
|
||||
import requests
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -31,6 +31,7 @@ class RecipeSage(Integration):
|
||||
except Exception as e:
|
||||
print('failed to parse yield or time ', str(e))
|
||||
|
||||
ingredient_parser = IngredientParser(self.request,True)
|
||||
ingredients_added = False
|
||||
for s in file['recipeInstructions']:
|
||||
step = Step.objects.create(
|
||||
@ -40,9 +41,9 @@ class RecipeSage(Integration):
|
||||
ingredients_added = True
|
||||
|
||||
for ingredient in file['recipeIngredient']:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient, Keyword
|
||||
|
||||
@ -41,11 +41,12 @@ class RezKonv(Integration):
|
||||
instruction='\n'.join(directions) + '\n\n', space=self.request.space,
|
||||
)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
if len(ingredient.strip()) > 0:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_food, get_unit
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Recipe, Step, Ingredient
|
||||
|
||||
@ -43,12 +43,13 @@ class Safron(Integration):
|
||||
|
||||
recipe = Recipe.objects.create(name=title, description=description, created_by=self.request.user, internal=True, space=self.request.space, )
|
||||
|
||||
step = Step.objects.create(instruction='\n'.join(directions), space=self.request.space,)
|
||||
step = Step.objects.create(instruction='\n'.join(directions), space=self.request.space, )
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in ingredients:
|
||||
amount, unit, ingredient, note = parse(ingredient)
|
||||
f = get_food(ingredient, self.request.space)
|
||||
u = get_unit(unit, self.request.space)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(ingredient)
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, space=self.request.space,
|
||||
))
|
||||
|
@ -1,4 +1,4 @@
|
||||
from cookbook.helper.ingredient_parser import parse
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
|
||||
|
||||
def test_ingredient_parser():
|
||||
@ -58,14 +58,16 @@ def test_ingredient_parser():
|
||||
"2L Wasser": (2, "L", "Wasser", ""),
|
||||
"1 (16 ounce) package dry lentils, rinsed": (1, "package", "dry lentils, rinsed", "16 ounce"),
|
||||
"2-3 c Water": (2, "c", "Water", "2-3"),
|
||||
"Pane (raffermo o secco) 80 g": (0, "", "Pane 80 g", "raffermo o secco"), #TODO this is actually not a good result but currently expected
|
||||
"Pane (raffermo o secco) 80 g": (0, "", "Pane 80 g", "raffermo o secco"), # TODO this is actually not a good result but currently expected
|
||||
}
|
||||
# for German you could say that if an ingredient does not have
|
||||
# an amount # and it starts with a lowercase letter, then that
|
||||
# is a unit ("etwas", "evtl.") does not apply to English tho
|
||||
|
||||
ingredient_parser = IngredientParser(None, False, ignore_automations=True)
|
||||
|
||||
count = 0
|
||||
for key, val in expectations.items():
|
||||
count += 1
|
||||
parsed = parse(key)
|
||||
parsed = ingredient_parser.parse(key)
|
||||
assert val == parsed
|
||||
|
@ -31,7 +31,7 @@ from rest_framework.viewsets import ViewSetMixin
|
||||
from treebeard.exceptions import PathOverflow, InvalidMoveToDescendant, InvalidPosition
|
||||
|
||||
from cookbook.helper.image_processing import handle_image
|
||||
from cookbook.helper.ingredient_parser import parse
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
|
||||
CustomIsOwner, CustomIsShare,
|
||||
CustomIsShared, CustomIsUser,
|
||||
@ -853,11 +853,11 @@ def recipe_from_source(request):
|
||||
},
|
||||
status=400)
|
||||
else:
|
||||
return JsonResponse({"recipe_json": get_from_scraper(scrape, request.space)})
|
||||
return JsonResponse({"recipe_json": get_from_scraper(scrape, request)})
|
||||
elif (mode == 'source') or (mode == 'url' and auto == 'false'):
|
||||
if not data or data == 'undefined':
|
||||
data = requests.get(url, headers=HEADERS).content
|
||||
recipe_json, recipe_tree, recipe_html, images = get_recipe_from_source(data, url, request.space)
|
||||
recipe_json, recipe_tree, recipe_html, images = get_recipe_from_source(data, url, request)
|
||||
if len(recipe_tree) == 0 and len(recipe_json) == 0:
|
||||
return JsonResponse(
|
||||
{
|
||||
@ -893,7 +893,9 @@ def get_backup(request):
|
||||
@group_required('user')
|
||||
def ingredient_from_string(request):
|
||||
text = request.POST['text']
|
||||
amount, unit, food, note = parse(text)
|
||||
|
||||
ingredient_parser = IngredientParser(request, False)
|
||||
amount, unit, food, note = ingredient_parser.parse(text)
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
|
@ -6,7 +6,7 @@ from django.http import JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from cookbook.helper.ingredient_parser import parse, get_unit, get_food
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.permission_helper import group_required
|
||||
from cookbook.models import TelegramBot, ShoppingList, ShoppingListEntry
|
||||
|
||||
@ -49,9 +49,12 @@ def hook(request, token):
|
||||
if not sl:
|
||||
sl = ShoppingList.objects.create(created_by=tb.created_by, space=tb.space)
|
||||
|
||||
amount, unit, ingredient, note = parse(data['message']['text'])
|
||||
f = get_food(ingredient, tb.space)
|
||||
u = get_unit(unit, tb.space)
|
||||
request.space = tb.space # TODO this is likely a bad idea. Verify and test
|
||||
request.user = tb.created_by
|
||||
ingredient_parser = IngredientParser(request, False)
|
||||
amount, unit, ingredient, note = ingredient_parser.parse(data['message']['text'])
|
||||
f = ingredient_parser.get_food(ingredient)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
sl.entries.add(
|
||||
ShoppingListEntry.objects.create(
|
||||
food=f, unit=u, amount=amount
|
||||
|
@ -26,10 +26,9 @@ from cookbook.forms import (CommentForm, Recipe, User,
|
||||
UserCreateForm, UserNameForm, UserPreference,
|
||||
UserPreferenceForm, SpaceJoinForm, SpaceCreateForm,
|
||||
SearchPreferenceForm)
|
||||
from cookbook.helper.ingredient_parser import parse
|
||||
from cookbook.helper.permission_helper import group_required, share_link_valid, has_group_permission
|
||||
from cookbook.models import (Comment, CookLog, InviteLink, MealPlan,
|
||||
RecipeBook, RecipeBookEntry, ViewLog, ShoppingList, Space, Keyword, RecipeImport, Unit,
|
||||
ViewLog, ShoppingList, Space, Keyword, RecipeImport, Unit,
|
||||
Food, UserFile, ShareLink)
|
||||
from cookbook.tables import (CookLogTable, RecipeTable, RecipeTableSmall,
|
||||
ViewLogTable, InviteLinkTable)
|
||||
|
@ -8,11 +8,22 @@
|
||||
:show="show_modal"
|
||||
@finish-action="finishAction"/>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-2 d-none d-md-block">
|
||||
</div>
|
||||
<div class="col-xl-8 col-12">
|
||||
<div class="container-fluid d-flex flex-column flex-grow-1">
|
||||
|
||||
<div class="row" v-if="this_model === Models.AUTOMATION">
|
||||
<div class="col-md-12">
|
||||
<b-alert show variant="warning">
|
||||
<b-badge>BETA</b-badge>
|
||||
{{ $t('warning_feature_beta') }}
|
||||
</b-alert>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6" style="margin-top: 1vh">
|
||||
<h3>
|
||||
@ -343,7 +354,7 @@ export default {
|
||||
this.makeToast(this.$t('Error'), err.bodyText, 'danger')
|
||||
})
|
||||
|
||||
if (automate){
|
||||
if (automate) {
|
||||
let apiClient = new ApiApiFactory()
|
||||
|
||||
let automation = {
|
||||
@ -352,13 +363,13 @@ export default {
|
||||
param_2: target.id
|
||||
}
|
||||
|
||||
if (this.this_model === this.Models.FOOD){
|
||||
if (this.this_model === this.Models.FOOD) {
|
||||
automation.type = 'FOOD_ALIAS'
|
||||
}
|
||||
if (this.this_model === this.Models.UNIT){
|
||||
if (this.this_model === this.Models.UNIT) {
|
||||
automation.type = 'UNIT_ALIAS'
|
||||
}
|
||||
if (this.this_model === this.Models.KEYWORD){
|
||||
if (this.this_model === this.Models.KEYWORD) {
|
||||
automation.type = 'KEYWORD_ALIAS'
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
</b-dropdown-item>
|
||||
|
||||
<b-dropdown-item v-if="show_merge" v-on:click="$emit('item-action', 'merge-automate')">
|
||||
<i class="fas fa-robot fa-fw"></i> {{$t('Merge')}} & {{$t('Automate')}}
|
||||
<i class="fas fa-robot fa-fw"></i> {{$t('Merge')}} & {{$t('Automate')}} <b-badge v-b-tooltip.hover :title="$t('warning_feature_beta')">BETA</b-badge>
|
||||
</b-dropdown-item>
|
||||
|
||||
</b-dropdown>
|
||||
|
@ -86,7 +86,7 @@
|
||||
<i class="fas fa-compress-arrows-alt fa-fw"></i> <b>{{$t('Merge')}}</b>: <span v-html="$t('merge_confirmation', {'source': source.name,'target':item.name})"></span>
|
||||
</b-list-group-item>
|
||||
<b-list-group-item v-if="useMerge" action v-on:click="$emit('item-action',{'action': 'merge-automate', 'target': item, 'source': source}); closeMenu()">
|
||||
<i class="fas fa-robot fa-fw"></i> <b>{{$t('Merge')}} & {{$t('Automate')}}</b>: <span v-html="$t('merge_confirmation', {'source': source.name,'target':item.name})"></span> {{$t('create_rule')}}
|
||||
<i class="fas fa-robot fa-fw"></i> <b>{{$t('Merge')}} & {{$t('Automate')}}</b>: <span v-html="$t('merge_confirmation', {'source': source.name,'target':item.name})"></span> {{$t('create_rule')}} <b-badge v-b-tooltip.hover :title="$t('warning_feature_beta')" >BETA</b-badge>
|
||||
</b-list-group-item>
|
||||
<b-list-group-item action v-on:click="closeMenu()">
|
||||
<i class="fas fa-times fa-fw"></i> <b>{{$t('Cancel')}}</b>
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"warning_feature_beta": "This feature is currently in a BETA (testing) state. Please expect bugs and possibly breaking changes in the future (possibly loosing feature related data) when using this feature.",
|
||||
"err_fetching_resource": "There was an error fetching a resource!",
|
||||
"err_creating_resource": "There was an error creating a resource!",
|
||||
"err_updating_resource": "There was an error updating a resource!",
|
||||
|
@ -1,183 +1,294 @@
|
||||
{
|
||||
"status": "done",
|
||||
"assets": {
|
||||
"../../templates/sw.js": {
|
||||
"name": "../../templates/sw.js",
|
||||
"path": "..\\..\\templates\\sw.js"
|
||||
},
|
||||
"css/chunk-vendors.css": {
|
||||
"name": "css/chunk-vendors.css",
|
||||
"path": "css\\chunk-vendors.css"
|
||||
},
|
||||
"js/chunk-vendors.js": {
|
||||
"name": "js/chunk-vendors.js",
|
||||
"path": "js\\chunk-vendors.js"
|
||||
},
|
||||
"css/cookbook_view.css": {
|
||||
"name": "css/cookbook_view.css",
|
||||
"path": "css\\cookbook_view.css"
|
||||
"path": "js\\chunk-vendors.js",
|
||||
"publicPath": "http://localhost:8080/js/chunk-vendors.js"
|
||||
},
|
||||
"js/cookbook_view.js": {
|
||||
"name": "js/cookbook_view.js",
|
||||
"path": "js\\cookbook_view.js"
|
||||
},
|
||||
"css/edit_internal_recipe.css": {
|
||||
"name": "css/edit_internal_recipe.css",
|
||||
"path": "css\\edit_internal_recipe.css"
|
||||
"path": "js\\cookbook_view.js",
|
||||
"publicPath": "http://localhost:8080/js/cookbook_view.js"
|
||||
},
|
||||
"js/edit_internal_recipe.js": {
|
||||
"name": "js/edit_internal_recipe.js",
|
||||
"path": "js\\edit_internal_recipe.js"
|
||||
"path": "js\\edit_internal_recipe.js",
|
||||
"publicPath": "http://localhost:8080/js/edit_internal_recipe.js"
|
||||
},
|
||||
"js/import_response_view.js": {
|
||||
"name": "js/import_response_view.js",
|
||||
"path": "js\\import_response_view.js"
|
||||
},
|
||||
"css/meal_plan_view.css": {
|
||||
"name": "css/meal_plan_view.css",
|
||||
"path": "css\\meal_plan_view.css"
|
||||
"path": "js\\import_response_view.js",
|
||||
"publicPath": "http://localhost:8080/js/import_response_view.js"
|
||||
},
|
||||
"js/meal_plan_view.js": {
|
||||
"name": "js/meal_plan_view.js",
|
||||
"path": "js\\meal_plan_view.js"
|
||||
},
|
||||
"css/model_list_view.css": {
|
||||
"name": "css/model_list_view.css",
|
||||
"path": "css\\model_list_view.css"
|
||||
"path": "js\\meal_plan_view.js",
|
||||
"publicPath": "http://localhost:8080/js/meal_plan_view.js"
|
||||
},
|
||||
"js/model_list_view.js": {
|
||||
"name": "js/model_list_view.js",
|
||||
"path": "js\\model_list_view.js"
|
||||
"path": "js\\model_list_view.js",
|
||||
"publicPath": "http://localhost:8080/js/model_list_view.js"
|
||||
},
|
||||
"js/offline_view.js": {
|
||||
"name": "js/offline_view.js",
|
||||
"path": "js\\offline_view.js"
|
||||
},
|
||||
"css/recipe_search_view.css": {
|
||||
"name": "css/recipe_search_view.css",
|
||||
"path": "css\\recipe_search_view.css"
|
||||
"path": "js\\offline_view.js",
|
||||
"publicPath": "http://localhost:8080/js/offline_view.js"
|
||||
},
|
||||
"js/recipe_search_view.js": {
|
||||
"name": "js/recipe_search_view.js",
|
||||
"path": "js\\recipe_search_view.js"
|
||||
},
|
||||
"css/recipe_view.css": {
|
||||
"name": "css/recipe_view.css",
|
||||
"path": "css\\recipe_view.css"
|
||||
"path": "js\\recipe_search_view.js",
|
||||
"publicPath": "http://localhost:8080/js/recipe_search_view.js"
|
||||
},
|
||||
"js/recipe_view.js": {
|
||||
"name": "js/recipe_view.js",
|
||||
"path": "js\\recipe_view.js"
|
||||
"path": "js\\recipe_view.js",
|
||||
"publicPath": "http://localhost:8080/js/recipe_view.js"
|
||||
},
|
||||
"js/supermarket_view.js": {
|
||||
"name": "js/supermarket_view.js",
|
||||
"path": "js\\supermarket_view.js"
|
||||
"path": "js\\supermarket_view.js",
|
||||
"publicPath": "http://localhost:8080/js/supermarket_view.js"
|
||||
},
|
||||
"js/user_file_view.js": {
|
||||
"name": "js/user_file_view.js",
|
||||
"path": "js\\user_file_view.js"
|
||||
"path": "js\\user_file_view.js",
|
||||
"publicPath": "http://localhost:8080/js/user_file_view.js"
|
||||
},
|
||||
"recipe_search_view.html": {
|
||||
"name": "recipe_search_view.html",
|
||||
"path": "recipe_search_view.html"
|
||||
"path": "recipe_search_view.html",
|
||||
"publicPath": "http://localhost:8080/recipe_search_view.html"
|
||||
},
|
||||
"recipe_view.html": {
|
||||
"name": "recipe_view.html",
|
||||
"path": "recipe_view.html"
|
||||
"path": "recipe_view.html",
|
||||
"publicPath": "http://localhost:8080/recipe_view.html"
|
||||
},
|
||||
"offline_view.html": {
|
||||
"name": "offline_view.html",
|
||||
"path": "offline_view.html"
|
||||
"path": "offline_view.html",
|
||||
"publicPath": "http://localhost:8080/offline_view.html"
|
||||
},
|
||||
"import_response_view.html": {
|
||||
"name": "import_response_view.html",
|
||||
"path": "import_response_view.html"
|
||||
"path": "import_response_view.html",
|
||||
"publicPath": "http://localhost:8080/import_response_view.html"
|
||||
},
|
||||
"supermarket_view.html": {
|
||||
"name": "supermarket_view.html",
|
||||
"path": "supermarket_view.html"
|
||||
"path": "supermarket_view.html",
|
||||
"publicPath": "http://localhost:8080/supermarket_view.html"
|
||||
},
|
||||
"user_file_view.html": {
|
||||
"name": "user_file_view.html",
|
||||
"path": "user_file_view.html"
|
||||
"path": "user_file_view.html",
|
||||
"publicPath": "http://localhost:8080/user_file_view.html"
|
||||
},
|
||||
"model_list_view.html": {
|
||||
"name": "model_list_view.html",
|
||||
"path": "model_list_view.html"
|
||||
"path": "model_list_view.html",
|
||||
"publicPath": "http://localhost:8080/model_list_view.html"
|
||||
},
|
||||
"edit_internal_recipe.html": {
|
||||
"name": "edit_internal_recipe.html",
|
||||
"path": "edit_internal_recipe.html"
|
||||
"path": "edit_internal_recipe.html",
|
||||
"publicPath": "http://localhost:8080/edit_internal_recipe.html"
|
||||
},
|
||||
"cookbook_view.html": {
|
||||
"name": "cookbook_view.html",
|
||||
"path": "cookbook_view.html"
|
||||
"path": "cookbook_view.html",
|
||||
"publicPath": "http://localhost:8080/cookbook_view.html"
|
||||
},
|
||||
"meal_plan_view.html": {
|
||||
"name": "meal_plan_view.html",
|
||||
"path": "meal_plan_view.html"
|
||||
"path": "meal_plan_view.html",
|
||||
"publicPath": "http://localhost:8080/meal_plan_view.html"
|
||||
},
|
||||
"manifest.json": {
|
||||
"name": "manifest.json",
|
||||
"path": "manifest.json"
|
||||
"path": "manifest.json",
|
||||
"publicPath": "http://localhost:8080/manifest.json"
|
||||
},
|
||||
"model_list_view.7cf8cfb04383ac21dae2.hot-update.js": {
|
||||
"name": "model_list_view.7cf8cfb04383ac21dae2.hot-update.js",
|
||||
"path": "model_list_view.7cf8cfb04383ac21dae2.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.7cf8cfb04383ac21dae2.hot-update.js"
|
||||
},
|
||||
"7cf8cfb04383ac21dae2.hot-update.json": {
|
||||
"name": "7cf8cfb04383ac21dae2.hot-update.json",
|
||||
"path": "7cf8cfb04383ac21dae2.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/7cf8cfb04383ac21dae2.hot-update.json"
|
||||
},
|
||||
"model_list_view.65f25fe27091809f7fcf.hot-update.js": {
|
||||
"name": "model_list_view.65f25fe27091809f7fcf.hot-update.js",
|
||||
"path": "model_list_view.65f25fe27091809f7fcf.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.65f25fe27091809f7fcf.hot-update.js"
|
||||
},
|
||||
"65f25fe27091809f7fcf.hot-update.json": {
|
||||
"name": "65f25fe27091809f7fcf.hot-update.json",
|
||||
"path": "65f25fe27091809f7fcf.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/65f25fe27091809f7fcf.hot-update.json"
|
||||
},
|
||||
"model_list_view.032182ad6990812f8035.hot-update.js": {
|
||||
"name": "model_list_view.032182ad6990812f8035.hot-update.js",
|
||||
"path": "model_list_view.032182ad6990812f8035.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.032182ad6990812f8035.hot-update.js"
|
||||
},
|
||||
"032182ad6990812f8035.hot-update.json": {
|
||||
"name": "032182ad6990812f8035.hot-update.json",
|
||||
"path": "032182ad6990812f8035.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/032182ad6990812f8035.hot-update.json"
|
||||
},
|
||||
"model_list_view.cbedf3e2489989eec8dd.hot-update.js": {
|
||||
"name": "model_list_view.cbedf3e2489989eec8dd.hot-update.js",
|
||||
"path": "model_list_view.cbedf3e2489989eec8dd.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.cbedf3e2489989eec8dd.hot-update.js"
|
||||
},
|
||||
"cbedf3e2489989eec8dd.hot-update.json": {
|
||||
"name": "cbedf3e2489989eec8dd.hot-update.json",
|
||||
"path": "cbedf3e2489989eec8dd.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/cbedf3e2489989eec8dd.hot-update.json"
|
||||
},
|
||||
"model_list_view.87a9208c092e31885f51.hot-update.js": {
|
||||
"name": "model_list_view.87a9208c092e31885f51.hot-update.js",
|
||||
"path": "model_list_view.87a9208c092e31885f51.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.87a9208c092e31885f51.hot-update.js"
|
||||
},
|
||||
"87a9208c092e31885f51.hot-update.json": {
|
||||
"name": "87a9208c092e31885f51.hot-update.json",
|
||||
"path": "87a9208c092e31885f51.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/87a9208c092e31885f51.hot-update.json"
|
||||
},
|
||||
"cookbook_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "cookbook_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "cookbook_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/cookbook_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"edit_internal_recipe.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "edit_internal_recipe.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "edit_internal_recipe.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/edit_internal_recipe.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"import_response_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "import_response_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "import_response_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/import_response_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"meal_plan_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "meal_plan_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "meal_plan_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/meal_plan_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"model_list_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "model_list_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "model_list_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"offline_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "offline_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "offline_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/offline_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"recipe_search_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "recipe_search_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "recipe_search_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/recipe_search_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"recipe_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "recipe_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "recipe_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/recipe_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"supermarket_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "supermarket_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "supermarket_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/supermarket_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"user_file_view.307bb5ac629ff8f5dba5.hot-update.js": {
|
||||
"name": "user_file_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"path": "user_file_view.307bb5ac629ff8f5dba5.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/user_file_view.307bb5ac629ff8f5dba5.hot-update.js"
|
||||
},
|
||||
"307bb5ac629ff8f5dba5.hot-update.json": {
|
||||
"name": "307bb5ac629ff8f5dba5.hot-update.json",
|
||||
"path": "307bb5ac629ff8f5dba5.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/307bb5ac629ff8f5dba5.hot-update.json"
|
||||
},
|
||||
"model_list_view.e2073a90ad8ff66f374c.hot-update.js": {
|
||||
"name": "model_list_view.e2073a90ad8ff66f374c.hot-update.js",
|
||||
"path": "model_list_view.e2073a90ad8ff66f374c.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.e2073a90ad8ff66f374c.hot-update.js"
|
||||
},
|
||||
"e2073a90ad8ff66f374c.hot-update.json": {
|
||||
"name": "e2073a90ad8ff66f374c.hot-update.json",
|
||||
"path": "e2073a90ad8ff66f374c.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/e2073a90ad8ff66f374c.hot-update.json"
|
||||
},
|
||||
"model_list_view.1b14899ea7152cc46f4e.hot-update.js": {
|
||||
"name": "model_list_view.1b14899ea7152cc46f4e.hot-update.js",
|
||||
"path": "model_list_view.1b14899ea7152cc46f4e.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.1b14899ea7152cc46f4e.hot-update.js"
|
||||
},
|
||||
"1b14899ea7152cc46f4e.hot-update.json": {
|
||||
"name": "1b14899ea7152cc46f4e.hot-update.json",
|
||||
"path": "1b14899ea7152cc46f4e.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/1b14899ea7152cc46f4e.hot-update.json"
|
||||
},
|
||||
"model_list_view.7a2ce4182c97623ab7e8.hot-update.js": {
|
||||
"name": "model_list_view.7a2ce4182c97623ab7e8.hot-update.js",
|
||||
"path": "model_list_view.7a2ce4182c97623ab7e8.hot-update.js",
|
||||
"publicPath": "http://localhost:8080/model_list_view.7a2ce4182c97623ab7e8.hot-update.js"
|
||||
},
|
||||
"7a2ce4182c97623ab7e8.hot-update.json": {
|
||||
"name": "7a2ce4182c97623ab7e8.hot-update.json",
|
||||
"path": "7a2ce4182c97623ab7e8.hot-update.json",
|
||||
"publicPath": "http://localhost:8080/7a2ce4182c97623ab7e8.hot-update.json"
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"recipe_search_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/recipe_search_view.css",
|
||||
"js/recipe_search_view.js"
|
||||
],
|
||||
"recipe_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/recipe_view.css",
|
||||
"js/recipe_view.js"
|
||||
],
|
||||
"offline_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"js/offline_view.js"
|
||||
],
|
||||
"import_response_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"js/import_response_view.js"
|
||||
],
|
||||
"supermarket_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"js/supermarket_view.js"
|
||||
],
|
||||
"user_file_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"js/user_file_view.js"
|
||||
],
|
||||
"model_list_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/model_list_view.css",
|
||||
"js/model_list_view.js"
|
||||
"js/model_list_view.js",
|
||||
"model_list_view.7a2ce4182c97623ab7e8.hot-update.js"
|
||||
],
|
||||
"edit_internal_recipe": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/edit_internal_recipe.css",
|
||||
"js/edit_internal_recipe.js"
|
||||
],
|
||||
"cookbook_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/cookbook_view.css",
|
||||
"js/cookbook_view.js"
|
||||
],
|
||||
"meal_plan_view": [
|
||||
"css/chunk-vendors.css",
|
||||
"js/chunk-vendors.js",
|
||||
"css/meal_plan_view.css",
|
||||
"js/meal_plan_view.js"
|
||||
]
|
||||
}
|
||||
},
|
||||
"publicPath": "http://localhost:8080/"
|
||||
}
|
Loading…
Reference in New Issue
Block a user