File size: 5,414 Bytes
2a842e2 a030b31 107d2dc a030b31 f1db4d5 2a842e2 b62963d 6246831 2a842e2 6246831 b62963d 107d2dc 2a842e2 107d2dc 2a842e2 6246831 b62963d 7c9b96e b62963d f1de91b b62963d 2a842e2 b62963d 107d2dc b62963d 107d2dc b62963d 2a842e2 b62963d 6246831 b62963d 2a842e2 b62963d 2a842e2 6246831 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
import spaces # For ZeroGPU decorator
import gradio as gr
from transformers import pipeline
from diffusers import StableDiffusionPipeline
import torch
import requests
import re
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from tempfile import NamedTemporaryFile
from gtts import gTTS
# --- USDA API Setup ---
USDA_API_KEY = "gcwe1gXmMveg7buqddggl6wAZa7Sd7wrZV87P31z"
USDA_SEARCH_URL = "https://api.nal.usda.gov/fdc/v1/foods/search"
def get_nutrients(ingredient):
params = {"api_key": USDA_API_KEY, "query": ingredient, "pageSize": 1}
try:
res = requests.get(USDA_SEARCH_URL, params=params)
data = res.json()
if 'foods' in data and len(data['foods']) > 0:
return {
n['nutrientName']: n['value'] for n in data['foods'][0].get('foodNutrients', [])
if n.get('nutrientName')
}
return {}
except:
return {}
def get_calories(ingredient):
nutrients = get_nutrients(ingredient)
return nutrients.get("Energy", 0.0)
# --- Load CPU-only model globally (safe) ---
recipe_model = pipeline("text-generation", model="samdak93/qrit-2")
# Globals to cache GPU models after loading
image_model = None
recipe_model_gpu = None # If you want to move recipe_model to GPU, handle similarly
# --- Utilities ---
forbidden = ["pork", "bacon", "ham", "lard", "gelatin", "alcohol", "beer", "wine", "rum", "whiskey", "vodka", "gin"]
def parse_ingredients(text):
match = re.search(r"(?i)ingredients:(.*?)(\n|directions:|instructions:|$)", text, re.DOTALL)
if match:
ingredients_block = match.group(1).strip()
return [line.strip("- *") for line in ingredients_block.split("\n") if line.strip()]
return []
def generate_recipe(key_ingredient):
for _ in range(5):
prompt = f"Create a halal recipe under 2000 calories that includes {key_ingredient}.\nIngredients:"
out = recipe_model(prompt, max_length=300, num_return_sequences=1)[0]['generated_text']
if any(h in out.lower() for h in forbidden):
continue
ingredients = parse_ingredients(out)
total_cal = sum(get_calories(i) for i in ingredients)
if total_cal <= 2000 and total_cal > 0:
return out, ingredients, total_cal
return "No valid recipe.", [], 0
def get_nutrient_breakdown(ingredients):
breakdown = {}
for ing in ingredients:
breakdown[ing] = get_nutrients(ing)
return breakdown
@spaces.GPU(duration=120)
def load_image_model():
global image_model
if image_model is None:
image_model = StableDiffusionPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
torch_dtype=torch.float16
).to("cuda")
return image_model
@spaces.GPU(duration=120)
def generate_image(prompt):
pipe = load_image_model()
with torch.autocast("cuda"):
image = pipe(prompt).images[0]
return image
def export_pdf(recipe_text, nutrients):
temp_pdf = NamedTemporaryFile(delete=False, suffix=".pdf")
c = canvas.Canvas(temp_pdf.name, pagesize=letter)
width, height = letter
c.setFont("Helvetica", 12)
c.drawString(50, height - 50, "Generated Halal Recipe")
text_obj = c.beginText(50, height - 70)
for line in recipe_text.split('\n'):
text_obj.textLine(line)
c.drawText(text_obj)
y = text_obj.getY() - 20
c.drawString(50, y, "Nutrient Breakdown:")
y -= 20
for ing, data in nutrients.items():
c.drawString(50, y, f"- {ing}")
y -= 15
for k, v in data.items():
c.drawString(70, y, f"{k}: {v}")
y -= 12
y -= 5
if y < 100:
c.showPage()
y = height - 50
c.save()
return temp_pdf.name
def generate_audio(recipe_text):
tts = gTTS(text=recipe_text)
temp_audio = NamedTemporaryFile(delete=False, suffix=".mp3")
tts.save(temp_audio.name)
return temp_audio.name
def app(key_ingredient):
recipe_text, ingredients, calories = generate_recipe(key_ingredient)
if not ingredients:
return "No valid recipe generated.", None, None, None, None
title_match = re.search(r"(?i)^title: (.+)$", recipe_text, re.MULTILINE)
title = title_match.group(1).strip() if title_match else f"Dish with {key_ingredient}"
image = generate_image(f"A delicious {title}, beautifully plated")
nutrients = get_nutrient_breakdown(ingredients)
pdf_path = export_pdf(recipe_text, nutrients)
audio_path = generate_audio(recipe_text)
display_text = f"{recipe_text}\n\nEstimated Calories: {int(calories)} kcal"
return display_text, image, nutrients, pdf_path, audio_path
# --- Gradio UI ---
with gr.Blocks() as demo:
gr.Markdown("## 🕌 Halal Recipe Generator - Advanced Edition")
with gr.Row():
key_input = gr.Textbox(label="Key Ingredient")
submit_btn = gr.Button("Generate Recipe")
output_text = gr.Textbox(label="Recipe Text")
output_img = gr.Image(label="Generated Dish")
output_table = gr.JSON(label="Nutrient Breakdown")
output_pdf = gr.File(label="Download Recipe PDF")
output_audio = gr.Audio(label="Recipe Narration", autoplay=False)
submit_btn.click(app, inputs=key_input,
outputs=[output_text, output_img, output_table, output_pdf, output_audio])
demo.launch(share=True, pwa=True, debug=True)
|