Spaces:
Runtime error
Runtime error
Download app.py from Nofarsagi123/RecipeWizard: direct link, hf CLI and curl.
- Browser
- Download file 6.79 kB
-
https://huggingface.co/spaces/Nofarsagi123/RecipeWizard/resolve/4d68da20f5b1e12639c5956fcc6ca8b4daa53968/app.py
- Command line
-
hf download hf://spaces/Nofarsagi123/RecipeWizard@4d68da20f5b1e12639c5956fcc6ca8b4daa53968/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Nofarsagi123/RecipeWizard/resolve/4d68da20f5b1e12639c5956fcc6ca8b4daa53968/app.py
6.79 kB
| import gradio as gr | |
| from datasets import load_dataset | |
| from sentence_transformers import SentenceTransformer | |
| import faiss | |
| import numpy as np | |
| from transformers import pipeline | |
| import time | |
| # --- 1. DATA LOADING AND PREPROCESSING (FINAL FIX) --- | |
| print("===== Application Startup =====") | |
| start_time = time.time() | |
| # Load dataset and limit to the first 20,000 rows | |
| dataset = load_dataset("corbt/all-recipes", split="train[:20000]") | |
| # Preprocessing functions to extract features from the raw text | |
| def extract_title_and_ingredients(sample): | |
| extraction = sample['input'][:sample['input'].find("Directions")] | |
| return {"text_for_embedding": extraction} | |
| def extract_each_feature(sample): | |
| """ | |
| FIXED: More robustly extracts recipe features and cleans duplicated content. | |
| """ | |
| full_text = sample['input'] | |
| # Extract Title | |
| title = full_text[:full_text.find("\\n")] | |
| # Extract Ingredients | |
| ingredients = "Not available" | |
| if "Ingredients:" in full_text: | |
| start_ing = full_text.find("Ingredients:") + len("Ingredients:") | |
| end_ing = full_text.find("Directions:") | |
| if end_ing > start_ing: | |
| ingredients = full_text[start_ing:end_ing].strip() | |
| # Extract and clean Directions | |
| directions = "Not available" | |
| if "Directions:" in full_text: | |
| start_dir = full_text.find("Directions:") + len("Directions:") | |
| # Take the text after the first "Directions:" | |
| temp_directions = full_text[start_dir:].strip() | |
| # If "Ingredients:" appears again, it's a duplicate. Cut it off. | |
| if "Ingredients:" in temp_directions: | |
| end_dir = temp_directions.find("Ingredients:") | |
| directions = temp_directions[:end_dir].strip() | |
| else: | |
| directions = temp_directions | |
| return { | |
| "title": title, | |
| "ingredients": ingredients, | |
| "directions": directions, | |
| } | |
| # Apply preprocessing | |
| dataset = dataset.map(extract_title_and_ingredients) | |
| dataset = dataset.map(extract_each_feature) | |
| # --- 2. EMBEDDING AND RECOMMENDATION ENGINE --- | |
| print("Loading embedding model...") | |
| model_name = "all-MiniLM-L6-v2" | |
| embedding_model = SentenceTransformer(f"sentence-transformers/{model_name}") | |
| print("Generating embeddings...") | |
| embeddings = embedding_model.encode(dataset['text_for_embedding'], show_progress_bar=True) | |
| embeddings = np.array(embeddings, dtype=np.float32) | |
| print("Building FAISS index...") | |
| dimension = embeddings.shape[1] | |
| index = faiss.IndexFlatL2(dimension) | |
| index.add(embeddings) | |
| print(f"Index is ready. Total vectors in index: {index.ntotal}") | |
| # --- 3. SYNTHETIC GENERATION (IMPROVED MODEL AND PROMPT) --- | |
| print("Loading generative model...") | |
| # Switched back to gpt2 for better instruction following | |
| generator = pipeline('text-generation', model='gpt2') | |
| def get_recommendations_and_generate(query_ingredients, k=3): | |
| # 1. Get Recommendations | |
| query_vector = embedding_model.encode([query_ingredients]) | |
| query_vector = np.array(query_vector, dtype=np.float32) | |
| distances, indices = index.search(query_vector, k) | |
| results = [] | |
| for idx_numpy in indices[0]: | |
| idx = int(idx_numpy) | |
| recipe = { | |
| "title": dataset[idx]['title'], | |
| "ingredients": dataset[idx]['ingredients'], | |
| "directions": dataset[idx]['directions'] | |
| } | |
| results.append(recipe) | |
| # 2. Generate a new recipe with a better "few-shot" prompt | |
| prompt = f"""Given the ingredients: {query_ingredients}, create a complete recipe. | |
| ### Title ### | |
| [A creative recipe title] | |
| ### Ingredients ### | |
| - [List of ingredients] | |
| ### Directions ### | |
| 1. [First step] | |
| 2. [Second step] | |
| 3. [And so on...] | |
| ### Title ### | |
| """ | |
| # Generate the recipe text | |
| generated_outputs = generator(prompt, max_new_tokens=250, num_return_sequences=1, pad_token_id=50256) | |
| generated_text = generated_outputs[0]['generated_text'].replace(prompt, "").strip() | |
| # 3. More robustly parse the generated text | |
| try: | |
| title = "AI Generated Recipe" | |
| ingredients = "" | |
| directions = "" | |
| if "### Ingredients ###" in generated_text: | |
| parts = generated_text.split("### Ingredients ###") | |
| title = parts[0].strip() | |
| rest = parts[1] | |
| if "### Directions ###" in rest: | |
| dir_parts = rest.split("### Directions ###") | |
| ingredients = dir_parts[0].strip() | |
| directions = dir_parts[1].strip() | |
| else: | |
| ingredients = rest.strip() | |
| else: | |
| directions = generated_text # Fallback | |
| generated_recipe = { | |
| "title": title, | |
| "ingredients": ingredients, | |
| "directions": directions | |
| } | |
| except Exception as e: | |
| print(f"Error parsing generated text: {e}") | |
| generated_recipe = { | |
| "title": "AI Generated Recipe (Parsing Error)", | |
| "ingredients": "Could not determine ingredients.", | |
| "directions": generated_text | |
| } | |
| return results[0], results[1], results[2], generated_recipe | |
| # --- 4. GRADIO USER INTERFACE --- | |
| def format_recipe(recipe): | |
| if not recipe or not recipe['title']: | |
| return "### No recipe found." | |
| return f"### {recipe['title']}\n**Ingredients:**\n{recipe['ingredients']}\n\n**Directions:**\n{recipe['directions']}" | |
| def recipe_wizard(ingredients): | |
| rec1, rec2, rec3, gen_rec = get_recommendations_and_generate(ingredients) | |
| return format_recipe(rec1), format_recipe(rec2), format_recipe(rec3), format_recipe(gen_rec) | |
| end_time = time.time() | |
| print(f"Models and data loaded in {end_time - start_time:.2f} seconds.") | |
| # Gradio Interface | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# 🍳 RecipeWizard AI") | |
| gr.Markdown("Enter the ingredients you have, and get recipe recommendations plus a new AI-generated idea!") | |
| with gr.Row(): | |
| ingredient_input = gr.Textbox(label="Your Ingredients", placeholder="e.g., chicken, rice, tomatoes, garlic") | |
| submit_btn = gr.Button("Get Recipes") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Recommended Recipes") | |
| output_rec1 = gr.Markdown() | |
| output_rec2 = gr.Markdown() | |
| output_rec3 = gr.Markdown() | |
| with gr.Column(scale=1): | |
| gr.Markdown("### ✨ AI-Generated Idea") | |
| output_gen = gr.Markdown() | |
| submit_btn.click( | |
| fn=recipe_wizard, | |
| inputs=ingredient_input, | |
| outputs=[output_rec1, output_rec2, output_rec3, output_gen] | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| ["chicken, broccoli, cheese"], | |
| ["ground beef, potatoes, onions"], | |
| ["flour, sugar, eggs, butter"] | |
| ], | |
| inputs=ingredient_input | |
| ) | |
| demo.launch() |