How it all began
A few years back, I started counting my calorie intake on the advice of my nutritionist in order to fix my abominable cholestrol levels (and let's face it, lose some weight). She suggested the Nutracheck app for tracking my food intake, which has a collection of all the foods and their nutritional information. Being obsessed with numbers, I took no time in conceding to her request.
I was a novice at cooking at the time and was mostly following online recipes to get by. Living in the UK without my mother, I was seeking the help of Pakistan's digital ammi, Food Fusion (@Foodfusionpk on youtube). Its a goldmine for all desi recipes with a 2–3 minute video format, perfect for amateurs like me who are also short on time (or just, start late and panic at 10pm when the food is not ready).
Nutracheck has the option to add custom dishes by adding their ingredients and directions. This custom dish has total calories as sum of all its ingredients' calories. Now, I am the kind of person who likes to cook something new often because I get bored of cooking the same things all the time. This obviously meant adding each ingredient of the dish line by line every single time I made something new to the app. It became cumbersome and I quickly realised I wanted to automate this process. Food fusion has their ingredients written in the description of the video. I could extract the ingredients from that description using Youtube Data API and then find a way to put it in nutracheck.
Getting ingredients from Youtube Data API
I created a project on google cloud and for the lack of a better name, called it 'fetch-food'. I enabled the Youtube Data API and generated an API key from the credentials, which is essential for authenticating requests from my Python script to the Youtube API.
I used the official Python client library for Google's discovery based APIs.
import googleapiclient.discovery
def parse_response(response: dict) -> dict | None:
"""Parses the response from the youtube api and returns a dictionary containing ingredients and title from the description of the video"""
if response['items'][0]['snippet']['channelTitle'] == 'Food Fusion':
description = response['items'][0]['snippet']['description']
start = description.find('Ingredients')
end = description.find('Directions', start)
return {"ingredients":description[start:end], "title": response['items'][0]['snippet']['title']}
else:
return None
def get_video_response(api_service_name: str, api_version: str) -> dict | None:
"""Prompts the user to provide the id for a food fusion video, sends it to youtube api v3 and returns a parsed response"""
youtube = googleapiclient.discovery.build(
api_service_name, api_version, developerKey=YOUR_YOUTUBE_API_KEY)
while True:
try:
id = input("Please enter id of the food fusion video: ")
request = youtube.videos().list(
part="snippet",
id=id
)
response = request.execute()
parsed_response = parse_response(response)
if parsed_response:
break
else:
print('Id does not belong to food fusion')
except Exception as e:
print(e)
return parsed_response
def main():
ingredients = get_video_response("youtube", "v3")
if __name__ == "__main__":
main()
In the code above, you can see in the get_video_response function, I ask the user to input the id of a food fusion video, which can be found on the address bar when navigating to the video. For example, In this URL, https://www.youtube.com/watch?v=Jc9X6u3H4Yk the id is 'Jc9X6u3H4Yk'. After receiving the id, the data is fetched which contains the title, description, publishedAt, channelId and channelTitle, categoryId, tags and thumbnails. I only need description so I single that out in the parse_response function after I check if the id indeed belongs to food fusion or not. Food fusion more or less has the same format of the description in which they write the ingredients and then directions. Using this information, I extracted out only the ingredients and returned them as a response.
That's it.
That is all I did and for a year or two, the little code just stayed in some folder I forgot existed. I had abandoned this because I didn't know how to easily sanitize the text into something an API would want, like separating out the ingredients from their quantity and unit. I wasn't invested enough to write my own parser either.
Using Google Gemini to sanitise the ingredients
Fast forward a few years I had stopped using Nutracheck because I believed I had become a calorie ninja who could decipher on her own what her daily consumption was. In reality though, I had reached my goal and developed good eating habits as a result so I didn't really feel the need to continue with nutracheck. ChatGPT was introduced around the same time. I was super pumped up about it, experimenting with it, asking it to write poetry in Allama Iqbal's style or songs in Taylor Swift style (Come on, we ALL did that). It occurred to me that I can use generative AI to sanitise the ingredients for me and use that as an input for a nutrition database. I opted for Google Gemini because it was easy to just get an API key and get started with the Google cloud project already set up. For the nutrition database, I found nutritionix API which was free to use and took natural language as input. Their cool demo is here.
I wrote a function called extract_ingredients that takes in the string of ingredients and sanitises it using google Gemini. An example of the ingredients look like this;
Ingredients: -Cooking oil 2 tbs -Adrak lehsan paste (Ginger Garlic paste) ½ tsp -Pyaz (Onion) finely chopped 1 medium -Zeera (Cumin seeds) 1 tsp -Chicken qeema (Mince) hand chopped 150g -Water 1–2 tbs -Kali mirch (Black pepper) crushed 1 tsp -Kashmiri lal mirch (Kashmiri red chilli) powder ½ tsp substitute: Paprika powder -Lal mirch powder (Red chilli powder) ½ tsp or to taste -Chicken powder ½ tsp -Zeera powder (Cumin powder) ½ tsp -Dhania powder (Coriander powder) ½ tsp -Haldi powder (Turmeric powder) ¼ tsp -Water 1–2 tbs -Tamatar (Tomato) chopped 1 small -Water 1–2 tbs -Iodized Himalayan pink salt ½ tsp or to taste -Water 1–2 tbs -Paneer (Cottage cheese) 120g -Cooking oil 1 tbs -Lal mirch (Red chilli) crushed -Kasuri methi (Dried fenugreek leaves) ½ tsp -Hari mirch (Green chilli) sliced -Hara dhania (Fresh coriander) chopped
What I want is to remove the urdu names from the text, bring the quantity to prefix the ingredient, use tbsp instead of tbs and use 'and' as seperator. I also asked it to ignore the ingredient that didn't have quantity.
I gave Gemini the following prompt;
Extract the english part of the ingredients and their amount. Bring the quantity before the ingredient. Correct the tbs to tbsp. I want the ingredients to be seperated by ' and '. Ignore any food that doesn't have quantity. If there is a vague quantity, for example '2–3 tbsp' then choose the higher value i.e. 3. An example of this is; '2 tbsp cooking oil and 1 tbsp Ginger garlic paste' \n - - - {ingredients} \n - - -
from google import genai
def extract_ingredients(ingredients: str) -> str:
"""Gives a list of ingredients to Gemini for sanitising and returns the sanitised response"""
prompt = f"Extract the english part of the ingredients and their amount. Bring the quantity before the ingredient. Correct the tbs to tbsp. I want the ingredients to be seperated by 'and '. Ignore any food that doesn't have quantity. If there is a vague quantity, for example '2-3 tbsp' then choose the higher value i.e. 3. An example of this is; '2 tbsp cooking oil and 1 tbsp Ginger garlic paste' \n ------ {ingredients} \n ------"
client = genai.Client(api_key=YOUR_GEMINI_API_KEY)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt
)
return response.text
def main():
ingredients = get_video_response("youtube", "v3")
sanitised_ingredients = extract_ingredients(ingredients["ingredients"])
if __name__ == "__main__":
main()
Now, I am still new to the world of prompt engineering. I thought my prompt was to the point and accurate but it gave me changing results everytime. Sometimes, it would add it's own sentences or it would mess up the quantity. So I did what any good developer would do. I gave gemini my own prompt and asked it to improve it. This is what it responded with;
You are a data-cleaning assistant. You will be given a list of cooking ingredients that include English and non-English names together with quantities. Your job is to extract only the English ingredient names and their quantities in a consistent, clean format for Nutritionix API parsing.
Follow these strict rules:
- Output Format:
- Each ingredient must follow this structure: {{quantity}} {{unit}} {{ingredient}}
- Separate all ingredients with ' and ' (exactly lowercase 'and' with spaces).
- Quantity Rules:
- Always put the quantity before the ingredient name.
- Convert all 'tbs' or 'tbs.' to 'tbsp'.
- If a range is given (e.g., '2–3 tbsp'), use the higher number (e.g., '3 tbsp').
- Ignore any ingredient that does not have a clear numeric quantity.
- Keep fractional amounts (e.g., '½ tsp' → '0.5 tsp').
- Ingredient Rules:
- Use only the English name (e.g., 'Lehsan (Garlic)' → 'Garlic').
- Remove any extra parentheses, Urdu/Hindi names, or descriptors not part of the core English ingredient.
- Output Consistency:
- No bullet points, commas, or newlines - only ' and ' as separators.
- Output must be a single clean line.
- Example:
- Input: -Lehsan (Garlic) 10–12 cloves -Pyaz (Onion) sliced 1 small -Cooking oil 2–3 tbs -Baisan (Gram flour) roasted 1 tbs
- Output: 12 cloves Garlic and 1 small Onion and 3 tbsp Cooking oil and 1 tbsp Gram flour Now clean and convert the following text accordingly: {ingredients}
def extract_ingredients(ingredients: str) -> str:
"""Gives a list of ingredients to Gemini for sanitising and returns the sanitised response"""
prompt = """
You are a data-cleaning assistant. You will be given a list of cooking ingredients that include English and non-English names together with quantities. Your job is to extract only the English ingredient names and their quantities in a consistent, clean format for Nutritionix API parsing.
Follow these strict rules:
1. Output Format:
- Each ingredient must follow this structure: {{quantity}} {{unit}} {{ingredient}}
- Separate all ingredients with ' and ' (exactly lowercase 'and' with spaces).
2. Quantity Rules:
- Always put the quantity before the ingredient name.
- Convert all 'tbs' or 'tbs.' to 'tbsp'.
- If a range is given (e.g., '2-3 tbsp'), use the higher number (e.g., '3 tbsp').
- Ignore any ingredient that does not have a clear numeric quantity.
- Keep fractional amounts (e.g., '½ tsp' → '0.5 tsp').
3. Ingredient Rules:
- Use only the English name (e.g., 'Lehsan (Garlic)' → 'Garlic').
- Remove any extra parentheses, Urdu/Hindi names, or descriptors not part of the core English ingredient.
4. Output Consistency:
- No bullet points, commas, or newlines - only ' and ' as separators.
- Output must be a single clean line.
5. Example:
- Input:
-Lehsan (Garlic) 10-12 cloves
-Pyaz (Onion) sliced 1 small
-Cooking oil 2-3 tbs
-Baisan (Gram flour) roasted 1 tbs
- Output:
12 cloves Garlic and 1 small Onion and 3 tbsp Cooking oil and 1 tbsp Gram flour
Now clean and convert the following text accordingly:
{}
""".format(ingredients)
client = genai.Client(api_key=config_loader.GEMINI_API_KEY)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt
)
return response.text
This gave accurate and reproducible response each time.
Calculating total calories using Nutritionix API
I created an account on the nutritionix and had an application id and key generated in order to connect to the database.
import requests
import json
def sum_calories(food_list: list) -> int:
"""Returns the sum of all calories in the food_list"""
total_calories = 0.0
for item in food_list:
try:
total_calories += item['calories']
except KeyError:
print(f"Error: Item {item['food_name']} is missing the 'calories' key.")
except TypeError:
print(f"Error: Calorie value for {item['food_name']} is not a number.")
return round(total_calories,2)
def filter_food_list(nutrition_data: dict) -> list:
"""Returns a list of foods with filtered key value pairs."""
return [
{
"food_name": n['food_name'],
"calories": n['nf_calories'],
"serving_qty": n['serving_qty'],
"serving_unit": n['serving_unit']
}
for n in nutrition_data['foods']
]
def fetch_nutrition(ingredients: str) -> int:
""" Passes a list of comma separated ingredients with their quantity to the nutritionix api and returns the sum of all calories in the food list """
url = "https://trackapi.nutritionix.com/v2/natural/nutrients"
headers = {
"Content-Type": "application/json",
"x-app-id": YOUR_NUTRITIONIX_ID,
"x-app-key": YOUR_NUTRITIONIX_API_KEY
}
payload = {
"query": ingredients
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
nutrition_data = response.json()
filtered_food_list = filter_food_list(nutrition_data)
return sum_calories(filtered_food_list)
def main():
ingredients = get_video_response("youtube", "v3")
title = ingredients['title']
sanitised_ingredients = extract_ingredients(ingredients["ingredients"])
total_calories = fetch_nutrition(sanitised_ingredients)
print(f"Total kilo calories in the {title} is", total_calories)
if __name__ == "__main__":
main()
In the above code, fetch_nutrition receives sanitised ingredients from google gemini and sends it through a POST request to Nutritionix API. This api responds with a dictionary containing each ingredient with all its nutritional information based on the quantity provided including calories, potassium, dietary fibre etc. The object structure is here. I only needed calories, serving quantity and serving unit so I extracted them out in filter_food_list then calculated the sum of calories in sum_calories function. So fetch_nutrition returns the total sum of calories in a dish. Ta daa!
A running example of the code using the id 'Jc9X6u3H4Yk'.
The total calories of Paneer Qeema Tawa Masala in the image above is 1003.03 kCal.
Problems
Obviously, I was just playing around with this little project. My aim was to do something I was curious about and not worry if it's the next best thing out there. There are many problems with this code, some of them are stated below;
1. Nutrition database
For the database. I just googled 'nutrition database' and this came up. Normally USDA FoodData Central is used because it is the most comprehensive. With Nutritionix, some of the items don't exist, for example, chicken powder. And it doesn't respond with an error, instead, it just gives chicken as a response which is obviously incorrect.
2. Restricting to Food fusion videos
I am strictly using Food fusion's videos. I can use it generically with any video that has ingredients in the description, or write a better prompt for gemini to extract ingredients from a block of text. It is easier to change the prompt should I change my database and therefore the structure of its API request.
Conclusion
I enjoyed the process even if it took ages. It made me look into many things I only used to hear people talk about like prompt engineering and using gemini api (cleared me of FOMO at the very least). The most important bit though, is that I now know how many calories I'm going to consume when I cook a meal from a video. No longer do I need to count every single ingredient that exists in a desi recipe (its a lot, I tell you). It also makes it easier for me to bounce back to nutracheck if need ever be (God forbid).
Now if you'll excuse me, I have a 10pm dinner panic to prevent.
Find the code
You can find the code here: https://github.com/sobia20/calorie-counter-from-youtube. You would need your own keys for Youtube, Gemini and Nutritionix. Put them in an env file and the config loader will pick them up for usage.
Suggestions
Apart from solving the issues I raised in the problems section, are there any suggestions you'd like to make on what I can do with this little project/idea?

Top comments (0)