import os
import streamlit as st
from groq import Groq
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
import pandas as pd
import docx
from pypdf import PdfReader
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
import tempfile
# -----------------------------
# GROQ CLIENT
# -----------------------------
client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
# -----------------------------
# PAGE CONFIG
# -----------------------------
st.set_page_config(
page_title="AI Study Assistant 📚",
page_icon="🎓",
layout="wide"
)
# -----------------------------
# SIDEBAR
# -----------------------------
st.sidebar.title("📌 Settings")
education_level = st.sidebar.selectbox(
"Select Education Level",
[
"Primary School",
"Middle School",
"Secondary School",
"High School",
"Undergraduate",
"Graduate"
]
)
st.sidebar.markdown("---")
st.sidebar.write("Developed by **Ahmad Bilal** | Fiverr Portfolio Demo")
# -----------------------------
# HEADER
# -----------------------------
st.markdown(
"""
🎓 AI Study Assistant
Upload study materials and ask questions instantly!
""",
unsafe_allow_html=True
)
# -----------------------------
# FILE UPLOADER
# -----------------------------
uploaded_files = st.file_uploader(
"Upload Study Documents",
type=["pdf","docx","txt","csv","xlsx"],
accept_multiple_files=True
)
valid_files = []
if uploaded_files:
MAX_FILE_SIZE = 20 * 1024 * 1024
for file in uploaded_files:
if file.size > MAX_FILE_SIZE:
st.error(f"{file.name} is too large. Upload files under 20MB.")
else:
valid_files.append(file)
st.success(f"{len(valid_files)} file(s) ready for processing")
# -----------------------------
# FILE LOADERS
# -----------------------------
def load_pdf(file):
reader = PdfReader(file)
text = ""
for page in reader.pages:
if page.extract_text():
text += page.extract_text()
return text
def load_docx(file):
doc = docx.Document(file)
return "\n".join([p.text for p in doc.paragraphs])
def load_csv(file):
df = pd.read_csv(file)
return df.to_string()
def load_xlsx(file):
df = pd.read_excel(file)
return df.to_string()
def load_txt(file):
return file.read().decode("utf-8")
# -----------------------------
# DOCUMENT PROCESSING
# -----------------------------
def process_docs(files):
text = ""
for file in files:
if file.type == "application/pdf":
text += load_pdf(file)
elif file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
text += load_docx(file)
elif file.type == "text/csv":
text += load_csv(file)
elif file.type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
text += load_xlsx(file)
else:
text += load_txt(file)
return text
# -----------------------------
# VECTOR STORE
# -----------------------------
@st.cache_resource
def create_vectorstore(text):
splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100
)
chunks = splitter.split_text(text)
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
vectorstore = FAISS.from_texts(chunks, embeddings)
return vectorstore
# -----------------------------
# PROMPT BUILDER
# -----------------------------
def build_prompt(context, question, level):
style = {
"Primary School": "Explain like teaching a 5 year old using fun examples.",
"Middle School": "Explain with easy examples.",
"Secondary School": "Explain clearly using simple ideas.",
"High School": "Explain with reasoning and examples.",
"Undergraduate": "Explain in academic but clear language.",
"Graduate": "Provide detailed academic explanation."
}
prompt = f"""
Use the study material below to answer the question.
Study Material:
{context}
Question:
{question}
Explanation Style:
{style[level]}
"""
return prompt
# -----------------------------
# GROQ LLM
# -----------------------------
def ask_llm(prompt):
chat_completion = client.chat.completions.create(
messages=[{"role":"user","content":prompt}],
model="llama-3.3-70b-versatile"
)
return chat_completion.choices[0].message.content
# -----------------------------
# SUMMARY
# -----------------------------
def generate_summary(text):
prompt = f"""
Create a short and simple summary of this study material.
{text}
"""
return ask_llm(prompt)
# -----------------------------
# PDF GENERATOR
# -----------------------------
def create_pdf(text):
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
styles = getSampleStyleSheet()
story = [Paragraph(text, styles["Normal"])]
doc = SimpleDocTemplate(temp_file.name)
doc.build(story)
return temp_file.name
# -----------------------------
# MAIN LOGIC
# -----------------------------
if valid_files:
raw_text = process_docs(valid_files)
vectorstore = create_vectorstore(raw_text)
st.markdown("---")
st.subheader("❓ Ask a Question")
question = st.text_input("Type your question")
if question:
col1, col2 = st.columns([2,1])
docs = vectorstore.similarity_search(question, k=3)
context = "\n".join([doc.page_content for doc in docs])
prompt = build_prompt(context, question, education_level)
answer = ask_llm(prompt)
with col1:
st.markdown("### 📖 Answer")
st.success(answer)
with col2:
st.markdown("### 📝 Summary")
if st.button("Generate Summary"):
summary = generate_summary(context)
st.info(summary)
st.download_button(
"Download Markdown",
summary,
file_name="summary.md"
)
pdf_file = create_pdf(summary)
with open(pdf_file, "rb") as f:
st.download_button(
"Download PDF",
f,
file_name="summary.pdf"
)
else:
st.info("📂 Upload at least one study document to start.")