Spaces:
Runtime error
Runtime error
| """ | |
| RAG pipeline: loads the FAISS index and builds a ConversationalRetrievalChain | |
| backed by Groq (llama-3.3-70b-versatile). Returns the answer and source chunks. | |
| """ | |
| import os | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_community.vectorstores import FAISS | |
| from langchain_classic.chains import ConversationalRetrievalChain | |
| from langchain_classic.memory import ConversationBufferMemory | |
| from langchain_groq import ChatGroq | |
| load_dotenv() | |
| EMBEDDING_MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" | |
| INDEX_DIR = Path("faiss_index") | |
| GROQ_MODEL = "llama-3.3-70b-versatile" | |
| TOP_K = 4 | |
| SYSTEM_PROMPT = ( | |
| "You are a helpful multilingual assistant that supports English, Arabic, and Malay. " | |
| "Always reply in the same language the user used. " | |
| "Base your answer strictly on the provided context. " | |
| "If the context does not contain enough information, say so honestly." | |
| ) | |
| def load_vectorstore() -> FAISS: | |
| if not INDEX_DIR.exists(): | |
| raise FileNotFoundError( | |
| "FAISS index not found. Run `python ingest.py` first." | |
| ) | |
| embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL) | |
| return FAISS.load_local( | |
| str(INDEX_DIR), embeddings, allow_dangerous_deserialization=True | |
| ) | |
| class RAGPipeline: | |
| def __init__(self): | |
| vectorstore = load_vectorstore() | |
| retriever = vectorstore.as_retriever(search_kwargs={"k": TOP_K}) | |
| llm = ChatGroq( | |
| model=GROQ_MODEL, | |
| api_key=os.environ["GROQ_API_KEY"], | |
| max_tokens=1024, | |
| ) | |
| memory = ConversationBufferMemory( | |
| memory_key="chat_history", | |
| return_messages=True, | |
| output_key="answer", | |
| ) | |
| self.chain = ConversationalRetrievalChain.from_llm( | |
| llm=llm, | |
| retriever=retriever, | |
| memory=memory, | |
| return_source_documents=True, | |
| output_key="answer", | |
| combine_docs_chain_kwargs={"prompt": _build_prompt()}, | |
| ) | |
| def ask(self, question: str) -> dict: | |
| """ | |
| Returns: | |
| { | |
| "answer": str, | |
| "sources": [{"content": str, "source": str}, ...] | |
| } | |
| """ | |
| result = self.chain.invoke({"question": question}) | |
| sources = [ | |
| { | |
| "content": doc.page_content, | |
| "source": doc.metadata.get("source", "unknown"), | |
| } | |
| for doc in result.get("source_documents", []) | |
| ] | |
| return {"answer": result["answer"], "sources": sources} | |
| def _build_prompt(): | |
| from langchain_core.prompts import PromptTemplate | |
| template = ( | |
| SYSTEM_PROMPT | |
| + "\n\nContext:\n{context}\n\nQuestion: {question}\n\nAnswer:" | |
| ) | |
| return PromptTemplate(input_variables=["context", "question"], template=template) | |