UniversityAI / rag.py
Alsmwal's picture
Upload 28 files
18ad9a9 verified
raw
history blame
4.57 kB
from dotenv import load_dotenv
import os
from qdrant_client import QdrantClient
from sentence_transformers import SentenceTransformer
from groq import Groq
# Load environment variables
load_dotenv()
QDRANT_URL = os.getenv("QDRANT_URL")
QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
COLLECTION_NAME = "student_materials"
# Connect to Qdrant
client = QdrantClient(
url=QDRANT_URL,
api_key=QDRANT_API_KEY,
)
# Initialize Groq client
groq_client = Groq(api_key=GROQ_API_KEY)
# Embedding model
embedder = SentenceTransformer("intfloat/e5-large")
def format_payload(p):
"""Make context clearer and reduce mixing between sheets/courses."""
text = p.payload.get("text", "")
course = p.payload.get("course", "Unknown Course")
sheet = p.payload.get("sheet_number", "Unknown Sheet")
return f"[COURSE: {course} | SHEET: {sheet}]\n{text}"
def search_qdrant(query):
"""Search Qdrant and return best chunks."""
# تحسين الـ query عشان الـ embedding يفهمه أحسن
enhanced_query = f"query: {query}"
vec = embedder.encode(enhanced_query).tolist()
results = client.query_points(
collection_name=COLLECTION_NAME,
query=vec,
limit=5, # زودت العدد عشان نجيب نتائج أكتر
)
chunks = []
print(f"📊 Found {len(results.points)} relevant chunks:")
for i, p in enumerate(results.points, 1):
print(f" {i}. Score: {p.score:.4f} | Course: {p.payload.get('course', 'N/A')} | Sheet: {p.payload.get('sheet_number', 'N/A')}")
chunks.append(format_payload(p))
return "\n\n---\n\n".join(chunks)
def rag_answer(question):
"""Generate answer using Groq's LLM with RAG context."""
print("\n🔍 Searching Qdrant...")
context = search_qdrant(question)
if not context:
context = "No relevant context found."
print("🤖 Generating answer using Groq...\n")
instructional_prompt = f"""
You are an academic AI assistant.
Use the retrieved context below to answer the question.
If the answer exists in the context, extract it directly.
If the context does NOT contain enough information, you may use your own general knowledge — but keep the answer accurate and concise.
Context:
{context}
Question:
{question}
Answer:
"""
# Groq chat completion
chat_completion = groq_client.chat.completions.create(
messages=[
{
"role": "user",
"content": instructional_prompt
}
],
model="llama-3.3-70b-versatile", # أو "mixtral-8x7b-32768" للسرعة الأعلى
temperature=0.1, # خليتها أقل عشان يلتزم بالـ context
max_tokens=1024,
top_p=1,
stream=False
)
return chat_completion.choices[0].message.content
def rag_answer_stream(question):
"""Generate answer using Groq's LLM with RAG context (Streaming)."""
print("\n🔍 Searching Qdrant...")
context = search_qdrant(question)
if not context:
context = "No relevant context found."
print("🤖 Generating answer using Groq (Streaming)...\n")
instructional_prompt = f"""
You are an academic AI assistant.
Use the retrieved context below to answer the question.
If the answer exists in the context, extract it directly.
If the context does NOT contain enough information, you may use your own general knowledge — but keep the answer accurate and concise.
Context:
{context}
Question:
{question}
Answer:
"""
stream = groq_client.chat.completions.create(
messages=[{"role": "user", "content": instructional_prompt}],
model="llama-3.3-70b-versatile",
temperature=0.1,
max_tokens=1024,
top_p=1,
stream=True
)
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
yield content
if __name__ == "__main__":
print("=" * 60)
print("📚 Academic RAG System (Powered by Groq)")
print("=" * 60)
user_q = input("\n💬 Enter your question: ")
try:
answer = rag_answer(user_q)
print("\n" + "=" * 60)
print("✅ AI Response:")
print("=" * 60)
print(answer)
print("=" * 60)
except Exception as e:
print(f"\n❌ Error: {e}")