Spaces:
Sleeping
Sleeping
File size: 5,196 Bytes
7c5bb5c 2fe9e9b cd8b0e1 2fe9e9b cd8b0e1 7c5bb5c 27a5d01 7c5bb5c 27a5d01 7c5bb5c 26a7a5c 7c5bb5c a97594e 27a5d01 7c5bb5c 27a5d01 7c5bb5c a97594e 7c5bb5c 27a5d01 7c5bb5c | 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 | 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()
|