Spaces:
Build error
Build error
File size: 6,558 Bytes
b21a8be d525585 c3e0374 dcde4b8 9d7c9f4 f26b898 9d7c9f4 d5ebf09 fa6fe88 697474f 9d7c9f4 1696771 9d7c9f4 697474f dcde4b8 c3e0374 697474f 1388552 be25f7d 1a07610 245a7c8 1a07610 9d7c9f4 db0c9ca fc83c21 db0c9ca 8094330 db0c9ca dcde4b8 db0c9ca 3379056 be25f7d 97eefa1 ac3441a dcde4b8 4c90401 dcde4b8 ac3441a 4c90401 be25f7d ac3441a 4c90401 dcde4b8 be25f7d ac3441a be25f7d 4c90401 6a40614 95325ed 0c5120f ff65a9d 4c90401 10c7691 ff65a9d 2a5d6eb ff65a9d 4c90401 10c7691 2a5d6eb c4c42ba 2a5d6eb 36957f3 4c90401 36957f3 c4c42ba 9d7c9f4 bcd25c4 97eefa1 fa1b6d5 1696771 bcd25c4 9d7c9f4 dcde4b8 245a7c8 8094330 36957f3 95325ed f0e5ff8 95325ed 38349fe a499d88 ac3441a 10c7691 4c90401 36957f3 4c90401 10c7691 | 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 | import streamlit as st
import pandas as pd
import chromadb
from sentence_transformers import SentenceTransformer
from transformers import pipeline, AutoModelForQuestionAnswering, AutoTokenizer
from PIL import Image
from io import BytesIO
import requests
# --- 1. Load Recipes Dataset ---
@st.cache_data
def load_recipes():
try:
recipes_df = pd.read_csv("recipes.csv")
recipes_df = recipes_df.rename(columns={"recipe_name": "title", "directions": "instructions"})
recipes_df = recipes_df[['title', 'ingredients', 'instructions', 'img_src']]
recipes_df.fillna("", inplace=True)
recipes_df["ingredients"] = recipes_df["ingredients"].str.lower().str.replace(r'[^\w\s]', '', regex=True)
recipes_df["combined_text"] = recipes_df["title"] + " " + recipes_df["ingredients"]
return recipes_df
except Exception as e:
st.error(f"โ Error loading recipes: {e}")
return pd.DataFrame()
recipes_df = load_recipes()
# --- 2. Load SentenceTransformer Model ---
@st.cache_resource
def load_embedding_model():
return SentenceTransformer("all-mpnet-base-v2")
embedding_model = load_embedding_model()
# --- 3. Initialize ChromaDB ---
chroma_client = chromadb.PersistentClient(path="./chroma_db")
collection = chroma_client.get_or_create_collection(name="recipe_collection")
# --- 4. Generate & Store Embeddings ---
def get_sentence_transformer_embeddings(text):
return embedding_model.encode(text).tolist()
try:
existing_data = collection.get()
existing_ids = set(existing_data["ids"]) if existing_data and "ids" in existing_data else set()
except Exception as e:
st.error(f"โ ChromaDB Error: {e}")
existing_ids = set()
for index, row in recipes_df.iterrows():
recipe_id = str(index)
if recipe_id in existing_ids:
continue
embedding = get_sentence_transformer_embeddings(row["combined_text"])
if embedding:
collection.add(embeddings=[embedding], documents=[row["combined_text"]], ids=[recipe_id])
# --- 5. Retrieve Similar Recipes ---
def retrieve_recipes(query, top_k=3):
query_embedding = get_sentence_transformer_embeddings(query)
results = collection.query(query_embeddings=[query_embedding], n_results=top_k)
if results and "ids" in results and results["ids"]:
recipe_indices = [int(id) for id in results["ids"][0] if id.isdigit()]
return recipes_df.iloc[recipe_indices] if recipe_indices else None
return None
# --- 6. Load LLM Model ---
@st.cache_resource
def load_llm_model():
tokenizer = AutoTokenizer.from_pretrained("deepset/roberta-base-squad2")
model = AutoModelForQuestionAnswering.from_pretrained("deepset/roberta-base-squad2")
return pipeline("question-answering", model=model, tokenizer=tokenizer)
llm_model = load_llm_model()
# --- 7. Load Classifier ---
@st.cache_resource
def load_classifier():
return pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
classifier = load_classifier()
# --- 8. Query Classification ---
def is_food_related(query):
labels = ["Food & Cooking", "General Knowledge"]
result = classifier(query, candidate_labels=labels, multi_label=False)
return result["labels"][0] == "Food & Cooking"
def answer_question(query, context=""):
greetings = ["hi", "hello", "hii", "hey", "greetings", "how are you", "what's up", "how's it going"]
query_cleaned = query.lower().strip()
if query_cleaned in greetings:
return "Hello! I'm here to assist with recipes and food-related questions. ๐ฝ๏ธ What would you like to know?"
if not is_food_related(query_cleaned):
return "I specialize in food-related topics! ๐ฝ๏ธ Please ask me about recipes, cooking methods, or ingredients."
# Retrieve related recipes only if the query is about food
related_recipes = retrieve_recipes(query, top_k=1)
if related_recipes is None or related_recipes.empty:
return "I specialize in recipes! ๐ฝ๏ธ Feel free to ask me about ingredients, cooking methods, or meal ideas. ๐"
# Use the most relevant recipe's instructions for answer generation
context = related_recipes.iloc[0]['instructions']
response = llm_model(question=query, context=context)
answer = response.get("answer", "").strip()
return answer if answer else "I'm not sure, but I can help with recipes! What would you like to cook?"
# --- 9. Display Image Function ---
def display_image(image_url, recipe_name):
try:
if not isinstance(image_url, str) or not image_url.startswith("http"):
raise ValueError("Invalid or missing image URL")
response = requests.get(image_url, timeout=5)
response.raise_for_status()
image = Image.open(BytesIO(response.content))
st.image(image, caption=recipe_name, use_container_width=True)
except requests.exceptions.RequestException as e:
st.warning(f"โ Image fetch error: {e}")
placeholder_url = "https://via.placeholder.com/300?text=No+Image"
st.image(placeholder_url, caption=recipe_name, use_container_width=True)
# --- 10. Streamlit UI ---
st.title("๐ฝ๏ธ AI Recipe & Q&A Assistant")
user_query = st.text_input("Enter your question or recipe search query:", "", key="main_query_input")
if "retrieved_recipes" not in st.session_state:
st.session_state["retrieved_recipes"] = None
if st.button("Ask AI"):
if user_query:
if is_food_related(user_query): # First check if it's a food-related query
response = answer_question(user_query)
st.subheader("๐ค AI Answer:")
st.write(response)
retrieved_recipes = retrieve_recipes(user_query)
if retrieved_recipes is not None and not retrieved_recipes.empty:
st.session_state["retrieved_recipes"] = retrieved_recipes
st.subheader("๐ด Found Recipes:")
for _, recipe in retrieved_recipes.iterrows():
st.markdown(f"### {recipe['title']}")
st.write(f"**Ingredients:** {recipe['ingredients']}")
st.write(f"**Instructions:** {recipe['instructions']}")
display_image(recipe.get('img_src', ''), recipe['title'])
else:
st.warning("โ ๏ธ No relevant recipes found.")
else:
# If query is not food-related, return only general response (No recipe retrieval)
st.subheader("๐ค AI Answer:")
st.write(answer_question(user_query))
|