Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import torch | |
| import cv2 | |
| import numpy as np | |
| from ultralytics import YOLO | |
| from PIL import Image | |
| import easyocr | |
| import requests | |
| def load_model(): | |
| # Load the pre-trained YOLOv8 model for object detection | |
| model = YOLO("yolov8n.pt") # You can use a custom-trained model for food detection | |
| return model | |
| def detect_ingredients(image, model): | |
| results = model(image) | |
| detected_items = set() | |
| for result in results: | |
| for box in result.boxes: | |
| cls = result.names[int(box.cls[0])] | |
| detected_items.add(cls) | |
| return list(detected_items) | |
| def extract_text(image): | |
| # Use EasyOCR to extract text from the image | |
| reader = easyocr.Reader(['en']) # Specify language | |
| results = reader.readtext(np.array(image)) # Convert PIL image to NumPy | |
| extracted_text = [text[1] for text in results] # Extract detected text | |
| return extracted_text | |
| MEALDB_API_URL = "https://www.themealdb.com/api/json/v1/1" | |
| def fetch_ingredients(): | |
| """Fetches a list of available ingredients from TheMealDB API.""" | |
| url = f"{MEALDB_API_URL}/list.php?i=list" | |
| response = requests.get(url) | |
| if response.status_code == 200: | |
| data = response.json() | |
| return [item["strIngredient"].lower() for item in data["meals"]] | |
| return [] | |
| def filter_valid_ingredients(detected_ingredients): | |
| """Filters detected ingredients against TheMealDB ingredient list.""" | |
| valid_ingredients = fetch_ingredients() | |
| return [ing for ing in detected_ingredients if ing.lower() in valid_ingredients] | |
| def get_recipes(ingredients): | |
| """Fetch recipes from TheMealDB based on detected ingredients.""" | |
| recipe_list = set() | |
| for ingredient in ingredients: | |
| url = f"{MEALDB_API_URL}/filter.php?i={ingredient}" | |
| response = requests.get(url) | |
| if response.status_code == 200: | |
| data = response.json() | |
| if data["meals"]: | |
| for meal in data["meals"]: | |
| recipe_list.add(meal["strMeal"]) | |
| return list(recipe_list) if recipe_list else ["No matching recipes found."] | |
| def main(): | |
| st.title("VQA Recipe Generator") | |
| st.write("Upload an image of ingredients, and we'll suggest recipes you can make!") | |
| with st.expander("How It Works"): | |
| st.write(""" | |
| 1. **Upload an Image**: Upload a photo of ingredients you have. | |
| 2. **Ingredient Detection**: The app uses a YOLOv8 model to detect visible ingredients. | |
| 3. **Text Extraction**: Any text in the image (e.g., labels) is extracted using EasyOCR. | |
| 4. **Ingredient Validation**: The detected ingredients are cross-checked with TheMealDB database. | |
| 5. **Recipe Suggestions**: The app fetches recipes that match the available ingredients. | |
| P.S This is a work in progress so it can't cater all ingredients and can't really detect if ingredients don't have labels. | |
| """) | |
| model = load_model() | |
| uploaded_file = st.file_uploader("Upload an image", type=["jpg", "png", "jpeg"]) | |
| if uploaded_file: | |
| image = Image.open(uploaded_file) | |
| st.image(image, caption="Uploaded Image", use_column_width=True) | |
| # Convert image for processing | |
| img_array = np.array(image) | |
| img_array = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR) | |
| with st.spinner("Detecting ingredients..."): | |
| detected_ingredients = detect_ingredients(img_array, model) | |
| extracted_text = extract_text(image) | |
| # Merge OCR text with detected objects | |
| detected_ingredients.extend(extracted_text) | |
| # Filter only valid ingredients from TheMealDB | |
| valid_ingredients = filter_valid_ingredients(detected_ingredients) | |
| st.subheader("Detected Ingredients:") | |
| st.write(", ".join(valid_ingredients)) | |
| recipes = get_recipes(valid_ingredients) | |
| st.subheader("Suggested Recipes:") | |
| for recipe in recipes: | |
| st.write(f"- {recipe}") | |
| if __name__ == "__main__": | |
| main() | |