multisource-rag / src /query_rag.py
MadhuChitikela
Initial commit: Multi-source RAG with FastAPI backend and lightweight frontend
05faae4
Raw
History Blame Contribute Delete
4.45 kB
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)