PadmasaliGovardhan
commited on
Commit
·
69f4d17
0
Parent(s):
initial Commit
Browse files- .gitignore +10 -0
- .python-version +1 -0
- README.md +0 -0
- backend/embeddings.py +13 -0
- backend/main.py +49 -0
- backend/rag_app.py +91 -0
- backend/requirements.txt +15 -0
- backend/store.py +23 -0
- frontend/app.html +413 -0
- frontend/index.html +197 -0
- frontend/landing.html +108 -0
- frontend/script.js +77 -0
- frontend/style.css +239 -0
- notebook/document.ipynb +0 -0
- notebook/document.py +300 -0
- notebook/document_2.ipynb +132 -0
- pyproject.toml +20 -0
- uv.lock +0 -0
.gitignore
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python-generated files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[oc]
|
| 4 |
+
build/
|
| 5 |
+
dist/
|
| 6 |
+
wheels/
|
| 7 |
+
*.egg-info
|
| 8 |
+
|
| 9 |
+
# Virtual environments
|
| 10 |
+
.venv
|
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.10
|
README.md
ADDED
|
File without changes
|
backend/embeddings.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# backend/embeddings.py
|
| 2 |
+
from sentence_transformers import SentenceTransformer
|
| 3 |
+
import numpy as np
|
| 4 |
+
|
| 5 |
+
class EmbeddingManager:
|
| 6 |
+
def __init__(self, model_name="all-MiniLM-L6-v2"):
|
| 7 |
+
self.model = SentenceTransformer(model_name)
|
| 8 |
+
print(f"✅ Loaded embedding model: {model_name}")
|
| 9 |
+
|
| 10 |
+
def generate_embeddings(self, texts):
|
| 11 |
+
"""Generate embeddings for a list of text chunks"""
|
| 12 |
+
return np.array(self.model.encode(texts, show_progress_bar=True))
|
| 13 |
+
|
backend/main.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# backend/main.py
|
| 2 |
+
from fastapi import FastAPI, UploadFile, Form, File
|
| 3 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
+
import fitz
|
| 5 |
+
import os
|
| 6 |
+
from rag_app import RAGApp
|
| 7 |
+
|
| 8 |
+
app = FastAPI(title="Personal Assistant")
|
| 9 |
+
rag = RAGApp()
|
| 10 |
+
|
| 11 |
+
app.add_middleware(
|
| 12 |
+
CORSMiddleware,
|
| 13 |
+
allow_origins=["*"],
|
| 14 |
+
allow_credentials=True,
|
| 15 |
+
allow_methods=["*"],
|
| 16 |
+
allow_headers=["*"],
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
UPLOAD_DIR = "../data/notes"
|
| 20 |
+
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
| 21 |
+
|
| 22 |
+
def extract_text_from_pdf(pdf_path):
|
| 23 |
+
text = ""
|
| 24 |
+
with fitz.open(pdf_path) as doc:
|
| 25 |
+
for page in doc:
|
| 26 |
+
text += page.get_text()
|
| 27 |
+
return text
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
@app.post("/upload_pdf/")
|
| 31 |
+
async def upload_pdf(file: UploadFile = File(...)):
|
| 32 |
+
path = os.path.join(UPLOAD_DIR, file.filename)
|
| 33 |
+
with open(path, "wb") as f:
|
| 34 |
+
f.write(await file.read())
|
| 35 |
+
text = extract_text_from_pdf(path)
|
| 36 |
+
chunks = rag.add_notes(text)
|
| 37 |
+
return {"status": "success", "message": f"{file.filename} Uploaded Sucessfully...."}
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@app.post("/ask/")
|
| 41 |
+
async def ask_question(query: str = Form(...)):
|
| 42 |
+
answer = rag.ask(query)
|
| 43 |
+
return {"question": query, "answer": answer}
|
| 44 |
+
def main():
|
| 45 |
+
print("Hello from rag-demo!")
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
if __name__ == "__main__":
|
| 49 |
+
main()
|
backend/rag_app.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# backend/rag_app.py
|
| 2 |
+
import os
|
| 3 |
+
from groq import Groq
|
| 4 |
+
from embeddings import EmbeddingManager
|
| 5 |
+
from store import VectorStore
|
| 6 |
+
|
| 7 |
+
class RAGApp:
|
| 8 |
+
def __init__(self):
|
| 9 |
+
self.embedder = EmbeddingManager()
|
| 10 |
+
self.vectorstore = VectorStore()
|
| 11 |
+
self.client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
| 12 |
+
|
| 13 |
+
def add_notes(self, text):
|
| 14 |
+
chunks = [text[i:i+1000] for i in range(0, len(text), 800)]
|
| 15 |
+
embeddings = self.embedder.generate_embeddings(chunks)
|
| 16 |
+
self.vectorstore.add_documents(chunks, embeddings)
|
| 17 |
+
return len(chunks)
|
| 18 |
+
|
| 19 |
+
def ask(self, query):
|
| 20 |
+
try:
|
| 21 |
+
# 1️⃣ Generate embedding for query
|
| 22 |
+
q_embed = self.embedder.generate_embeddings([query])[0]
|
| 23 |
+
|
| 24 |
+
# 2️⃣ Retrieve most relevant chunks from FAISS
|
| 25 |
+
docs = self.vectorstore.retrieve_similar_docs(q_embed, top_k=3)
|
| 26 |
+
context = "\n\n".join(docs)
|
| 27 |
+
|
| 28 |
+
# 3️⃣ Prepare the system and user prompts
|
| 29 |
+
messages = [
|
| 30 |
+
{
|
| 31 |
+
"role": "system",
|
| 32 |
+
"content": (
|
| 33 |
+
"You are a world-class engineering tutor specializing in Electronics, Embedded Systems, and Programming. "
|
| 34 |
+
"Your teaching style dynamically adapts based on the student's question type.\n\n"
|
| 35 |
+
|
| 36 |
+
"### 🧩 Behavior Rules:\n"
|
| 37 |
+
"1️⃣ If the question is **conceptual** (e.g., 'What is a pointer?', 'Explain interrupts'), "
|
| 38 |
+
"explain step-by-step using **analogies, visuals, and motivation**, making the student visualize the concept.\n"
|
| 39 |
+
"2️⃣ If the question involves **code** (e.g., 'debug this C code', 'why segmentation fault?'), "
|
| 40 |
+
"analyze it line-by-line, show errors, give corrected code, and explain *why* the fix works.\n"
|
| 41 |
+
"3️⃣ If it’s **hardware-related** (e.g., 'How does ADC work?', 'explain timers in STM32'), "
|
| 42 |
+
"combine conceptual flow with **real-world hardware behavior**, including timing, registers, and signals.\n"
|
| 43 |
+
"4️⃣ If it’s about **theory from uploaded notes**, summarize precisely and add context from real-world embedded applications.\n\n"
|
| 44 |
+
|
| 45 |
+
"### 🧠 Response Structure:\n"
|
| 46 |
+
"1. **Motivation / Why It Matters** — start with real-world relevance.\n"
|
| 47 |
+
"2. **Concept Breakdown / Explanation** — clear step-by-step teaching.\n"
|
| 48 |
+
"3. **Analogy** — relate it to an everyday or engineering scenario.\n"
|
| 49 |
+
"4. **Code or Example** — short, syntax-highlighted block with explanation.\n"
|
| 50 |
+
"5. **Practical Insight** — how engineers use this in real systems.\n"
|
| 51 |
+
"6. **Common Mistakes + Tips** — warn about beginner pitfalls.\n\n"
|
| 52 |
+
|
| 53 |
+
"### ✨ Style Guidelines:\n"
|
| 54 |
+
"- Use **bold keywords**, emojis (🧠 ⚙️ 💡 📘 ⚠️ 🪄), and markdown for structure.\n"
|
| 55 |
+
"- Be friendly yet technically precise — like a top professor explaining to a beginner.\n"
|
| 56 |
+
"- Don’t mention words like 'simplified' or 'spoon feeding'.\n"
|
| 57 |
+
"- Never say 'as an AI model'.\n"
|
| 58 |
+
"- If context from notes is relevant, integrate it smoothly into the explanation.\n\n"
|
| 59 |
+
|
| 60 |
+
"Your ultimate goal: make the student truly *understand* the concept — not memorize it."
|
| 61 |
+
),
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"role": "user",
|
| 65 |
+
"content": f"Context:\n{context}\n\nQuestion: {query}\nAnswer:",
|
| 66 |
+
},
|
| 67 |
+
]
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# 4️⃣ Call Groq API
|
| 72 |
+
completion = self.client.chat.completions.create(
|
| 73 |
+
model="openai/gpt-oss-20b",
|
| 74 |
+
messages=messages,
|
| 75 |
+
temperature=0.3,
|
| 76 |
+
max_completion_tokens=800,
|
| 77 |
+
top_p=1
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
# 5️⃣ Extract response
|
| 81 |
+
for chunk in completion:
|
| 82 |
+
key, value = chunk
|
| 83 |
+
if key == 'choices':
|
| 84 |
+
return value[0].message.content.strip()
|
| 85 |
+
|
| 86 |
+
return "No valid response from model."
|
| 87 |
+
|
| 88 |
+
except Exception as e:
|
| 89 |
+
print("❌ Error in ask():", e)
|
| 90 |
+
return f"Error: {e}"
|
| 91 |
+
|
backend/requirements.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
langchain
|
| 2 |
+
groq
|
| 3 |
+
sentence-transformers
|
| 4 |
+
python-multipart
|
| 5 |
+
langchain-core
|
| 6 |
+
langchain-community
|
| 7 |
+
pypdf
|
| 8 |
+
pymupdf
|
| 9 |
+
faiss-cpu
|
| 10 |
+
chromadb
|
| 11 |
+
uvicorn
|
| 12 |
+
|
| 13 |
+
openai
|
| 14 |
+
uvicorn
|
| 15 |
+
fastapi
|
backend/store.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# backend/store.py
|
| 2 |
+
import os
|
| 3 |
+
import chromadb
|
| 4 |
+
from chromadb.config import Settings
|
| 5 |
+
|
| 6 |
+
class VectorStore:
|
| 7 |
+
def __init__(self, path="../data/vector_store"):
|
| 8 |
+
self.client = chromadb.PersistentClient(path=path, settings=Settings(anonymized_telemetry=False))
|
| 9 |
+
self.collection = self.client.get_or_create_collection(name="ece_concepts")
|
| 10 |
+
print(f"✅ Vector store initialized at {path}")
|
| 11 |
+
|
| 12 |
+
def add_documents(self, docs, embeddings):
|
| 13 |
+
"""Store docs with embeddings"""
|
| 14 |
+
ids = [str(i) for i in range(len(docs))]
|
| 15 |
+
self.collection.add(documents=docs, embeddings=embeddings.tolist(), ids=ids)
|
| 16 |
+
print(f"🧠 Stored {len(docs)} chunks in vector DB.")
|
| 17 |
+
|
| 18 |
+
def retrieve_similar_docs(self, query_embedding, top_k=3):
|
| 19 |
+
"""Retrieve top-k relevant chunks"""
|
| 20 |
+
results = self.collection.query(query_embeddings=[query_embedding.tolist()], n_results=top_k)
|
| 21 |
+
docs = results["documents"][0]
|
| 22 |
+
return docs
|
| 23 |
+
|
frontend/app.html
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>AI Notes Assistant</title>
|
| 7 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 8 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 9 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
| 10 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
|
| 11 |
+
<style>
|
| 12 |
+
/* Global Styles */
|
| 13 |
+
* {
|
| 14 |
+
margin: 0;
|
| 15 |
+
padding: 0;
|
| 16 |
+
box-sizing: border-box;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
body {
|
| 20 |
+
font-family: 'Inter', sans-serif;
|
| 21 |
+
background: linear-gradient(135deg, #0f0f0f 0%, #2c2c2c 50%, #0f0f0f 100%);
|
| 22 |
+
color: #e0e0e0;
|
| 23 |
+
min-height: 100vh;
|
| 24 |
+
display: flex;
|
| 25 |
+
justify-content: center;
|
| 26 |
+
align-items: center;
|
| 27 |
+
overflow-x: hidden;
|
| 28 |
+
position: relative;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
/* Animated Background Particles for Extra Attractiveness */
|
| 32 |
+
body::before {
|
| 33 |
+
content: '';
|
| 34 |
+
position: absolute;
|
| 35 |
+
top: 0;
|
| 36 |
+
left: 0;
|
| 37 |
+
width: 100%;
|
| 38 |
+
height: 100%;
|
| 39 |
+
background: radial-gradient(circle at 20% 50%, rgba(184, 134, 11, 0.1) 0%, transparent 50%),
|
| 40 |
+
radial-gradient(circle at 80% 20%, rgba(218, 165, 32, 0.1) 0%, transparent 50%),
|
| 41 |
+
radial-gradient(circle at 40% 80%, rgba(255, 215, 0, 0.05) 0%, transparent 50%);
|
| 42 |
+
animation: particleFloat 10s ease-in-out infinite alternate;
|
| 43 |
+
z-index: -1;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
@keyframes particleFloat {
|
| 47 |
+
0% { transform: translateY(0px) rotate(0deg); }
|
| 48 |
+
100% { transform: translateY(-20px) rotate(5deg); }
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.container {
|
| 52 |
+
max-width: 1200px;
|
| 53 |
+
width: 100%;
|
| 54 |
+
padding: 20px;
|
| 55 |
+
display: grid;
|
| 56 |
+
grid-template-columns: 1fr 2fr;
|
| 57 |
+
gap: 30px;
|
| 58 |
+
align-items: start;
|
| 59 |
+
position: relative;
|
| 60 |
+
z-index: 1;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/* Header */
|
| 64 |
+
.header {
|
| 65 |
+
grid-column: 1 / -1;
|
| 66 |
+
text-align: center;
|
| 67 |
+
margin-bottom: 40px;
|
| 68 |
+
animation: fadeInDown 1s ease-out;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.header h1 {
|
| 72 |
+
font-size: 3rem;
|
| 73 |
+
font-weight: 800;
|
| 74 |
+
background: linear-gradient(45deg, #b8860b, #daa520, #ffd700);
|
| 75 |
+
-webkit-background-clip: text;
|
| 76 |
+
-webkit-text-fill-color: transparent;
|
| 77 |
+
background-clip: text;
|
| 78 |
+
text-shadow: 0 0 30px rgba(184, 134, 11, 0.6), 0 0 60px rgba(255, 215, 0, 0.3);
|
| 79 |
+
margin-bottom: 10px;
|
| 80 |
+
animation: glowPulse 2s ease-in-out infinite alternate;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
@keyframes glowPulse {
|
| 84 |
+
0% { text-shadow: 0 0 30px rgba(184, 134, 11, 0.6); }
|
| 85 |
+
100% { text-shadow: 0 0 40px rgba(255, 215, 0, 0.8); }
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.header .subtitle {
|
| 89 |
+
font-size: 1.2rem;
|
| 90 |
+
font-weight: 400;
|
| 91 |
+
color: #a8a8a8;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/* Upload Section - Super Attractive */
|
| 95 |
+
.upload-section {
|
| 96 |
+
background: rgba(15, 15, 15, 0.95);
|
| 97 |
+
border: 2px solid #b8860b;
|
| 98 |
+
border-radius: 25px;
|
| 99 |
+
padding: 30px;
|
| 100 |
+
text-align: center;
|
| 101 |
+
box-shadow: 0 15px 40px rgba(184, 134, 11, 0.3), inset 0 0 20px rgba(184, 134, 11, 0.1);
|
| 102 |
+
transition: all 0.4s ease;
|
| 103 |
+
position: relative;
|
| 104 |
+
overflow: hidden;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.upload-section::before {
|
| 108 |
+
content: '';
|
| 109 |
+
position: absolute;
|
| 110 |
+
top: -50%;
|
| 111 |
+
left: -50%;
|
| 112 |
+
width: 200%;
|
| 113 |
+
height: 200%;
|
| 114 |
+
background: conic-gradient(from 0deg, transparent, rgba(184, 134, 11, 0.1), transparent);
|
| 115 |
+
animation: rotateGlow 8s linear infinite;
|
| 116 |
+
z-index: -1;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
@keyframes rotateGlow {
|
| 120 |
+
0% { transform: rotate(0deg); }
|
| 121 |
+
100% { transform: rotate(360deg); }
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
.upload-section:hover {
|
| 125 |
+
transform: translateY(-8px) scale(1.02);
|
| 126 |
+
box-shadow: 0 20px 50px rgba(184, 134, 11, 0.5), inset 0 0 30px rgba(255, 215, 0, 0.2);
|
| 127 |
+
border-color: #ffd700;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
.file-label {
|
| 131 |
+
display: inline-block;
|
| 132 |
+
padding: 12px 24px;
|
| 133 |
+
background: linear-gradient(45deg, #b8860b, #daa520, #ffd700, #b8860b);
|
| 134 |
+
color: #ffffff;
|
| 135 |
+
border-radius: 30px;
|
| 136 |
+
cursor: pointer;
|
| 137 |
+
font-weight: 700;
|
| 138 |
+
font-size: 1rem;
|
| 139 |
+
transition: all 0.4s ease;
|
| 140 |
+
margin-bottom: 20px;
|
| 141 |
+
box-shadow: 0 6px 20px rgba(184, 134, 11, 0.4);
|
| 142 |
+
position: relative;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
.file-label::after {
|
| 146 |
+
content: '';
|
| 147 |
+
position: absolute;
|
| 148 |
+
top: 0;
|
| 149 |
+
left: 0;
|
| 150 |
+
right: 0;
|
| 151 |
+
bottom: 0;
|
| 152 |
+
background: linear-gradient(45deg, rgba(255, 255, 255, 0.2), transparent);
|
| 153 |
+
border-radius: 30px;
|
| 154 |
+
opacity: 0;
|
| 155 |
+
transition: opacity 0.3s ease;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.file-label:hover {
|
| 159 |
+
background: linear-gradient(45deg, #ffd700, #b8860b, #daa520, #ffd700);
|
| 160 |
+
transform: scale(1.08) translateY(-2px);
|
| 161 |
+
box-shadow: 0 8px 25px rgba(255, 215, 0, 0.6);
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
.file-label:hover::after {
|
| 165 |
+
opacity: 1;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.file-label i {
|
| 169 |
+
margin-right: 10px;
|
| 170 |
+
animation: iconBounce 1.5s ease-in-out infinite;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
@keyframes iconBounce {
|
| 174 |
+
0%, 100% { transform: translateY(0); }
|
| 175 |
+
50% { transform: translateY(-3px); }
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
#pdfInput {
|
| 179 |
+
display: none;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
.btn {
|
| 183 |
+
padding: 10px 20px;
|
| 184 |
+
border: none;
|
| 185 |
+
border-radius: 30px;
|
| 186 |
+
font-weight: 700;
|
| 187 |
+
cursor: pointer;
|
| 188 |
+
transition: all 0.4s ease;
|
| 189 |
+
font-size: 1rem;
|
| 190 |
+
position: relative;
|
| 191 |
+
overflow: hidden;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.btn::before {
|
| 195 |
+
content: '';
|
| 196 |
+
position: absolute;
|
| 197 |
+
top: 0;
|
| 198 |
+
left: -100%;
|
| 199 |
+
width: 100%;
|
| 200 |
+
height: 100%;
|
| 201 |
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
|
| 202 |
+
transition: left 0.5s ease;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
.btn:hover::before {
|
| 206 |
+
left: 100%;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
.btn-primary {
|
| 210 |
+
background: linear-gradient(45deg, #b8860b, #daa520, #ffd700);
|
| 211 |
+
color: #ffffff;
|
| 212 |
+
box-shadow: 0 6px 20px rgba(184, 134, 11, 0.4);
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
.btn-primary:hover {
|
| 216 |
+
background: linear-gradient(45deg, #ffd700, #b8860b, #daa520);
|
| 217 |
+
transform: scale(1.08) translateY(-2px);
|
| 218 |
+
box-shadow: 0 8px 25px rgba(255, 215, 0, 0.6);
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
.btn-primary i {
|
| 222 |
+
margin-right: 8px;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
.status {
|
| 226 |
+
margin-top: 15px;
|
| 227 |
+
font-weight: 500;
|
| 228 |
+
color: #a8a8a8;
|
| 229 |
+
font-size: 0.9rem;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
/* Chat Section */
|
| 233 |
+
.chat-section {
|
| 234 |
+
background: rgba(15, 15, 15, 0.95);
|
| 235 |
+
border: 2px solid #b8860b;
|
| 236 |
+
border-radius: 25px;
|
| 237 |
+
padding: 30px;
|
| 238 |
+
display: flex;
|
| 239 |
+
flex-direction: column;
|
| 240 |
+
height: 600px;
|
| 241 |
+
box-shadow: 0 15px 40px rgba(184, 134, 11, 0.3);
|
| 242 |
+
transition: all 0.4s ease;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
.chat-section:hover {
|
| 246 |
+
transform: translateY(-5px);
|
| 247 |
+
box-shadow: 0 20px 50px rgba(184, 134, 11, 0.5);
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
.chat-box {
|
| 251 |
+
flex: 1;
|
| 252 |
+
overflow-y: auto;
|
| 253 |
+
padding: 20px;
|
| 254 |
+
background: rgba(44, 44, 44, 0.6);
|
| 255 |
+
border-radius: 15px;
|
| 256 |
+
margin-bottom: 20px;
|
| 257 |
+
scrollbar-width: thin;
|
| 258 |
+
scrollbar-color: #b8860b #2c2c2c;
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
.chat-box::-webkit-scrollbar {
|
| 262 |
+
width: 8px;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
.chat-box::-webkit-scrollbar-track {
|
| 266 |
+
background: #2c2c2c;
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
.chat-box::-webkit-scrollbar-thumb {
|
| 270 |
+
background: #b8860b;
|
| 271 |
+
border-radius: 4px;
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
.message {
|
| 275 |
+
margin-bottom: 15px;
|
| 276 |
+
padding: 15px;
|
| 277 |
+
border-radius: 15px;
|
| 278 |
+
animation: fadeIn 0.5s ease-out;
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
.message.user {
|
| 282 |
+
background: linear-gradient(45deg, #b8860b, #daa520);
|
| 283 |
+
color: #ffffff;
|
| 284 |
+
align-self: flex-end;
|
| 285 |
+
text-align: right;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
.message.ai {
|
| 289 |
+
background: rgba(184, 134, 11, 0.1);
|
| 290 |
+
color: #e0e0e0;
|
| 291 |
+
border-left: 4px solid #b8860b;
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
.input-area {
|
| 295 |
+
display: flex;
|
| 296 |
+
gap: 10px;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
#userInput {
|
| 300 |
+
flex: 1;
|
| 301 |
+
padding: 15px;
|
| 302 |
+
border: 2px solid #b8860b;
|
| 303 |
+
border-radius: 50px;
|
| 304 |
+
background: rgba(44, 44, 44, 0.8);
|
| 305 |
+
color: #e0e0e0;
|
| 306 |
+
font-size: 1rem;
|
| 307 |
+
outline: none;
|
| 308 |
+
transition: all 0.3s ease;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
#userInput:focus {
|
| 312 |
+
border-color: #ffd700;
|
| 313 |
+
box-shadow: 0 0 15px rgba(255, 215, 0, 0.5);
|
| 314 |
+
transform: scale(1.02);
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
.btn-send {
|
| 318 |
+
background: linear-gradient(45deg, #b8860b, #daa520);
|
| 319 |
+
color: #ffffff;
|
| 320 |
+
border-radius: 50%;
|
| 321 |
+
width: 50px;
|
| 322 |
+
height: 50px;
|
| 323 |
+
display: flex;
|
| 324 |
+
align-items: center;
|
| 325 |
+
justify-content: center;
|
| 326 |
+
transition: all 0.3s ease;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
.btn-send:hover {
|
| 330 |
+
background: linear-gradient(45deg, #daa520, #b8860b);
|
| 331 |
+
transform: scale(1.1) rotate(5deg);
|
| 332 |
+
box-shadow: 0 5px 15px rgba(184, 134, 11, 0.4);
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
/* Animations */
|
| 336 |
+
@keyframes fadeInDown {
|
| 337 |
+
from {
|
| 338 |
+
opacity: 0;
|
| 339 |
+
transform: translateY(-30px);
|
| 340 |
+
}
|
| 341 |
+
to {
|
| 342 |
+
opacity: 1;
|
| 343 |
+
transform: translateY(0);
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
@keyframes fadeIn {
|
| 348 |
+
from {
|
| 349 |
+
opacity: 0;
|
| 350 |
+
transform: translateY(10px);
|
| 351 |
+
}
|
| 352 |
+
to {
|
| 353 |
+
opacity: 1;
|
| 354 |
+
transform: translateY(0);
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
/* Responsive Design */
|
| 359 |
+
@media (max-width: 768px) {
|
| 360 |
+
.container {
|
| 361 |
+
grid-template-columns: 1fr;
|
| 362 |
+
gap: 20px;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
.header h1 {
|
| 366 |
+
font-size: 2rem;
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
.chat-section {
|
| 370 |
+
height: 500px;
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
</style>
|
| 374 |
+
</head>
|
| 375 |
+
<body>
|
| 376 |
+
<div class="container">
|
| 377 |
+
<header class="header">
|
| 378 |
+
<h1><i class="fas fa-book-open"></i> AI Notes Assistant</h1>
|
| 379 |
+
<p class="subtitle">Upload your notes & chat intelligently</p>
|
| 380 |
+
</header>
|
| 381 |
+
|
| 382 |
+
<!-- Upload Section -->
|
| 383 |
+
<section class="upload-section">
|
| 384 |
+
<label class="file-label" for="pdfInput">
|
| 385 |
+
<i class="fas fa-cloud-upload-alt"></i> Choose PDF
|
| 386 |
+
</label>
|
| 387 |
+
<input type="file" id="pdfInput" accept=".pdf" hidden />
|
| 388 |
+
<button id="uploadBtn" class="btn btn-primary">
|
| 389 |
+
<i class="fas fa-upload"></i> Upload
|
| 390 |
+
</button>
|
| 391 |
+
<div id="uploadStatus" class="status"></div>
|
| 392 |
+
</section>
|
| 393 |
+
|
| 394 |
+
<!-- Chat Section -->
|
| 395 |
+
<section class="chat-section">
|
| 396 |
+
<div class="chat-box" id="chatBox">
|
| 397 |
+
<!-- Messages will be appended here -->
|
| 398 |
+
</div>
|
| 399 |
+
|
| 400 |
+
<div class="input-area">
|
| 401 |
+
<input type="text" id="userInput" placeholder="Ask a question…" autocomplete="off" />
|
| 402 |
+
<button id="sendBtn" class="btn btn-send" title="Send">
|
| 403 |
+
<i class="fas fa-paper-plane"></i>
|
| 404 |
+
</button>
|
| 405 |
+
</div>
|
| 406 |
+
</section>
|
| 407 |
+
</div>
|
| 408 |
+
|
| 409 |
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
| 410 |
+
<script src="script.js"></script>
|
| 411 |
+
</body>
|
| 412 |
+
</html>
|
| 413 |
+
|
frontend/index.html
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>AI Notes Assistant | Your Personal AI Tutor</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 9 |
+
<style>
|
| 10 |
+
body {
|
| 11 |
+
background: #0a0a0a;
|
| 12 |
+
color: #e8e7e7;
|
| 13 |
+
font-family: 'Inter', sans-serif;
|
| 14 |
+
overflow-x: hidden;
|
| 15 |
+
}
|
| 16 |
+
.gold-gradient {
|
| 17 |
+
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
|
| 18 |
+
}
|
| 19 |
+
.gold-accent { color: #D4AF37; }
|
| 20 |
+
.gold-glow {
|
| 21 |
+
box-shadow: 0 0 20px rgba(212, 175, 55, 0.3);
|
| 22 |
+
transition: all 0.3s ease;
|
| 23 |
+
}
|
| 24 |
+
.glass {
|
| 25 |
+
background: rgba(20, 20, 30, 0.4);
|
| 26 |
+
backdrop-filter: blur(20px);
|
| 27 |
+
border: 1px solid rgba(212, 175, 55, 0.2);
|
| 28 |
+
}
|
| 29 |
+
.hero-text {
|
| 30 |
+
font-family: 'Space Grotesk', sans-serif;
|
| 31 |
+
background: linear-gradient(45deg, #ffffff, #D4AF37);
|
| 32 |
+
background-clip: text;
|
| 33 |
+
-webkit-background-clip: text;
|
| 34 |
+
-webkit-text-fill-color: transparent;
|
| 35 |
+
animation: glitch 2s infinite;
|
| 36 |
+
}
|
| 37 |
+
@keyframes glitch {
|
| 38 |
+
0%, 90%, 100% { transform: translate(0); }
|
| 39 |
+
10% { transform: translate(-1px, -1px); }
|
| 40 |
+
20% { transform: translate(1px, 1px); }
|
| 41 |
+
30% { transform: translate(-2px, 0); }
|
| 42 |
+
}
|
| 43 |
+
.particles {
|
| 44 |
+
position: fixed;
|
| 45 |
+
top: 0;
|
| 46 |
+
left: 0;
|
| 47 |
+
width: 100%;
|
| 48 |
+
height: 100%;
|
| 49 |
+
pointer-events: none;
|
| 50 |
+
z-index: -1;
|
| 51 |
+
}
|
| 52 |
+
.particle {
|
| 53 |
+
position: absolute;
|
| 54 |
+
width: 2px;
|
| 55 |
+
height: 2px;
|
| 56 |
+
background: #D4AF37;
|
| 57 |
+
border-radius: 50%;
|
| 58 |
+
animation: float 6s infinite linear;
|
| 59 |
+
}
|
| 60 |
+
@keyframes float {
|
| 61 |
+
0% { transform: translateY(100vh) scale(0); opacity: 0; }
|
| 62 |
+
10% { opacity: 1; }
|
| 63 |
+
90% { opacity: 1; }
|
| 64 |
+
100% { transform: translateY(-10px) scale(1); opacity: 0; }
|
| 65 |
+
}
|
| 66 |
+
.neural-line {
|
| 67 |
+
position: absolute;
|
| 68 |
+
height: 1px;
|
| 69 |
+
background: linear-gradient(90deg, transparent, #D4AF37, transparent);
|
| 70 |
+
animation: neural 4s infinite;
|
| 71 |
+
}
|
| 72 |
+
@keyframes neural {
|
| 73 |
+
0% { width: 0; left: 0; }
|
| 74 |
+
50% { width: 100%; }
|
| 75 |
+
100% { width: 0; left: 100%; }
|
| 76 |
+
}
|
| 77 |
+
.bento-grid {
|
| 78 |
+
display: grid;
|
| 79 |
+
grid-template-columns: repeat(12, 1fr);
|
| 80 |
+
grid-template-rows: auto auto auto;
|
| 81 |
+
gap: 1.5rem;
|
| 82 |
+
}
|
| 83 |
+
.span-6 { grid-column: span 6; }
|
| 84 |
+
.span-4 { grid-column: span 4; }
|
| 85 |
+
.span-8 { grid-column: span 8; }
|
| 86 |
+
.typing {
|
| 87 |
+
border-right: 2px solid #D4AF37;
|
| 88 |
+
animation: blink 1s infinite;
|
| 89 |
+
}
|
| 90 |
+
@keyframes blink {
|
| 91 |
+
0%, 50% { border-color: transparent; }
|
| 92 |
+
51%, 100% { border-color: #D4AF37; }
|
| 93 |
+
}
|
| 94 |
+
</style>
|
| 95 |
+
</head>
|
| 96 |
+
<body class="gold-gradient relative">
|
| 97 |
+
<!-- Golden Particles & Neural Network -->
|
| 98 |
+
<div class="particles" id="particles"></div>
|
| 99 |
+
<div class="neural-line" style="top: 20%; left: 10%; animation-delay: 0s;"></div>
|
| 100 |
+
<div class="neural-line" style="top: 60%; left: 70%; animation-delay: 2s;"></div>
|
| 101 |
+
<div class="neural-line" style="top: 80%; left: 20%; animation-delay: 1s;"></div>
|
| 102 |
+
|
| 103 |
+
<!-- Hero Section -->
|
| 104 |
+
<section class="min-h-screen flex items-center justify-center relative px-4 pt-16">
|
| 105 |
+
<div class="text-center max-w-7xl mx-auto">
|
| 106 |
+
<h1 class="text-7xl md:text-9xl font-black hero-text mb-4">
|
| 107 |
+
AI Notes
|
| 108 |
+
<span class="block text-5xl md:text-7xl text-gold-accent">Assistant</span>
|
| 109 |
+
</h1>
|
| 110 |
+
<p class="text-xl md:text-2xl text-gray-300 mb-8 max-w-3xl mx-auto typing" id="hero-subtitle">
|
| 111 |
+
Your genius-level AI tutor that masters your notes instantly...
|
| 112 |
+
</p>
|
| 113 |
+
<a href="app.html" class="inline-block bg-white text-black font-bold py-4 px-8 rounded-full text-lg gold-glow hover:scale-105 transition-all duration-300">
|
| 114 |
+
Launch Genius Mode
|
| 115 |
+
</a>
|
| 116 |
+
</div>
|
| 117 |
+
</section>
|
| 118 |
+
|
| 119 |
+
<!-- Bento Grid: How It Works -->
|
| 120 |
+
<section class="py-24 px-4 max-w-7xl mx-auto">
|
| 121 |
+
<h2 class="text-5xl font-black text-center mb-16 text-gold-accent">The Infinite Intelligence Pipeline</h2>
|
| 122 |
+
<div class="bento-grid">
|
| 123 |
+
<div class="span-4 glass p-6 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500">
|
| 124 |
+
<div class="text-4xl mb-4">📄</div>
|
| 125 |
+
<h3 class="text-xl font-semibold mb-2">Upload</h3>
|
| 126 |
+
<p>Any notes, PDFs, textbooks</p>
|
| 127 |
+
</div>
|
| 128 |
+
<div class="span-4 glass p-6 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500 row-span-2">
|
| 129 |
+
<div class="text-4xl mb-4">🧠</div>
|
| 130 |
+
<h3 class="text-xl font-semibold mb-2">Embed & Index</h3>
|
| 131 |
+
<p>Sentence Transformers + FAISS Vector DB<br>99.9% recall accuracy</p>
|
| 132 |
+
</div>
|
| 133 |
+
<div class="span-4 glass p-6 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500">
|
| 134 |
+
<div class="text-4xl mb-4">⚡</div>
|
| 135 |
+
<h3 class="text-xl font-semibold mb-2">Query</h3>
|
| 136 |
+
<p>Ask anything, in any language</p>
|
| 137 |
+
</div>
|
| 138 |
+
<div class="span-8 glass p-8 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500 row-span-2">
|
| 139 |
+
<h3 class="text-2xl font-bold mb-4 text-gold-accent">Powered by Groq's Fastest Model</h3>
|
| 140 |
+
<p class="text-lg">gpt-oss-20b delivers human-like reasoning at 500+ tokens/sec</p>
|
| 141 |
+
</div>
|
| 142 |
+
<div class="span-6 glass p-6 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500">
|
| 143 |
+
<div class="text-4xl mb-4">🎯</div>
|
| 144 |
+
<h3 class="text-xl font-semibold mb-2">Retrieve</h3>
|
| 145 |
+
<p>Top-5 semantic matches</p>
|
| 146 |
+
</div>
|
| 147 |
+
<div class="span-6 glass p-6 rounded-2xl gold-glow hover:scale-[1.02] transition-all duration-500">
|
| 148 |
+
<div class="text-4xl mb-4">✨</div>
|
| 149 |
+
<h3 class="text-xl font-semibold mb-2">Generate</h3>
|
| 150 |
+
<p>Context-aware mastery</p>
|
| 151 |
+
</div>
|
| 152 |
+
</div>
|
| 153 |
+
</section>
|
| 154 |
+
|
| 155 |
+
<!-- CTA Section -->
|
| 156 |
+
<section class="py-24 text-center">
|
| 157 |
+
<h2 class="text-5xl font-black mb-4 text-gold-accent">Become Unstoppable</h2>
|
| 158 |
+
<p class="text-xl text-gray-300 mb-8">Join to ace exams with Me</p>
|
| 159 |
+
<a href="app.html" class="inline-block bg-white text-black font-bold py-4 px-10 rounded-full text-xl gold-glow hover:scale-105 transition-all duration-300">
|
| 160 |
+
Now You are Ready to Start
|
| 161 |
+
</a>
|
| 162 |
+
</section>
|
| 163 |
+
|
| 164 |
+
<script>
|
| 165 |
+
// Typing Effect
|
| 166 |
+
const subtitle = "Your genius-level AI tutor that masters your notes instantly...";
|
| 167 |
+
let i = 0;
|
| 168 |
+
const type = () => {
|
| 169 |
+
document.getElementById('hero-subtitle').textContent = subtitle.slice(0, i);
|
| 170 |
+
i++;
|
| 171 |
+
if (i <= subtitle.length) setTimeout(type, 80);
|
| 172 |
+
};
|
| 173 |
+
setTimeout(type, 1000);
|
| 174 |
+
|
| 175 |
+
// Golden Particles
|
| 176 |
+
function createParticles() {
|
| 177 |
+
const particles = document.getElementById('particles');
|
| 178 |
+
for (let i = 0; i < 50; i++) {
|
| 179 |
+
const particle = document.createElement('div');
|
| 180 |
+
particle.className = 'particle';
|
| 181 |
+
particle.style.left = Math.random() * 100 + '%';
|
| 182 |
+
particle.style.animationDelay = Math.random() * 6 + 's';
|
| 183 |
+
particle.style.animationDuration = (Math.random() * 3 + 3) + 's';
|
| 184 |
+
particles.appendChild(particle);
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
createParticles();
|
| 188 |
+
setInterval(createParticles, 3000);
|
| 189 |
+
</script>
|
| 190 |
+
<footer class="text-center py-8 text-gray-500 text-sm">
|
| 191 |
+
<p>© 2025 AI Notes Assistant | Built By
|
| 192 |
+
<a href="https://www.linkedin.com/in/govardhanpadmasali/" target="_blank" style="color: #0ea5e9; text-decoration: underline; font-weight: bold;">This Guy</a>
|
| 193 |
+
</p>
|
| 194 |
+
</footer>
|
| 195 |
+
|
| 196 |
+
</body>
|
| 197 |
+
</html>
|
frontend/landing.html
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>AI Notes Assistant | RAG Chatbot</title>
|
| 7 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css">
|
| 8 |
+
<style>
|
| 9 |
+
body {
|
| 10 |
+
background: radial-gradient(circle at top, #0f172a, #000);
|
| 11 |
+
color: #e2e8f0;
|
| 12 |
+
font-family: "Poppins", sans-serif;
|
| 13 |
+
}
|
| 14 |
+
.flow-step {
|
| 15 |
+
background: #1e293b;
|
| 16 |
+
padding: 1.2rem;
|
| 17 |
+
border-radius: 1rem;
|
| 18 |
+
box-shadow: 0 0 10px #0ea5e9;
|
| 19 |
+
}
|
| 20 |
+
.connector {
|
| 21 |
+
height: 2px;
|
| 22 |
+
background: #38bdf8;
|
| 23 |
+
width: 60px;
|
| 24 |
+
margin: auto;
|
| 25 |
+
}
|
| 26 |
+
</style>
|
| 27 |
+
</head>
|
| 28 |
+
<body class="flex flex-col items-center min-h-screen">
|
| 29 |
+
|
| 30 |
+
<!-- 📸 Top Section -->
|
| 31 |
+
<header class="text-center mt-8">
|
| 32 |
+
<img src="assets/ai_notes_logo.png" alt="AI Notes Assistant Logo" class="mx-auto w-40 h-40 rounded-full shadow-lg border border-cyan-400">
|
| 33 |
+
<h1 class="text-4xl font-extrabold mt-4 text-cyan-300">AI Notes Assistant 🤖</h1>
|
| 34 |
+
<p class="text-lg text-gray-300 mt-2 max-w-2xl mx-auto">
|
| 35 |
+
Upload your notes, research papers, or textbooks and chat with them!
|
| 36 |
+
Powered by <strong>Retrieval-Augmented Generation (RAG)</strong>, this AI acts like a world-class tutor — giving detailed, real-world explanations for your questions.
|
| 37 |
+
</p>
|
| 38 |
+
</header>
|
| 39 |
+
|
| 40 |
+
<!-- ⚙️ Workflow Section -->
|
| 41 |
+
<section class="mt-12 text-center">
|
| 42 |
+
<h2 class="text-3xl font-semibold text-cyan-300 mb-6">🔄 How It Works</h2>
|
| 43 |
+
<div class="flex flex-col items-center space-y-4">
|
| 44 |
+
|
| 45 |
+
<div class="flow-step">
|
| 46 |
+
<h3 class="font-bold text-xl text-cyan-400">📁 Step 1: Upload Notes</h3>
|
| 47 |
+
<p>Upload PDFs or documents (like textbooks, notes, or manuals).</p>
|
| 48 |
+
</div>
|
| 49 |
+
<div class="connector"></div>
|
| 50 |
+
|
| 51 |
+
<div class="flow-step">
|
| 52 |
+
<h3 class="font-bold text-xl text-cyan-400">🧩 Step 2: Chunking & Embedding</h3>
|
| 53 |
+
<p>The text is split into small chunks and converted into numerical embeddings using <b>Sentence Transformers</b>.</p>
|
| 54 |
+
</div>
|
| 55 |
+
<div class="connector"></div>
|
| 56 |
+
|
| 57 |
+
<div class="flow-step">
|
| 58 |
+
<h3 class="font-bold text-xl text-cyan-400">📚 Step 3: Vector Storage</h3>
|
| 59 |
+
<p>Chunks are stored in a <b>FAISS vector database</b> for efficient semantic search.</p>
|
| 60 |
+
</div>
|
| 61 |
+
<div class="connector"></div>
|
| 62 |
+
|
| 63 |
+
<div class="flow-step">
|
| 64 |
+
<h3 class="font-bold text-xl text-cyan-400">💬 Step 4: Ask Questions</h3>
|
| 65 |
+
<p>Ask natural language questions related to your uploaded material.</p>
|
| 66 |
+
</div>
|
| 67 |
+
<div class="connector"></div>
|
| 68 |
+
|
| 69 |
+
<div class="flow-step">
|
| 70 |
+
<h3 class="font-bold text-xl text-cyan-400">🧠 Step 5: RAG Model Response</h3>
|
| 71 |
+
<p>The system retrieves relevant chunks and uses the <b>Groq LLM (gpt-oss-20b)</b> to generate context-aware, step-by-step explanations.</p>
|
| 72 |
+
</div>
|
| 73 |
+
</div>
|
| 74 |
+
</section>
|
| 75 |
+
|
| 76 |
+
<!-- 💡 Tech Stack -->
|
| 77 |
+
<section class="mt-16 max-w-4xl text-center">
|
| 78 |
+
<h2 class="text-3xl font-semibold text-cyan-300 mb-4">⚙️ Tech Stack</h2>
|
| 79 |
+
<div class="grid grid-cols-2 sm:grid-cols-4 gap-6 text-gray-200">
|
| 80 |
+
<div class="flow-step">🐍 Python (FastAPI)</div>
|
| 81 |
+
<div class="flow-step">🧠 Groq API (gpt-oss-20b)</div>
|
| 82 |
+
<div class="flow-step">📦 FAISS Vector Store</div>
|
| 83 |
+
<div class="flow-step">🎨 HTML / CSS / JS Frontend</div>
|
| 84 |
+
</div>
|
| 85 |
+
</section>
|
| 86 |
+
|
| 87 |
+
<!-- 🚀 CTA -->
|
| 88 |
+
<section class="mt-12 text-center">
|
| 89 |
+
<h2 class="text-2xl text-cyan-300 mb-4">🚀 Try the AI Notes Assistant</h2>
|
| 90 |
+
<a href="app.html" class="bg-cyan-500 hover:bg-cyan-400 text-black font-bold py-2 px-6 rounded-lg transition duration-300">
|
| 91 |
+
Open Application
|
| 92 |
+
</a>
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
</section>
|
| 97 |
+
|
| 98 |
+
<!-- 📜 Footer -->
|
| 99 |
+
<footer class="mt-16 text-gray-400 text-sm mb-4">
|
| 100 |
+
<p>Developed by <a href="https://www.linkedin.com/in/govardhanpadmasali/" target="_blank" style="color: blue; text-decoration: underline; font-weight: bold;">Visit him</a> | B.Tech ECE | Embedded & AI Integration Project</p>
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
<p>© 2025 AI Notes Assistant | Powered by Groq + FAISS + FastAPI</p>
|
| 104 |
+
</footer>
|
| 105 |
+
|
| 106 |
+
</body>
|
| 107 |
+
</html>
|
| 108 |
+
|
frontend/script.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const backendURL = "http://127.0.0.1:8000"; // change if deployed
|
| 2 |
+
const uploadBtn = document.getElementById("uploadBtn");
|
| 3 |
+
const sendBtn = document.getElementById("sendBtn");
|
| 4 |
+
const pdfInput = document.getElementById("pdfInput");
|
| 5 |
+
const uploadStatus = document.getElementById("uploadStatus");
|
| 6 |
+
const chatBox = document.getElementById("chatBox");
|
| 7 |
+
const userInput = document.getElementById("userInput");
|
| 8 |
+
|
| 9 |
+
// ---------- Upload ----------
|
| 10 |
+
uploadBtn.addEventListener("click", async () => {
|
| 11 |
+
const file = pdfInput.files[0];
|
| 12 |
+
if (!file) return showStatus("⚠️ Please select a PDF first!", "orange");
|
| 13 |
+
|
| 14 |
+
const formData = new FormData();
|
| 15 |
+
formData.append("file", file);
|
| 16 |
+
|
| 17 |
+
showStatus("📤 Uploading…", "#ffba08");
|
| 18 |
+
try {
|
| 19 |
+
const res = await fetch(`${backendURL}/upload_pdf/`, {
|
| 20 |
+
method: "POST",
|
| 21 |
+
body: formData,
|
| 22 |
+
});
|
| 23 |
+
const data = await res.json();
|
| 24 |
+
showStatus(data.message || "✅ Upload complete!", "#4ade80");
|
| 25 |
+
} catch (e) {
|
| 26 |
+
showStatus("❌ Upload failed.", "#ef4444");
|
| 27 |
+
}
|
| 28 |
+
});
|
| 29 |
+
|
| 30 |
+
function showStatus(txt, color) {
|
| 31 |
+
uploadStatus.textContent = txt;
|
| 32 |
+
uploadStatus.style.color = color;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
// ---------- Chat ----------
|
| 36 |
+
sendBtn.addEventListener("click", sendQuery);
|
| 37 |
+
userInput.addEventListener("keydown", e => { if (e.key === "Enter") sendQuery(); });
|
| 38 |
+
|
| 39 |
+
async function sendQuery() {
|
| 40 |
+
const query = userInput.value.trim();
|
| 41 |
+
if (!query) return;
|
| 42 |
+
appendMessage(query, "user");
|
| 43 |
+
userInput.value = "";
|
| 44 |
+
const thinking = appendMessage("Thinking…", "bot");
|
| 45 |
+
|
| 46 |
+
const formData = new URLSearchParams();
|
| 47 |
+
formData.append("query", query);
|
| 48 |
+
|
| 49 |
+
try {
|
| 50 |
+
const res = await fetch(`${backendURL}/ask/`, {
|
| 51 |
+
method: "POST",
|
| 52 |
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
| 53 |
+
body: formData,
|
| 54 |
+
});
|
| 55 |
+
const data = await res.json();
|
| 56 |
+
chatBox.removeChild(thinking);
|
| 57 |
+
appendMessage(data.answer || "⚠️ No response from model.", "bot", true);
|
| 58 |
+
} catch (err) {
|
| 59 |
+
console.error(err);
|
| 60 |
+
chatBox.removeChild(thinking);
|
| 61 |
+
appendMessage("❌ Error connecting to backend.", "bot");
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
// ---------- Message Helper ----------
|
| 66 |
+
function appendMessage(text, sender, isMarkdown = false) {
|
| 67 |
+
const div = document.createElement("div");
|
| 68 |
+
div.className = `message ${sender}`;
|
| 69 |
+
if (isMarkdown) {
|
| 70 |
+
div.innerHTML = marked.parse(text);
|
| 71 |
+
} else {
|
| 72 |
+
div.textContent = text;
|
| 73 |
+
}
|
| 74 |
+
chatBox.appendChild(div);
|
| 75 |
+
chatBox.scrollTop = chatBox.scrollHeight;
|
| 76 |
+
return div;
|
| 77 |
+
}
|
frontend/style.css
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ==== RESET & BASE ==== */
|
| 2 |
+
*,
|
| 3 |
+
*::before,
|
| 4 |
+
*::after {
|
| 5 |
+
box-sizing: border-box;
|
| 6 |
+
margin: 0;
|
| 7 |
+
padding: 0;
|
| 8 |
+
}
|
| 9 |
+
html { font-size: 100%; }
|
| 10 |
+
body {
|
| 11 |
+
font-family: 'Inter', sans-serif;
|
| 12 |
+
background: #000;
|
| 13 |
+
color: #fff;
|
| 14 |
+
min-height: 100vh;
|
| 15 |
+
display: flex;
|
| 16 |
+
align-items: center;
|
| 17 |
+
justify-content: center;
|
| 18 |
+
padding: 1rem;
|
| 19 |
+
background-image:
|
| 20 |
+
radial-gradient(circle at 10% 20%, rgba(255,255,255,.03) 0%, transparent 20%),
|
| 21 |
+
radial-gradient(circle at 90% 80%, rgba(255,255,255,.03) 0%, transparent 20%);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
/* ==== CONTAINER ==== */
|
| 25 |
+
/* ==== CONTAINER ==== */
|
| 26 |
+
.container {
|
| 27 |
+
width: 100%;
|
| 28 |
+
max-width: 780px;
|
| 29 |
+
margin: 0 auto;
|
| 30 |
+
background: rgba(255, 255, 255, 0.06);
|
| 31 |
+
backdrop-filter: blur(12px);
|
| 32 |
+
-webkit-backdrop-filter: blur(12px);
|
| 33 |
+
border-radius: 1.5rem;
|
| 34 |
+
box-shadow: 0 8px 32px rgba(0,0,0,.4);
|
| 35 |
+
overflow: hidden;
|
| 36 |
+
display: flex;
|
| 37 |
+
flex-direction: column;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/* ==== HEADER ==== */
|
| 41 |
+
.header {
|
| 42 |
+
text-align: center;
|
| 43 |
+
padding: 1.8rem 1.2rem 1rem;
|
| 44 |
+
border-bottom: 1px solid rgba(255,255,255,.08);
|
| 45 |
+
}
|
| 46 |
+
.header h1 {
|
| 47 |
+
font-size: 1.75rem;
|
| 48 |
+
font-weight: 700;
|
| 49 |
+
display: flex;
|
| 50 |
+
align-items: center;
|
| 51 |
+
justify-content: center;
|
| 52 |
+
gap: .5rem;
|
| 53 |
+
}
|
| 54 |
+
.header .subtitle {
|
| 55 |
+
margin-top: .4rem;
|
| 56 |
+
font-size: .95rem;
|
| 57 |
+
opacity: .75;
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
/* ==== UPLOAD SECTION ==== */
|
| 61 |
+
.upload-section {
|
| 62 |
+
padding: 1.5rem 1.2rem;
|
| 63 |
+
display: flex;
|
| 64 |
+
flex-direction: column;
|
| 65 |
+
gap: .75rem;
|
| 66 |
+
align-items: center;
|
| 67 |
+
}
|
| 68 |
+
.file-label {
|
| 69 |
+
cursor: pointer;
|
| 70 |
+
background: rgba(255,255,255,.08);
|
| 71 |
+
border: 1px dashed rgba(255,255,255,.2);
|
| 72 |
+
border-radius: .75rem;
|
| 73 |
+
padding: .75rem 1.2rem;
|
| 74 |
+
font-size: .95rem;
|
| 75 |
+
transition: all .2s ease;
|
| 76 |
+
display: flex;
|
| 77 |
+
align-items: center;
|
| 78 |
+
gap: .5rem;
|
| 79 |
+
}
|
| 80 |
+
.file-label:hover { background: rgba(255,255,255,.12); }
|
| 81 |
+
#uploadBtn {
|
| 82 |
+
margin-top: .5rem;
|
| 83 |
+
}
|
| 84 |
+
.status {
|
| 85 |
+
min-height: 1.4rem;
|
| 86 |
+
font-size: .85rem;
|
| 87 |
+
text-align: center;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* ==== BUTTONS ==== */
|
| 91 |
+
.btn {
|
| 92 |
+
cursor: pointer;
|
| 93 |
+
font-weight: 600;
|
| 94 |
+
border: none;
|
| 95 |
+
border-radius: .6rem;
|
| 96 |
+
padding: .55rem 1rem;
|
| 97 |
+
font-size: .95rem;
|
| 98 |
+
transition: all .2s ease;
|
| 99 |
+
display: inline-flex;
|
| 100 |
+
align-items: center;
|
| 101 |
+
gap: .4rem;
|
| 102 |
+
}
|
| 103 |
+
.btn-primary {
|
| 104 |
+
background: #fff;
|
| 105 |
+
color: #000;
|
| 106 |
+
}
|
| 107 |
+
.btn-primary:hover { background: #f0f0f0; transform: translateY(-1px); }
|
| 108 |
+
.btn-send {
|
| 109 |
+
background: transparent;
|
| 110 |
+
color: #fff;
|
| 111 |
+
font-size: 1.1rem;
|
| 112 |
+
}
|
| 113 |
+
.btn-send:hover { color: #ccc; }
|
| 114 |
+
|
| 115 |
+
/* ==== CHAT SECTION ==== */
|
| 116 |
+
.chat-section {
|
| 117 |
+
flex: 1;
|
| 118 |
+
display: flex;
|
| 119 |
+
flex-direction: column;
|
| 120 |
+
padding: 0 1.2rem 1.2rem;
|
| 121 |
+
}
|
| 122 |
+
.chat-box {
|
| 123 |
+
flex: 1;
|
| 124 |
+
overflow-y: auto;
|
| 125 |
+
padding: .5rem 0;
|
| 126 |
+
display: flex;
|
| 127 |
+
flex-direction: column;
|
| 128 |
+
gap: .75rem;
|
| 129 |
+
max-height: 55vh;
|
| 130 |
+
}
|
| 131 |
+
.chat-box::-webkit-scrollbar { width: 6px; }
|
| 132 |
+
.chat-box::-webkit-scrollbar-thumb {
|
| 133 |
+
background: rgba(255,255,255,.2);
|
| 134 |
+
border-radius: 3px;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
/* ==== MESSAGES ==== */
|
| 138 |
+
.message {
|
| 139 |
+
max-width: 86%;
|
| 140 |
+
padding: .85rem 1.1rem;
|
| 141 |
+
border-radius: 1.1rem;
|
| 142 |
+
line-height: 1.5;
|
| 143 |
+
font-size: .95rem;
|
| 144 |
+
word-wrap: break-word;
|
| 145 |
+
animation: fadeIn .25s ease-out;
|
| 146 |
+
}
|
| 147 |
+
.message.user {
|
| 148 |
+
align-self: flex-end;
|
| 149 |
+
background: #fff;
|
| 150 |
+
color: #000;
|
| 151 |
+
border-bottom-right-radius: .35rem;
|
| 152 |
+
}
|
| 153 |
+
.message.bot {
|
| 154 |
+
align-self: flex-start;
|
| 155 |
+
background: rgba(255,255,255,.09);
|
| 156 |
+
color: #eee;
|
| 157 |
+
border-bottom-left-radius: .35rem;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
/* ==== MARKDOWN STYLES (inside bot) ==== */
|
| 161 |
+
.message.bot h1,
|
| 162 |
+
.message.bot h2,
|
| 163 |
+
.message.bot h3 {
|
| 164 |
+
color: #fff;
|
| 165 |
+
margin: .6rem 0 .4rem;
|
| 166 |
+
font-weight: 600;
|
| 167 |
+
}
|
| 168 |
+
.message.bot h1 { font-size: 1.35rem; }
|
| 169 |
+
.message.bot h2 { font-size: 1.2rem; }
|
| 170 |
+
.message.bot h3 { font-size: 1.05rem; }
|
| 171 |
+
|
| 172 |
+
.message.bot pre {
|
| 173 |
+
background: #111;
|
| 174 |
+
color: #f1f1f1;
|
| 175 |
+
padding: .85rem;
|
| 176 |
+
border-radius: .6rem;
|
| 177 |
+
margin: .6rem 0;
|
| 178 |
+
overflow-x: auto;
|
| 179 |
+
font-size: .85rem;
|
| 180 |
+
}
|
| 181 |
+
.message.bot code {
|
| 182 |
+
background: rgba(255,255,255,.12);
|
| 183 |
+
color: #fff;
|
| 184 |
+
padding: .15rem .4rem;
|
| 185 |
+
border-radius: .35rem;
|
| 186 |
+
font-family: 'Fira Mono', Consolas, monospace;
|
| 187 |
+
}
|
| 188 |
+
.message.bot table {
|
| 189 |
+
width: 100%;
|
| 190 |
+
border-collapse: collapse;
|
| 191 |
+
margin: .8rem 0;
|
| 192 |
+
font-size: .88rem;
|
| 193 |
+
}
|
| 194 |
+
.message.bot th,
|
| 195 |
+
.message.bot td {
|
| 196 |
+
border: 1px solid rgba(255,255,255,.15);
|
| 197 |
+
padding: .55rem .75rem;
|
| 198 |
+
text-align: left;
|
| 199 |
+
}
|
| 200 |
+
.message.bot th {
|
| 201 |
+
background: rgba(255,255,255,.1);
|
| 202 |
+
font-weight: 600;
|
| 203 |
+
}
|
| 204 |
+
.message.bot tr:nth-child(even) td { background: rgba(255,255,255,.03); }
|
| 205 |
+
|
| 206 |
+
/* ==== INPUT AREA ==== */
|
| 207 |
+
.input-area {
|
| 208 |
+
display: flex;
|
| 209 |
+
gap: .5rem;
|
| 210 |
+
margin-top: .75rem;
|
| 211 |
+
padding-top: .75rem;
|
| 212 |
+
border-top: 1px solid rgba(255,255,255,.08);
|
| 213 |
+
}
|
| 214 |
+
#userInput {
|
| 215 |
+
flex: 1;
|
| 216 |
+
background: rgba(255,255,255,.08);
|
| 217 |
+
border: none;
|
| 218 |
+
border-radius: .75rem;
|
| 219 |
+
padding: .75rem 1rem;
|
| 220 |
+
color: #fff;
|
| 221 |
+
font-size: .95rem;
|
| 222 |
+
outline: none;
|
| 223 |
+
transition: background .2s;
|
| 224 |
+
}
|
| 225 |
+
#userInput::placeholder { color: rgba(255,255,255,.5); }
|
| 226 |
+
#userInput:focus { background: rgba(255,255,255,.14); }
|
| 227 |
+
|
| 228 |
+
/* ==== ANIMATIONS ==== */
|
| 229 |
+
@keyframes fadeIn {
|
| 230 |
+
from { opacity: 0; transform: translateY(8px); }
|
| 231 |
+
to { opacity: 1; transform: none; }
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
/* ==== RESPONSIVE ==== */
|
| 235 |
+
@media (max-width: 480px) {
|
| 236 |
+
.container { border-radius: 1rem; }
|
| 237 |
+
.header h1 { font-size: 1.5rem; }
|
| 238 |
+
.message { font-size: .9rem; }
|
| 239 |
+
}
|
notebook/document.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebook/document.py
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
# coding: utf-8
|
| 3 |
+
|
| 4 |
+
# In[1]:
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
from langchain_core.documents import Document
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
# In[6]:
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
doc = Document(
|
| 14 |
+
page_content="Hii here theh rag_demo working...........",
|
| 15 |
+
metadata= {
|
| 16 |
+
"source" : "web",
|
| 17 |
+
"pages" : 1,
|
| 18 |
+
"data of created" : "2026-10-30",
|
| 19 |
+
"Author" : "MaskMan"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
)
|
| 24 |
+
doc
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
# In[7]:
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
import os
|
| 31 |
+
|
| 32 |
+
os.makedirs("../data/text_files", exist_ok=True)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# In[37]:
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
sample_texts= {
|
| 39 |
+
"../data/text_files/python_intro.txt" : """Python is a high-level, interpreted, general-purpose programming language. Created by Guido van Rossum and first released in 1991, it is known for its emphasis on code readability and its use of significant indentation. The name "Python" was inspired by the British comedy series Monty Python's Flying Circus.
|
| 40 |
+
Key Characteristics and Features:
|
| 41 |
+
Readability: Python's syntax is designed to be clear and concise, often described as English-like, making it easier to learn and understand compared to many other languages.
|
| 42 |
+
Interpreted: Python code does not need to be compiled before execution. An interpreter runs the code directly, allowing for rapid development and testing.
|
| 43 |
+
Dynamically Typed: Variable types are determined at runtime, meaning you don't need to explicitly declare the type of a variable when you create it.
|
| 44 |
+
High-Level Language: Python abstracts away many low-level details of computer hardware, allowing developers to focus on higher-level problem-solving.
|
| 45 |
+
Multiple Programming Paradigms: It supports various programming styles, including object-oriented, imperative, and functional programming.
|
| 46 |
+
Extensive Standard Library: Python comes with a large collection of modules and packages that provide pre-written code for a wide range of tasks, reducing the need to write everything from scratch.
|
| 47 |
+
Cross-Platform Compatibility: Python can run on various operating systems, including Windows, macOS, and Linux, without requiring significant code changes.
|
| 48 |
+
Free and Open-Source: Python is freely available for use and distribution, and its source code is open for modification and improvement by a global community.
|
| 49 |
+
Common Applications:
|
| 50 |
+
Python is widely used in diverse fields, including:
|
| 51 |
+
Web Development: Frameworks like Django and Flask facilitate building web applications.
|
| 52 |
+
Data Science and Machine Learning: Libraries such as NumPy, Pandas, Scikit-learn, TensorFlow, and PyTorch are essential for data analysis, visualization, and building machine learning models.
|
| 53 |
+
Automation and Scripting: Its simplicity makes it ideal for automating repetitive tasks and system administration.
|
| 54 |
+
Software Development: Used for building desktop applications and integrating with other systems.
|
| 55 |
+
Artificial Intelligence: A popular choice for developing AI algorithms and applications."""
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
for path, content in sample_texts.items():
|
| 61 |
+
with open(path, 'w', encoding="utf-8") as f:
|
| 62 |
+
f.write(content)
|
| 63 |
+
print("txt created sucessfully......!")
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
# In[ ]:
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
sample_texts= {
|
| 71 |
+
"../data/text_files/rag_introtxt" : """Retrieval-Augmented Generation (RAG) is an artificial intelligence (AI) framework that improves large language models (LLMs) by giving them access to up-to-date, external data sources. This process makes LLM-generated responses more accurate, context-specific, and reliable than those produced by the model's original, static training data alone.
|
| 72 |
+
How RAG works
|
| 73 |
+
A RAG system follows a series of steps to generate a response for a user query:
|
| 74 |
+
Ingestion: A knowledge base, which can contain a variety of data types like PDFs, databases, and websites, is created. An embedding model converts this data into numerical representations, called vectors, and stores them in a vector database.
|
| 75 |
+
Retrieval: When a user submits a query, the system uses a retriever model to search the vector database for the most relevant information.
|
| 76 |
+
Augmentation: The retrieved, contextual information is added to the user's original query to create an enhanced prompt.
|
| 77 |
+
Generation: The augmented prompt is sent to the large language model, which uses both its initial training data and the newly retrieved information to create a final, well-grounded response.
|
| 78 |
+
Key benefits of using RAG
|
| 79 |
+
Reduces "hallucinations": Since RAG grounds responses in factual, external data, it significantly lowers the risk of the LLM presenting false or nonsensical information.
|
| 80 |
+
Provides up-to-date information: RAG systems can be updated continuously with fresh information without the need for expensive and time-consuming model retraining.
|
| 81 |
+
Adds domain-specific knowledge: Companies can connect LLMs to their own internal documents, product manuals, or policies, enabling them to produce more specialized and relevant answers.
|
| 82 |
+
Builds user trust: RAG allows the model to cite its sources, giving users the ability to verify the information for themselves.
|
| 83 |
+
Increases cost efficiency: Organizations can improve the performance of a foundational model for specific tasks by using RAG, which is far less expensive than fine-tuning or retraining the entire LLM.
|
| 84 |
+
Common RAG applications
|
| 85 |
+
Customer service chatbots: A chatbot can provide specific, up-to-date information by referencing a company's internal knowledge base and product manuals.
|
| 86 |
+
Research assistants: RAG can help financial analysts, medical professionals, and other researchers quickly access and synthesize information from vast databases of records, journals, and reports.
|
| 87 |
+
Internal knowledge management: Employees can query an organization's documents using conversational language to find actionable insights, streamline onboarding, or get HR support.
|
| 88 |
+
Content generation: The technology can be used to gather information from multiple authoritative sources and generate more reliable articles or summaries.
|
| 89 |
+
"""
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
for path, content in sample_texts.items():
|
| 95 |
+
with open(path, 'w', encoding="utf-8") as f:
|
| 96 |
+
f.write(content)
|
| 97 |
+
print("txt created sucessfully......!")
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# In[8]:
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
from langchain_community.document_loaders import TextLoader
|
| 105 |
+
|
| 106 |
+
loader = TextLoader("../data/text_files/python_intro.txt", encoding="utf-8")
|
| 107 |
+
|
| 108 |
+
document = loader.load()
|
| 109 |
+
print(document)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# In[9]:
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
from langchain_community.document_loaders import DirectoryLoader
|
| 116 |
+
|
| 117 |
+
dir_loader = DirectoryLoader(
|
| 118 |
+
"../data/text_files",
|
| 119 |
+
glob="**/*.txt",
|
| 120 |
+
loader_cls=TextLoader,
|
| 121 |
+
show_progress=False
|
| 122 |
+
|
| 123 |
+
)
|
| 124 |
+
documents = dir_loader.load()
|
| 125 |
+
documents
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
# In[10]:
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
from langchain_community.document_loaders import PyPDFLoader, PyMuPDFLoader
|
| 132 |
+
|
| 133 |
+
my_dir = DirectoryLoader(
|
| 134 |
+
"../data/pdf",
|
| 135 |
+
glob="**/*.pdf",
|
| 136 |
+
loader_cls= PyMuPDFLoader,
|
| 137 |
+
show_progress= False
|
| 138 |
+
|
| 139 |
+
)
|
| 140 |
+
dir_documents = my_dir.load()
|
| 141 |
+
dir_documents
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
# In[12]:
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
type(dir_documents[0])
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
# ### Embedding Part
|
| 151 |
+
#
|
| 152 |
+
|
| 153 |
+
# In[17]:
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
import numpy as np
|
| 157 |
+
from sentence_transformers import SentenceTransformer
|
| 158 |
+
import chromadb
|
| 159 |
+
from chromadb.config import Settings
|
| 160 |
+
import uuid
|
| 161 |
+
from typing import List, Any, Tuple, Dict
|
| 162 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
# In[24]:
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
class EmbeddingManager:
|
| 170 |
+
def __init__(self, model_name : str = "all-MiniLM-L6-v2"):
|
| 171 |
+
self.model_name = model_name
|
| 172 |
+
self.model = None
|
| 173 |
+
self._load_model()
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def _load_model(self):
|
| 177 |
+
try:
|
| 178 |
+
print(f"Loading embedding model: {self.model_name}")
|
| 179 |
+
self.model = SentenceTransformer(self.model_name)
|
| 180 |
+
print(f"model loaded Sucessfully. Embedding dimension.{self.model.get_sentence_embedding_dimension()}")
|
| 181 |
+
except Exception as e:
|
| 182 |
+
print(f"Error loading model {self.model_name}: {e}")
|
| 183 |
+
raise
|
| 184 |
+
def generate_embeddings(self, texts: List[str]) -> np.ndarray:
|
| 185 |
+
if not self.model:
|
| 186 |
+
raise ValueError("Model not loaded")
|
| 187 |
+
|
| 188 |
+
print(f"Generating embeddings for {len(texts)} texts...")
|
| 189 |
+
embeddings = self.model.encode(texts, show_progress_bar=True)
|
| 190 |
+
print(f"Generated embeddings with shape: {embeddings.shape}")
|
| 191 |
+
return embeddings
|
| 192 |
+
|
| 193 |
+
embedding_manager=EmbeddingManager()
|
| 194 |
+
embedding_manager
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
# In[28]:
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
import os
|
| 204 |
+
class VectorStore:
|
| 205 |
+
"""Manages document embeddings in a ChromaDB vector store"""
|
| 206 |
+
|
| 207 |
+
def __init__(self, collection_name: str = "pdf_documents", persist_directory: str = "../data/vector_store"):
|
| 208 |
+
"""
|
| 209 |
+
Initialize the vector store
|
| 210 |
+
|
| 211 |
+
Args:
|
| 212 |
+
collection_name: Name of the ChromaDB collection
|
| 213 |
+
persist_directory: Directory to persist the vector store
|
| 214 |
+
"""
|
| 215 |
+
self.collection_name = collection_name
|
| 216 |
+
self.persist_directory = persist_directory
|
| 217 |
+
self.client = None
|
| 218 |
+
self.collection = None
|
| 219 |
+
self._initialize_store()
|
| 220 |
+
|
| 221 |
+
def _initialize_store(self):
|
| 222 |
+
"""Initialize ChromaDB client and collection"""
|
| 223 |
+
try:
|
| 224 |
+
# Create persistent ChromaDB client
|
| 225 |
+
os.makedirs(self.persist_directory, exist_ok=True)
|
| 226 |
+
self.client = chromadb.PersistentClient(path=self.persist_directory)
|
| 227 |
+
|
| 228 |
+
# Get or create collection
|
| 229 |
+
self.collection = self.client.get_or_create_collection(
|
| 230 |
+
name=self.collection_name,
|
| 231 |
+
metadata={"description": "PDF document embeddings for RAG"}
|
| 232 |
+
)
|
| 233 |
+
print(f"Vector store initialized. Collection: {self.collection_name}")
|
| 234 |
+
print(f"Existing documents in collection: {self.collection.count()}")
|
| 235 |
+
|
| 236 |
+
except Exception as e:
|
| 237 |
+
print(f"Error initializing vector store: {e}")
|
| 238 |
+
raise
|
| 239 |
+
|
| 240 |
+
def add_documents(self, documents: List[Any], embeddings: np.ndarray):
|
| 241 |
+
"""
|
| 242 |
+
Add documents and their embeddings to the vector store
|
| 243 |
+
|
| 244 |
+
Args:
|
| 245 |
+
documents: List of LangChain documents
|
| 246 |
+
embeddings: Corresponding embeddings for the documents
|
| 247 |
+
"""
|
| 248 |
+
if len(documents) != len(embeddings):
|
| 249 |
+
raise ValueError("Number of documents must match number of embeddings")
|
| 250 |
+
|
| 251 |
+
print(f"Adding {len(documents)} documents to vector store...")
|
| 252 |
+
|
| 253 |
+
# Prepare data for ChromaDB
|
| 254 |
+
ids = []
|
| 255 |
+
metadatas = []
|
| 256 |
+
documents_text = []
|
| 257 |
+
embeddings_list = []
|
| 258 |
+
|
| 259 |
+
for i, (doc, embedding) in enumerate(zip(documents, embeddings)):
|
| 260 |
+
# Generate unique ID
|
| 261 |
+
doc_id = f"doc_{uuid.uuid4().hex[:8]}_{i}"
|
| 262 |
+
ids.append(doc_id)
|
| 263 |
+
|
| 264 |
+
# Prepare metadata
|
| 265 |
+
metadata = dict(doc.metadata)
|
| 266 |
+
metadata['doc_index'] = i
|
| 267 |
+
metadata['content_length'] = len(doc.page_content)
|
| 268 |
+
metadatas.append(metadata)
|
| 269 |
+
|
| 270 |
+
# Document content
|
| 271 |
+
documents_text.append(doc.page_content)
|
| 272 |
+
|
| 273 |
+
# Embedding
|
| 274 |
+
embeddings_list.append(embedding.tolist())
|
| 275 |
+
|
| 276 |
+
# Add to collection
|
| 277 |
+
try:
|
| 278 |
+
self.collection.add(
|
| 279 |
+
ids=ids,
|
| 280 |
+
embeddings=embeddings_list,
|
| 281 |
+
metadatas=metadatas,
|
| 282 |
+
documents=documents_text
|
| 283 |
+
)
|
| 284 |
+
print(f"Successfully added {len(documents)} documents to vector store")
|
| 285 |
+
print(f"Total documents in collection: {self.collection.count()}")
|
| 286 |
+
|
| 287 |
+
except Exception as e:
|
| 288 |
+
print(f"Error adding documents to vector store: {e}")
|
| 289 |
+
raise
|
| 290 |
+
|
| 291 |
+
vectorstore=VectorStore()
|
| 292 |
+
vectorstore
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
# In[ ]:
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
|
notebook/document_2.ipynb
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 9,
|
| 6 |
+
"id": "4806dd83",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [],
|
| 9 |
+
"source": [
|
| 10 |
+
"# backend/embeddings.py\n",
|
| 11 |
+
"from sentence_transformers import SentenceTransformer\n",
|
| 12 |
+
"import numpy as np\n",
|
| 13 |
+
"\n",
|
| 14 |
+
"class EmbeddingManager:\n",
|
| 15 |
+
" def __init__(self, model_name=\"all-MiniLM-L6-v2\"):\n",
|
| 16 |
+
" self.model = SentenceTransformer(model_name)\n",
|
| 17 |
+
" print(f\"✅ Loaded embedding model: {model_name}\")\n",
|
| 18 |
+
"\n",
|
| 19 |
+
" def generate_embeddings(self, texts):\n",
|
| 20 |
+
" \"\"\"Generate embeddings for a list of text chunks\"\"\"\n",
|
| 21 |
+
" return np.array(self.model.encode(texts, show_progress_bar=True))\n"
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"cell_type": "code",
|
| 26 |
+
"execution_count": 10,
|
| 27 |
+
"id": "f6db2d1b",
|
| 28 |
+
"metadata": {},
|
| 29 |
+
"outputs": [],
|
| 30 |
+
"source": [
|
| 31 |
+
"# backend/store.py\n",
|
| 32 |
+
"import os\n",
|
| 33 |
+
"import chromadb\n",
|
| 34 |
+
"from chromadb.config import Settings\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"class VectorStore:\n",
|
| 37 |
+
" def __init__(self, path=\"../data/vector_store\"):\n",
|
| 38 |
+
" self.client = chromadb.PersistentClient(path=path, settings=Settings(anonymized_telemetry=False))\n",
|
| 39 |
+
" self.collection = self.client.get_or_create_collection(name=\"ece_concepts\")\n",
|
| 40 |
+
" print(f\"✅ Vector store initialized at {path}\")\n",
|
| 41 |
+
"\n",
|
| 42 |
+
" def add_documents(self, docs, embeddings):\n",
|
| 43 |
+
" \"\"\"Store docs with embeddings\"\"\"\n",
|
| 44 |
+
" ids = [str(i) for i in range(len(docs))]\n",
|
| 45 |
+
" self.collection.add(documents=docs, embeddings=embeddings.tolist(), ids=ids)\n",
|
| 46 |
+
" print(f\"🧠 Stored {len(docs)} chunks in vector DB.\")\n",
|
| 47 |
+
"\n",
|
| 48 |
+
" def retrieve_similar_docs(self, query_embedding, top_k=3):\n",
|
| 49 |
+
" \"\"\"Retrieve top-k relevant chunks\"\"\"\n",
|
| 50 |
+
" results = self.collection.query(query_embeddings=[query_embedding.tolist()], n_results=top_k)\n",
|
| 51 |
+
" docs = results[\"documents\"][0]\n",
|
| 52 |
+
" return docs\n"
|
| 53 |
+
]
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"cell_type": "code",
|
| 57 |
+
"execution_count": null,
|
| 58 |
+
"id": "19755831",
|
| 59 |
+
"metadata": {},
|
| 60 |
+
"outputs": [
|
| 61 |
+
{
|
| 62 |
+
"ename": "ModuleNotFoundError",
|
| 63 |
+
"evalue": "No module named 'langchain_ollama'",
|
| 64 |
+
"output_type": "error",
|
| 65 |
+
"traceback": [
|
| 66 |
+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 67 |
+
"\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
|
| 68 |
+
"Cell \u001b[0;32mIn[11], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# backend/rag_app.py\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mlangchain_ollama\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m OllamaLLM\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01membeddings\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m EmbeddingManager\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mstore\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m VectorStore\n",
|
| 69 |
+
"\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'langchain_ollama'"
|
| 70 |
+
]
|
| 71 |
+
}
|
| 72 |
+
],
|
| 73 |
+
"source": [
|
| 74 |
+
"# backend/rag_app.py\n",
|
| 75 |
+
"import os\n",
|
| 76 |
+
"from openai import OpenAI\n",
|
| 77 |
+
"from embeddings import EmbeddingManager\n",
|
| 78 |
+
"from store import VectorStore\n",
|
| 79 |
+
"\n",
|
| 80 |
+
"class RAGApp:\n",
|
| 81 |
+
" def __init__(self):\n",
|
| 82 |
+
" self.embedder = EmbeddingManager()\n",
|
| 83 |
+
" self.vectorstore = VectorStore()\n",
|
| 84 |
+
" # Load your key securely (from env variable)\n",
|
| 85 |
+
" self.client = OpenAI(api_key=os.getenv(\"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\"))\n",
|
| 86 |
+
"\n",
|
| 87 |
+
" def add_notes(self, text):\n",
|
| 88 |
+
" chunks = [text[i:i+1000] for i in range(0, len(text), 800)]\n",
|
| 89 |
+
" embeddings = self.embedder.generate_embeddings(chunks)\n",
|
| 90 |
+
" self.vectorstore.add_documents(chunks, embeddings)\n",
|
| 91 |
+
" return len(chunks)\n",
|
| 92 |
+
"\n",
|
| 93 |
+
" def ask(self, query):\n",
|
| 94 |
+
" q_embed = self.embedder.generate_embeddings([query])[0]\n",
|
| 95 |
+
" docs = self.vectorstore.retrieve_similar_docs(q_embed, top_k=3)\n",
|
| 96 |
+
" context = \"\\n\\n\".join(docs)\n",
|
| 97 |
+
" prompt = f\"Use the following context to answer:\\n{context}\\n\\nQuestion: {query}\\nAnswer:\"\n",
|
| 98 |
+
"\n",
|
| 99 |
+
" # Call OpenAI-compatible API\n",
|
| 100 |
+
" response = self.client.chat.completions.create(\n",
|
| 101 |
+
" model=\"gpt-oss-20b\", # your model name\n",
|
| 102 |
+
" messages=[\n",
|
| 103 |
+
" {\"role\": \"system\", \"content\": \"You are an AI tutor specialized in ECE concepts.\"},\n",
|
| 104 |
+
" {\"role\": \"user\", \"content\": prompt},\n",
|
| 105 |
+
" ],\n",
|
| 106 |
+
" )\n",
|
| 107 |
+
" return response.choices[0].message.content\n"
|
| 108 |
+
]
|
| 109 |
+
}
|
| 110 |
+
],
|
| 111 |
+
"metadata": {
|
| 112 |
+
"kernelspec": {
|
| 113 |
+
"display_name": "rag_demo",
|
| 114 |
+
"language": "python",
|
| 115 |
+
"name": "python3"
|
| 116 |
+
},
|
| 117 |
+
"language_info": {
|
| 118 |
+
"codemirror_mode": {
|
| 119 |
+
"name": "ipython",
|
| 120 |
+
"version": 3
|
| 121 |
+
},
|
| 122 |
+
"file_extension": ".py",
|
| 123 |
+
"mimetype": "text/x-python",
|
| 124 |
+
"name": "python",
|
| 125 |
+
"nbconvert_exporter": "python",
|
| 126 |
+
"pygments_lexer": "ipython3",
|
| 127 |
+
"version": "3.10.12"
|
| 128 |
+
}
|
| 129 |
+
},
|
| 130 |
+
"nbformat": 4,
|
| 131 |
+
"nbformat_minor": 5
|
| 132 |
+
}
|
pyproject.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "rag-demo"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "Add your description here"
|
| 5 |
+
readme = "README.md"
|
| 6 |
+
requires-python = ">=3.10"
|
| 7 |
+
dependencies = [
|
| 8 |
+
"chromadb>=1.3.0",
|
| 9 |
+
"faiss-cpu>=1.12.0",
|
| 10 |
+
"fastapi>=0.120.3",
|
| 11 |
+
"ipykernel>=7.1.0",
|
| 12 |
+
"langchain>=1.0.3",
|
| 13 |
+
"langchain-community>=0.4.1",
|
| 14 |
+
"langchain-core>=1.0.2",
|
| 15 |
+
"openai>=2.6.1",
|
| 16 |
+
"pymupdf>=1.26.5",
|
| 17 |
+
"pypdf>=6.1.3",
|
| 18 |
+
"sentence-transformers>=5.1.2",
|
| 19 |
+
"uvicorn>=0.38.0",
|
| 20 |
+
]
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|