Spaces:
Sleeping
Sleeping
MadhuChitikela
Initial commit: Multi-source RAG with FastAPI backend and lightweight frontend
05faae4 | import os | |
| import sys | |
| from dotenv import load_dotenv | |
| from pinecone import Pinecone | |
| from langchain_groq import ChatGroq | |
| from langchain_core.prompts import PromptTemplate | |
| from langchain.chains import LLMChain | |
| # Load dotenv to read environment variables | |
| load_dotenv() | |
| # Check credentials | |
| PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY") | |
| GROQ_API_KEY = os.environ.get("GROQ_API_KEY") | |
| INDEX_NAME = os.environ.get("PINECONE_INDEX_NAME", "multiragsystem") | |
| if not PINECONE_API_KEY: | |
| print("[ERROR] PINECONE_API_KEY not found in environment. Please set it in your .env file.") | |
| sys.exit(1) | |
| if not GROQ_API_KEY: | |
| print("[ERROR] GROQ_API_KEY not found in environment. Please set it in your .env file.") | |
| sys.exit(1) | |
| # Initialize Pinecone | |
| pc = Pinecone(api_key=PINECONE_API_KEY) | |
| index = pc.Index(INDEX_NAME) | |
| # Target namespaces to search | |
| NAMESPACES = ["products", "stocks", "deals", "documents", "news"] | |
| TOP_K_PER_NAMESPACE = 3 | |
| # Initialize ChatGroq LLM | |
| llm = ChatGroq( | |
| model="llama-3.3-70b-specdec", | |
| temperature=0, | |
| groq_api_key=GROQ_API_KEY | |
| ) | |
| prompt = PromptTemplate( | |
| template="""You are a helpful assistant. Answer the question based ONLY on the provided context. | |
| If the answer is not contained in the context, say "I don't know". Do not attempt to make up an answer. | |
| Context: | |
| {context} | |
| Question: {question} | |
| Answer with precise citations in parentheses like (Source: namespace, field=value) based on the metadata of the context chunks you used.""", | |
| input_variables=["context", "question"] | |
| ) | |
| chain = LLMChain(llm=llm, prompt=prompt) | |
| def query_all_namespaces(question): | |
| all_chunks = [] | |
| for ns in NAMESPACES: | |
| try: | |
| # Query Pinecone using index.search (server-side integrated embeddings) | |
| resp = index.search( | |
| namespace=ns, | |
| query={ | |
| "inputs": { | |
| "text": question | |
| }, | |
| "top_k": TOP_K_PER_NAMESPACE | |
| } | |
| ) | |
| for match in resp.get('matches', []): | |
| metadata = match.get('metadata', {}) | |
| all_chunks.append({ | |
| "text": metadata.get('text', ''), | |
| "score": match.get('score', 0.0), | |
| "namespace": ns, | |
| "metadata": metadata | |
| }) | |
| except Exception as e: | |
| print(f"[WARNING] Failed to query namespace '{ns}': {e}") | |
| if not all_chunks: | |
| return "I don't know (no matching vectors found).", [] | |
| # Sort all results by similarity score descending | |
| all_chunks.sort(key=lambda x: x['score'], reverse=True) | |
| # Take top 6 chunks overall | |
| top_chunks = all_chunks[:6] | |
| # Construct context string | |
| context_blocks = [] | |
| for idx, c in enumerate(top_chunks): | |
| # Format metadata for LLM citation reference | |
| meta_str = ", ".join([f"{k}={v}" for k, v in c["metadata"].items() if k != "text"]) | |
| context_blocks.append(f"Chunk {idx+1} [Namespace: {c['namespace']}] (Metadata: {meta_str})\nContent:\n{c['text']}") | |
| context = "\n\n---\n\n".join(context_blocks) | |
| # Run chain | |
| answer = chain.run(context=context, question=question) | |
| return answer, top_chunks | |
| if __name__ == "__main__": | |
| print("============================================================") | |
| print("🧠 MULTI-SOURCE RAG QUERY CLI ACTIVE (Type 'exit' to quit)") | |
| print("============================================================") | |
| while True: | |
| try: | |
| q = input("\nYour question: ").strip() | |
| except (KeyboardInterrupt, EOFError): | |
| print("\nExiting...") | |
| break | |
| if not q: | |
| continue | |
| if q.lower() == "exit": | |
| break | |
| print("\nSearching Pinecone index...") | |
| answer, sources = query_all_namespaces(q) | |
| print("\n" + "="*60) | |
| print("Answer:", answer) | |
| print("\nSources:") | |
| if sources: | |
| for idx, src in enumerate(sources): | |
| meta_summary = ", ".join([f"{k}: {v}" for k, v in src['metadata'].items() if k not in ('text', 'source_type', 'source_name')][:3]) | |
| print(f" [{idx+1}] Namespace '{src['namespace']}' (score {src['score']:.3f}) | {meta_summary}") | |
| else: | |
| print(" No sources found.") | |
| print("="*60) | |