import os import zipfile import gradio as gr from langchain_openai import ChatOpenAI from langchain.embeddings import HuggingFaceEmbeddings from langchain_chroma import Chroma from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate from langchain.chains import LLMChain # Unzip vector DB if not already extracted if not os.path.exists("geometry_chroma"): with zipfile.ZipFile("geometry_chroma.zip", 'r') as zip_ref: zip_ref.extractall(".") # Load vector DB embedding_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") vectordb = Chroma(persist_directory="geometry_chroma", embedding_function=embedding_model) retriever = vectordb.as_retriever() # Set OpenAI key (use Secrets or .env later) os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") llm = ChatOpenAI(model_name="gpt-4.1", temperature=0.2) # ✅ Prompt templates templates = { "flashcard": PromptTemplate( input_variables=["context", "query"], template=""" {context} Create 5 flashcards based on the topic: "{query}" Each flashcard should include: - A clear question - A short answer Focus on high school geometry understanding. """ ), "lesson plan": PromptTemplate( input_variables=["context", "query"], template=""" Given the following retrieved SOL text: {context} Generate a Geometry lesson plan based on: "{query}" Include: 1. Simple explanation of the concept. 2. Real-world example. 3. Engaging class activity. Be concise and curriculum-aligned for high school. """ ), "worksheet": PromptTemplate( input_variables=["context", "query"], template=""" {context} Create a student worksheet for: "{query}" Include: - Concept summary - A worked example - 3 practice problems """ ), "proofs": PromptTemplate( input_variables=["context", "query"], template=""" {context} Generate a proof-focused geometry lesson plan for: "{query}" Include: - Student-friendly explanation - Real-world connection - One short class activity """ ), "general question": ChatPromptTemplate.from_messages([ HumanMessagePromptTemplate.from_template( """ You are a Virginia Geometry SOL assistant. From the following SOL context: {context} Identify the SOL standard (e.g., G.RLT.1) that best matches this query: "{query}" Respond with: 1. The exact SOL code (e.g., G.RLT.1) 2. The exact description line from the SOL guide Do not summarize. Only copy from the context. """ ) ]) } def generate_prompt_output(prompt_type, query, retriever, llm): # Try to extract SOL code sol_match = re.search(r"\bG\.[A-Z]+\.\d+\b", query) matched_code = sol_match.group(0) if sol_match else None if matched_code: # Retrieve and filter by metadata all_docs = retriever.vectorstore._collection.get(include=['documents', 'metadatas']) filtered = [] for doc_text, metadata in zip(all_docs['documents'], all_docs['metadatas']): if metadata.get('standard') == matched_code: filtered.append(doc_text) context = "\n\n".join(filtered) else: # fallback to semantic retrieval docs = retriever.get_relevant_documents(query) context = "\n\n".join([doc.page_content for doc in docs]) chain = LLMChain(llm=llm, prompt=templates[prompt_type]) return chain.run({"context": context, "query": query}) # ✅ Gradio UI with gr.Blocks() as demo: gr.Markdown("# 📐 Geometry Teaching Assistant") with gr.Row(): query = gr.Textbox(label="Enter a geometry topic") prompt_type = gr.Dropdown( ["general question", "lesson plan", "worksheet", "proofs", "flashcard"], value="general question", label="Prompt Type" ) output = gr.Textbox(label="Generated Output", lines=12, interactive=True) btn = gr.Button("Generate") btn.click(fn=generate_output, inputs=[prompt_type, query], outputs=output) demo.launch()