Shafaq25's picture
Update app.py
cd8b0e1 verified
import os
import gradio as gr
from pinecone import Pinecone, ServerlessSpec
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext, Settings
from llama_index.vector_stores.pinecone import PineconeVectorStore
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
# --- System Prompt ---
SYSTEM_PROMPT = """You are Shifu, a polite and professional Healthy Recipe assistant.
Answer ONLY using the information found in the indexed recipe document(s).
If the answer is not in the document(s), say: "I couldn’t find that in the document."
Keep responses concise, helpful, and friendly.
"""
# ===== CONFIG =====
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
if not PINECONE_API_KEY or not OPENAI_API_KEY:
raise RuntimeError("Missing PINECONE_API_KEY or OPENAI_API_KEY")
DATA_DIR = "data"
BANNER_PATH = os.path.join(DATA_DIR, "shafaq_banner.png")
if not os.path.exists(BANNER_PATH):
raise RuntimeError("Banner not found at: data/shafaq_banner.png")
EMBED_MODEL = "text-embedding-3-small"
LLM_MODEL = "gpt-4o-mini"
TOP_K = 4
# ===== LlamaIndex & Pinecone =====
Settings.embed_model = OpenAIEmbedding(model=EMBED_MODEL, api_key=OPENAI_API_KEY)
Settings.llm = OpenAI(model=LLM_MODEL, api_key=OPENAI_API_KEY, system_prompt=SYSTEM_PROMPT)
pc = Pinecone(api_key=PINECONE_API_KEY)
def ensure_index(name: str, dim: int = 1536):
names = [i["name"] for i in pc.list_indexes()]
if name not in names:
pc.create_index(
name=name, dimension=dim, metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)
return pc.Index(name)
pinecone_index = ensure_index("shafaq-recipes-index", dim=1536)
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
def bootstrap_index():
if not os.path.isdir(DATA_DIR):
raise RuntimeError("No 'data/' directory found.")
docs = SimpleDirectoryReader(DATA_DIR).load_data()
if not docs:
raise RuntimeError("No documents found in data/.")
storage_ctx = StorageContext.from_defaults(vector_store=vector_store)
VectorStoreIndex.from_documents(docs, storage_context=storage_ctx, show_progress=True)
bootstrap_index()
def answer(query: str) -> str:
if not query.strip():
return "Please enter a question."
index = VectorStoreIndex.from_vector_store(vector_store)
resp = index.as_query_engine(similarity_top_k=TOP_K).query(query)
return str(resp)
FAQS = [
"",
"How long do these breakfast recipes last in the fridge?",
"Can I freeze any of these recipes?",
"Are there gluten-free breakfast options?",
"How can I make these breakfasts dairy-free?",
"What can I use instead of eggs?",
"Can I use different veggies or toppings?",
"I don’t have almond or coconut milk. What else can I use?",
"How can I add more flavor to these recipes?",
"What if I don’t have protein powder?",
"Can I prep these meals ahead of time?",
]
def use_faq(selected_faq: str, free_text: str):
prompt = (selected_faq or "").strip() or (free_text or "").strip()
if not prompt:
return "", "Please select a FAQ or type your question."
return prompt, answer(prompt)
# ===== UI =====
CSS = """
.header { text-align: left; }
.logo img { width:100%; max-width: 320px; border-radius: 12px; }
.title { font-weight: 700; font-size: 1.8rem; color: #41644A; margin-bottom: 4px; }
.subnote { font-size: 1rem; color: #6C757D; margin-bottom: 20px; }
.section-title { font-weight: 600; margin-top: 12px; }
"""
with gr.Blocks(css=CSS, theme=gr.themes.Soft(primary_hue="green", secondary_hue="orange")) as demo:
with gr.Row():
with gr.Column(scale=1, min_width=350):
gr.Image(value=BANNER_PATH, show_label=False, elem_classes=["logo"])
with gr.Column(scale=2):
gr.Markdown("""
<div style="text-align: left; margin-bottom: 1.5rem;">
<h1 style="font-size: 2.4rem; font-weight: 800; color: #2F4F4F; margin: 0;">
Shafaq’s Breakfast Buddy
</h1>
<p style="font-size: 1.2rem; color: #6C757D; margin-top: 6px;">
Healthy Recipe Recommender based on what’s in your kitchen 🍳🥑
</p>
</div>
""")
gr.Markdown("#### Ask from Frequently Asked Questions")
faq = gr.Dropdown(choices=FAQS, value=FAQS[0], label="Select a common question")
gr.Markdown("#### Or type your question")
user_q = gr.Textbox(
label="Your question",
placeholder="e.g., Suggest a healthy breakfast with oats and banana",
lines=2
)
ask_btn = gr.Button("Get Recipe 💡", variant="primary")
chosen_prompt = gr.Textbox(label="Query sent", interactive=False)
answer_box = gr.Markdown()
# ✅ Must be INSIDE the same column/block
ask_btn.click(use_faq, inputs=[faq, user_q], outputs=[chosen_prompt, answer_box])
if __name__ == "__main__":
demo.launch()