def hook(request, token): try: tb = get_object_or_404(TelegramBot, webhook_token=token) data = json.loads(request.body.decode()) if tb.chat_id == '': tb.chat_id = data['message']['chat']['id'] tb.save() if tb.chat_id == str(data['message']['chat']['id']): 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, food, note = ingredient_parser.parse( data['message']['text']) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) ShoppingListEntry.objects.create(food=f, unit=u, amount=amount, created_by=request.user, space=request.space) return JsonResponse({'data': data['message']['text']}) except Exception: traceback.print_exc() return JsonResponse({})
def hook(request, token): try: tb = get_object_or_404(TelegramBot, webhook_token=token) data = json.loads(request.body.decode()) if tb.chat_id == '': tb.chat_id = data['message']['chat']['id'] tb.save() if tb.chat_id == str(data['message']['chat']['id']): sl = ShoppingList.objects.filter( Q(created_by=tb.created_by)).filter( finished=False, space=tb.space).order_by('-created_at').first() if not sl: sl = ShoppingList.objects.create(created_by=tb.created_by, space=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)) return JsonResponse({'data': data['message']['text']}) except Exception: pass return JsonResponse({})
def get_recipe_from_file(self, file): ingredient_mode = False direction_mode = False ingredients = [] directions = [] for line in file.replace('\r', '').replace('\n\n', '\n').split('\n'): if 'Titel:' in line: title = line.replace('Titel:', '').strip() if 'Kategorien:' in line: tags = line.replace('Kategorien:', '').strip() if ingredient_mode and ('quelle' in line.lower() or 'source' in line.lower() or (line == '' and len(ingredients) > 0)): ingredient_mode = False direction_mode = True if ingredient_mode: if line != '' and '===' not in line and 'Zubereitung' not in line: ingredients.append(line.strip()) if direction_mode: if line.strip() != '' and line.strip() != '=====': directions.append(line.strip()) if 'Zutaten:' in line or 'Ingredients' in line or 'Menge:' in line: ingredient_mode = True recipe = Recipe.objects.create(name=title, created_by=self.request.user, internal=True, space=self.request.space) for k in tags.split(','): keyword, created = Keyword.objects.get_or_create( name=k.strip(), space=self.request.space) recipe.keywords.add(keyword) step = Step.objects.create( 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, food, note = ingredient_parser.parse(ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): servings = 1 ingredients = [] directions = [] for line in file.replace('\r', '').split('\n'): if not line.startswith('MMMMM') and line.strip != '': if 'Title:' in line: title = line.replace('Title:', '').strip() else: if 'Categories:' in line: tags = line.replace('Categories:', '').strip() else: if 'Yield:' in line: servings_text = line.replace('Yield:', '').strip() else: if re.match('\s{2,}([0-9])+', line): ingredients.append(line.strip()) else: directions.append(line.strip()) try: servings = re.findall('([0-9])+', servings_text)[0] except Exception as e: print('failed parsing servings ', e) recipe = Recipe.objects.create(name=title, servings=servings, created_by=self.request.user, internal=True, space=self.request.space) for k in tags.split(','): keyword, created = Keyword.objects.get_or_create( name=k.strip(), space=self.request.space) recipe.keywords.add(keyword) step = Step.objects.create( 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 = 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, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): recipe_html = file.getvalue().decode("utf-8") recipe_json, recipe_tree, html_data, images = get_recipe_from_source( recipe_html, 'CookBookApp', self.request) recipe = Recipe.objects.create(name=recipe_json['name'].strip(), created_by=self.request.user, internal=True, space=self.request.space) try: recipe.servings = re.findall('([0-9])+', recipe_json['recipeYield'])[0] except Exception as e: pass try: recipe.working_time = iso_duration_to_minutes( recipe_json['prepTime']) recipe.waiting_time = iso_duration_to_minutes( recipe_json['cookTime']) except Exception: pass step = Step.objects.create( instruction=recipe_json['recipeInstructions'], space=self.request.space, ) if 'nutrition' in recipe_json: step.instruction = step.instruction + '\n\n' + recipe_json[ 'nutrition'] step.save() recipe.steps.add(step) ingredient_parser = IngredientParser(self.request, True) for ingredient in recipe_json['recipeIngredient']: f = ingredient_parser.get_food(ingredient['ingredient']['text']) u = ingredient_parser.get_unit(ingredient['unit']['text']) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=ingredient['amount'], note=ingredient['note'], space=self.request.space, )) if len(images) > 0: try: response = requests.get(images[0]) self.import_recipe_image(recipe, BytesIO(response.content)) except Exception as e: print('failed to import image ', str(e)) recipe.save() return recipe
def get_recipe_from_file(self, file): source_url = '' ingredient_mode = 0 ingredients = [] directions = [] for i, fl in enumerate(file.readlines(), start=0): line = fl.decode("utf-8") if i == 0: title = line.strip() else: if line.startswith('https:') or line.startswith('http:'): source_url = line.strip() else: if ingredient_mode == 1 and len(line.strip()) == 0: ingredient_mode = 2 if re.match(r'^([0-9])[^.](.)*$', line) and ingredient_mode < 2: ingredient_mode = 1 ingredients.append(line.strip()) else: directions.append(line.strip()) recipe = Recipe.objects.create( name=title, created_by=self.request.user, internal=True, space=self.request.space, ) step = Step.objects.create( instruction='\n'.join(directions), space=self.request.space, ) if source_url != '': 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 = 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, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): ingredient_mode = False direction_mode = False ingredients = [] directions = [] for fl in file.readlines(): line = fl.decode("utf-8") if 'Title:' in line: title = line.replace('Title:', '').replace('"', '').strip() if 'Description:' in line: description = line.replace('Description:', '').strip() if 'Original URL:' in line or 'Source:' in line or 'Yield:' in line or 'Total:' in line: if len(line.strip().split(':')[1]) > 0: directions.append(line.strip() + '\n') if ingredient_mode: if len(line) > 2 and 'Instructions:' not in line: ingredients.append(line.strip()) if direction_mode: if len(line) > 2: directions.append(line.strip() + '\n') if 'Ingredients:' in line: ingredient_mode = True if 'Instructions:' in line: ingredient_mode = False direction_mode = True 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) + '\n\n', space=self.request.space, ) ingredient_parser = IngredientParser(self.request, True) for ingredient in ingredients: if len(ingredient.strip()) > 0: amount, unit, food, note = ingredient_parser.parse(ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): recipe = Recipe.objects.create(name=file['name'].strip(), created_by=self.request.user, internal=True, space=self.request.space) try: if file['recipeYield'] != '': recipe.servings = int(file['recipeYield']) if file['totalTime'] != '': recipe.waiting_time = int(file['totalTime']) - int( file['timePrep']) if file['prepTime'] != '': recipe.working_time = int(file['timePrep']) recipe.save() 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( instruction=s['text'], space=self.request.space, ) if not ingredients_added: ingredients_added = True for ingredient in file['recipeIngredient']: amount, unit, food, note = ingredient_parser.parse( ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) if len(file['image']) > 0: try: response = requests.get(file['image'][0]) self.import_recipe_image(recipe, BytesIO(response.content)) except Exception as e: print('failed to import image ', str(e)) return recipe
def get_recipe_from_file(self, file): # 'file' comes is as a beautifulsoup object recipe = Recipe.objects.create(name=file.find("h2", {"itemprop": "name"}).text.strip(), created_by=self.request.user, internal=True, space=self.request.space, ) # add 'Courses' and 'Categories' as keywords for course in file.find_all("span", {"itemprop": "recipeCourse"}): keyword, created = Keyword.objects.get_or_create(name=course.text, space=self.request.space) recipe.keywords.add(keyword) for category in file.find_all("meta", {"itemprop": "recipeCategory"}): keyword, created = Keyword.objects.get_or_create(name=category.get("content"), space=self.request.space) recipe.keywords.add(keyword) try: recipe.servings = parse_servings(file.find("span", {"itemprop": "recipeYield"}).text.strip()) recipe.working_time = iso_duration_to_minutes(file.find("span", {"meta": "prepTime"}).text.strip()) recipe.waiting_time = iso_duration_to_minutes(file.find("span", {"meta": "cookTime"}).text.strip()) recipe.save() except AttributeError: pass 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 = 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, )) for s in file.find("div", {"itemprop": "recipeDirections"}).find_all("p"): if s.text == "": continue step.instruction += s.text + ' \n' if file.find("span", {"itemprop": "recipeSource"}).text != '': step.instruction += "\n\nImported from: " + file.find("span", {"itemprop": "recipeSource"}).text step.save() recipe.steps.add(step) # import the Primary recipe image that is stored in the Zip try: for f in self.files: if '.zip' in f['name']: import_zip = ZipFile(f['file']) self.import_recipe_image(recipe, BytesIO(import_zip.read(file.find("img", class_="recipe-photo").get("src"))), filetype='.jpeg') except Exception as e: print(recipe.name, ': failed to import image ', str(e)) return recipe
def get_recipe_from_file(self, file): recipe = Recipe.objects.create(name=file['name'].strip(), created_by=self.request.user, internal=True, space=self.request.space) if file['servings'] != '': recipe.servings = file['servings'] if file['timeCook'] != '': recipe.waiting_time = file['timeCook'] if file['timePrep'] != '': recipe.working_time = file['timePrep'] recipe.save() step = Step.objects.create( instruction=file['directions'], space=self.request.space, ) 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, food, note = ingredient_parser.parse(ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) if file['image'] != '': self.import_recipe_image( recipe, BytesIO( base64.b64decode(file['image'].replace( 'data:image/jpeg;base64,', ''))), filetype='.jpeg') return recipe
def test(request): if not settings.DEBUG: return HttpResponseRedirect(reverse('index')) from cookbook.helper.ingredient_parser import IngredientParser parser = IngredientParser(request, False) data = { 'original': '1 LoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutlLoremipsumdolorsitametconsetetursadipscingelitrseddiamnonumyeirmodtemporinviduntutl' } data['parsed'] = parser.parse(data['original']) return render(request, 'test.html', {'data': data})
def ingredient_from_string(request): text = request.POST['text'] ingredient_parser = IngredientParser(request, False) amount, unit, food, note = ingredient_parser.parse(text) return JsonResponse( { 'amount': amount, 'unit': unit, 'food': food, 'note': note }, status=200)
def get_recipe_from_file(self, file): recipe = Recipe.objects.create(name=file['name'].strip(), created_by=self.request.user, internal=True, servings=file['servings'], space=self.request.space, waiting_time=file['cook_time'], working_time=file['prep_time']) instructions = '' if file["info"] != '': instructions += file["info"] if file["directions"] != '': instructions += file["directions"] if file["source"] != '': instructions += file["source"] step = Step.objects.create( instruction=instructions, space=self.request.space, ) ingredient_parser = IngredientParser(self.request, True) for ingredient in file['ingredients']: 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, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): recipe_json = json.loads(file.getvalue().decode("utf-8")) description = '' if len(recipe_json['description'].strip()) > 500 else recipe_json['description'].strip() recipe = Recipe.objects.create( name=recipe_json['name'].strip(), description=description, created_by=self.request.user, internal=True, space=self.request.space) # TODO parse times (given in PT2H3M ) # @vabene check recipe_url_import.iso_duration_to_minutes I think it does what you are looking for ingredients_added = False for s in recipe_json['recipe_instructions']: step = Step.objects.create( instruction=s['text'], space=self.request.space, ) if not ingredients_added: ingredients_added = True 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 = ingredient_parser.get_food(ingredient['food']) u = ingredient_parser.get_unit(ingredient['unit']) amount = ingredient['quantity'] note = ingredient['note'] else: 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, )) except Exception: pass recipe.steps.add(step) for f in self.files: if '.zip' in f['name']: import_zip = ZipFile(f['file']) try: self.import_recipe_image(recipe, BytesIO(import_zip.read(f'recipes/{recipe_json["slug"]}/images/min-original.webp')), filetype=get_filetype(f'recipes/{recipe_json["slug"]}/images/original')) except Exception: pass return recipe
def get_recipe_from_file(self, file): recipe_json = json.loads(file.getvalue().decode("utf-8")) description = '' if len(recipe_json['description'].strip( )) > 500 else recipe_json['description'].strip() recipe = Recipe.objects.create(name=recipe_json['name'].strip(), description=description, created_by=self.request.user, internal=True, servings=recipe_json['recipeYield'], space=self.request.space) try: recipe.working_time = iso_duration_to_minutes( recipe_json['prepTime']) recipe.waiting_time = iso_duration_to_minutes( recipe_json['cookTime']) except Exception: pass if 'url' in recipe_json: recipe.source_url = recipe_json['url'].strip() if 'recipeCategory' in recipe_json: try: recipe.keywords.add( Keyword.objects.get_or_create( space=self.request.space, name=recipe_json['recipeCategory'])[0]) except Exception: pass if 'keywords' in recipe_json: try: for x in recipe_json['keywords'].split(','): if x.strip() != '': recipe.keywords.add( Keyword.objects.get_or_create( space=self.request.space, name=x)[0]) except Exception: pass ingredients_added = False for s in recipe_json['recipeInstructions']: step = Step.objects.create( instruction=s, space=self.request.space, ) if not ingredients_added: if len(recipe_json['description'].strip()) > 500: step.instruction = recipe_json['description'].strip( ) + '\n\n' + step.instruction ingredients_added = True ingredient_parser = IngredientParser(self.request, True) for ingredient in recipe_json['recipeIngredient']: amount, unit, food, note = ingredient_parser.parse( ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) if 'nutrition' in recipe_json: try: recipe.nutrition.calories = recipe_json['nutrition'][ 'calories'].replace(' kcal', '').replace(' ', '') recipe.nutrition.proteins = recipe_json['nutrition'][ 'calories'].replace(' g', '').replace(',', '.').replace(' ', '') recipe.nutrition.fats = recipe_json['nutrition'][ 'calories'].replace(' g', '').replace(',', '.').replace(' ', '') recipe.nutrition.carbohydrates = recipe_json['nutrition'][ 'calories'].replace(' g', '').replace(',', '.').replace(' ', '') except Exception: pass for f in self.files: if '.zip' in f['name']: import_zip = ZipFile(f['file']) for z in import_zip.filelist: if re.match(f'^(.)+{recipe.name}/full.jpg$', z.filename): self.import_recipe_image( recipe, BytesIO(import_zip.read(z.filename)), filetype=get_filetype(z.filename)) return recipe
def get_from_scraper(scrape, request): # converting the scrape_me object to the existing json format based on ld+json recipe_json = {} try: recipe_json['name'] = parse_name(scrape.title() or None) except Exception: recipe_json['name'] = None if not recipe_json['name']: try: recipe_json['name'] = scrape.schema.data.get('name') or '' except Exception: recipe_json['name'] = '' try: description = scrape.schema.data.get("description") or '' except Exception: description = '' recipe_json['description'] = parse_description(description) try: servings = scrape.yields() or None except Exception: servings = None if not servings: try: servings = scrape.schema.data.get('recipeYield') or 1 except Exception: servings = 1 if type(servings) != int: try: servings = int(re.findall(r'\b\d+\b', servings)[0]) except Exception: servings = 1 recipe_json['servings'] = max(servings, 1) try: recipe_json['prepTime'] = get_minutes( scrape.schema.data.get("prepTime")) or 0 except Exception: recipe_json['prepTime'] = 0 try: recipe_json['cookTime'] = get_minutes( scrape.schema.data.get("cookTime")) or 0 except Exception: recipe_json['cookTime'] = 0 if recipe_json['cookTime'] + recipe_json['prepTime'] == 0: try: recipe_json['prepTime'] = get_minutes(scrape.total_time()) or 0 except Exception: try: get_minutes(scrape.schema.data.get("totalTime")) or 0 except Exception: pass try: recipe_json['image'] = parse_image(scrape.image()) or None except Exception: recipe_json['image'] = None if not recipe_json['image']: try: recipe_json['image'] = parse_image( scrape.schema.data.get('image')) or '' except Exception: recipe_json['image'] = '' keywords = [] try: if scrape.schema.data.get("keywords"): keywords += listify_keywords(scrape.schema.data.get("keywords")) except Exception: pass try: if scrape.schema.data.get('recipeCategory'): keywords += listify_keywords( scrape.schema.data.get("recipeCategory")) except Exception: pass try: if scrape.schema.data.get('recipeCuisine'): keywords += listify_keywords( scrape.schema.data.get("recipeCuisine")) except Exception: pass try: 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 = ingredient_parser.parse(x) ingredients.append({ 'amount': amount, 'unit': { 'text': unit, 'id': random.randrange(10000, 99999) }, 'ingredient': { 'text': ingredient, 'id': random.randrange(10000, 99999) }, 'note': note, 'original': x }) except Exception: ingredients.append({ 'amount': 0, 'unit': { 'text': '', 'id': random.randrange(10000, 99999) }, 'ingredient': { 'text': x, 'id': random.randrange(10000, 99999) }, 'note': '', 'original': x }) recipe_json['recipeIngredient'] = ingredients except Exception: recipe_json['recipeIngredient'] = ingredients try: recipe_json['recipeInstructions'] = parse_instructions( scrape.instructions()) except Exception: recipe_json['recipeInstructions'] = "" if scrape.url: recipe_json['url'] = scrape.url recipe_json['recipeInstructions'] += "\n\nImported from " + scrape.url return recipe_json
def get_recipe_from_file(self, file): # Create initial recipe with just a title and a description recipe = Recipe.objects.create( name=file['title'], created_by=self.request.user, internal=True, space=self.request.space, ) # set the description as an empty string for later use for the source URL, in case there is no description text. recipe.description = '' try: if file['description'] != '': recipe.description = file['description'].strip() except Exception as e: print(recipe.name, ': failed to parse recipe description ', str(e)) instructions = file['instructions'] if not instructions: instructions = '' step = Step.objects.create( instruction=instructions, space=self.request.space, ) # Append the original import url to the step (if it exists) try: if file['url'] != '': step.instruction += '\n\n' + _( 'Imported from') + ': ' + file['url'] step.save() except Exception as e: print(recipe.name, ': failed to import source url ', str(e)) 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, food, note = ingredient_parser.parse(food) 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, original_text=ingredient, space=self.request.space, )) except Exception as e: print(recipe.name, ': failed to parse recipe ingredients ', str(e)) recipe.steps.add(step) # Attempt to import prep/cooking times # quick hack, this assumes only one number in the quantity field. try: if file['quantity'] != '': for item in file['quantity'].split(' '): if item.isdigit(): recipe.servings = int(item) break except Exception as e: print(recipe.name, ': failed to parse quantity ', str(e)) try: if file['totalTime'] != '': recipe.waiting_time = int(file['totalTime']) except Exception as e: print(recipe.name, ': failed to parse total times ', str(e)) try: if file['preparationTime'] != '': recipe.working_time = int(file['preparationTime']) except Exception as e: print(recipe.name, ': failed to parse prep time ', str(e)) try: if file['cookingTime'] != '': recipe.waiting_time = int(file['cookingTime']) except Exception as e: print(recipe.name, ': failed to parse cooking time ', str(e)) recipe.save() # Import the recipe keywords try: if file['keywords'] != '': for keyword in file['keywords'].split(';'): k, created = Keyword.objects.get_or_create( name=keyword.strip(), space=self.request.space) recipe.keywords.add(k) recipe.save() except Exception as e: print(recipe.name, ': failed to parse keywords ', str(e)) # TODO: Parse Nutritional Information # Import the original image from the zip file, if we cannot do that, attempt to download it again. try: if file['pictures'][0] != '': image_file_name = file['pictures'][0].split('/')[-1] for f in self.files: if '.rtk' in f['name']: import_zip = ZipFile(f['file']) self.import_recipe_image( recipe, BytesIO(import_zip.read(image_file_name)), filetype=get_filetype(image_file_name)) else: if file['originalPicture'] != '': response = requests.get(file['originalPicture']) if imghdr.what(BytesIO(response.content)) is not None: self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype( file['originalPicture'])) else: raise Exception("Original image failed to download.") except Exception as e: print(recipe.name, ': failed to import image ', str(e)) return recipe
def get_recipe_from_file(self, file): ingredient_mode = False direction_mode = False image_url = None tags = None ingredients = [] directions = [] description = '' for line in file.replace('\r', '').split('\n'): if line.strip() != '': if 'Title:' in line: title = line.replace('Title:', '').replace('"', '').strip() if 'Description:' in line: description = line.replace('Description:', '').strip() if 'Source:' in line or 'Serves:' in line or 'Prep Time:' in line or 'Cook Time:' in line: directions.append(line.strip() + '\n') if 'Photo Url:' in line: image_url = line.replace('Photo Url:', '').strip() if 'Tags:' in line: tags = line.replace('Tags:', '').strip() if ingredient_mode: if len(line) > 2 and 'Instructions:' not in line: ingredients.append(line.strip()) if direction_mode: if len(line) > 2: directions.append(line.strip() + '\n') if 'Ingredients:' in line: ingredient_mode = True if 'Directions:' in line: ingredient_mode = False direction_mode = True 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) + '\n\n', space=self.request.space, ) if tags: for k in tags.split(','): 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 = 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, )) recipe.steps.add(step) if image_url: try: response = requests.get(image_url) self.import_recipe_image(recipe, BytesIO(response.content)) except Exception as e: print('failed to import image ', str(e)) return recipe
def test_ingredient_parser(): expectations = { "2¼ l Wasser": (2.25, "l", "Wasser", ""), "2¼l Wasser": (2.25, "l", "Wasser", ""), "¼ l Wasser": (0.25, "l", "Wasser", ""), "3l Wasser": (3, "l", "Wasser", ""), "4 l Wasser": (4, "l", "Wasser", ""), "½l Wasser": (0.5, "l", "Wasser", ""), "⅛ Liter Sauerrahm": (0.125, "Liter", "Sauerrahm", ""), "5 Zwiebeln": (5, "", "Zwiebeln", ""), "3 Zwiebeln, gehackt": (3, "", "Zwiebeln", "gehackt"), "5 Zwiebeln (gehackt)": (5, "", "Zwiebeln", "gehackt"), "1 Zwiebel(n)": (1, "", "Zwiebel(n)", ""), "4 1/2 Zwiebeln": (4.5, "", "Zwiebeln", ""), "4 ½ Zwiebeln": (4.5, "", "Zwiebeln", ""), "1/2 EL Mehl": (0.5, "EL", "Mehl", ""), "1/2 Zwiebel": (0.5, "", "Zwiebel", ""), "1/5g Mehl, gesiebt": (0.2, "g", "Mehl", "gesiebt"), "1/2 Zitrone, ausgepresst": (0.5, "", "Zitrone", "ausgepresst"), "etwas Mehl": (0, "", "etwas Mehl", ""), "Öl zum Anbraten": (0, "", "Öl zum Anbraten", ""), "n. B. Knoblauch, zerdrückt": (0, "", "n. B. Knoblauch", "zerdrückt"), "Kräuter, mediterrane (Oregano, Rosmarin, Basilikum)": (0, "", "Kräuter, mediterrane", "Oregano, Rosmarin, Basilikum"), "600 g Kürbisfleisch (Hokkaido), geschält, entkernt und geraspelt": (600, "g", "Kürbisfleisch (Hokkaido)", "geschält, entkernt und geraspelt"), "Muskat": (0, "", "Muskat", ""), "200 g Mehl, glattes": (200, "g", "Mehl", "glattes"), "1 Ei(er)": (1, "", "Ei(er)", ""), "1 Prise(n) Salz": (1, "Prise(n)", "Salz", ""), "etwas Wasser, lauwarmes": (0, "", "etwas Wasser", "lauwarmes"), "Strudelblätter, fertige, für zwei Strudel": (0, "", "Strudelblätter", "fertige, für zwei Strudel"), "barrel-aged Bourbon": (0, "", "barrel-aged Bourbon", ""), "golden syrup": (0, "", "golden syrup", ""), "unsalted butter, for greasing": (0, "", "unsalted butter", "for greasing"), "unsalted butter , for greasing": (0, "", "unsalted butter", "for greasing"), # trim "1 small sprig of fresh rosemary": (1, "small", "sprig of fresh rosemary", ""), # does not always work perfectly! "75 g fresh breadcrumbs": (75, "g", "fresh breadcrumbs", ""), "4 acorn squash , or onion squash (600-800g)": (4, "acorn", "squash , or onion squash", "600-800g"), "1 x 250 g packet of cooked mixed grains , such as spelt and wild rice": (1, "x", "250 g packet of cooked mixed grains", "such as spelt and wild rice"), "1 big bunch of fresh mint , (60g)": (1, "big", "bunch of fresh mint ,", "60g"), "1 large red onion": (1, "large", "red onion", ""), # "2-3 TL Curry": (), # idk what it should use here either "1 Zwiebel gehackt": (1, "Zwiebel", "gehackt", ""), "1 EL Kokosöl": (1, "EL", "Kokosöl", ""), "0.5 paket jäst (à 50 g)": (0.5, "paket", "jäst", "à 50 g"), "ägg": (0, "", "ägg", ""), "50 g smör eller margarin": (50, "g", "smör eller margarin", ""), "3,5 l Wasser": (3.5, "l", "Wasser", ""), "3.5 l Wasser": (3.5, "l", "Wasser", ""), "400 g Karotte(n)": (400, "g", "Karotte(n)", ""), "400g unsalted butter": (400, "g", "butter", "unsalted"), "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 } # 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 = ingredient_parser.parse(key) assert val == parsed
def get_recipe_from_file(self, file): # 'file' comes is as a beautifulsoup object recipe = Recipe.objects.create(name=file.find("div", {"id": "name"}).text.strip(), created_by=self.request.user, internal=True, space=self.request.space, ) for category in file.find_all("span", {"class": "recipeCategory"}): keyword, created = Keyword.objects.get_or_create(name=category.text, space=self.request.space) recipe.keywords.add(keyword) try: recipe.servings = parse_servings(file.find("a", {"id": "recipeYield"}).text.strip()) recipe.working_time = iso_duration_to_minutes(file.find("span", {"meta": "prepTime"}).text.strip()) recipe.waiting_time = iso_duration_to_minutes(file.find("span", {"meta": "cookTime"}).text.strip()) recipe.description = (file.find("div ", {"id": "description"}).text.strip())[:512] except AttributeError: pass try: if len(file.find("span", {"id": "starred"}).text.strip()) > 0: recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=_('Favorite'))[0]) except AttributeError: pass step = Step.objects.create(instruction='', space=self.request.space, ) ingredient_parser = IngredientParser(self.request, True) for ingredient in file.find_all("li", {"class": "recipeIngredient"}): if ingredient.text == "": continue amount, unit, food, note = ingredient_parser.parse(ingredient.text.strip()) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add(Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space, )) for s in file.find_all("li", {"class": "instruction"}): if s.text == "": continue step.instruction += s.text.strip() + ' \n\n' for s in file.find_all("li", {"class": "recipeNote"}): if s.text == "": continue step.instruction += s.text.strip() + ' \n\n' try: if file.find("a", {"id": "original_link"}).text != '': step.instruction += "\n\n" + _("Imported from") + ": " + file.find("a", {"id": "original_link"}).text step.save() except AttributeError: pass recipe.steps.add(step) # import the Primary recipe image that is stored in the Zip try: for f in self.files: if '.zip' in f['name']: import_zip = ZipFile(f['file']) self.import_recipe_image(recipe, BytesIO(import_zip.read(file.find("img", class_="recipeImage").get("src"))), filetype='.jpeg') except Exception as e: print(recipe.name, ': failed to import image ', str(e)) recipe.save() return recipe
if source_url := scrape.url: recipe_json['source_url'] = source_url try: keywords.append( source_url.replace('http://', '').replace('https://', '').split('/')[0]) except Exception: pass try: recipe_json['keywords'] = parse_keywords( list(set(map(str.casefold, keywords))), request.space) except AttributeError: recipe_json['keywords'] = keywords ingredient_parser = IngredientParser(request, True) recipe_json['steps'] = [] for i in parse_instructions(scrape.instructions()): recipe_json['steps'].append({ 'instruction': i, 'ingredients': [], }) if len(recipe_json['steps']) == 0: recipe_json['steps'].append({ 'instruction': '', 'ingredients': [], }) if len(
def get_recipe_from_file(self, file): recipe_json = file recipe = Recipe.objects.create(name=recipe_json['title'].strip(), created_by=self.request.user, internal=True, space=self.request.space) if 'yield' in recipe_json: recipe.servings = parse_servings(recipe_json['yield']) if 'cookTime' in recipe_json: recipe.waiting_time = parse_time(recipe_json['cookTime']) if 'prepTime' in recipe_json: recipe.working_time = parse_time(recipe_json['prepTime']) if 'favorite' in recipe_json and recipe_json['favorite']: recipe.keywords.add( Keyword.objects.get_or_create(space=self.request.space, name=_('Favorite'))[0]) if 'categories' in recipe_json: try: for x in recipe_json['categories']: recipe.keywords.add( Keyword.objects.get_or_create(space=self.request.space, name=x)[0]) except Exception: pass instruction = '' if 'text' in recipe_json: instruction += f'*{recipe_json["text"].strip()}* \n' if 'instructions' in recipe_json: instruction += recipe_json["instructions"].strip() + ' \n' if 'notes' in recipe_json: instruction += recipe_json["notes"].strip() + ' \n' if 'link' in recipe_json: recipe.source_url = recipe_json['link'] step = Step.objects.create( instruction=instruction, space=self.request.space, ) ingredient_parser = IngredientParser(self.request, True) for ingredient in recipe_json['ingredients'].split('\n'): if ingredient.strip() != '': amount, unit, food, note = ingredient_parser.parse(ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) recipe.steps.add(step) if recipe_json.get("images", None): try: self.import_recipe_image( recipe, BytesIO(base64.b64decode(recipe_json['images'][0])), filetype='.jpeg') except Exception: pass return recipe
def get_recipe_from_file(self, file): ingredient_mode = False direction_mode = False ingredients = [] directions = [] for fl in file.readlines(): line = fl.decode("utf-8") if 'Title:' in line: title = line.replace('Title:', '').strip() if 'Description:' in line: description = line.replace('Description:', '').strip() if 'Yield:' in line: directions.append( _('Servings') + ' ' + line.replace('Yield:', '').strip() + '\n') if 'Cook:' in line: directions.append( _('Waiting time') + ' ' + line.replace('Cook:', '').strip() + '\n') if 'Prep:' in line: directions.append( _('Preparation Time') + ' ' + line.replace('Prep:', '').strip() + '\n') if 'Cookbook:' in line: directions.append( _('Cookbook') + ' ' + line.replace('Cookbook:', '').strip() + '\n') if 'Section:' in line: directions.append( _('Section') + ' ' + line.replace('Section:', '').strip() + '\n') if ingredient_mode: if len(line) > 2 and 'Instructions:' not in line: ingredients.append(line.strip()) if direction_mode: if len(line) > 2: directions.append(line.strip()) if 'Ingredients:' in line: ingredient_mode = True if 'Instructions:' in line: ingredient_mode = False direction_mode = True 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, ) ingredient_parser = IngredientParser(self.request, True) for ingredient in ingredients: 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, )) recipe.steps.add(step) return recipe
def get_recipe_from_file(self, file): recipe_xml = file recipe = Recipe.objects.create( name=recipe_xml.find('title').text.strip(), created_by=self.request.user, internal=True, space=self.request.space) if recipe_xml.find('preptime') is not None: recipe.working_time = parse_time( recipe_xml.find('preptime').text.strip()) if recipe_xml.find('cooktime') is not None: recipe.waiting_time = parse_time( recipe_xml.find('cooktime').text.strip()) if recipe_xml.find('quantity') is not None: recipe.servings = parse_servings( recipe_xml.find('quantity').text.strip()) recipe.servings_text = parse_servings_text( recipe_xml.find('quantity').text.strip()) if recipe_xml.find('url') is not None: recipe.source_url = recipe_xml.find('url').text.strip() if recipe_xml.find( 'description' ) is not None: # description is a list of <li>'s with text if len(recipe_xml.find('description')) > 0: recipe.description = recipe_xml.find( 'description')[0].text[:512] for step in recipe_xml.find('recipetext').getchildren(): step = Step.objects.create( instruction=step.text.strip(), space=self.request.space, ) recipe.steps.add(step) ingredient_parser = IngredientParser(self.request, True) for ingredient in recipe_xml.find('ingredient').getchildren(): if ingredient.text.strip() != '': amount, unit, food, note = ingredient_parser.parse( ingredient.text.strip()) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) recipe.steps.first().ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space, )) if recipe_xml.find('imageurl') is not None: try: response = requests.get( recipe_xml.find('imageurl').text.strip()) self.import_recipe_image(recipe, BytesIO(response.content)) except Exception as e: print('failed to import image ', str(e)) recipe.save() return recipe
def get_recipe_from_file(self, file): ingredient_mode = False direction_mode = False description_mode = False ingredients = [] directions = [] descriptions = [] for fl in file.readlines(): line = fl.decode("utf-8") if 'title:' in line: title = line.replace('title:', '').replace('"', '').strip() if 'image:' in line: image = line.replace('image:', '').strip() if 'tags:' in line: tags = line.replace('tags:', '').strip() if ingredient_mode: if len(line) > 2 and 'directions:' not in line: ingredients.append(line[2:]) if '---' in line and direction_mode: direction_mode = False description_mode = True if direction_mode: if len(line) > 2: directions.append(line[2:]) if 'ingredients:' in line: ingredient_mode = True if 'directions:' in line: ingredient_mode = False direction_mode = True if description_mode and len(line) > 3 and '---' not in line: descriptions.append(line) recipe = Recipe.objects.create(name=title, created_by=self.request.user, internal=True, space=self.request.space) for k in tags.split(','): print(f'adding keyword {k.strip()}') keyword, created = Keyword.objects.get_or_create(name=k.strip(), space=self.request.space) recipe.keywords.add(keyword) step = Step.objects.create( 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 = 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, )) recipe.steps.add(step) for f in self.files: if '.zip' in f['name']: import_zip = ZipFile(f['file']) for z in import_zip.filelist: if re.match(f'^images/{image}$', z.filename): self.import_recipe_image(recipe, BytesIO(import_zip.read(z.filename)), filetype=get_filetype(z.filename)) return recipe
def import_url(request): if request.space.max_recipes != 0 and Recipe.objects.filter( space=request.space ).count( ) >= request.space.max_recipes: # TODO move to central helper function messages.add_message( request, messages.WARNING, _('You have reached the maximum number of recipes for your space.') ) return HttpResponseRedirect(reverse('index')) if request.space.max_users != 0 and UserPreference.objects.filter( space=request.space).count() > request.space.max_users: messages.add_message( request, messages.WARNING, _('You have more users than allowed in your space.')) return HttpResponseRedirect(reverse('index')) if request.method == 'POST': data = json.loads(request.body) data['cookTime'] = parse_cooktime(data.get('cookTime', '')) data['prepTime'] = parse_cooktime(data.get('prepTime', '')) recipe = Recipe.objects.create( name=data['name'], description=data['description'], waiting_time=data['cookTime'], working_time=data['prepTime'], servings=data['servings'], internal=True, created_by=request.user, space=request.space, ) step = Step.objects.create( instruction=data['recipeInstructions'], space=request.space, ) recipe.steps.add(step) for kw in data['keywords']: if data['all_keywords']: # do not remove this check :) https://github.com/vabene1111/recipes/issues/645 k, created = Keyword.objects.get_or_create(name=kw['text'], space=request.space) recipe.keywords.add(k) else: try: k = Keyword.objects.get(name=kw['text'], space=request.space) recipe.keywords.add(k) except ObjectDoesNotExist: pass ingredient_parser = IngredientParser(request, True) for ing in data['recipeIngredient']: ingredient = Ingredient(space=request.space, ) if food_text := ing['ingredient']['text'].strip(): ingredient.food = ingredient_parser.get_food(food_text) if ing['unit']: if unit_text := ing['unit']['text'].strip(): ingredient.unit = ingredient_parser.get_unit(unit_text) # TODO properly handle no_amount recipes if isinstance(ing['amount'], str): try: ingredient.amount = float(ing['amount'].replace(',', '.')) except ValueError: ingredient.no_amount = True pass elif isinstance(ing['amount'], float) \ or isinstance(ing['amount'], int): ingredient.amount = ing['amount'] ingredient.note = ing['note'].strip() if 'note' in ing else '' ingredient.save() step.ingredients.add(ingredient)
def get_recipe_from_file(self, file): with gzip.open(file, 'r') as recipe_zip: recipe_json = json.loads(recipe_zip.read().decode("utf-8")) recipe = Recipe.objects.create(name=recipe_json['name'].strip(), created_by=self.request.user, internal=True, space=self.request.space) if 'description' in recipe_json: recipe.description = '' if len( recipe_json['description'].strip( )) > 500 else recipe_json['description'].strip() try: if 'servings' in recipe_json['servings']: recipe.servings = parse_servings(recipe_json['servings']) recipe.servings_text = parse_servings_text( recipe_json['servings']) if len(recipe_json['cook_time'].strip()) > 0: recipe.waiting_time = re.findall( r'\d+', recipe_json['cook_time'])[0] if len(recipe_json['prep_time'].strip()) > 0: recipe.working_time = re.findall( r'\d+', recipe_json['prep_time'])[0] except Exception: pass recipe.save() instructions = recipe_json['directions'] if recipe_json['notes'] and len(recipe_json['notes'].strip()) > 0: instructions += '\n\n### ' + _( 'Notes') + ' \n' + recipe_json['notes'] if recipe_json['nutritional_info'] and len( recipe_json['nutritional_info'].strip()) > 0: instructions += '\n\n### ' + _( 'Nutritional Information' ) + ' \n' + recipe_json['nutritional_info'] try: if len(recipe_json['source'].strip()) > 0 or len( recipe_json['source_url'].strip()) > 0: instructions += '\n\n### ' + _( 'Source') + ' \n' + recipe_json['source'].strip( ) + ' \n' + recipe_json['source_url'].strip() except AttributeError: pass step = Step.objects.create( instruction=instructions, space=self.request.space, ) if 'description' in recipe_json and len( recipe_json['description'].strip()) > 500: step.instruction = recipe_json['description'].strip( ) + '\n\n' + step.instruction if 'categories' in recipe_json: for c in recipe_json['categories']: 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, food, note = ingredient_parser.parse( ingredient) f = ingredient_parser.get_food(food) u = ingredient_parser.get_unit(unit) step.ingredients.add( Ingredient.objects.create( food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space, )) except AttributeError: pass recipe.steps.add(step) if recipe_json.get("photo_data", None): self.import_recipe_image( recipe, BytesIO(base64.b64decode(recipe_json['photo_data'])), filetype='.jpeg') return recipe