# app.py import gradio as gr import os from transformers import pipeline from sentence_transformers import SentenceTransformer import faiss import numpy as np import json import re # --- Load necessary components for the RAG system --- # These paths are relative to the Space's root directory FAISS_INDEX_PATH = "sol_faiss_index.bin" DOCUMENT_IDS_PATH = "sol_document_ids.json" # Load SentenceTransformer model # Ensure this model is downloaded or available in the environment # For Spaces, you might need to add it to requirements.txt or directly download if space has internet # It's better to declare it globally or as a shared resource. try: model = SentenceTransformer('all-mpnet-base-v2') except Exception as e: print(f"Error loading SentenceTransformer model: {e}") print("Attempting to load from local cache or download on first use.") # If running in a Space, the model will be downloaded to cache if not present. # Ensure you have internet access in your Space settings. # Load FAISS index try: index = faiss.read_index(FAISS_INDEX_PATH) except Exception as e: print(f"Error loading FAISS index: {e}") # Handle error, maybe create a dummy index or exit index = None # Placeholder if loading fails # Load document IDs try: with open(DOCUMENT_IDS_PATH, "r") as f: document_ids = json.load(f) except Exception as e: print(f"Error loading document IDs: {e}") document_ids = [] # Placeholder if loading fails # Placeholder for the actual content of "10 Geometry Mathematics Instructional Guide.pdf" # In a real deployed scenario, this content would be loaded from a file # that you upload to your Hugging Face Space or fetched at runtime. # For now, we'll assume it's available or that 'documents' are pre-processed and loaded. # You would typically load the 'documents' list created in Step 2 here. # For deployment, it's best to save the `documents` list (sol_data) as a JSON # and load it back. Let's add that. # Assuming you've saved sol_data as 'sol_documents.json' SOL_DOCUMENTS_PATH = "sol_documents.json" try: with open(SOL_DOCUMENTS_PATH, "r") as f: documents = json.load(f) except Exception as e: print(f"Error loading sol documents: {e}") documents = [] # Placeholder # Load LLM for generation # For a Hugging Face Space, you need to ensure the model is available. # 'google/gemma-2b-it' is a good option. # Ensure you set up environment variables or secrets for API keys if using paid models. try: # llm_pipeline = pipeline("text-generation", model="TinyLlama/TinyLlama-1.1B-Chat-v1.0") llm_pipeline = pipeline("text-generation", model="google/gemma-2b-it") except Exception as e: print(f"Error loading LLM pipeline: {e}") llm_pipeline = None # Placeholder def retrieve_and_generate_app(query, top_k=3): if not model or not index or not document_ids or not documents or not llm_pipeline: return "System not fully initialized. Please check logs for missing components." try: # 1. Query Embedding query_embedding = model.encode([query]) # 2. Retrieval using FAISS D, I = index.search(query_embedding, top_k) retrieved_docs = [] for i in I[0]: sol_id = document_ids[i] retrieved_content = next((doc["content"] for doc in documents if doc["id"] == sol_id), "Content not found.") retrieved_docs.append({"id": sol_id, "content": retrieved_content}) # 3. Context Construction context = "\n\n".join([f"SOL {doc['id']}: {doc['content']}" for doc in retrieved_docs]) # 4. LLM Generation prompt = f""" Given the following information about Virginia Standards of Learning (SOLs): {context} Based on this information, answer the following question: {query} If the question is about a specific SOL number, provide a direct explanation for that SOL. If asked for lesson plans, worksheets, or proofs, explain what the document generally entails and whether it provides such materials. Be concise and to the point. """ print(f"\n--- PROMPT SENT TO LLM ---\n{prompt}\n--------------------------\n") response = llm_pipeline(prompt, max_new_tokens=500, num_return_sequences=1, do_sample=True, temperature=0.7) generated_text = response[0]['generated_text'] print(f"\n--- RAW GENERATED TEXT ---\n{generated_text}\n--------------------------\n") answer_start_marker = f"Based on this information, answer the following question:\n{query}" if answer_start_marker in generated_text: answer = generated_text.split(answer_start_marker, 1)[1].strip() answer = re.sub(r'If the question is about a specific SOL number,.*?$', '', answer, flags=re.DOTALL).strip() else: answer = generated_text print(f"\n--- FINAL ANSWER ---\n{answer}\n--------------------\n") return answer if answer else "No valid response generated. Check logs for details." except Exception as e: print(f"\n--- ERROR ---\n{str(e)}\n------------\n") return f"An error occurred: {str(e)}. Please check the logs for more details." # Create Gradio interface demo = gr.Interface( fn=retrieve_and_generate_app, inputs=gr.Textbox(lines=2, placeholder="Enter your geometry-related question here..."), outputs=gr.Textbox(label="Generated Answer"), title="Virginia SOL Geometry Assistant", description="Ask questions about the Geometry SOL Instructional Guide" ) if __name__ == "__main__": demo.launch()