Pranil Bankar commited on
Commit Β·
4d67ec7
1
Parent(s): e7be528
Deploy Application
Browse filesThis view is limited to 50 files because it contains too many changes. Β See raw diff
- .dockerignore +7 -0
- .gitattributes +1 -34
- .gitignore +2 -2
- .python-version +1 -0
- Backend/__init__.py +1 -0
- Backend/main.py +122 -0
- Backend/routers/__init__.py +1 -0
- Backend/routers/qa.py +194 -0
- Backend/schemas.py +143 -0
- Classification/Evaluation_metrics/eval_accuracy_f1.png +3 -0
- Classification/Evaluation_metrics/eval_metrics.json +9 -0
- Classification/Evaluation_metrics/learning_rate_schedule.png +3 -0
- Classification/Evaluation_metrics/training_dashboard.png +3 -0
- Classification/Evaluation_metrics/training_log.json +1065 -0
- Classification/Evaluation_metrics/training_loss_curve.png +3 -0
- Classification/__init__.py +1 -0
- Classification/checkpoints/best_model/config.json +93 -0
- Classification/checkpoints/best_model/model.safetensors +3 -0
- Classification/checkpoints/best_model/special_tokens_map.json +7 -0
- Classification/checkpoints/best_model/tokenizer.json +0 -0
- Classification/checkpoints/best_model/tokenizer_config.json +55 -0
- Classification/checkpoints/best_model/training_args.bin +0 -0
- Classification/checkpoints/best_model/vocab.txt +0 -0
- Classification/classify_and_extract.py +214 -0
- Classification/config.json +19 -0
- Classification/data/label_map.json +33 -0
- Classification/data/new_generated_questions.json +402 -0
- Classification/data/sample_questions.json +32 -0
- Classification/data/train_split.json +0 -0
- Classification/data/val_split.json +0 -0
- Classification/dataset.py +109 -0
- Classification/dataset_multilabel.py +59 -0
- Classification/predict.py +171 -0
- Classification/predict_multilabel.py +73 -0
- Classification/train.py +177 -0
- Classification/train_multilabel.py +132 -0
- DEPLOYMENT.md +145 -0
- Dockerfile +21 -0
- Frontend/app.js +432 -0
- Frontend/index.html +159 -0
- Frontend/styles.css +723 -0
- Procfile +1 -0
- README.md +213 -9
- pdf_to_embedding/.env.example +10 -0
- pdf_to_embedding/clean_pdf_to_json.py +234 -0
- pdf_to_embedding/embed_and_upload.py +103 -0
- pdf_to_embedding/json_ouput/11th Ncert output/Kebo101.json +119 -0
- pdf_to_embedding/json_ouput/11th Ncert output/Kebo102.json +137 -0
- pdf_to_embedding/json_ouput/11th Ncert output/Kebo103.json +138 -0
- pdf_to_embedding/json_ouput/11th Ncert output/Kebo104.json +174 -0
.dockerignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
.git/
|
| 5 |
+
Frontend/
|
| 6 |
+
pdf_to_embedding/*.pdf
|
| 7 |
+
.env
|
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
.venv
|
| 2 |
-
.env
|
| 3 |
__pycache__
|
| 4 |
*.pyc
|
| 5 |
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
*.env
|
| 3 |
__pycache__
|
| 4 |
*.pyc
|
| 5 |
|
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.11
|
Backend/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Backend package
|
Backend/main.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
main.py β FastAPI application entry point for the NEET Biology Q&A system
|
| 3 |
+
|
| 4 |
+
Run:
|
| 5 |
+
uvicorn Backend.main:app --reload --port 8000
|
| 6 |
+
|
| 7 |
+
Docs:
|
| 8 |
+
http://localhost:8000/docs (Swagger UI)
|
| 9 |
+
http://localhost:8000/redoc (ReDoc)
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import time
|
| 13 |
+
from contextlib import asynccontextmanager
|
| 14 |
+
|
| 15 |
+
from fastapi import FastAPI
|
| 16 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 17 |
+
|
| 18 |
+
from Backend.schemas import HealthResponse
|
| 19 |
+
from Backend.routers.qa import router as qa_router
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
# ==============================
|
| 23 |
+
# STARTUP / SHUTDOWN
|
| 24 |
+
# ==============================
|
| 25 |
+
@asynccontextmanager
|
| 26 |
+
async def lifespan(app: FastAPI):
|
| 27 |
+
"""
|
| 28 |
+
Pre-load heavy models at startup so the first request is fast.
|
| 29 |
+
"""
|
| 30 |
+
print("\nπ Starting NEET Biology Q&A Backend...")
|
| 31 |
+
start = time.time()
|
| 32 |
+
|
| 33 |
+
# Pre-load BERT classifier (singleton)
|
| 34 |
+
from Classification.classify_and_extract import get_predictor
|
| 35 |
+
get_predictor()
|
| 36 |
+
|
| 37 |
+
# Pre-load embedding model (singleton)
|
| 38 |
+
from rag.retriever import get_embedding_model
|
| 39 |
+
get_embedding_model()
|
| 40 |
+
|
| 41 |
+
elapsed = time.time() - start
|
| 42 |
+
print(f"β
All models loaded in {elapsed:.1f}s β server ready!\n")
|
| 43 |
+
|
| 44 |
+
yield # App runs here
|
| 45 |
+
|
| 46 |
+
print("\nπ Shutting down NEET Biology Q&A Backend.")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# ==============================
|
| 50 |
+
# APP INSTANCE
|
| 51 |
+
# ==============================
|
| 52 |
+
app = FastAPI(
|
| 53 |
+
title="NEET Biology Q&A API",
|
| 54 |
+
description=(
|
| 55 |
+
"AI-powered Question Answering system for NEET Biology. "
|
| 56 |
+
"Uses BERT classification for chapter detection and a "
|
| 57 |
+
"RAG pipeline with NCERT textbook context for accurate answers."
|
| 58 |
+
),
|
| 59 |
+
version="1.0.0",
|
| 60 |
+
lifespan=lifespan,
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# ==============================
|
| 65 |
+
# CORS β Allow frontend access
|
| 66 |
+
# ==============================
|
| 67 |
+
app.add_middleware(
|
| 68 |
+
CORSMiddleware,
|
| 69 |
+
allow_origins=[
|
| 70 |
+
"http://localhost:3000", # React/Next.js dev
|
| 71 |
+
"http://localhost:5173", # Vite dev
|
| 72 |
+
"http://localhost:5500", # Live Server
|
| 73 |
+
"http://127.0.0.1:5500",
|
| 74 |
+
"*", # Allow all for development
|
| 75 |
+
],
|
| 76 |
+
allow_credentials=True,
|
| 77 |
+
allow_methods=["*"],
|
| 78 |
+
allow_headers=["*"],
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
# ==============================
|
| 83 |
+
# ROUTES
|
| 84 |
+
# ==============================
|
| 85 |
+
app.include_router(qa_router)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
@app.get(
|
| 89 |
+
"/health",
|
| 90 |
+
response_model=HealthResponse,
|
| 91 |
+
tags=["System"],
|
| 92 |
+
summary="Health check",
|
| 93 |
+
)
|
| 94 |
+
async def health_check():
|
| 95 |
+
"""Check if the server and all components are running."""
|
| 96 |
+
from Classification.classify_and_extract import _predictor
|
| 97 |
+
from rag.retriever import _embedding_model, _supabase_client
|
| 98 |
+
|
| 99 |
+
return HealthResponse(
|
| 100 |
+
status="ok",
|
| 101 |
+
version="1.0.0",
|
| 102 |
+
components={
|
| 103 |
+
"bert_classifier": "loaded" if _predictor is not None else "not loaded",
|
| 104 |
+
"embedding_model": "loaded" if _embedding_model is not None else "not loaded",
|
| 105 |
+
"supabase": "connected" if _supabase_client is not None else "not connected",
|
| 106 |
+
},
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
@app.get("/", tags=["System"])
|
| 111 |
+
async def root():
|
| 112 |
+
"""API root β welcome message."""
|
| 113 |
+
return {
|
| 114 |
+
"message": "NEET Biology Q&A API",
|
| 115 |
+
"version": "1.0.0",
|
| 116 |
+
"docs": "/docs",
|
| 117 |
+
"endpoints": {
|
| 118 |
+
"POST /api/qa": "Full Q&A pipeline (classify + answer + verify)",
|
| 119 |
+
"POST /api/classify": "Chapter classification + topic extraction only",
|
| 120 |
+
"GET /health": "Health check",
|
| 121 |
+
},
|
| 122 |
+
}
|
Backend/routers/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Backend routers package
|
Backend/routers/qa.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
qa.py β Question Answering API router
|
| 3 |
+
|
| 4 |
+
Endpoints:
|
| 5 |
+
POST /qa β Full RAG pipeline (classify + retrieve + answer + verify)
|
| 6 |
+
POST /classify β Classification only (BERT chapter + topic extraction)
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import traceback
|
| 10 |
+
from fastapi import APIRouter, HTTPException
|
| 11 |
+
|
| 12 |
+
from Backend.schemas import (
|
| 13 |
+
QuestionRequest,
|
| 14 |
+
QAResponse,
|
| 15 |
+
ClassifyOnlyRequest,
|
| 16 |
+
ClassifyOnlyResponse,
|
| 17 |
+
ClassificationResult,
|
| 18 |
+
TopicInfo,
|
| 19 |
+
SourceChunk,
|
| 20 |
+
IsNeetBioRequest,
|
| 21 |
+
IsNeetBioResponse
|
| 22 |
+
)
|
| 23 |
+
from rag.pipeline import run_pipeline
|
| 24 |
+
from Classification.classify_and_extract import classify_question, get_predictor
|
| 25 |
+
|
| 26 |
+
router = APIRouter(prefix="/api", tags=["Question Answering"])
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# ==============================
|
| 30 |
+
# POST /api/qa
|
| 31 |
+
# ==============================
|
| 32 |
+
@router.post(
|
| 33 |
+
"/qa",
|
| 34 |
+
response_model=QAResponse,
|
| 35 |
+
summary="Answer a NEET Biology question",
|
| 36 |
+
description=(
|
| 37 |
+
"Runs the full pipeline: BERT classifies the chapter, "
|
| 38 |
+
"retrieves relevant NCERT chunks, generates an answer with "
|
| 39 |
+
"justification, and verifies correctness."
|
| 40 |
+
),
|
| 41 |
+
)
|
| 42 |
+
async def answer_question(req: QuestionRequest):
|
| 43 |
+
"""
|
| 44 |
+
Full Q&A pipeline:
|
| 45 |
+
1. BERT β chapter prediction + topic extraction
|
| 46 |
+
2. Supabase β retrieve NCERT chunks (filtered by chapter)
|
| 47 |
+
3. Groq LLM β generate answer + justification
|
| 48 |
+
4. Groq LLM β verify answer
|
| 49 |
+
5. Compute confidence score
|
| 50 |
+
"""
|
| 51 |
+
try:
|
| 52 |
+
result = run_pipeline(
|
| 53 |
+
question=req.question,
|
| 54 |
+
chapter_filter=req.chapter_filter,
|
| 55 |
+
top_k=req.top_k,
|
| 56 |
+
use_classifier=req.use_classifier,
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
# Build classification model if present
|
| 60 |
+
classification = None
|
| 61 |
+
if result.get("classification"):
|
| 62 |
+
raw = result["classification"]
|
| 63 |
+
classification = ClassificationResult(
|
| 64 |
+
chapter=raw["chapter"],
|
| 65 |
+
chapter_id=raw["chapter_id"],
|
| 66 |
+
chapter_confidence=raw["chapter_confidence"],
|
| 67 |
+
rejected=raw.get("rejected", False),
|
| 68 |
+
rejection_reason=raw.get("rejection_reason", ""),
|
| 69 |
+
entropy=raw.get("entropy", 0.0),
|
| 70 |
+
margin=raw.get("margin", 0.0),
|
| 71 |
+
topics=[
|
| 72 |
+
TopicInfo(
|
| 73 |
+
section_code=t["section_code"],
|
| 74 |
+
section_title=t["section_title"],
|
| 75 |
+
similarity=t["similarity"],
|
| 76 |
+
)
|
| 77 |
+
for t in raw.get("topics", [])
|
| 78 |
+
],
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
# Build sources
|
| 82 |
+
sources = [
|
| 83 |
+
SourceChunk(
|
| 84 |
+
chapter=s.get("chapter"),
|
| 85 |
+
section=s.get("section"),
|
| 86 |
+
section_title=s.get("section_title"),
|
| 87 |
+
text_content=s.get("text_content"),
|
| 88 |
+
similarity=s.get("similarity", 0.0),
|
| 89 |
+
)
|
| 90 |
+
for s in result.get("sources", [])
|
| 91 |
+
]
|
| 92 |
+
|
| 93 |
+
return QAResponse(
|
| 94 |
+
question=result["question"],
|
| 95 |
+
classification=classification,
|
| 96 |
+
answer=result["answer"],
|
| 97 |
+
justification=result.get("justification", []),
|
| 98 |
+
sources=sources,
|
| 99 |
+
confidence=result.get("confidence", 0.0),
|
| 100 |
+
verified=result.get("verified", False),
|
| 101 |
+
verifier_note=result.get("verifier_note", ""),
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
except Exception as e:
|
| 105 |
+
traceback.print_exc()
|
| 106 |
+
raise HTTPException(
|
| 107 |
+
status_code=500,
|
| 108 |
+
detail=f"Pipeline error: {str(e)}",
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# ==============================
|
| 113 |
+
# POST /api/classify
|
| 114 |
+
# ==============================
|
| 115 |
+
@router.post(
|
| 116 |
+
"/classify",
|
| 117 |
+
response_model=ClassifyOnlyResponse,
|
| 118 |
+
summary="Classify a question (chapter + topics only)",
|
| 119 |
+
description=(
|
| 120 |
+
"Runs only the BERT classifier + topic extraction. "
|
| 121 |
+
"Does NOT generate an answer. Useful for quick categorization."
|
| 122 |
+
),
|
| 123 |
+
)
|
| 124 |
+
async def classify_only(req: ClassifyOnlyRequest):
|
| 125 |
+
"""
|
| 126 |
+
Classification only (no RAG):
|
| 127 |
+
1. BERT β chapter prediction
|
| 128 |
+
2. Supabase retrieval β topic extraction
|
| 129 |
+
"""
|
| 130 |
+
try:
|
| 131 |
+
raw = classify_question(req.question)
|
| 132 |
+
|
| 133 |
+
classification = ClassificationResult(
|
| 134 |
+
chapter=raw["chapter"],
|
| 135 |
+
chapter_id=raw["chapter_id"],
|
| 136 |
+
chapter_confidence=raw["chapter_confidence"],
|
| 137 |
+
rejected=raw.get("rejected", False),
|
| 138 |
+
rejection_reason=raw.get("rejection_reason", ""),
|
| 139 |
+
entropy=raw.get("entropy", 0.0),
|
| 140 |
+
margin=raw.get("margin", 0.0),
|
| 141 |
+
topics=[
|
| 142 |
+
TopicInfo(
|
| 143 |
+
section_code=t["section_code"],
|
| 144 |
+
section_title=t["section_title"],
|
| 145 |
+
similarity=t["similarity"],
|
| 146 |
+
)
|
| 147 |
+
for t in raw.get("topics", [])
|
| 148 |
+
],
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
return ClassifyOnlyResponse(
|
| 152 |
+
question=req.question,
|
| 153 |
+
classification=classification,
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
except Exception as e:
|
| 157 |
+
traceback.print_exc()
|
| 158 |
+
raise HTTPException(
|
| 159 |
+
status_code=500,
|
| 160 |
+
detail=f"Classification error: {str(e)}",
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
# ==============================
|
| 165 |
+
# POST /api/is-neet-bio
|
| 166 |
+
# ==============================
|
| 167 |
+
@router.post(
|
| 168 |
+
"/is-neet-bio",
|
| 169 |
+
response_model=IsNeetBioResponse,
|
| 170 |
+
summary="Quickly check if a string is a valid NEET Biology question",
|
| 171 |
+
)
|
| 172 |
+
async def is_neet_bio(req: IsNeetBioRequest):
|
| 173 |
+
"""
|
| 174 |
+
Runs only the BERT classifier prediction to check OOD (Out-Of-Domain) logic.
|
| 175 |
+
Fast path validation for frontend to prevent garbage from triggering the RAG pipeline.
|
| 176 |
+
"""
|
| 177 |
+
try:
|
| 178 |
+
predictor = get_predictor()
|
| 179 |
+
bert_result = predictor.predict(req.question)
|
| 180 |
+
|
| 181 |
+
rejected = bert_result.get("rejected", False)
|
| 182 |
+
reason = bert_result.get("rejection_reason", "")
|
| 183 |
+
|
| 184 |
+
return IsNeetBioResponse(
|
| 185 |
+
is_valid=not rejected,
|
| 186 |
+
rejected=rejected,
|
| 187 |
+
reason=reason
|
| 188 |
+
)
|
| 189 |
+
except Exception as e:
|
| 190 |
+
traceback.print_exc()
|
| 191 |
+
raise HTTPException(
|
| 192 |
+
status_code=500,
|
| 193 |
+
detail=f"Validation error: {str(e)}",
|
| 194 |
+
)
|
Backend/schemas.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
schemas.py β Pydantic models for FastAPI request/response validation
|
| 3 |
+
|
| 4 |
+
Defines the complete API contract for the NEET Biology Q&A system.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from pydantic import BaseModel, Field
|
| 8 |
+
from typing import Optional
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
# ==============================
|
| 12 |
+
# REQUEST MODELS
|
| 13 |
+
# ==============================
|
| 14 |
+
|
| 15 |
+
class QuestionRequest(BaseModel):
|
| 16 |
+
"""Request body for the /qa endpoint."""
|
| 17 |
+
question: str = Field(
|
| 18 |
+
...,
|
| 19 |
+
min_length=5,
|
| 20 |
+
max_length=500,
|
| 21 |
+
description="The NEET Biology question to answer.",
|
| 22 |
+
examples=["What is the role of cofactors in enzyme activity?"],
|
| 23 |
+
)
|
| 24 |
+
chapter_filter: Optional[str] = Field(
|
| 25 |
+
default=None,
|
| 26 |
+
description="Optional: manually specify a chapter to filter retrieval. "
|
| 27 |
+
"If omitted, BERT classifier auto-detects the chapter.",
|
| 28 |
+
examples=["Biomolecules"],
|
| 29 |
+
)
|
| 30 |
+
top_k: int = Field(
|
| 31 |
+
default=5,
|
| 32 |
+
ge=1,
|
| 33 |
+
le=20,
|
| 34 |
+
description="Number of NCERT chunks to retrieve for context.",
|
| 35 |
+
)
|
| 36 |
+
use_classifier: bool = Field(
|
| 37 |
+
default=True,
|
| 38 |
+
description="Whether to use the BERT classifier for auto chapter detection.",
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# ==============================
|
| 43 |
+
# RESPONSE MODELS
|
| 44 |
+
# ==============================
|
| 45 |
+
|
| 46 |
+
class TopicInfo(BaseModel):
|
| 47 |
+
"""A predicted topic/subtopic from the NCERT syllabus."""
|
| 48 |
+
section_code: str = Field(..., description="Section code (e.g., '9.8')")
|
| 49 |
+
section_title: str = Field(..., description="Section title (e.g., 'Enzymes')")
|
| 50 |
+
similarity: float = Field(..., description="Cosine similarity score (0-1)")
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class ClassificationResult(BaseModel):
|
| 54 |
+
"""BERT classification output for the question."""
|
| 55 |
+
chapter: str = Field(..., description="Predicted NCERT chapter name")
|
| 56 |
+
chapter_id: int = Field(..., description="Chapter ID (0-30)")
|
| 57 |
+
chapter_confidence: float = Field(..., description="BERT confidence score (0-1)")
|
| 58 |
+
topics: list[TopicInfo] = Field(
|
| 59 |
+
default=[],
|
| 60 |
+
description="Top 1-3 relevant topics/subtopics within the chapter",
|
| 61 |
+
)
|
| 62 |
+
rejected: bool = Field(default=False, description="True if rejected by OOD gating")
|
| 63 |
+
rejection_reason: str = Field(default="", description="Reason for rejection")
|
| 64 |
+
entropy: float = Field(default=0.0, description="Normalized entropy of prediction")
|
| 65 |
+
margin: float = Field(default=0.0, description="Confidence margin between top-1 and top-2")
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
class IsNeetBioRequest(BaseModel):
|
| 69 |
+
"""Request body for the /is-neet-bio validation endpoint."""
|
| 70 |
+
question: str = Field(
|
| 71 |
+
...,
|
| 72 |
+
min_length=3,
|
| 73 |
+
max_length=500,
|
| 74 |
+
description="The question to validate."
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
class IsNeetBioResponse(BaseModel):
|
| 78 |
+
"""Response indicating whether the query is valid NEET biology."""
|
| 79 |
+
is_valid: bool
|
| 80 |
+
rejected: bool
|
| 81 |
+
reason: str
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class SourceChunk(BaseModel):
|
| 85 |
+
"""A retrieved NCERT text chunk used as context."""
|
| 86 |
+
chapter: Optional[str] = None
|
| 87 |
+
section: Optional[str] = None
|
| 88 |
+
section_title: Optional[str] = None
|
| 89 |
+
text_content: Optional[str] = None
|
| 90 |
+
similarity: float = 0.0
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class QAResponse(BaseModel):
|
| 94 |
+
"""Full response from the Q&A pipeline."""
|
| 95 |
+
question: str = Field(..., description="The original question")
|
| 96 |
+
classification: Optional[ClassificationResult] = Field(
|
| 97 |
+
default=None,
|
| 98 |
+
description="BERT classification result (chapter + topics)",
|
| 99 |
+
)
|
| 100 |
+
answer: str = Field(..., description="Generated answer from NCERT context")
|
| 101 |
+
justification: list[str] = Field(
|
| 102 |
+
default=[],
|
| 103 |
+
description="Step-by-step justification of the answer",
|
| 104 |
+
)
|
| 105 |
+
sources: list[SourceChunk] = Field(
|
| 106 |
+
default=[],
|
| 107 |
+
description="Retrieved NCERT chunks used as evidence",
|
| 108 |
+
)
|
| 109 |
+
confidence: float = Field(
|
| 110 |
+
...,
|
| 111 |
+
ge=0.0,
|
| 112 |
+
le=1.0,
|
| 113 |
+
description="Overall confidence score (0-1)",
|
| 114 |
+
)
|
| 115 |
+
verified: bool = Field(..., description="Whether the answer passed verification")
|
| 116 |
+
verifier_note: str = Field(
|
| 117 |
+
default="",
|
| 118 |
+
description="Explanation from the verifier",
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
class ClassifyOnlyRequest(BaseModel):
|
| 123 |
+
"""Request body for the /classify endpoint (no RAG, just classification)."""
|
| 124 |
+
question: str = Field(
|
| 125 |
+
...,
|
| 126 |
+
min_length=5,
|
| 127 |
+
max_length=500,
|
| 128 |
+
description="The NEET Biology question to classify.",
|
| 129 |
+
examples=["What is the role of mitochondria in ATP synthesis?"],
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
class ClassifyOnlyResponse(BaseModel):
|
| 134 |
+
"""Response from the /classify endpoint."""
|
| 135 |
+
question: str
|
| 136 |
+
classification: ClassificationResult
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class HealthResponse(BaseModel):
|
| 140 |
+
"""Health check response."""
|
| 141 |
+
status: str = "ok"
|
| 142 |
+
version: str = "1.0.0"
|
| 143 |
+
components: dict = {}
|
Classification/Evaluation_metrics/eval_accuracy_f1.png
ADDED
|
Git LFS Details
|
Classification/Evaluation_metrics/eval_metrics.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eval_loss": 0.42191559076309204,
|
| 3 |
+
"eval_accuracy": 0.9118942731277533,
|
| 4 |
+
"eval_f1": 0.9167823247394992,
|
| 5 |
+
"eval_runtime": 6.542,
|
| 6 |
+
"eval_samples_per_second": 173.496,
|
| 7 |
+
"eval_steps_per_second": 10.853,
|
| 8 |
+
"epoch": 5.0
|
| 9 |
+
}
|
Classification/Evaluation_metrics/learning_rate_schedule.png
ADDED
|
Git LFS Details
|
Classification/Evaluation_metrics/training_dashboard.png
ADDED
|
Git LFS Details
|
Classification/Evaluation_metrics/training_log.json
ADDED
|
@@ -0,0 +1,1065 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"loss": 3.5175,
|
| 4 |
+
"grad_norm": 5.565041542053223,
|
| 5 |
+
"learning_rate": 1.4084507042253523e-06,
|
| 6 |
+
"epoch": 0.035211267605633804,
|
| 7 |
+
"step": 10
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"loss": 3.442,
|
| 11 |
+
"grad_norm": 5.5761823654174805,
|
| 12 |
+
"learning_rate": 2.8169014084507046e-06,
|
| 13 |
+
"epoch": 0.07042253521126761,
|
| 14 |
+
"step": 20
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"loss": 3.4738,
|
| 18 |
+
"grad_norm": 4.932906627655029,
|
| 19 |
+
"learning_rate": 4.225352112676057e-06,
|
| 20 |
+
"epoch": 0.1056338028169014,
|
| 21 |
+
"step": 30
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"loss": 3.4348,
|
| 25 |
+
"grad_norm": 4.843143463134766,
|
| 26 |
+
"learning_rate": 5.633802816901409e-06,
|
| 27 |
+
"epoch": 0.14084507042253522,
|
| 28 |
+
"step": 40
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"loss": 3.4126,
|
| 32 |
+
"grad_norm": 4.041543006896973,
|
| 33 |
+
"learning_rate": 7.042253521126761e-06,
|
| 34 |
+
"epoch": 0.176056338028169,
|
| 35 |
+
"step": 50
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"loss": 3.4001,
|
| 39 |
+
"grad_norm": 4.474198818206787,
|
| 40 |
+
"learning_rate": 8.450704225352114e-06,
|
| 41 |
+
"epoch": 0.2112676056338028,
|
| 42 |
+
"step": 60
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"loss": 3.4608,
|
| 46 |
+
"grad_norm": 4.319010257720947,
|
| 47 |
+
"learning_rate": 9.859154929577466e-06,
|
| 48 |
+
"epoch": 0.24647887323943662,
|
| 49 |
+
"step": 70
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"loss": 3.3525,
|
| 53 |
+
"grad_norm": 5.172270774841309,
|
| 54 |
+
"learning_rate": 1.1267605633802819e-05,
|
| 55 |
+
"epoch": 0.28169014084507044,
|
| 56 |
+
"step": 80
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"loss": 3.3754,
|
| 60 |
+
"grad_norm": 5.9189839363098145,
|
| 61 |
+
"learning_rate": 1.2676056338028171e-05,
|
| 62 |
+
"epoch": 0.31690140845070425,
|
| 63 |
+
"step": 90
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"loss": 3.2967,
|
| 67 |
+
"grad_norm": 5.190176010131836,
|
| 68 |
+
"learning_rate": 1.4084507042253522e-05,
|
| 69 |
+
"epoch": 0.352112676056338,
|
| 70 |
+
"step": 100
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"loss": 3.2748,
|
| 74 |
+
"grad_norm": 5.891371726989746,
|
| 75 |
+
"learning_rate": 1.5492957746478872e-05,
|
| 76 |
+
"epoch": 0.3873239436619718,
|
| 77 |
+
"step": 110
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"loss": 3.3054,
|
| 81 |
+
"grad_norm": 5.310686111450195,
|
| 82 |
+
"learning_rate": 1.6901408450704228e-05,
|
| 83 |
+
"epoch": 0.4225352112676056,
|
| 84 |
+
"step": 120
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"loss": 3.2041,
|
| 88 |
+
"grad_norm": 8.007060050964355,
|
| 89 |
+
"learning_rate": 1.830985915492958e-05,
|
| 90 |
+
"epoch": 0.45774647887323944,
|
| 91 |
+
"step": 130
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"loss": 3.1923,
|
| 95 |
+
"grad_norm": 6.142883777618408,
|
| 96 |
+
"learning_rate": 1.9718309859154933e-05,
|
| 97 |
+
"epoch": 0.49295774647887325,
|
| 98 |
+
"step": 140
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"loss": 3.1226,
|
| 102 |
+
"grad_norm": 7.110233783721924,
|
| 103 |
+
"learning_rate": 1.9874804381846636e-05,
|
| 104 |
+
"epoch": 0.528169014084507,
|
| 105 |
+
"step": 150
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"loss": 2.9466,
|
| 109 |
+
"grad_norm": 6.629207611083984,
|
| 110 |
+
"learning_rate": 1.9718309859154933e-05,
|
| 111 |
+
"epoch": 0.5633802816901409,
|
| 112 |
+
"step": 160
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"loss": 2.9508,
|
| 116 |
+
"grad_norm": 7.121689796447754,
|
| 117 |
+
"learning_rate": 1.9561815336463226e-05,
|
| 118 |
+
"epoch": 0.5985915492957746,
|
| 119 |
+
"step": 170
|
| 120 |
+
},
|
| 121 |
+
{
|
| 122 |
+
"loss": 2.8045,
|
| 123 |
+
"grad_norm": 7.066350936889648,
|
| 124 |
+
"learning_rate": 1.940532081377152e-05,
|
| 125 |
+
"epoch": 0.6338028169014085,
|
| 126 |
+
"step": 180
|
| 127 |
+
},
|
| 128 |
+
{
|
| 129 |
+
"loss": 2.5482,
|
| 130 |
+
"grad_norm": 6.999160289764404,
|
| 131 |
+
"learning_rate": 1.9248826291079815e-05,
|
| 132 |
+
"epoch": 0.6690140845070423,
|
| 133 |
+
"step": 190
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"loss": 2.5868,
|
| 137 |
+
"grad_norm": 8.449387550354004,
|
| 138 |
+
"learning_rate": 1.9092331768388108e-05,
|
| 139 |
+
"epoch": 0.704225352112676,
|
| 140 |
+
"step": 200
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"loss": 2.3915,
|
| 144 |
+
"grad_norm": 7.70518684387207,
|
| 145 |
+
"learning_rate": 1.89358372456964e-05,
|
| 146 |
+
"epoch": 0.7394366197183099,
|
| 147 |
+
"step": 210
|
| 148 |
+
},
|
| 149 |
+
{
|
| 150 |
+
"loss": 2.4275,
|
| 151 |
+
"grad_norm": 8.197113037109375,
|
| 152 |
+
"learning_rate": 1.8779342723004698e-05,
|
| 153 |
+
"epoch": 0.7746478873239436,
|
| 154 |
+
"step": 220
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"loss": 2.1541,
|
| 158 |
+
"grad_norm": 7.156861305236816,
|
| 159 |
+
"learning_rate": 1.862284820031299e-05,
|
| 160 |
+
"epoch": 0.8098591549295775,
|
| 161 |
+
"step": 230
|
| 162 |
+
},
|
| 163 |
+
{
|
| 164 |
+
"loss": 2.1481,
|
| 165 |
+
"grad_norm": 8.494321823120117,
|
| 166 |
+
"learning_rate": 1.8466353677621284e-05,
|
| 167 |
+
"epoch": 0.8450704225352113,
|
| 168 |
+
"step": 240
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"loss": 2.1078,
|
| 172 |
+
"grad_norm": 5.825531482696533,
|
| 173 |
+
"learning_rate": 1.830985915492958e-05,
|
| 174 |
+
"epoch": 0.8802816901408451,
|
| 175 |
+
"step": 250
|
| 176 |
+
},
|
| 177 |
+
{
|
| 178 |
+
"loss": 1.9146,
|
| 179 |
+
"grad_norm": 6.99673318862915,
|
| 180 |
+
"learning_rate": 1.8153364632237873e-05,
|
| 181 |
+
"epoch": 0.9154929577464789,
|
| 182 |
+
"step": 260
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"loss": 1.8766,
|
| 186 |
+
"grad_norm": 8.612900733947754,
|
| 187 |
+
"learning_rate": 1.7996870109546166e-05,
|
| 188 |
+
"epoch": 0.9507042253521126,
|
| 189 |
+
"step": 270
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"loss": 1.7913,
|
| 193 |
+
"grad_norm": 7.821394443511963,
|
| 194 |
+
"learning_rate": 1.7840375586854463e-05,
|
| 195 |
+
"epoch": 0.9859154929577465,
|
| 196 |
+
"step": 280
|
| 197 |
+
},
|
| 198 |
+
{
|
| 199 |
+
"eval_loss": 1.6347781419754028,
|
| 200 |
+
"eval_accuracy": 0.7083700440528634,
|
| 201 |
+
"eval_f1": 0.6049143027945829,
|
| 202 |
+
"eval_runtime": 6.5467,
|
| 203 |
+
"eval_samples_per_second": 173.369,
|
| 204 |
+
"eval_steps_per_second": 10.845,
|
| 205 |
+
"epoch": 1.0,
|
| 206 |
+
"step": 284
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"loss": 1.5623,
|
| 210 |
+
"grad_norm": 8.131426811218262,
|
| 211 |
+
"learning_rate": 1.7683881064162756e-05,
|
| 212 |
+
"epoch": 1.0211267605633803,
|
| 213 |
+
"step": 290
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"loss": 1.5953,
|
| 217 |
+
"grad_norm": 8.78809642791748,
|
| 218 |
+
"learning_rate": 1.752738654147105e-05,
|
| 219 |
+
"epoch": 1.056338028169014,
|
| 220 |
+
"step": 300
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"loss": 1.6067,
|
| 224 |
+
"grad_norm": 5.926104545593262,
|
| 225 |
+
"learning_rate": 1.7370892018779345e-05,
|
| 226 |
+
"epoch": 1.091549295774648,
|
| 227 |
+
"step": 310
|
| 228 |
+
},
|
| 229 |
+
{
|
| 230 |
+
"loss": 1.5927,
|
| 231 |
+
"grad_norm": 7.396566867828369,
|
| 232 |
+
"learning_rate": 1.721439749608764e-05,
|
| 233 |
+
"epoch": 1.1267605633802817,
|
| 234 |
+
"step": 320
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"loss": 1.4279,
|
| 238 |
+
"grad_norm": 8.511696815490723,
|
| 239 |
+
"learning_rate": 1.705790297339593e-05,
|
| 240 |
+
"epoch": 1.1619718309859155,
|
| 241 |
+
"step": 330
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"loss": 1.4992,
|
| 245 |
+
"grad_norm": 6.154587745666504,
|
| 246 |
+
"learning_rate": 1.6901408450704228e-05,
|
| 247 |
+
"epoch": 1.1971830985915493,
|
| 248 |
+
"step": 340
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"loss": 1.4041,
|
| 252 |
+
"grad_norm": 13.939669609069824,
|
| 253 |
+
"learning_rate": 1.674491392801252e-05,
|
| 254 |
+
"epoch": 1.232394366197183,
|
| 255 |
+
"step": 350
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"loss": 1.4161,
|
| 259 |
+
"grad_norm": 7.556514263153076,
|
| 260 |
+
"learning_rate": 1.6588419405320814e-05,
|
| 261 |
+
"epoch": 1.267605633802817,
|
| 262 |
+
"step": 360
|
| 263 |
+
},
|
| 264 |
+
{
|
| 265 |
+
"loss": 1.2424,
|
| 266 |
+
"grad_norm": 7.370925426483154,
|
| 267 |
+
"learning_rate": 1.643192488262911e-05,
|
| 268 |
+
"epoch": 1.3028169014084507,
|
| 269 |
+
"step": 370
|
| 270 |
+
},
|
| 271 |
+
{
|
| 272 |
+
"loss": 1.248,
|
| 273 |
+
"grad_norm": 6.655207633972168,
|
| 274 |
+
"learning_rate": 1.6275430359937403e-05,
|
| 275 |
+
"epoch": 1.3380281690140845,
|
| 276 |
+
"step": 380
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"loss": 1.1601,
|
| 280 |
+
"grad_norm": 9.040409088134766,
|
| 281 |
+
"learning_rate": 1.6118935837245697e-05,
|
| 282 |
+
"epoch": 1.3732394366197183,
|
| 283 |
+
"step": 390
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"loss": 1.1461,
|
| 287 |
+
"grad_norm": 8.453059196472168,
|
| 288 |
+
"learning_rate": 1.5962441314553993e-05,
|
| 289 |
+
"epoch": 1.408450704225352,
|
| 290 |
+
"step": 400
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"loss": 1.2187,
|
| 294 |
+
"grad_norm": 7.965033054351807,
|
| 295 |
+
"learning_rate": 1.5805946791862286e-05,
|
| 296 |
+
"epoch": 1.443661971830986,
|
| 297 |
+
"step": 410
|
| 298 |
+
},
|
| 299 |
+
{
|
| 300 |
+
"loss": 1.1057,
|
| 301 |
+
"grad_norm": 7.8456645011901855,
|
| 302 |
+
"learning_rate": 1.564945226917058e-05,
|
| 303 |
+
"epoch": 1.4788732394366197,
|
| 304 |
+
"step": 420
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"loss": 1.1947,
|
| 308 |
+
"grad_norm": 6.965514659881592,
|
| 309 |
+
"learning_rate": 1.5492957746478872e-05,
|
| 310 |
+
"epoch": 1.5140845070422535,
|
| 311 |
+
"step": 430
|
| 312 |
+
},
|
| 313 |
+
{
|
| 314 |
+
"loss": 1.1401,
|
| 315 |
+
"grad_norm": 5.833000659942627,
|
| 316 |
+
"learning_rate": 1.533646322378717e-05,
|
| 317 |
+
"epoch": 1.5492957746478875,
|
| 318 |
+
"step": 440
|
| 319 |
+
},
|
| 320 |
+
{
|
| 321 |
+
"loss": 1.137,
|
| 322 |
+
"grad_norm": 6.739829063415527,
|
| 323 |
+
"learning_rate": 1.5179968701095462e-05,
|
| 324 |
+
"epoch": 1.584507042253521,
|
| 325 |
+
"step": 450
|
| 326 |
+
},
|
| 327 |
+
{
|
| 328 |
+
"loss": 1.0756,
|
| 329 |
+
"grad_norm": 7.934983253479004,
|
| 330 |
+
"learning_rate": 1.5023474178403756e-05,
|
| 331 |
+
"epoch": 1.619718309859155,
|
| 332 |
+
"step": 460
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"loss": 0.9483,
|
| 336 |
+
"grad_norm": 7.326385021209717,
|
| 337 |
+
"learning_rate": 1.4866979655712051e-05,
|
| 338 |
+
"epoch": 1.6549295774647887,
|
| 339 |
+
"step": 470
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"loss": 1.016,
|
| 343 |
+
"grad_norm": 4.909506797790527,
|
| 344 |
+
"learning_rate": 1.4710485133020344e-05,
|
| 345 |
+
"epoch": 1.6901408450704225,
|
| 346 |
+
"step": 480
|
| 347 |
+
},
|
| 348 |
+
{
|
| 349 |
+
"loss": 1.0134,
|
| 350 |
+
"grad_norm": 7.309936046600342,
|
| 351 |
+
"learning_rate": 1.4553990610328639e-05,
|
| 352 |
+
"epoch": 1.7253521126760565,
|
| 353 |
+
"step": 490
|
| 354 |
+
},
|
| 355 |
+
{
|
| 356 |
+
"loss": 1.0056,
|
| 357 |
+
"grad_norm": 9.106132507324219,
|
| 358 |
+
"learning_rate": 1.4397496087636934e-05,
|
| 359 |
+
"epoch": 1.76056338028169,
|
| 360 |
+
"step": 500
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"loss": 1.1269,
|
| 364 |
+
"grad_norm": 7.531581401824951,
|
| 365 |
+
"learning_rate": 1.4241001564945227e-05,
|
| 366 |
+
"epoch": 1.795774647887324,
|
| 367 |
+
"step": 510
|
| 368 |
+
},
|
| 369 |
+
{
|
| 370 |
+
"loss": 1.0258,
|
| 371 |
+
"grad_norm": 6.902132511138916,
|
| 372 |
+
"learning_rate": 1.4084507042253522e-05,
|
| 373 |
+
"epoch": 1.8309859154929577,
|
| 374 |
+
"step": 520
|
| 375 |
+
},
|
| 376 |
+
{
|
| 377 |
+
"loss": 1.0024,
|
| 378 |
+
"grad_norm": 10.563477516174316,
|
| 379 |
+
"learning_rate": 1.3928012519561815e-05,
|
| 380 |
+
"epoch": 1.8661971830985915,
|
| 381 |
+
"step": 530
|
| 382 |
+
},
|
| 383 |
+
{
|
| 384 |
+
"loss": 0.8689,
|
| 385 |
+
"grad_norm": 5.611667633056641,
|
| 386 |
+
"learning_rate": 1.377151799687011e-05,
|
| 387 |
+
"epoch": 1.9014084507042255,
|
| 388 |
+
"step": 540
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"loss": 0.8298,
|
| 392 |
+
"grad_norm": 6.363973617553711,
|
| 393 |
+
"learning_rate": 1.3615023474178406e-05,
|
| 394 |
+
"epoch": 1.936619718309859,
|
| 395 |
+
"step": 550
|
| 396 |
+
},
|
| 397 |
+
{
|
| 398 |
+
"loss": 0.7272,
|
| 399 |
+
"grad_norm": 8.456687927246094,
|
| 400 |
+
"learning_rate": 1.34585289514867e-05,
|
| 401 |
+
"epoch": 1.971830985915493,
|
| 402 |
+
"step": 560
|
| 403 |
+
},
|
| 404 |
+
{
|
| 405 |
+
"eval_loss": 0.7739513516426086,
|
| 406 |
+
"eval_accuracy": 0.8704845814977974,
|
| 407 |
+
"eval_f1": 0.8655265093934765,
|
| 408 |
+
"eval_runtime": 6.2617,
|
| 409 |
+
"eval_samples_per_second": 181.26,
|
| 410 |
+
"eval_steps_per_second": 11.339,
|
| 411 |
+
"epoch": 2.0,
|
| 412 |
+
"step": 568
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"loss": 0.8506,
|
| 416 |
+
"grad_norm": 7.487066745758057,
|
| 417 |
+
"learning_rate": 1.3302034428794994e-05,
|
| 418 |
+
"epoch": 2.007042253521127,
|
| 419 |
+
"step": 570
|
| 420 |
+
},
|
| 421 |
+
{
|
| 422 |
+
"loss": 0.7333,
|
| 423 |
+
"grad_norm": 5.738982677459717,
|
| 424 |
+
"learning_rate": 1.3145539906103288e-05,
|
| 425 |
+
"epoch": 2.0422535211267605,
|
| 426 |
+
"step": 580
|
| 427 |
+
},
|
| 428 |
+
{
|
| 429 |
+
"loss": 0.7168,
|
| 430 |
+
"grad_norm": 4.924327373504639,
|
| 431 |
+
"learning_rate": 1.2989045383411583e-05,
|
| 432 |
+
"epoch": 2.0774647887323945,
|
| 433 |
+
"step": 590
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"loss": 0.7653,
|
| 437 |
+
"grad_norm": 3.7934069633483887,
|
| 438 |
+
"learning_rate": 1.2832550860719876e-05,
|
| 439 |
+
"epoch": 2.112676056338028,
|
| 440 |
+
"step": 600
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"loss": 0.7952,
|
| 444 |
+
"grad_norm": 6.368825912475586,
|
| 445 |
+
"learning_rate": 1.2676056338028171e-05,
|
| 446 |
+
"epoch": 2.147887323943662,
|
| 447 |
+
"step": 610
|
| 448 |
+
},
|
| 449 |
+
{
|
| 450 |
+
"loss": 0.6612,
|
| 451 |
+
"grad_norm": 5.713892936706543,
|
| 452 |
+
"learning_rate": 1.2519561815336466e-05,
|
| 453 |
+
"epoch": 2.183098591549296,
|
| 454 |
+
"step": 620
|
| 455 |
+
},
|
| 456 |
+
{
|
| 457 |
+
"loss": 0.6836,
|
| 458 |
+
"grad_norm": 6.111892223358154,
|
| 459 |
+
"learning_rate": 1.2363067292644759e-05,
|
| 460 |
+
"epoch": 2.2183098591549295,
|
| 461 |
+
"step": 630
|
| 462 |
+
},
|
| 463 |
+
{
|
| 464 |
+
"loss": 0.7365,
|
| 465 |
+
"grad_norm": 8.857637405395508,
|
| 466 |
+
"learning_rate": 1.2206572769953053e-05,
|
| 467 |
+
"epoch": 2.2535211267605635,
|
| 468 |
+
"step": 640
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"loss": 0.6132,
|
| 472 |
+
"grad_norm": 3.4862544536590576,
|
| 473 |
+
"learning_rate": 1.2050078247261348e-05,
|
| 474 |
+
"epoch": 2.288732394366197,
|
| 475 |
+
"step": 650
|
| 476 |
+
},
|
| 477 |
+
{
|
| 478 |
+
"loss": 0.6442,
|
| 479 |
+
"grad_norm": 6.8738861083984375,
|
| 480 |
+
"learning_rate": 1.1893583724569641e-05,
|
| 481 |
+
"epoch": 2.323943661971831,
|
| 482 |
+
"step": 660
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"loss": 0.6584,
|
| 486 |
+
"grad_norm": 3.2398829460144043,
|
| 487 |
+
"learning_rate": 1.1737089201877936e-05,
|
| 488 |
+
"epoch": 2.359154929577465,
|
| 489 |
+
"step": 670
|
| 490 |
+
},
|
| 491 |
+
{
|
| 492 |
+
"loss": 0.5896,
|
| 493 |
+
"grad_norm": 4.472248077392578,
|
| 494 |
+
"learning_rate": 1.158059467918623e-05,
|
| 495 |
+
"epoch": 2.3943661971830985,
|
| 496 |
+
"step": 680
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"loss": 0.5091,
|
| 500 |
+
"grad_norm": 5.502006530761719,
|
| 501 |
+
"learning_rate": 1.1424100156494524e-05,
|
| 502 |
+
"epoch": 2.4295774647887325,
|
| 503 |
+
"step": 690
|
| 504 |
+
},
|
| 505 |
+
{
|
| 506 |
+
"loss": 0.6145,
|
| 507 |
+
"grad_norm": 4.565939903259277,
|
| 508 |
+
"learning_rate": 1.1267605633802819e-05,
|
| 509 |
+
"epoch": 2.464788732394366,
|
| 510 |
+
"step": 700
|
| 511 |
+
},
|
| 512 |
+
{
|
| 513 |
+
"loss": 0.5311,
|
| 514 |
+
"grad_norm": 4.030102252960205,
|
| 515 |
+
"learning_rate": 1.1111111111111113e-05,
|
| 516 |
+
"epoch": 2.5,
|
| 517 |
+
"step": 710
|
| 518 |
+
},
|
| 519 |
+
{
|
| 520 |
+
"loss": 0.5494,
|
| 521 |
+
"grad_norm": 5.067589282989502,
|
| 522 |
+
"learning_rate": 1.0954616588419406e-05,
|
| 523 |
+
"epoch": 2.535211267605634,
|
| 524 |
+
"step": 720
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"loss": 0.5832,
|
| 528 |
+
"grad_norm": 9.302046775817871,
|
| 529 |
+
"learning_rate": 1.0798122065727701e-05,
|
| 530 |
+
"epoch": 2.5704225352112675,
|
| 531 |
+
"step": 730
|
| 532 |
+
},
|
| 533 |
+
{
|
| 534 |
+
"loss": 0.4302,
|
| 535 |
+
"grad_norm": 2.904606819152832,
|
| 536 |
+
"learning_rate": 1.0641627543035994e-05,
|
| 537 |
+
"epoch": 2.6056338028169015,
|
| 538 |
+
"step": 740
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"loss": 0.4584,
|
| 542 |
+
"grad_norm": 7.644087314605713,
|
| 543 |
+
"learning_rate": 1.0485133020344289e-05,
|
| 544 |
+
"epoch": 2.640845070422535,
|
| 545 |
+
"step": 750
|
| 546 |
+
},
|
| 547 |
+
{
|
| 548 |
+
"loss": 0.5171,
|
| 549 |
+
"grad_norm": 3.483180284500122,
|
| 550 |
+
"learning_rate": 1.0328638497652584e-05,
|
| 551 |
+
"epoch": 2.676056338028169,
|
| 552 |
+
"step": 760
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"loss": 0.5933,
|
| 556 |
+
"grad_norm": 6.797661781311035,
|
| 557 |
+
"learning_rate": 1.0172143974960877e-05,
|
| 558 |
+
"epoch": 2.711267605633803,
|
| 559 |
+
"step": 770
|
| 560 |
+
},
|
| 561 |
+
{
|
| 562 |
+
"loss": 0.5288,
|
| 563 |
+
"grad_norm": 7.253881931304932,
|
| 564 |
+
"learning_rate": 1.0015649452269172e-05,
|
| 565 |
+
"epoch": 2.7464788732394365,
|
| 566 |
+
"step": 780
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"loss": 0.5413,
|
| 570 |
+
"grad_norm": 3.835197687149048,
|
| 571 |
+
"learning_rate": 9.859154929577466e-06,
|
| 572 |
+
"epoch": 2.7816901408450705,
|
| 573 |
+
"step": 790
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"loss": 0.4847,
|
| 577 |
+
"grad_norm": 4.124076843261719,
|
| 578 |
+
"learning_rate": 9.70266040688576e-06,
|
| 579 |
+
"epoch": 2.816901408450704,
|
| 580 |
+
"step": 800
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"loss": 0.4481,
|
| 584 |
+
"grad_norm": 5.035274982452393,
|
| 585 |
+
"learning_rate": 9.546165884194054e-06,
|
| 586 |
+
"epoch": 2.852112676056338,
|
| 587 |
+
"step": 810
|
| 588 |
+
},
|
| 589 |
+
{
|
| 590 |
+
"loss": 0.486,
|
| 591 |
+
"grad_norm": 4.004342079162598,
|
| 592 |
+
"learning_rate": 9.389671361502349e-06,
|
| 593 |
+
"epoch": 2.887323943661972,
|
| 594 |
+
"step": 820
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"loss": 0.4158,
|
| 598 |
+
"grad_norm": 8.212543487548828,
|
| 599 |
+
"learning_rate": 9.233176838810642e-06,
|
| 600 |
+
"epoch": 2.9225352112676055,
|
| 601 |
+
"step": 830
|
| 602 |
+
},
|
| 603 |
+
{
|
| 604 |
+
"loss": 0.3879,
|
| 605 |
+
"grad_norm": 7.012823104858398,
|
| 606 |
+
"learning_rate": 9.076682316118937e-06,
|
| 607 |
+
"epoch": 2.9577464788732395,
|
| 608 |
+
"step": 840
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"loss": 0.4711,
|
| 612 |
+
"grad_norm": 3.63045072555542,
|
| 613 |
+
"learning_rate": 8.920187793427231e-06,
|
| 614 |
+
"epoch": 2.992957746478873,
|
| 615 |
+
"step": 850
|
| 616 |
+
},
|
| 617 |
+
{
|
| 618 |
+
"eval_loss": 0.5145121812820435,
|
| 619 |
+
"eval_accuracy": 0.8986784140969163,
|
| 620 |
+
"eval_f1": 0.907173419320349,
|
| 621 |
+
"eval_runtime": 6.3694,
|
| 622 |
+
"eval_samples_per_second": 178.195,
|
| 623 |
+
"eval_steps_per_second": 11.147,
|
| 624 |
+
"epoch": 3.0,
|
| 625 |
+
"step": 852
|
| 626 |
+
},
|
| 627 |
+
{
|
| 628 |
+
"loss": 0.4283,
|
| 629 |
+
"grad_norm": 7.712802886962891,
|
| 630 |
+
"learning_rate": 8.763693270735524e-06,
|
| 631 |
+
"epoch": 3.028169014084507,
|
| 632 |
+
"step": 860
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"loss": 0.3899,
|
| 636 |
+
"grad_norm": 3.2548012733459473,
|
| 637 |
+
"learning_rate": 8.60719874804382e-06,
|
| 638 |
+
"epoch": 3.063380281690141,
|
| 639 |
+
"step": 870
|
| 640 |
+
},
|
| 641 |
+
{
|
| 642 |
+
"loss": 0.3646,
|
| 643 |
+
"grad_norm": 7.220994472503662,
|
| 644 |
+
"learning_rate": 8.450704225352114e-06,
|
| 645 |
+
"epoch": 3.0985915492957745,
|
| 646 |
+
"step": 880
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"loss": 0.3313,
|
| 650 |
+
"grad_norm": 2.882326126098633,
|
| 651 |
+
"learning_rate": 8.294209702660407e-06,
|
| 652 |
+
"epoch": 3.1338028169014085,
|
| 653 |
+
"step": 890
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"loss": 0.4364,
|
| 657 |
+
"grad_norm": 3.5633955001831055,
|
| 658 |
+
"learning_rate": 8.137715179968702e-06,
|
| 659 |
+
"epoch": 3.169014084507042,
|
| 660 |
+
"step": 900
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"loss": 0.2967,
|
| 664 |
+
"grad_norm": 1.0878703594207764,
|
| 665 |
+
"learning_rate": 7.981220657276996e-06,
|
| 666 |
+
"epoch": 3.204225352112676,
|
| 667 |
+
"step": 910
|
| 668 |
+
},
|
| 669 |
+
{
|
| 670 |
+
"loss": 0.3765,
|
| 671 |
+
"grad_norm": 4.074843883514404,
|
| 672 |
+
"learning_rate": 7.82472613458529e-06,
|
| 673 |
+
"epoch": 3.23943661971831,
|
| 674 |
+
"step": 920
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"loss": 0.3718,
|
| 678 |
+
"grad_norm": 3.4090213775634766,
|
| 679 |
+
"learning_rate": 7.668231611893584e-06,
|
| 680 |
+
"epoch": 3.2746478873239435,
|
| 681 |
+
"step": 930
|
| 682 |
+
},
|
| 683 |
+
{
|
| 684 |
+
"loss": 0.3826,
|
| 685 |
+
"grad_norm": 9.247264862060547,
|
| 686 |
+
"learning_rate": 7.511737089201878e-06,
|
| 687 |
+
"epoch": 3.3098591549295775,
|
| 688 |
+
"step": 940
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"loss": 0.2875,
|
| 692 |
+
"grad_norm": 4.87561559677124,
|
| 693 |
+
"learning_rate": 7.355242566510172e-06,
|
| 694 |
+
"epoch": 3.345070422535211,
|
| 695 |
+
"step": 950
|
| 696 |
+
},
|
| 697 |
+
{
|
| 698 |
+
"loss": 0.322,
|
| 699 |
+
"grad_norm": 6.722829341888428,
|
| 700 |
+
"learning_rate": 7.198748043818467e-06,
|
| 701 |
+
"epoch": 3.380281690140845,
|
| 702 |
+
"step": 960
|
| 703 |
+
},
|
| 704 |
+
{
|
| 705 |
+
"loss": 0.4269,
|
| 706 |
+
"grad_norm": 4.985360145568848,
|
| 707 |
+
"learning_rate": 7.042253521126761e-06,
|
| 708 |
+
"epoch": 3.415492957746479,
|
| 709 |
+
"step": 970
|
| 710 |
+
},
|
| 711 |
+
{
|
| 712 |
+
"loss": 0.3102,
|
| 713 |
+
"grad_norm": 6.112848281860352,
|
| 714 |
+
"learning_rate": 6.885758998435055e-06,
|
| 715 |
+
"epoch": 3.4507042253521125,
|
| 716 |
+
"step": 980
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"loss": 0.3138,
|
| 720 |
+
"grad_norm": 2.813039779663086,
|
| 721 |
+
"learning_rate": 6.72926447574335e-06,
|
| 722 |
+
"epoch": 3.4859154929577465,
|
| 723 |
+
"step": 990
|
| 724 |
+
},
|
| 725 |
+
{
|
| 726 |
+
"loss": 0.3323,
|
| 727 |
+
"grad_norm": 4.038683891296387,
|
| 728 |
+
"learning_rate": 6.572769953051644e-06,
|
| 729 |
+
"epoch": 3.52112676056338,
|
| 730 |
+
"step": 1000
|
| 731 |
+
},
|
| 732 |
+
{
|
| 733 |
+
"loss": 0.366,
|
| 734 |
+
"grad_norm": 2.771172046661377,
|
| 735 |
+
"learning_rate": 6.416275430359938e-06,
|
| 736 |
+
"epoch": 3.556338028169014,
|
| 737 |
+
"step": 1010
|
| 738 |
+
},
|
| 739 |
+
{
|
| 740 |
+
"loss": 0.3743,
|
| 741 |
+
"grad_norm": 5.438896179199219,
|
| 742 |
+
"learning_rate": 6.259780907668233e-06,
|
| 743 |
+
"epoch": 3.591549295774648,
|
| 744 |
+
"step": 1020
|
| 745 |
+
},
|
| 746 |
+
{
|
| 747 |
+
"loss": 0.3858,
|
| 748 |
+
"grad_norm": 5.540735721588135,
|
| 749 |
+
"learning_rate": 6.103286384976527e-06,
|
| 750 |
+
"epoch": 3.626760563380282,
|
| 751 |
+
"step": 1030
|
| 752 |
+
},
|
| 753 |
+
{
|
| 754 |
+
"loss": 0.2838,
|
| 755 |
+
"grad_norm": 3.3250198364257812,
|
| 756 |
+
"learning_rate": 5.946791862284821e-06,
|
| 757 |
+
"epoch": 3.6619718309859155,
|
| 758 |
+
"step": 1040
|
| 759 |
+
},
|
| 760 |
+
{
|
| 761 |
+
"loss": 0.2888,
|
| 762 |
+
"grad_norm": 4.223079204559326,
|
| 763 |
+
"learning_rate": 5.790297339593115e-06,
|
| 764 |
+
"epoch": 3.697183098591549,
|
| 765 |
+
"step": 1050
|
| 766 |
+
},
|
| 767 |
+
{
|
| 768 |
+
"loss": 0.3347,
|
| 769 |
+
"grad_norm": 6.852585792541504,
|
| 770 |
+
"learning_rate": 5.633802816901409e-06,
|
| 771 |
+
"epoch": 3.732394366197183,
|
| 772 |
+
"step": 1060
|
| 773 |
+
},
|
| 774 |
+
{
|
| 775 |
+
"loss": 0.2995,
|
| 776 |
+
"grad_norm": 2.4974894523620605,
|
| 777 |
+
"learning_rate": 5.477308294209703e-06,
|
| 778 |
+
"epoch": 3.767605633802817,
|
| 779 |
+
"step": 1070
|
| 780 |
+
},
|
| 781 |
+
{
|
| 782 |
+
"loss": 0.3614,
|
| 783 |
+
"grad_norm": 2.6977944374084473,
|
| 784 |
+
"learning_rate": 5.320813771517997e-06,
|
| 785 |
+
"epoch": 3.802816901408451,
|
| 786 |
+
"step": 1080
|
| 787 |
+
},
|
| 788 |
+
{
|
| 789 |
+
"loss": 0.3058,
|
| 790 |
+
"grad_norm": 3.4490833282470703,
|
| 791 |
+
"learning_rate": 5.164319248826292e-06,
|
| 792 |
+
"epoch": 3.8380281690140845,
|
| 793 |
+
"step": 1090
|
| 794 |
+
},
|
| 795 |
+
{
|
| 796 |
+
"loss": 0.2763,
|
| 797 |
+
"grad_norm": 2.6724023818969727,
|
| 798 |
+
"learning_rate": 5.007824726134586e-06,
|
| 799 |
+
"epoch": 3.873239436619718,
|
| 800 |
+
"step": 1100
|
| 801 |
+
},
|
| 802 |
+
{
|
| 803 |
+
"loss": 0.3458,
|
| 804 |
+
"grad_norm": 1.8767718076705933,
|
| 805 |
+
"learning_rate": 4.85133020344288e-06,
|
| 806 |
+
"epoch": 3.908450704225352,
|
| 807 |
+
"step": 1110
|
| 808 |
+
},
|
| 809 |
+
{
|
| 810 |
+
"loss": 0.3269,
|
| 811 |
+
"grad_norm": 13.369972229003906,
|
| 812 |
+
"learning_rate": 4.694835680751174e-06,
|
| 813 |
+
"epoch": 3.943661971830986,
|
| 814 |
+
"step": 1120
|
| 815 |
+
},
|
| 816 |
+
{
|
| 817 |
+
"loss": 0.3508,
|
| 818 |
+
"grad_norm": 9.277174949645996,
|
| 819 |
+
"learning_rate": 4.538341158059468e-06,
|
| 820 |
+
"epoch": 3.97887323943662,
|
| 821 |
+
"step": 1130
|
| 822 |
+
},
|
| 823 |
+
{
|
| 824 |
+
"eval_loss": 0.4453487694263458,
|
| 825 |
+
"eval_accuracy": 0.9030837004405287,
|
| 826 |
+
"eval_f1": 0.9101041734248071,
|
| 827 |
+
"eval_runtime": 6.2611,
|
| 828 |
+
"eval_samples_per_second": 181.279,
|
| 829 |
+
"eval_steps_per_second": 11.34,
|
| 830 |
+
"epoch": 4.0,
|
| 831 |
+
"step": 1136
|
| 832 |
+
},
|
| 833 |
+
{
|
| 834 |
+
"loss": 0.3061,
|
| 835 |
+
"grad_norm": 5.516575336456299,
|
| 836 |
+
"learning_rate": 4.381846635367762e-06,
|
| 837 |
+
"epoch": 4.014084507042254,
|
| 838 |
+
"step": 1140
|
| 839 |
+
},
|
| 840 |
+
{
|
| 841 |
+
"loss": 0.3649,
|
| 842 |
+
"grad_norm": 5.982604026794434,
|
| 843 |
+
"learning_rate": 4.225352112676057e-06,
|
| 844 |
+
"epoch": 4.049295774647887,
|
| 845 |
+
"step": 1150
|
| 846 |
+
},
|
| 847 |
+
{
|
| 848 |
+
"loss": 0.2965,
|
| 849 |
+
"grad_norm": 7.574158668518066,
|
| 850 |
+
"learning_rate": 4.068857589984351e-06,
|
| 851 |
+
"epoch": 4.084507042253521,
|
| 852 |
+
"step": 1160
|
| 853 |
+
},
|
| 854 |
+
{
|
| 855 |
+
"loss": 0.2558,
|
| 856 |
+
"grad_norm": 2.2732813358306885,
|
| 857 |
+
"learning_rate": 3.912363067292645e-06,
|
| 858 |
+
"epoch": 4.119718309859155,
|
| 859 |
+
"step": 1170
|
| 860 |
+
},
|
| 861 |
+
{
|
| 862 |
+
"loss": 0.2397,
|
| 863 |
+
"grad_norm": 4.167398929595947,
|
| 864 |
+
"learning_rate": 3.755868544600939e-06,
|
| 865 |
+
"epoch": 4.154929577464789,
|
| 866 |
+
"step": 1180
|
| 867 |
+
},
|
| 868 |
+
{
|
| 869 |
+
"loss": 0.2143,
|
| 870 |
+
"grad_norm": 1.0560132265090942,
|
| 871 |
+
"learning_rate": 3.5993740219092334e-06,
|
| 872 |
+
"epoch": 4.190140845070423,
|
| 873 |
+
"step": 1190
|
| 874 |
+
},
|
| 875 |
+
{
|
| 876 |
+
"loss": 0.3412,
|
| 877 |
+
"grad_norm": 12.945590019226074,
|
| 878 |
+
"learning_rate": 3.4428794992175273e-06,
|
| 879 |
+
"epoch": 4.225352112676056,
|
| 880 |
+
"step": 1200
|
| 881 |
+
},
|
| 882 |
+
{
|
| 883 |
+
"loss": 0.2683,
|
| 884 |
+
"grad_norm": 2.5129096508026123,
|
| 885 |
+
"learning_rate": 3.286384976525822e-06,
|
| 886 |
+
"epoch": 4.26056338028169,
|
| 887 |
+
"step": 1210
|
| 888 |
+
},
|
| 889 |
+
{
|
| 890 |
+
"loss": 0.2002,
|
| 891 |
+
"grad_norm": 2.868868827819824,
|
| 892 |
+
"learning_rate": 3.1298904538341164e-06,
|
| 893 |
+
"epoch": 4.295774647887324,
|
| 894 |
+
"step": 1220
|
| 895 |
+
},
|
| 896 |
+
{
|
| 897 |
+
"loss": 0.2111,
|
| 898 |
+
"grad_norm": 5.586353778839111,
|
| 899 |
+
"learning_rate": 2.9733959311424103e-06,
|
| 900 |
+
"epoch": 4.330985915492958,
|
| 901 |
+
"step": 1230
|
| 902 |
+
},
|
| 903 |
+
{
|
| 904 |
+
"loss": 0.1924,
|
| 905 |
+
"grad_norm": 2.2831079959869385,
|
| 906 |
+
"learning_rate": 2.8169014084507046e-06,
|
| 907 |
+
"epoch": 4.366197183098592,
|
| 908 |
+
"step": 1240
|
| 909 |
+
},
|
| 910 |
+
{
|
| 911 |
+
"loss": 0.1564,
|
| 912 |
+
"grad_norm": 1.5656145811080933,
|
| 913 |
+
"learning_rate": 2.6604068857589986e-06,
|
| 914 |
+
"epoch": 4.401408450704225,
|
| 915 |
+
"step": 1250
|
| 916 |
+
},
|
| 917 |
+
{
|
| 918 |
+
"loss": 0.2483,
|
| 919 |
+
"grad_norm": 1.9988621473312378,
|
| 920 |
+
"learning_rate": 2.503912363067293e-06,
|
| 921 |
+
"epoch": 4.436619718309859,
|
| 922 |
+
"step": 1260
|
| 923 |
+
},
|
| 924 |
+
{
|
| 925 |
+
"loss": 0.2739,
|
| 926 |
+
"grad_norm": 2.6662495136260986,
|
| 927 |
+
"learning_rate": 2.347417840375587e-06,
|
| 928 |
+
"epoch": 4.471830985915493,
|
| 929 |
+
"step": 1270
|
| 930 |
+
},
|
| 931 |
+
{
|
| 932 |
+
"loss": 0.2701,
|
| 933 |
+
"grad_norm": 7.080715656280518,
|
| 934 |
+
"learning_rate": 2.190923317683881e-06,
|
| 935 |
+
"epoch": 4.507042253521127,
|
| 936 |
+
"step": 1280
|
| 937 |
+
},
|
| 938 |
+
{
|
| 939 |
+
"loss": 0.2675,
|
| 940 |
+
"grad_norm": 2.611051082611084,
|
| 941 |
+
"learning_rate": 2.0344287949921754e-06,
|
| 942 |
+
"epoch": 4.542253521126761,
|
| 943 |
+
"step": 1290
|
| 944 |
+
},
|
| 945 |
+
{
|
| 946 |
+
"loss": 0.2305,
|
| 947 |
+
"grad_norm": 2.516238212585449,
|
| 948 |
+
"learning_rate": 1.8779342723004696e-06,
|
| 949 |
+
"epoch": 4.577464788732394,
|
| 950 |
+
"step": 1300
|
| 951 |
+
},
|
| 952 |
+
{
|
| 953 |
+
"loss": 0.2796,
|
| 954 |
+
"grad_norm": 2.024088144302368,
|
| 955 |
+
"learning_rate": 1.7214397496087637e-06,
|
| 956 |
+
"epoch": 4.612676056338028,
|
| 957 |
+
"step": 1310
|
| 958 |
+
},
|
| 959 |
+
{
|
| 960 |
+
"loss": 0.2608,
|
| 961 |
+
"grad_norm": 4.545577049255371,
|
| 962 |
+
"learning_rate": 1.5649452269170582e-06,
|
| 963 |
+
"epoch": 4.647887323943662,
|
| 964 |
+
"step": 1320
|
| 965 |
+
},
|
| 966 |
+
{
|
| 967 |
+
"loss": 0.1957,
|
| 968 |
+
"grad_norm": 7.018043041229248,
|
| 969 |
+
"learning_rate": 1.4084507042253523e-06,
|
| 970 |
+
"epoch": 4.683098591549296,
|
| 971 |
+
"step": 1330
|
| 972 |
+
},
|
| 973 |
+
{
|
| 974 |
+
"loss": 0.2977,
|
| 975 |
+
"grad_norm": 1.9592317342758179,
|
| 976 |
+
"learning_rate": 1.2519561815336464e-06,
|
| 977 |
+
"epoch": 4.71830985915493,
|
| 978 |
+
"step": 1340
|
| 979 |
+
},
|
| 980 |
+
{
|
| 981 |
+
"loss": 0.2935,
|
| 982 |
+
"grad_norm": 2.5041024684906006,
|
| 983 |
+
"learning_rate": 1.0954616588419406e-06,
|
| 984 |
+
"epoch": 4.753521126760563,
|
| 985 |
+
"step": 1350
|
| 986 |
+
},
|
| 987 |
+
{
|
| 988 |
+
"loss": 0.2294,
|
| 989 |
+
"grad_norm": 2.4718971252441406,
|
| 990 |
+
"learning_rate": 9.389671361502348e-07,
|
| 991 |
+
"epoch": 4.788732394366197,
|
| 992 |
+
"step": 1360
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"loss": 0.2916,
|
| 996 |
+
"grad_norm": 1.6896077394485474,
|
| 997 |
+
"learning_rate": 7.824726134585291e-07,
|
| 998 |
+
"epoch": 4.823943661971831,
|
| 999 |
+
"step": 1370
|
| 1000 |
+
},
|
| 1001 |
+
{
|
| 1002 |
+
"loss": 0.2454,
|
| 1003 |
+
"grad_norm": 1.6241123676300049,
|
| 1004 |
+
"learning_rate": 6.259780907668232e-07,
|
| 1005 |
+
"epoch": 4.859154929577465,
|
| 1006 |
+
"step": 1380
|
| 1007 |
+
},
|
| 1008 |
+
{
|
| 1009 |
+
"loss": 0.2732,
|
| 1010 |
+
"grad_norm": 1.5693773031234741,
|
| 1011 |
+
"learning_rate": 4.694835680751174e-07,
|
| 1012 |
+
"epoch": 4.894366197183099,
|
| 1013 |
+
"step": 1390
|
| 1014 |
+
},
|
| 1015 |
+
{
|
| 1016 |
+
"loss": 0.2474,
|
| 1017 |
+
"grad_norm": 1.2409546375274658,
|
| 1018 |
+
"learning_rate": 3.129890453834116e-07,
|
| 1019 |
+
"epoch": 4.929577464788732,
|
| 1020 |
+
"step": 1400
|
| 1021 |
+
},
|
| 1022 |
+
{
|
| 1023 |
+
"loss": 0.198,
|
| 1024 |
+
"grad_norm": 5.357175827026367,
|
| 1025 |
+
"learning_rate": 1.564945226917058e-07,
|
| 1026 |
+
"epoch": 4.964788732394366,
|
| 1027 |
+
"step": 1410
|
| 1028 |
+
},
|
| 1029 |
+
{
|
| 1030 |
+
"loss": 0.1852,
|
| 1031 |
+
"grad_norm": 0.5980310440063477,
|
| 1032 |
+
"learning_rate": 0.0,
|
| 1033 |
+
"epoch": 5.0,
|
| 1034 |
+
"step": 1420
|
| 1035 |
+
},
|
| 1036 |
+
{
|
| 1037 |
+
"eval_loss": 0.42191559076309204,
|
| 1038 |
+
"eval_accuracy": 0.9118942731277533,
|
| 1039 |
+
"eval_f1": 0.9167823247394992,
|
| 1040 |
+
"eval_runtime": 6.6973,
|
| 1041 |
+
"eval_samples_per_second": 169.471,
|
| 1042 |
+
"eval_steps_per_second": 10.601,
|
| 1043 |
+
"epoch": 5.0,
|
| 1044 |
+
"step": 1420
|
| 1045 |
+
},
|
| 1046 |
+
{
|
| 1047 |
+
"train_runtime": 510.4172,
|
| 1048 |
+
"train_samples_per_second": 44.454,
|
| 1049 |
+
"train_steps_per_second": 2.782,
|
| 1050 |
+
"total_flos": 1492886076971520.0,
|
| 1051 |
+
"train_loss": 1.0440410888530838,
|
| 1052 |
+
"epoch": 5.0,
|
| 1053 |
+
"step": 1420
|
| 1054 |
+
},
|
| 1055 |
+
{
|
| 1056 |
+
"eval_loss": 0.42191559076309204,
|
| 1057 |
+
"eval_accuracy": 0.9118942731277533,
|
| 1058 |
+
"eval_f1": 0.9167823247394992,
|
| 1059 |
+
"eval_runtime": 6.542,
|
| 1060 |
+
"eval_samples_per_second": 173.496,
|
| 1061 |
+
"eval_steps_per_second": 10.853,
|
| 1062 |
+
"epoch": 5.0,
|
| 1063 |
+
"step": 1420
|
| 1064 |
+
}
|
| 1065 |
+
]
|
Classification/Evaluation_metrics/training_loss_curve.png
ADDED
|
Git LFS Details
|
Classification/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Classification Package β BERT-based NEET Biology Question Classifier
|
Classification/checkpoints/best_model/config.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_name_or_path": "bert-base-uncased",
|
| 3 |
+
"architectures": [
|
| 4 |
+
"BertForSequenceClassification"
|
| 5 |
+
],
|
| 6 |
+
"attention_probs_dropout_prob": 0.1,
|
| 7 |
+
"classifier_dropout": null,
|
| 8 |
+
"gradient_checkpointing": false,
|
| 9 |
+
"hidden_act": "gelu",
|
| 10 |
+
"hidden_dropout_prob": 0.1,
|
| 11 |
+
"hidden_size": 768,
|
| 12 |
+
"id2label": {
|
| 13 |
+
"0": "LABEL_0",
|
| 14 |
+
"1": "LABEL_1",
|
| 15 |
+
"2": "LABEL_2",
|
| 16 |
+
"3": "LABEL_3",
|
| 17 |
+
"4": "LABEL_4",
|
| 18 |
+
"5": "LABEL_5",
|
| 19 |
+
"6": "LABEL_6",
|
| 20 |
+
"7": "LABEL_7",
|
| 21 |
+
"8": "LABEL_8",
|
| 22 |
+
"9": "LABEL_9",
|
| 23 |
+
"10": "LABEL_10",
|
| 24 |
+
"11": "LABEL_11",
|
| 25 |
+
"12": "LABEL_12",
|
| 26 |
+
"13": "LABEL_13",
|
| 27 |
+
"14": "LABEL_14",
|
| 28 |
+
"15": "LABEL_15",
|
| 29 |
+
"16": "LABEL_16",
|
| 30 |
+
"17": "LABEL_17",
|
| 31 |
+
"18": "LABEL_18",
|
| 32 |
+
"19": "LABEL_19",
|
| 33 |
+
"20": "LABEL_20",
|
| 34 |
+
"21": "LABEL_21",
|
| 35 |
+
"22": "LABEL_22",
|
| 36 |
+
"23": "LABEL_23",
|
| 37 |
+
"24": "LABEL_24",
|
| 38 |
+
"25": "LABEL_25",
|
| 39 |
+
"26": "LABEL_26",
|
| 40 |
+
"27": "LABEL_27",
|
| 41 |
+
"28": "LABEL_28",
|
| 42 |
+
"29": "LABEL_29",
|
| 43 |
+
"30": "LABEL_30"
|
| 44 |
+
},
|
| 45 |
+
"initializer_range": 0.02,
|
| 46 |
+
"intermediate_size": 3072,
|
| 47 |
+
"label2id": {
|
| 48 |
+
"LABEL_0": 0,
|
| 49 |
+
"LABEL_1": 1,
|
| 50 |
+
"LABEL_10": 10,
|
| 51 |
+
"LABEL_11": 11,
|
| 52 |
+
"LABEL_12": 12,
|
| 53 |
+
"LABEL_13": 13,
|
| 54 |
+
"LABEL_14": 14,
|
| 55 |
+
"LABEL_15": 15,
|
| 56 |
+
"LABEL_16": 16,
|
| 57 |
+
"LABEL_17": 17,
|
| 58 |
+
"LABEL_18": 18,
|
| 59 |
+
"LABEL_19": 19,
|
| 60 |
+
"LABEL_2": 2,
|
| 61 |
+
"LABEL_20": 20,
|
| 62 |
+
"LABEL_21": 21,
|
| 63 |
+
"LABEL_22": 22,
|
| 64 |
+
"LABEL_23": 23,
|
| 65 |
+
"LABEL_24": 24,
|
| 66 |
+
"LABEL_25": 25,
|
| 67 |
+
"LABEL_26": 26,
|
| 68 |
+
"LABEL_27": 27,
|
| 69 |
+
"LABEL_28": 28,
|
| 70 |
+
"LABEL_29": 29,
|
| 71 |
+
"LABEL_3": 3,
|
| 72 |
+
"LABEL_30": 30,
|
| 73 |
+
"LABEL_4": 4,
|
| 74 |
+
"LABEL_5": 5,
|
| 75 |
+
"LABEL_6": 6,
|
| 76 |
+
"LABEL_7": 7,
|
| 77 |
+
"LABEL_8": 8,
|
| 78 |
+
"LABEL_9": 9
|
| 79 |
+
},
|
| 80 |
+
"layer_norm_eps": 1e-12,
|
| 81 |
+
"max_position_embeddings": 512,
|
| 82 |
+
"model_type": "bert",
|
| 83 |
+
"num_attention_heads": 12,
|
| 84 |
+
"num_hidden_layers": 12,
|
| 85 |
+
"pad_token_id": 0,
|
| 86 |
+
"position_embedding_type": "absolute",
|
| 87 |
+
"problem_type": "single_label_classification",
|
| 88 |
+
"torch_dtype": "float32",
|
| 89 |
+
"transformers_version": "4.44.2",
|
| 90 |
+
"type_vocab_size": 2,
|
| 91 |
+
"use_cache": true,
|
| 92 |
+
"vocab_size": 30522
|
| 93 |
+
}
|
Classification/checkpoints/best_model/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4dc413b168615077249f695852209c7677b5f5c1e11ce559df894893b9e5fdf4
|
| 3 |
+
size 438047852
|
Classification/checkpoints/best_model/special_tokens_map.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cls_token": "[CLS]",
|
| 3 |
+
"mask_token": "[MASK]",
|
| 4 |
+
"pad_token": "[PAD]",
|
| 5 |
+
"sep_token": "[SEP]",
|
| 6 |
+
"unk_token": "[UNK]"
|
| 7 |
+
}
|
Classification/checkpoints/best_model/tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Classification/checkpoints/best_model/tokenizer_config.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"added_tokens_decoder": {
|
| 3 |
+
"0": {
|
| 4 |
+
"content": "[PAD]",
|
| 5 |
+
"lstrip": false,
|
| 6 |
+
"normalized": false,
|
| 7 |
+
"rstrip": false,
|
| 8 |
+
"single_word": false,
|
| 9 |
+
"special": true
|
| 10 |
+
},
|
| 11 |
+
"100": {
|
| 12 |
+
"content": "[UNK]",
|
| 13 |
+
"lstrip": false,
|
| 14 |
+
"normalized": false,
|
| 15 |
+
"rstrip": false,
|
| 16 |
+
"single_word": false,
|
| 17 |
+
"special": true
|
| 18 |
+
},
|
| 19 |
+
"101": {
|
| 20 |
+
"content": "[CLS]",
|
| 21 |
+
"lstrip": false,
|
| 22 |
+
"normalized": false,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false,
|
| 25 |
+
"special": true
|
| 26 |
+
},
|
| 27 |
+
"102": {
|
| 28 |
+
"content": "[SEP]",
|
| 29 |
+
"lstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false,
|
| 33 |
+
"special": true
|
| 34 |
+
},
|
| 35 |
+
"103": {
|
| 36 |
+
"content": "[MASK]",
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"normalized": false,
|
| 39 |
+
"rstrip": false,
|
| 40 |
+
"single_word": false,
|
| 41 |
+
"special": true
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"clean_up_tokenization_spaces": true,
|
| 45 |
+
"cls_token": "[CLS]",
|
| 46 |
+
"do_lower_case": true,
|
| 47 |
+
"mask_token": "[MASK]",
|
| 48 |
+
"model_max_length": 512,
|
| 49 |
+
"pad_token": "[PAD]",
|
| 50 |
+
"sep_token": "[SEP]",
|
| 51 |
+
"strip_accents": null,
|
| 52 |
+
"tokenize_chinese_chars": true,
|
| 53 |
+
"tokenizer_class": "BertTokenizer",
|
| 54 |
+
"unk_token": "[UNK]"
|
| 55 |
+
}
|
Classification/checkpoints/best_model/training_args.bin
ADDED
|
Binary file (5.18 kB). View file
|
|
|
Classification/checkpoints/best_model/vocab.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Classification/classify_and_extract.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
classify_and_extract.py β BERT Chapter Classifier + Topic Extractor
|
| 3 |
+
|
| 4 |
+
Orchestrates:
|
| 5 |
+
1. BERT classifier β predicts which NCERT chapter a question belongs to
|
| 6 |
+
2. Supabase retriever β finds relevant chunks within that chapter
|
| 7 |
+
3. Topic extractor β extracts unique topics/subtopics from retrieved chunks
|
| 8 |
+
|
| 9 |
+
Usage:
|
| 10 |
+
from Classification.classify_and_extract import classify_question
|
| 11 |
+
result = classify_question("What is the role of cofactors in enzyme activity?")
|
| 12 |
+
print(result)
|
| 13 |
+
|
| 14 |
+
Returns:
|
| 15 |
+
{
|
| 16 |
+
"chapter": "Biomolecules",
|
| 17 |
+
"chapter_id": 8,
|
| 18 |
+
"chapter_confidence": 0.94,
|
| 19 |
+
"topics": [
|
| 20 |
+
{"section_code": "9.8", "section_title": "Enzymes", "similarity": 0.82},
|
| 21 |
+
{"section_code": "9.8.6", "section_title": "Co-factors", "similarity": 0.71},
|
| 22 |
+
]
|
| 23 |
+
}
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
from Classification.predict import ClassifierPredictor
|
| 27 |
+
from rag.retriever import retrieve_chunks
|
| 28 |
+
|
| 29 |
+
# ==============================
|
| 30 |
+
# CONFIG
|
| 31 |
+
# ==============================
|
| 32 |
+
TOPIC_SIMILARITY_THRESHOLD = 0.45 # Minimum similarity to consider a topic relevant
|
| 33 |
+
MAX_TOPICS = 3 # Maximum topics/subtopics to return
|
| 34 |
+
MIN_TOPICS = 1 # Minimum topics to always return (top-1 fallback)
|
| 35 |
+
RETRIEVAL_TOP_K = 10 # Fetch more chunks to find diverse topics
|
| 36 |
+
|
| 37 |
+
# ==============================
|
| 38 |
+
# SINGLETON PREDICTOR
|
| 39 |
+
# ==============================
|
| 40 |
+
_predictor: ClassifierPredictor = None
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def get_predictor() -> ClassifierPredictor:
|
| 44 |
+
global _predictor
|
| 45 |
+
if _predictor is None:
|
| 46 |
+
_predictor = ClassifierPredictor()
|
| 47 |
+
return _predictor
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# ==============================
|
| 51 |
+
# MAIN FUNCTION
|
| 52 |
+
# ==============================
|
| 53 |
+
def classify_question(
|
| 54 |
+
question: str,
|
| 55 |
+
similarity_threshold: float = TOPIC_SIMILARITY_THRESHOLD,
|
| 56 |
+
max_topics: int = MAX_TOPICS,
|
| 57 |
+
min_topics: int = MIN_TOPICS,
|
| 58 |
+
) -> dict:
|
| 59 |
+
"""
|
| 60 |
+
Classify a NEET Biology question into chapter + topic/subtopic.
|
| 61 |
+
|
| 62 |
+
Steps:
|
| 63 |
+
1. BERT predicts the chapter (91.7% F1 accuracy)
|
| 64 |
+
2. Retriever fetches top-k chunks filtered to that chapter
|
| 65 |
+
3. Unique (section_code, section_title) pairs are extracted
|
| 66 |
+
4. Filtered by similarity threshold, capped at max_topics
|
| 67 |
+
5. At least min_topics are always returned (fallback to top-1)
|
| 68 |
+
|
| 69 |
+
Args:
|
| 70 |
+
question : The student's question.
|
| 71 |
+
similarity_threshold : Min similarity score for a topic to qualify.
|
| 72 |
+
max_topics : Maximum number of topics to return.
|
| 73 |
+
min_topics : Minimum number of topics to always return.
|
| 74 |
+
|
| 75 |
+
Returns:
|
| 76 |
+
{
|
| 77 |
+
"chapter": str,
|
| 78 |
+
"chapter_id": int,
|
| 79 |
+
"chapter_confidence": float,
|
| 80 |
+
"topics": [
|
| 81 |
+
{"section_code": str, "section_title": str, "similarity": float},
|
| 82 |
+
...
|
| 83 |
+
]
|
| 84 |
+
}
|
| 85 |
+
"""
|
| 86 |
+
# ββ Step 1: BERT Chapter Prediction ββ
|
| 87 |
+
predictor = get_predictor()
|
| 88 |
+
bert_result = predictor.predict(question)
|
| 89 |
+
|
| 90 |
+
chapter_name = bert_result["chapter"]
|
| 91 |
+
chapter_id = bert_result["chapter_id"]
|
| 92 |
+
chapter_confidence = bert_result["confidence"]
|
| 93 |
+
rejected = bert_result.get("rejected", False)
|
| 94 |
+
rejection_reason = bert_result.get("rejection_reason", "")
|
| 95 |
+
entropy = bert_result.get("entropy", 0.0)
|
| 96 |
+
margin = bert_result.get("margin", 0.0)
|
| 97 |
+
|
| 98 |
+
print(f"[Classify] BERT β {chapter_name} (confidence: {chapter_confidence:.2%})")
|
| 99 |
+
|
| 100 |
+
if rejected:
|
| 101 |
+
print(f"[Classify] β Rejected: {rejection_reason}")
|
| 102 |
+
return {
|
| 103 |
+
"chapter": chapter_name,
|
| 104 |
+
"chapter_id": chapter_id,
|
| 105 |
+
"chapter_confidence": chapter_confidence,
|
| 106 |
+
"topics": [],
|
| 107 |
+
"rejected": rejected,
|
| 108 |
+
"rejection_reason": rejection_reason,
|
| 109 |
+
"entropy": entropy,
|
| 110 |
+
"margin": margin
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
# ββ Step 2: Retrieve chunks filtered by predicted chapter ββ
|
| 114 |
+
chunks = retrieve_chunks(
|
| 115 |
+
question,
|
| 116 |
+
chapter_filter=chapter_name,
|
| 117 |
+
top_k=RETRIEVAL_TOP_K,
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
if not chunks:
|
| 121 |
+
print("[Classify] β οΈ No chunks retrieved β returning chapter only.")
|
| 122 |
+
return {
|
| 123 |
+
"chapter": chapter_name,
|
| 124 |
+
"chapter_id": chapter_id,
|
| 125 |
+
"chapter_confidence": chapter_confidence,
|
| 126 |
+
"topics": [],
|
| 127 |
+
"rejected": False,
|
| 128 |
+
"rejection_reason": "",
|
| 129 |
+
"entropy": entropy,
|
| 130 |
+
"margin": margin
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
# ββ Step 3: Extract unique topics, keeping highest similarity per topic ββ
|
| 134 |
+
topic_map = {} # key: (section_code, section_title) β best similarity
|
| 135 |
+
|
| 136 |
+
for chunk in chunks:
|
| 137 |
+
section_code = chunk.get("section") or ""
|
| 138 |
+
section_title = chunk.get("section_title") or ""
|
| 139 |
+
similarity = chunk.get("similarity", 0.0)
|
| 140 |
+
|
| 141 |
+
if not section_code and not section_title:
|
| 142 |
+
continue
|
| 143 |
+
|
| 144 |
+
key = (section_code, section_title)
|
| 145 |
+
|
| 146 |
+
# Keep the highest similarity for each unique topic
|
| 147 |
+
if key not in topic_map or similarity > topic_map[key]:
|
| 148 |
+
topic_map[key] = similarity
|
| 149 |
+
|
| 150 |
+
# Sort by similarity descending
|
| 151 |
+
sorted_topics = sorted(topic_map.items(), key=lambda x: x[1], reverse=True)
|
| 152 |
+
|
| 153 |
+
# ββ Step 4: Apply threshold + min/max constraints ββ
|
| 154 |
+
filtered = [
|
| 155 |
+
{
|
| 156 |
+
"section_code": code,
|
| 157 |
+
"section_title": title,
|
| 158 |
+
"similarity": round(sim, 4),
|
| 159 |
+
}
|
| 160 |
+
for (code, title), sim in sorted_topics
|
| 161 |
+
if sim >= similarity_threshold
|
| 162 |
+
]
|
| 163 |
+
|
| 164 |
+
# Cap at max_topics
|
| 165 |
+
filtered = filtered[:max_topics]
|
| 166 |
+
|
| 167 |
+
# Fallback: if nothing passes threshold, always return top-1
|
| 168 |
+
if len(filtered) < min_topics and sorted_topics:
|
| 169 |
+
for i in range(min(min_topics, len(sorted_topics))):
|
| 170 |
+
(code, title), sim = sorted_topics[i]
|
| 171 |
+
entry = {
|
| 172 |
+
"section_code": code,
|
| 173 |
+
"section_title": title,
|
| 174 |
+
"similarity": round(sim, 4),
|
| 175 |
+
}
|
| 176 |
+
if entry not in filtered:
|
| 177 |
+
filtered.append(entry)
|
| 178 |
+
filtered = filtered[:max_topics]
|
| 179 |
+
|
| 180 |
+
print(f"[Classify] Topics found: {len(filtered)}")
|
| 181 |
+
for t in filtered:
|
| 182 |
+
print(f" β {t['section_code']} - {t['section_title']} (sim: {t['similarity']:.4f})")
|
| 183 |
+
|
| 184 |
+
return {
|
| 185 |
+
"chapter": chapter_name,
|
| 186 |
+
"chapter_id": chapter_id,
|
| 187 |
+
"chapter_confidence": chapter_confidence,
|
| 188 |
+
"topics": filtered,
|
| 189 |
+
"rejected": rejected,
|
| 190 |
+
"rejection_reason": rejection_reason,
|
| 191 |
+
"entropy": entropy,
|
| 192 |
+
"margin": margin
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
# ==============================
|
| 197 |
+
# QUICK TEST
|
| 198 |
+
# ==============================
|
| 199 |
+
if __name__ == "__main__":
|
| 200 |
+
test_questions = [
|
| 201 |
+
"What is the role of cofactors in enzyme activity?",
|
| 202 |
+
"Explain the process of meiosis and its significance.",
|
| 203 |
+
"What are the different types of immunity?",
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
for q in test_questions:
|
| 207 |
+
print(f"\n{'='*60}")
|
| 208 |
+
print(f"Q: {q}")
|
| 209 |
+
print(f"{'='*60}")
|
| 210 |
+
result = classify_question(q)
|
| 211 |
+
print(f"\nπ Chapter: {result['chapter']} (confidence: {result['chapter_confidence']:.2%})")
|
| 212 |
+
print(f"π Topics:")
|
| 213 |
+
for t in result['topics']:
|
| 214 |
+
print(f" {t['section_code']} β {t['section_title']} (similarity: {t['similarity']:.4f})")
|
Classification/config.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model_name": "bert-base-uncased",
|
| 3 |
+
"max_length": 128,
|
| 4 |
+
"num_labels": 31,
|
| 5 |
+
"batch_size": 16,
|
| 6 |
+
"learning_rate": 2e-5,
|
| 7 |
+
"num_epochs": 5,
|
| 8 |
+
"warmup_ratio": 0.1,
|
| 9 |
+
"weight_decay": 0.01,
|
| 10 |
+
"max_grad_norm": 1.0,
|
| 11 |
+
"lr_scheduler_type": "linear",
|
| 12 |
+
"output_dir": "Classification/checkpoints",
|
| 13 |
+
"logging_steps": 10,
|
| 14 |
+
"evaluation_strategy": "epoch",
|
| 15 |
+
"save_strategy": "epoch",
|
| 16 |
+
"load_best_model_at_end": true,
|
| 17 |
+
"metric_for_best_model": "f1",
|
| 18 |
+
"seed": 42
|
| 19 |
+
}
|
Classification/data/label_map.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"0": "The Living World",
|
| 3 |
+
"1": "Biological Classification",
|
| 4 |
+
"2": "Plant Kingdom",
|
| 5 |
+
"3": "Animal Kingdom",
|
| 6 |
+
"4": "Morphology of Flowering Plants",
|
| 7 |
+
"5": "Anatomy of Flowering Plants",
|
| 8 |
+
"6": "Structural Organisation in Animals",
|
| 9 |
+
"7": "Cell: The Unit of Life",
|
| 10 |
+
"8": "Biomolecules",
|
| 11 |
+
"9": "Cell Cycle and Cell Division",
|
| 12 |
+
"10": "Photosynthesis in Higher Plants",
|
| 13 |
+
"11": "Respiration in Plants",
|
| 14 |
+
"12": "Plant Growth and Development",
|
| 15 |
+
"13": "Breathing and Exchange of Gases",
|
| 16 |
+
"14": "Body Fluids and Circulation",
|
| 17 |
+
"15": "Excretory Products and their Elimination",
|
| 18 |
+
"16": "Locomotion and Movement",
|
| 19 |
+
"17": "Neural Control and Coordination",
|
| 20 |
+
"18": "Chemical Coordination and Integration",
|
| 21 |
+
"19": "Human Reproduction",
|
| 22 |
+
"20": "Reproductive Health",
|
| 23 |
+
"21": "Principles of Inheritance and Variation",
|
| 24 |
+
"22": "Molecular Basis of Inheritance",
|
| 25 |
+
"23": "Evolution",
|
| 26 |
+
"24": "Human Health and Disease",
|
| 27 |
+
"25": "Microbes in Human Welfare",
|
| 28 |
+
"26": "Biotechnology: Principles and Processes",
|
| 29 |
+
"27": "Biotechnology and Its Applications",
|
| 30 |
+
"28": "Organisms and Populations",
|
| 31 |
+
"29": "Ecosystem",
|
| 32 |
+
"30": "Biodiversity and Conservation"
|
| 33 |
+
}
|
Classification/data/new_generated_questions.json
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"question": "A patient exhibits excessive dilute urine production and low blood pressure. If this condition is caused by a lack of ADH, which structures in the nephron and which endocrine gland are primarily involved?",
|
| 4 |
+
"chapter_ids": [15, 18]
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"question": "How does the syncytial nature of cardiac muscle fibers allow for the coordinated contraction of the heart chambers, and how is this regulated by the autonomic nervous system?",
|
| 8 |
+
"chapter_ids": [6, 14, 17]
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"question": "Which specific phase of Prophase I in meiosis is responsible for the genetic recombination that leads to variations observed in the F2 generation of a Mendelian dihybrid cross?",
|
| 12 |
+
"chapter_ids": [9, 21]
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"question": "Compare the structure of the cell wall in Monerans, Fungi, and Plantae, and identify which kingdom utilizes chitin as a primary structural polysaccharide.",
|
| 16 |
+
"chapter_ids": [1, 7, 8]
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"question": "During photorespiration, the oxygenation of RuBP occurs in the chloroplast. In which two other organelles do the subsequent steps of this 'wasteful' process take place?",
|
| 20 |
+
"chapter_ids": [7, 10]
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"question": "In the human female reproductive cycle, which hormone surge triggers ovulation, and which structure is formed from the remains of the Graafian follicle to maintain the endometrium?",
|
| 24 |
+
"chapter_ids": [18, 19]
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"question": "How does the secretion of HCl by parietal cells in the stomach create an acidic environment necessary for the activation of proenzymes involved in protein digestion?",
|
| 28 |
+
"chapter_ids": [8, 13]
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"question": "Identify the type of aestivation where margins of sepals or petals overlap one another but not in any particular direction, commonly seen in Cassia and Gulmohur.",
|
| 32 |
+
"chapter_ids": [4]
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"question": "In a DNA molecule, if the percentage of Cytosine is 20%, calculate the percentage of Adenine using Chargaff's rule.",
|
| 36 |
+
"chapter_ids": [22, 8]
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"question": "Explain how the 'lock and key' hypothesis of enzyme action relates to the tertiary structure of proteins and the concept of competitive inhibition.",
|
| 40 |
+
"chapter_ids": [8, 26]
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"question": "Which phytohormone is responsible for apical dominance, and how is its transport affected when the shoot tip is removed in tea plantations?",
|
| 44 |
+
"chapter_ids": [12, 4]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"question": "Differentiate between the vascular bundles of a dicot stem and a monocot stem based on the presence of cambium and the arrangement of tissues.",
|
| 48 |
+
"chapter_ids": [5]
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"question": "A person living at high altitudes has a higher RBC count than someone living in the plains. This is an example of which type of adaptation and which organ releases the stimulating hormone?",
|
| 52 |
+
"chapter_ids": [14, 18, 28]
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"question": "Describe the flow of energy through a detritus food chain compared to a grazing food chain in a terrestrial ecosystem.",
|
| 56 |
+
"chapter_ids": [29]
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"question": "How do the p-p bonds in ATP store energy, and how is this energy utilized during the sliding filament theory of muscle contraction?",
|
| 60 |
+
"chapter_ids": [8, 11, 16]
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"question": "Identify the primary messenger and the secondary messenger (like cAMP) involved in the mechanism of action of water-soluble hormones.",
|
| 64 |
+
"chapter_ids": [18, 8]
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"question": "In the lac operon, what is the role of the inducer (lactose), and how does its absence affect the binding of RNA polymerase to the promoter?",
|
| 68 |
+
"chapter_ids": [22]
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"question": "Which specific immune cells are targeted by the HIV virus, and how does this lead to the opportunistic infections seen in AIDS patients?",
|
| 72 |
+
"chapter_ids": [24, 25]
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"question": "How does the use of statins, produced by the yeast Monascus purpureus, lower blood cholesterol levels through competitive inhibition?",
|
| 76 |
+
"chapter_ids": [25, 8]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"question": "The use of Bt-toxin in cotton plants targets which specific order of insects, and what is the physiological mechanism of its action in the insect gut?",
|
| 80 |
+
"chapter_ids": [27, 3]
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"question": "Distinguish between 'In-situ' and 'Ex-situ' conservation strategies, and classify a 'Sacred Grove' and a 'Zoological Park' accordingly.",
|
| 84 |
+
"chapter_ids": [30]
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"question": "What is the evolutionary significance of the 'Analogy' seen in the wings of a butterfly and a bird, and does it represent convergent or divergent evolution?",
|
| 88 |
+
"chapter_ids": [23, 3]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"question": "Explain the process of 'Translation' in protein synthesis, specifically the role of aminoacyl-tRNA synthetase and the Ribosome's P and A sites.",
|
| 92 |
+
"chapter_ids": [22, 7]
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"question": "In an ECG, what does the T-wave represent, and how does a flattened T-wave correlate with the oxygenation of the heart muscle?",
|
| 96 |
+
"chapter_ids": [14]
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"question": "During the C4 pathway, why is the CO2 fixation in bundle sheath cells considered more efficient in preventing photorespiration than in C3 plants?",
|
| 100 |
+
"chapter_ids": [10, 5]
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"question": "Which part of the brain is responsible for thermoregulation and the control of the master endocrine gland?",
|
| 104 |
+
"chapter_ids": [17, 18]
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"question": "If a father is colorblind and the mother is a carrier, what is the probability that their son will be colorblind?",
|
| 108 |
+
"chapter_ids": [21]
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"question": "Identify the unique features of the phylum Echinodermata, specifically their water vascular system and its role in locomotion.",
|
| 112 |
+
"chapter_ids": [3, 16]
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"question": "Describe the 'Z-scheme' of light reaction and the role of the oxygen-evolving complex in Phostosystem II.",
|
| 116 |
+
"chapter_ids": [10]
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"question": "What is the difference between 'Innate Immunity' and 'Acquired Immunity' in terms of specificity and memory?",
|
| 120 |
+
"chapter_ids": [24]
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"question": "How does the increase in BOD (Biochemical Oxygen Demand) indicate the level of organic pollution in a water body?",
|
| 124 |
+
"chapter_ids": [25, 29]
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"question": "In the process of PCR, explain the importance of 'Taq Polymerase' and why it must be thermostable.",
|
| 128 |
+
"chapter_ids": [26, 1]
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"question": "Which specific mineral ion is essential for the photolysis of water during photosynthesis and the maintenance of the ribosome structure?",
|
| 132 |
+
"chapter_ids": [10, 7]
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"question": "How do 'barrier methods' of contraception differ from 'IUDs' in terms of preventing fertilization versus implantation?",
|
| 136 |
+
"chapter_ids": [20, 19]
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"question": "Describe the transition from a 'Notochord' to a 'Vertebral Column' during the embryonic development of higher vertebrates.",
|
| 140 |
+
"chapter_ids": [3, 23]
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"question": "In the Krebs cycle, which 4-carbon compound combines with Acetyl CoA to form Citric Acid?",
|
| 144 |
+
"chapter_ids": [11]
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
"question": "Identify the hormonal changes that lead to 'Parturition' and the role of the 'Fetal Ejection Reflex'.",
|
| 148 |
+
"chapter_ids": [19, 18]
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"question": "What is 'Saltatory Conduction', and how does the presence of Myelin sheaths and Nodes of Ranvier speed up nerve impulse transmission?",
|
| 152 |
+
"chapter_ids": [17, 6]
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"question": "Discuss the 'Competitive Exclusion Principle' by Gause and how it applies to the distribution of species in a niche.",
|
| 156 |
+
"chapter_ids": [28]
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"question": "Which taxonomic category is the most inclusive and which is the most specific in the hierarchy of classification?",
|
| 160 |
+
"chapter_ids": [0]
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"question": "Explain the significance of 'Double Fertilization' in Angiosperms and the resulting ploidy of the endosperm.",
|
| 164 |
+
"chapter_ids": [2, 19]
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"question": "How do 'Restriction Endonucleases' identify palindromic sequences in DNA for gene cloning?",
|
| 168 |
+
"chapter_ids": [26, 22]
|
| 169 |
+
},
|
| 170 |
+
{
|
| 171 |
+
"question": "What is the role of 'Pneumatophores' in plants like Rhizophora, and in which specific ecosystem are they found?",
|
| 172 |
+
"chapter_ids": [4, 28]
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"question": "Describe the Bohr effect and how the partial pressure of CO2 influences the oxygen dissociation curve of hemoglobin.",
|
| 176 |
+
"chapter_ids": [13, 14]
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"question": "How does the 'Symplastic' pathway of water movement in roots differ from the 'Apoplastic' pathway regarding the Casparian strip?",
|
| 180 |
+
"chapter_ids": [5, 12]
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"question": "What are 'Homologous Organs', and how do they provide evidence for 'Adaptive Radiation' using the example of Darwin's finches?",
|
| 184 |
+
"chapter_ids": [23]
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"question": "Which enzyme is responsible for the conversion of glucose-6-phosphate to fructose-6-phosphate in glycolysis?",
|
| 188 |
+
"chapter_ids": [11, 8]
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"question": "Identify the structural differences between 'Smooth Endoplasmic Reticulum' and 'Rough Endoplasmic Reticulum' and their primary functions.",
|
| 192 |
+
"chapter_ids": [7]
|
| 193 |
+
},
|
| 194 |
+
{
|
| 195 |
+
"question": "In a population of 1000 individuals, if the frequency of a recessive allele is 0.4, calculate the number of heterozygous individuals using the Hardy-Weinberg principle.",
|
| 196 |
+
"chapter_ids": [23, 21]
|
| 197 |
+
},
|
| 198 |
+
{
|
| 199 |
+
"question": "Explain the role of 'Meiosis II' in the production of male gametes in humans and the resulting number of spermatids.",
|
| 200 |
+
"chapter_ids": [19, 9]
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"question": "What is 'Apomixis', and why is it commercially significant in the hybrid seed industry?",
|
| 204 |
+
"chapter_ids": [2, 21]
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"question": "Identify the hormone secreted by the Heart wall that helps in reducing blood pressure.",
|
| 208 |
+
"chapter_ids": [14, 18]
|
| 209 |
+
},
|
| 210 |
+
{
|
| 211 |
+
"question": "During muscle contraction, which band within the sarcomere remains constant in length while others shorten?",
|
| 212 |
+
"chapter_ids": [16, 6]
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"question": "How does 'Mutualism' differ from 'Commensalism' using the example of the Fig tree and the Wasp?",
|
| 216 |
+
"chapter_ids": [28]
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"question": "Which secondary metabolite is used as a drug for treating cancer, and from which plant is it derived?",
|
| 220 |
+
"chapter_ids": [8, 0]
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"question": "What is the function of the 'Tapetum' in the microsporangium wall of a flowering plant?",
|
| 224 |
+
"chapter_ids": [2]
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"question": "How does the 'Counter Current Mechanism' in the Henle's loop and vasa recta help in the concentration of urine?",
|
| 228 |
+
"chapter_ids": [15, 14]
|
| 229 |
+
},
|
| 230 |
+
{
|
| 231 |
+
"question": "Explain 'RNA Interference' (RNAi) as a method of cellular defense in plants against nematode infestation.",
|
| 232 |
+
"chapter_ids": [27, 22]
|
| 233 |
+
},
|
| 234 |
+
{
|
| 235 |
+
"question": "What is 'Pedigree Analysis', and how can it be used to determine if a trait is autosomal dominant or X-linked recessive?",
|
| 236 |
+
"chapter_ids": [21]
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"question": "Identify the three main types of 'RNA' involved in protein synthesis and their specific roles.",
|
| 240 |
+
"chapter_ids": [22, 7]
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"question": "Describe the structure of 'Flagella' in prokaryotes versus eukaryotes and the arrangement of microtubules in the latter.",
|
| 244 |
+
"chapter_ids": [1, 7]
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"question": "How does 'Eutrophication' lead to the depletion of oxygen in a lake and the subsequent death of aquatic life?",
|
| 248 |
+
"chapter_ids": [29, 30]
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"question": "Identify the gland that acts as both exocrine and endocrine, and name the hormones it secretes to regulate blood glucose levels.",
|
| 252 |
+
"chapter_ids": [18, 8]
|
| 253 |
+
},
|
| 254 |
+
{
|
| 255 |
+
"question": "What is the 'Link Reaction' in aerobic respiration, and what are its products before entering the Krebs cycle?",
|
| 256 |
+
"chapter_ids": [11]
|
| 257 |
+
},
|
| 258 |
+
{
|
| 259 |
+
"question": "How does 'Natural Selection' act on 'Industrial Melanism' in the case of the Peppered Moth in England?",
|
| 260 |
+
"chapter_ids": [23]
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"question": "Which enzyme is used to join the 'Okazaki fragments' on the lagging strand during DNA replication?",
|
| 264 |
+
"chapter_ids": [22, 26]
|
| 265 |
+
},
|
| 266 |
+
{
|
| 267 |
+
"question": "Explain the concept of 'Resource Partitioning' as a mechanism to avoid competition among species.",
|
| 268 |
+
"chapter_ids": [28]
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"question": "What is the function of 'Leydig Cells' in the testes and which hormone stimulates them?",
|
| 272 |
+
"chapter_ids": [19, 18]
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"question": "Distinguish between 'Incomplete Dominance' and 'Co-dominance' using the examples of Snapdragons and ABO blood groups.",
|
| 276 |
+
"chapter_ids": [21, 14]
|
| 277 |
+
},
|
| 278 |
+
{
|
| 279 |
+
"question": "How do 'Methanogens' contribute to the production of biogas in a rural setting?",
|
| 280 |
+
"chapter_ids": [1, 25]
|
| 281 |
+
},
|
| 282 |
+
{
|
| 283 |
+
"question": "Describe the role of 'Phycoerythrin' in Rhodophyceae and how it enables them to live in deep sea waters.",
|
| 284 |
+
"chapter_ids": [2, 10]
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"question": "Which part of the human ear is responsible for maintaining body balance and posture?",
|
| 288 |
+
"chapter_ids": [17]
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"question": "Identify the stage of the cell cycle where 'DNA Replication' occurs and the amount of DNA per cell is doubled.",
|
| 292 |
+
"chapter_ids": [9, 7]
|
| 293 |
+
},
|
| 294 |
+
{
|
| 295 |
+
"question": "How does 'Gene Gun' (Biolistics) differ from 'Micro-injection' as a method of introducing alien DNA into host cells?",
|
| 296 |
+
"chapter_ids": [26]
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"question": "What is 'Ecological Succession', and distinguish between 'Hydrarch' and 'Xerarch' succession.",
|
| 300 |
+
"chapter_ids": [29]
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"question": "How do 'Stomata' open and close based on the turgidity of 'Guard Cells'?",
|
| 304 |
+
"chapter_ids": [12, 5]
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"question": "Explain the significance of the 'S-shaped' (Sigmoid) growth curve in a population with limited resources.",
|
| 308 |
+
"chapter_ids": [28, 12]
|
| 309 |
+
},
|
| 310 |
+
{
|
| 311 |
+
"question": "What are 'Prions', and how do they differ from 'Viruses' and 'Viroids' in terms of composition?",
|
| 312 |
+
"chapter_ids": [1]
|
| 313 |
+
},
|
| 314 |
+
{
|
| 315 |
+
"question": "Identify the primary lymphoid organs where immature lymphocytes differentiate into antigen-sensitive lymphocytes.",
|
| 316 |
+
"chapter_ids": [24]
|
| 317 |
+
},
|
| 318 |
+
{
|
| 319 |
+
"question": "Describe the 'Placentation' where ovules are borne on the central axis and septa are absent, as seen in Dianthus.",
|
| 320 |
+
"chapter_ids": [4]
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"question": "How does 'Ethylene' act as a gaseous phytohormone in fruit ripening and the 'Respiratory Climacteric'?",
|
| 324 |
+
"chapter_ids": [12, 11]
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"question": "What is 'Down's Syndrome', and how does it relate to 'Aneuploidy' during meiosis?",
|
| 328 |
+
"chapter_ids": [21, 9]
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"question": "Identify the specific enzyme that facilitates the formation of a peptide bond between two amino acids.",
|
| 332 |
+
"chapter_ids": [8, 22]
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"question": "Describe the structure of 'Myoglobin' and its affinity for oxygen compared to hemoglobin in muscle tissues.",
|
| 336 |
+
"chapter_ids": [8, 16, 13]
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"question": "What is 'Biofortification', and how can it help in addressing 'Hidden Hunger' in developing countries?",
|
| 340 |
+
"chapter_ids": [25, 27]
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"question": "How does 'Allosteric Regulation' control metabolic pathways through feedback inhibition?",
|
| 344 |
+
"chapter_ids": [8]
|
| 345 |
+
},
|
| 346 |
+
{
|
| 347 |
+
"question": "Explain the 'Fluid Mosaic Model' of the plasma membrane and the role of 'Integral Proteins'.",
|
| 348 |
+
"chapter_ids": [7]
|
| 349 |
+
},
|
| 350 |
+
{
|
| 351 |
+
"question": "What is 'Species Diversity', and how does it vary with latitude from the equator to the poles?",
|
| 352 |
+
"chapter_ids": [30]
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"question": "Identify the vector for 'Malaria' and 'Filariasis' and the causative organisms involved in each.",
|
| 356 |
+
"chapter_ids": [24, 3]
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"question": "How does 'Gene Flow' differ from 'Genetic Drift' in changing the allele frequencies of a population?",
|
| 360 |
+
"chapter_ids": [23]
|
| 361 |
+
},
|
| 362 |
+
{
|
| 363 |
+
"question": "What is the 'Corpus Luteum', and how does its degeneration lead to 'Menstruation' if fertilization does not occur?",
|
| 364 |
+
"chapter_ids": [19, 18]
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
"question": "Describe the role of 'Carbonic Anhydrase' in the transport of CO2 in the blood.",
|
| 368 |
+
"chapter_ids": [13, 14, 8]
|
| 369 |
+
},
|
| 370 |
+
{
|
| 371 |
+
"question": "Which stage of the 'Plasmodium' life cycle is infectious to humans, and where does fertilization of the parasite occur?",
|
| 372 |
+
"chapter_ids": [24, 3]
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
"question": "How does the 'Hypothalamus' regulate the secretion of 'Thyroid Stimulating Hormone' (TSH) from the pituitary?",
|
| 376 |
+
"chapter_ids": [18, 17]
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"question": "Explain the term 'Totipotency' and its application in 'Plant Tissue Culture'.",
|
| 380 |
+
"chapter_ids": [27, 12]
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"question": "What is 'Competitive Inhibition' of enzymes, and use the example of 'Malonate' and 'Succinate Dehydrogenase'.",
|
| 384 |
+
"chapter_ids": [8, 11]
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"question": "Describe the 'Double Helix' structure of DNA, focusing on the anti-parallel nature of the two strands.",
|
| 388 |
+
"chapter_ids": [22, 8]
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
"question": "What are 'Pioneer Species', and what is their role in 'Primary Succession' on a bare rock?",
|
| 392 |
+
"chapter_ids": [29, 2]
|
| 393 |
+
},
|
| 394 |
+
{
|
| 395 |
+
"question": "Identify the cells in the 'Islets of Langerhans' that secrete 'Glucagon' and 'Insulin'.",
|
| 396 |
+
"chapter_ids": [18, 8]
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
"question": "How does 'Global Warming' affect the 'Hydrological Cycle' and the distribution of biomes?",
|
| 400 |
+
"chapter_ids": [29, 28]
|
| 401 |
+
}
|
| 402 |
+
]
|
Classification/data/sample_questions.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"question": "Which of the following is the powerhouse of the cell?",
|
| 4 |
+
"chapter": "Cell: The Unit of Life",
|
| 5 |
+
"chapter_id": 8
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
"question": "What is the function of ribosomes in a cell?",
|
| 9 |
+
"chapter": "Cell: The Unit of Life",
|
| 10 |
+
"chapter_id": 8
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"question": "Which enzyme breaks down starch into maltose?",
|
| 14 |
+
"chapter": "Biomolecules",
|
| 15 |
+
"chapter_id": 9
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"question": "What is the role of cofactors in enzyme activity?",
|
| 19 |
+
"chapter": "Biomolecules",
|
| 20 |
+
"chapter_id": 9
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"question": "What is binomial nomenclature?",
|
| 24 |
+
"chapter": "The Living World",
|
| 25 |
+
"chapter_id": 1
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"question": "Who proposed the two-kingdom classification system?",
|
| 29 |
+
"chapter": "Biological Classification",
|
| 30 |
+
"chapter_id": 2
|
| 31 |
+
}
|
| 32 |
+
]
|
Classification/data/train_split.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Classification/data/val_split.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Classification/dataset.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
dataset.py β PyTorch Dataset for NEET Biology question classification
|
| 3 |
+
|
| 4 |
+
Expected JSON format for training data (see data/sample_questions.json):
|
| 5 |
+
[
|
| 6 |
+
{
|
| 7 |
+
"question" : "Which organelle is the powerhouse of the cell?",
|
| 8 |
+
"chapter" : "Cell: The Unit of Life",
|
| 9 |
+
"chapter_id" : 8 β integer label, must start from 0, contiguous
|
| 10 |
+
},
|
| 11 |
+
...
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
chapter_id mapping MUST be consistent and saved separately in label_map.json.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import json
|
| 18 |
+
import torch
|
| 19 |
+
from torch.utils.data import Dataset
|
| 20 |
+
from transformers import AutoTokenizer
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class NEETDataset(Dataset):
|
| 24 |
+
"""
|
| 25 |
+
Tokenizes NEET Biology questions for BertForSequenceClassification.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
def __init__(self, data_path: str, tokenizer: AutoTokenizer, max_length: int = 128):
|
| 29 |
+
"""
|
| 30 |
+
Args:
|
| 31 |
+
data_path : Path to JSON file with labeled questions.
|
| 32 |
+
tokenizer : HuggingFace tokenizer (bert-base-uncased).
|
| 33 |
+
max_length : Max token length β 128 is fine for single questions.
|
| 34 |
+
"""
|
| 35 |
+
with open(data_path, "r", encoding="utf-8") as f:
|
| 36 |
+
self.data = json.load(f)
|
| 37 |
+
|
| 38 |
+
self.tokenizer = tokenizer
|
| 39 |
+
self.max_length = max_length
|
| 40 |
+
|
| 41 |
+
def __len__(self):
|
| 42 |
+
return len(self.data)
|
| 43 |
+
|
| 44 |
+
def __getitem__(self, idx):
|
| 45 |
+
item = self.data[idx]
|
| 46 |
+
question = item["question"]
|
| 47 |
+
label = item["chapter_id"] # integer class label
|
| 48 |
+
|
| 49 |
+
encoding = self.tokenizer(
|
| 50 |
+
question,
|
| 51 |
+
max_length=self.max_length,
|
| 52 |
+
padding="max_length",
|
| 53 |
+
truncation=True,
|
| 54 |
+
return_tensors="pt",
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
return {
|
| 58 |
+
"input_ids" : encoding["input_ids"].squeeze(0), # (max_length,)
|
| 59 |
+
"attention_mask" : encoding["attention_mask"].squeeze(0), # (max_length,)
|
| 60 |
+
"labels" : torch.tensor(label, dtype=torch.long),
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def build_label_map(data_path: str, output_path: str = None) -> dict:
|
| 65 |
+
"""
|
| 66 |
+
Scans the dataset and builds a {chapter_id: chapter_name} mapping.
|
| 67 |
+
Saves it to output_path as JSON if provided.
|
| 68 |
+
|
| 69 |
+
Run this once before training to verify your label space.
|
| 70 |
+
"""
|
| 71 |
+
with open(data_path, "r", encoding="utf-8") as f:
|
| 72 |
+
data = json.load(f)
|
| 73 |
+
|
| 74 |
+
label_map = {}
|
| 75 |
+
for item in data:
|
| 76 |
+
cid = item["chapter_id"]
|
| 77 |
+
name = item["chapter"]
|
| 78 |
+
if cid not in label_map:
|
| 79 |
+
label_map[cid] = name
|
| 80 |
+
|
| 81 |
+
# Sort by label integer for readability
|
| 82 |
+
label_map = dict(sorted(label_map.items()))
|
| 83 |
+
|
| 84 |
+
if output_path:
|
| 85 |
+
with open(output_path, "w", encoding="utf-8") as f:
|
| 86 |
+
json.dump(label_map, f, indent=2)
|
| 87 |
+
print(f"Label map saved to {output_path}")
|
| 88 |
+
|
| 89 |
+
return label_map
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
if __name__ == "__main__":
|
| 93 |
+
# Quick sanity check
|
| 94 |
+
from transformers import AutoTokenizer
|
| 95 |
+
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
|
| 96 |
+
|
| 97 |
+
ds = NEETDataset("Classification/data/sample_questions.json", tokenizer)
|
| 98 |
+
print(f"Dataset size: {len(ds)}")
|
| 99 |
+
sample = ds[0]
|
| 100 |
+
print(f"input_ids shape : {sample['input_ids'].shape}")
|
| 101 |
+
print(f"label : {sample['labels'].item()}")
|
| 102 |
+
|
| 103 |
+
label_map = build_label_map(
|
| 104 |
+
"Classification/data/sample_questions.json",
|
| 105 |
+
output_path="Classification/data/label_map.json"
|
| 106 |
+
)
|
| 107 |
+
print(f"\nLabel map ({len(label_map)} classes):")
|
| 108 |
+
for cid, name in label_map.items():
|
| 109 |
+
print(f" {cid}: {name}")
|
Classification/dataset_multilabel.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
dataset_multilabel.py β PyTorch Dataset for Multi-Label NEET Biology classification
|
| 3 |
+
|
| 4 |
+
Expected JSON format:
|
| 5 |
+
[
|
| 6 |
+
{
|
| 7 |
+
"question" : "Which structures are common to both plant cells and animal cells?",
|
| 8 |
+
"chapter_ids" : [7, 8] # list of ints
|
| 9 |
+
},
|
| 10 |
+
...
|
| 11 |
+
]
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
import json
|
| 15 |
+
import torch
|
| 16 |
+
from torch.utils.data import Dataset
|
| 17 |
+
from transformers import AutoTokenizer
|
| 18 |
+
|
| 19 |
+
class NEETMultiLabelDataset(Dataset):
|
| 20 |
+
def __init__(self, data_path: str, tokenizer: AutoTokenizer, num_labels: int, max_length: int = 128):
|
| 21 |
+
with open(data_path, "r", encoding="utf-8") as f:
|
| 22 |
+
self.data = json.load(f)
|
| 23 |
+
|
| 24 |
+
self.tokenizer = tokenizer
|
| 25 |
+
self.max_length = max_length
|
| 26 |
+
self.num_labels = num_labels
|
| 27 |
+
|
| 28 |
+
def __len__(self):
|
| 29 |
+
return len(self.data)
|
| 30 |
+
|
| 31 |
+
def __getitem__(self, idx):
|
| 32 |
+
item = self.data[idx]
|
| 33 |
+
question = item["question"]
|
| 34 |
+
|
| 35 |
+
# This will handle both string dicts or lists of IDs depending on generation
|
| 36 |
+
# We expect item["chapter_ids"] to be a list of integers
|
| 37 |
+
label_ids = item.get("chapter_ids", [])
|
| 38 |
+
if not isinstance(label_ids, list):
|
| 39 |
+
label_ids = [label_ids]
|
| 40 |
+
|
| 41 |
+
# Create a one-hot float vector for BCEWithLogitsLoss
|
| 42 |
+
labels = torch.zeros(self.num_labels, dtype=torch.float)
|
| 43 |
+
for c_id in label_ids:
|
| 44 |
+
if 0 <= c_id < self.num_labels:
|
| 45 |
+
labels[c_id] = 1.0
|
| 46 |
+
|
| 47 |
+
encoding = self.tokenizer(
|
| 48 |
+
question,
|
| 49 |
+
max_length=self.max_length,
|
| 50 |
+
padding="max_length",
|
| 51 |
+
truncation=True,
|
| 52 |
+
return_tensors="pt",
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
return {
|
| 56 |
+
"input_ids": encoding["input_ids"].squeeze(0),
|
| 57 |
+
"attention_mask": encoding["attention_mask"].squeeze(0),
|
| 58 |
+
"labels": labels,
|
| 59 |
+
}
|
Classification/predict.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
predict.py β Inference wrapper for the fine-tuned BERT chapter classifier
|
| 3 |
+
|
| 4 |
+
Usage:
|
| 5 |
+
from Classification.predict import ClassifierPredictor
|
| 6 |
+
predictor = ClassifierPredictor()
|
| 7 |
+
result = predictor.predict("Which organelle is the powerhouse of the cell?")
|
| 8 |
+
print(result)
|
| 9 |
+
# β {"chapter": "Cell: The Unit of Life", "chapter_id": 8, "confidence": 0.97, "top3": [...]}
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import json
|
| 13 |
+
import torch
|
| 14 |
+
import torch.nn.functional as F
|
| 15 |
+
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
| 16 |
+
|
| 17 |
+
# ==============================
|
| 18 |
+
# CONFIG
|
| 19 |
+
# ==============================
|
| 20 |
+
DEFAULT_MODEL_DIR = "Classification/checkpoints/best_model"
|
| 21 |
+
LABEL_MAP_PATH = "Classification/data/label_map.json"
|
| 22 |
+
MAX_LENGTH = 128
|
| 23 |
+
CONFIDENCE_WARNING = 0.6 # Warn if top prediction confidence is below this
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class ClassifierPredictor:
|
| 27 |
+
"""
|
| 28 |
+
Loads a fine-tuned bert-base-uncased checkpoint and predicts
|
| 29 |
+
the NCERT Biology chapter for a given question.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
def __init__(self, model_dir: str = DEFAULT_MODEL_DIR):
|
| 33 |
+
print(f"[Classifier] Loading model from: {model_dir}")
|
| 34 |
+
|
| 35 |
+
# Load label map {str(chapter_id): chapter_name}
|
| 36 |
+
with open(LABEL_MAP_PATH) as f:
|
| 37 |
+
raw_map = json.load(f)
|
| 38 |
+
# Keys from JSON are strings β convert to int
|
| 39 |
+
self.label_map = {int(k): v for k, v in raw_map.items()}
|
| 40 |
+
|
| 41 |
+
# Device
|
| 42 |
+
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 43 |
+
print(f"[Classifier] Using device: {self.device}")
|
| 44 |
+
|
| 45 |
+
# Load model & tokenizer
|
| 46 |
+
self.tokenizer = AutoTokenizer.from_pretrained(model_dir)
|
| 47 |
+
self.model = AutoModelForSequenceClassification.from_pretrained(model_dir)
|
| 48 |
+
self.model.eval()
|
| 49 |
+
self.model.to(self.device)
|
| 50 |
+
|
| 51 |
+
print(f"[Classifier] Ready β {len(self.label_map)} chapters.")
|
| 52 |
+
|
| 53 |
+
def predict(self, question: str, top_k: int = 3) -> dict:
|
| 54 |
+
"""
|
| 55 |
+
Predicts the chapter for a given NEET Biology question.
|
| 56 |
+
|
| 57 |
+
Returns:
|
| 58 |
+
{
|
| 59 |
+
"chapter" : "Biomolecules",
|
| 60 |
+
"chapter_id" : 9,
|
| 61 |
+
"confidence" : 0.94,
|
| 62 |
+
"top3" : [
|
| 63 |
+
{"chapter": "Biomolecules", "chapter_id": 9, "confidence": 0.94},
|
| 64 |
+
{"chapter": "Cell Organelles", "chapter_id": 8, "confidence": 0.04},
|
| 65 |
+
{"chapter": "The Living World", "chapter_id": 1, "confidence": 0.01},
|
| 66 |
+
]
|
| 67 |
+
}
|
| 68 |
+
"""
|
| 69 |
+
inputs = self.tokenizer(
|
| 70 |
+
question,
|
| 71 |
+
max_length=MAX_LENGTH,
|
| 72 |
+
padding="max_length",
|
| 73 |
+
truncation=True,
|
| 74 |
+
return_tensors="pt",
|
| 75 |
+
)
|
| 76 |
+
inputs = {k: v.to(self.device) for k, v in inputs.items()}
|
| 77 |
+
|
| 78 |
+
with torch.no_grad():
|
| 79 |
+
logits = self.model(**inputs).logits # (1, num_labels)
|
| 80 |
+
|
| 81 |
+
probs = F.softmax(logits, dim=-1).squeeze(0) # (num_labels,)
|
| 82 |
+
|
| 83 |
+
# Calculate Normalized Entropy
|
| 84 |
+
num_labels = len(self.label_map)
|
| 85 |
+
entropy = -torch.sum(probs * torch.log(probs + 1e-9)).item()
|
| 86 |
+
normalized_entropy = entropy / torch.log(torch.tensor(num_labels, dtype=torch.float32)).item()
|
| 87 |
+
|
| 88 |
+
# Top-k predictions
|
| 89 |
+
top_probs, top_ids = torch.topk(probs, k=min(top_k, num_labels))
|
| 90 |
+
|
| 91 |
+
top_predictions = []
|
| 92 |
+
for prob, label_id in zip(top_probs.tolist(), top_ids.tolist()):
|
| 93 |
+
top_predictions.append({
|
| 94 |
+
"chapter" : self.label_map.get(label_id, f"Unknown({label_id})"),
|
| 95 |
+
"chapter_id" : label_id,
|
| 96 |
+
"confidence" : round(prob, 4),
|
| 97 |
+
})
|
| 98 |
+
|
| 99 |
+
best = top_predictions[0]
|
| 100 |
+
margin = top_probs[0].item() - top_probs[1].item() if len(top_probs) > 1 else 1.0
|
| 101 |
+
|
| 102 |
+
# Heuristic Keyword Check (Expanded list)
|
| 103 |
+
question_lower = question.lower()
|
| 104 |
+
bio_keywords = [
|
| 105 |
+
"cell", "dna", "plant", "animal", "human", "body", "blood", "heart",
|
| 106 |
+
"gene", "protein", "virus", "bacteria", "disease", "reproduction",
|
| 107 |
+
"organ", "tissue", "biology", "enzyme", "acid", "carbon", "oxygen",
|
| 108 |
+
"water", "bone", "muscle", "lung", "brain", "leaf", "root", "stem",
|
| 109 |
+
"flower", "seed", "fruit", "chromosome", "rna", "atp", "metabolism",
|
| 110 |
+
"photosynthesis", "respiration", "digestion", "nervous", "hormone"
|
| 111 |
+
]
|
| 112 |
+
has_bio_signal = any(kw in question_lower for kw in bio_keywords)
|
| 113 |
+
|
| 114 |
+
# Dynamic Confidence Threshold
|
| 115 |
+
# If the question contains no known biology words, be highly skeptical.
|
| 116 |
+
min_confidence = 0.55 if has_bio_signal else 0.85
|
| 117 |
+
|
| 118 |
+
# OOD Rejection Rules
|
| 119 |
+
rejected = False
|
| 120 |
+
rejection_reason = ""
|
| 121 |
+
|
| 122 |
+
if best["confidence"] < min_confidence:
|
| 123 |
+
rejected = True
|
| 124 |
+
if not has_bio_signal:
|
| 125 |
+
rejection_reason = f"No biological keywords found & Confidence too low ({best['confidence']:.2f} < 0.85 for generic text)"
|
| 126 |
+
else:
|
| 127 |
+
rejection_reason = f"Top-1 confidence too low ({best['confidence']:.2f} < 0.55)"
|
| 128 |
+
elif margin < 0.12:
|
| 129 |
+
rejected = True
|
| 130 |
+
rejection_reason = f"Margin between top 2 chapters too small ({margin:.2f} < 0.12)"
|
| 131 |
+
elif normalized_entropy > 0.86:
|
| 132 |
+
rejected = True
|
| 133 |
+
rejection_reason = f"Model uncertainty too high (Entropy {normalized_entropy:.2f} > 0.86)"
|
| 134 |
+
|
| 135 |
+
if best["confidence"] < CONFIDENCE_WARNING and not rejected:
|
| 136 |
+
print(
|
| 137 |
+
f"[Classifier] β οΈ Low confidence ({best['confidence']:.2f}) for question:\n"
|
| 138 |
+
f" '{question}'\n"
|
| 139 |
+
f" Consider checking if this chapter is in the training data."
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
return {
|
| 143 |
+
"chapter" : best["chapter"],
|
| 144 |
+
"chapter_id" : best["chapter_id"],
|
| 145 |
+
"confidence" : best["confidence"],
|
| 146 |
+
"top3" : top_predictions,
|
| 147 |
+
"rejected" : rejected,
|
| 148 |
+
"rejection_reason": rejection_reason,
|
| 149 |
+
"entropy" : round(normalized_entropy, 4),
|
| 150 |
+
"margin" : round(margin, 4)
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
# ==============================
|
| 155 |
+
# QUICK TEST
|
| 156 |
+
# ==============================
|
| 157 |
+
if __name__ == "__main__":
|
| 158 |
+
predictor = ClassifierPredictor()
|
| 159 |
+
|
| 160 |
+
test_questions = [
|
| 161 |
+
"What is the role of mitochondria in ATP synthesis?",
|
| 162 |
+
"Explain the process of endospore formation in bacteria.",
|
| 163 |
+
"What is the significance of the two-kingdom classification?",
|
| 164 |
+
]
|
| 165 |
+
|
| 166 |
+
for q in test_questions:
|
| 167 |
+
result = predictor.predict(q)
|
| 168 |
+
print(f"\nQ: {q}")
|
| 169 |
+
print(f"β Chapter: {result['chapter']} (confidence: {result['confidence']:.2%})")
|
| 170 |
+
top3_display = [(p['chapter'], f"{p['confidence']:.2%}") for p in result['top3']]
|
| 171 |
+
print(f" Top 3: {top3_display}")
|
Classification/predict_multilabel.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
predict_multilabel.py β Inference wrapper for fine-tuned Multi-Label BERT
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import json
|
| 6 |
+
import torch
|
| 7 |
+
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
| 8 |
+
|
| 9 |
+
DEFAULT_MODEL_DIR = "Classification/checkpoints_multilabel/best_model"
|
| 10 |
+
LABEL_MAP_PATH = "Classification/data/label_map.json"
|
| 11 |
+
MAX_LENGTH = 128
|
| 12 |
+
THRESHOLD = 0.5
|
| 13 |
+
|
| 14 |
+
class MultiLabelPredictor:
|
| 15 |
+
def __init__(self, model_dir: str = DEFAULT_MODEL_DIR):
|
| 16 |
+
print(f"[MultiLabel Predictor] Loading model from: {model_dir}")
|
| 17 |
+
|
| 18 |
+
with open(LABEL_MAP_PATH) as f:
|
| 19 |
+
raw_map = json.load(f)
|
| 20 |
+
self.label_map = {int(k): v for k, v in raw_map.items()}
|
| 21 |
+
|
| 22 |
+
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
| 23 |
+
print(f"[MultiLabel Predictor] Using device: {self.device}")
|
| 24 |
+
|
| 25 |
+
self.tokenizer = AutoTokenizer.from_pretrained(model_dir)
|
| 26 |
+
self.model = AutoModelForSequenceClassification.from_pretrained(model_dir)
|
| 27 |
+
self.model.eval()
|
| 28 |
+
self.model.to(self.device)
|
| 29 |
+
|
| 30 |
+
def predict(self, question: str) -> list:
|
| 31 |
+
inputs = self.tokenizer(
|
| 32 |
+
question,
|
| 33 |
+
max_length=MAX_LENGTH,
|
| 34 |
+
padding="max_length",
|
| 35 |
+
truncation=True,
|
| 36 |
+
return_tensors="pt",
|
| 37 |
+
)
|
| 38 |
+
inputs = {k: v.to(self.device) for k, v in inputs.items()}
|
| 39 |
+
|
| 40 |
+
with torch.no_grad():
|
| 41 |
+
logits = self.model(**inputs).logits
|
| 42 |
+
|
| 43 |
+
# Apply sigmoid for independent probabilities
|
| 44 |
+
probs = torch.sigmoid(logits).squeeze(0)
|
| 45 |
+
|
| 46 |
+
results = []
|
| 47 |
+
for label_id, prob in enumerate(probs.tolist()):
|
| 48 |
+
if prob >= THRESHOLD:
|
| 49 |
+
results.append({
|
| 50 |
+
"chapter": self.label_map.get(label_id, f"Unknown({label_id})"),
|
| 51 |
+
"chapter_id": label_id,
|
| 52 |
+
"confidence": round(prob, 4),
|
| 53 |
+
})
|
| 54 |
+
|
| 55 |
+
# Sort by confidence
|
| 56 |
+
results = sorted(results, key=lambda x: x["confidence"], reverse=True)
|
| 57 |
+
return results
|
| 58 |
+
|
| 59 |
+
if __name__ == "__main__":
|
| 60 |
+
import sys
|
| 61 |
+
try:
|
| 62 |
+
predictor = MultiLabelPredictor()
|
| 63 |
+
except Exception as e:
|
| 64 |
+
print(f"Error loading model: {e}")
|
| 65 |
+
sys.exit(1)
|
| 66 |
+
|
| 67 |
+
qs = ["Which structures are common to both plant cells and animal cells?"]
|
| 68 |
+
for q in qs:
|
| 69 |
+
print(f"\nQ: {q}")
|
| 70 |
+
preds = predictor.predict(q)
|
| 71 |
+
print("Predictions:")
|
| 72 |
+
for p in preds:
|
| 73 |
+
print(f" - {p['chapter']} : {p['confidence']:.2%}")
|
Classification/train.py
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
train.py β Fine-tune bert-base-uncased for NEET Biology chapter classification
|
| 3 |
+
|
| 4 |
+
Flow:
|
| 5 |
+
1. Load config from config.json
|
| 6 |
+
2. Load and split the labeled dataset (80/20 train/val split)
|
| 7 |
+
3. Load bert-base-uncased with a classification head
|
| 8 |
+
4. Fine-tune using HuggingFace Trainer API
|
| 9 |
+
5. Evaluate & save the best checkpoint
|
| 10 |
+
|
| 11 |
+
Run:
|
| 12 |
+
python -m Classification.train
|
| 13 |
+
|
| 14 |
+
When you have your real labeled data, replace the path in DATA_PATH.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
import json
|
| 18 |
+
import os
|
| 19 |
+
import numpy as np
|
| 20 |
+
from sklearn.model_selection import train_test_split
|
| 21 |
+
from sklearn.metrics import accuracy_score, f1_score
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
from transformers import (
|
| 25 |
+
AutoTokenizer,
|
| 26 |
+
AutoModelForSequenceClassification,
|
| 27 |
+
TrainingArguments,
|
| 28 |
+
Trainer,
|
| 29 |
+
EarlyStoppingCallback,
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
from Classification.dataset import NEETDataset, build_label_map
|
| 33 |
+
|
| 34 |
+
# ==============================
|
| 35 |
+
# CONFIG
|
| 36 |
+
# ==============================
|
| 37 |
+
CONFIG_PATH = "Classification/config.json"
|
| 38 |
+
DATA_PATH = "Classification/data/generated_questions.json"
|
| 39 |
+
|
| 40 |
+
with open(CONFIG_PATH, encoding="utf-8") as f:
|
| 41 |
+
cfg = json.load(f)
|
| 42 |
+
|
| 43 |
+
MODEL_NAME = cfg["model_name"] # "bert-base-uncased"
|
| 44 |
+
MAX_LENGTH = cfg["max_length"] # 128
|
| 45 |
+
BATCH_SIZE = cfg["batch_size"] # 16
|
| 46 |
+
LR = cfg["learning_rate"] # 2e-5
|
| 47 |
+
EPOCHS = cfg["num_epochs"] # 5
|
| 48 |
+
OUTPUT_DIR = cfg["output_dir"] # "Classification/checkpoints"
|
| 49 |
+
SEED = cfg["seed"] # 42
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# ==============================
|
| 53 |
+
# STEP 1: Build label map
|
| 54 |
+
# ==============================
|
| 55 |
+
print("Loading label map...")
|
| 56 |
+
with open("Classification/data/label_map.json", "r", encoding="utf-8") as f:
|
| 57 |
+
label_map = json.load(f)
|
| 58 |
+
num_labels = len(label_map)
|
| 59 |
+
print(f"Number of classes (chapters): {num_labels}")
|
| 60 |
+
|
| 61 |
+
# Update config num_labels dynamically
|
| 62 |
+
cfg["num_labels"] = num_labels
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
# ==============================
|
| 66 |
+
# STEP 2: Load & split data
|
| 67 |
+
# ==============================
|
| 68 |
+
with open(DATA_PATH, encoding="utf-8") as f:
|
| 69 |
+
all_data = json.load(f)
|
| 70 |
+
|
| 71 |
+
train_data, val_data = train_test_split(
|
| 72 |
+
all_data, test_size=0.2, random_state=SEED, stratify=[d["chapter_id"] for d in all_data]
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
# Save splits for transparency
|
| 76 |
+
os.makedirs("Classification/data", exist_ok=True)
|
| 77 |
+
with open("Classification/data/train_split.json", "w", encoding="utf-8") as f:
|
| 78 |
+
json.dump(train_data, f, indent=2)
|
| 79 |
+
with open("Classification/data/val_split.json", "w", encoding="utf-8") as f:
|
| 80 |
+
json.dump(val_data, f, indent=2)
|
| 81 |
+
|
| 82 |
+
print(f"Train: {len(train_data)} | Val: {len(val_data)}")
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# ==============================
|
| 86 |
+
# STEP 3: Tokenizer & Datasets
|
| 87 |
+
# ==============================
|
| 88 |
+
print(f"Loading tokenizer: {MODEL_NAME}")
|
| 89 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
| 90 |
+
|
| 91 |
+
# Write splits to temp files (NEETDataset reads from JSON path)
|
| 92 |
+
train_dataset = NEETDataset("Classification/data/train_split.json", tokenizer, MAX_LENGTH)
|
| 93 |
+
val_dataset = NEETDataset("Classification/data/val_split.json", tokenizer, MAX_LENGTH)
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
# ==============================
|
| 97 |
+
# STEP 4: Load BERT Model
|
| 98 |
+
# ==============================
|
| 99 |
+
print(f"Loading {MODEL_NAME} with {num_labels} output labels...")
|
| 100 |
+
model = AutoModelForSequenceClassification.from_pretrained(
|
| 101 |
+
MODEL_NAME,
|
| 102 |
+
num_labels=num_labels,
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# ==============================
|
| 107 |
+
# STEP 5: Metrics
|
| 108 |
+
# ==============================
|
| 109 |
+
def compute_metrics(eval_pred):
|
| 110 |
+
logits, labels = eval_pred
|
| 111 |
+
preds = np.argmax(logits, axis=-1)
|
| 112 |
+
acc = accuracy_score(labels, preds)
|
| 113 |
+
f1 = f1_score(labels, preds, average="macro", zero_division=0)
|
| 114 |
+
return {"accuracy": acc, "f1": f1}
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
# ==============================
|
| 118 |
+
# STEP 6: Training Arguments
|
| 119 |
+
# ==============================
|
| 120 |
+
training_args = TrainingArguments(
|
| 121 |
+
output_dir=OUTPUT_DIR,
|
| 122 |
+
num_train_epochs=EPOCHS,
|
| 123 |
+
per_device_train_batch_size=BATCH_SIZE,
|
| 124 |
+
per_device_eval_batch_size=BATCH_SIZE,
|
| 125 |
+
learning_rate=LR,
|
| 126 |
+
warmup_ratio=cfg["warmup_ratio"],
|
| 127 |
+
weight_decay=cfg["weight_decay"],
|
| 128 |
+
evaluation_strategy=cfg["evaluation_strategy"],
|
| 129 |
+
save_strategy=cfg["save_strategy"],
|
| 130 |
+
load_best_model_at_end=cfg["load_best_model_at_end"],
|
| 131 |
+
metric_for_best_model=cfg["metric_for_best_model"],
|
| 132 |
+
logging_steps=cfg["logging_steps"],
|
| 133 |
+
seed=SEED,
|
| 134 |
+
report_to="none", # set to "wandb" or "tensorboard" if you want tracking
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
# ==============================
|
| 139 |
+
# STEP 7: Train
|
| 140 |
+
# ==============================
|
| 141 |
+
trainer = Trainer(
|
| 142 |
+
model=model,
|
| 143 |
+
args=training_args,
|
| 144 |
+
train_dataset=train_dataset,
|
| 145 |
+
eval_dataset=val_dataset,
|
| 146 |
+
tokenizer=tokenizer,
|
| 147 |
+
compute_metrics=compute_metrics,
|
| 148 |
+
callbacks=[EarlyStoppingCallback(early_stopping_patience=2)],
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
print("\nStarting training...")
|
| 152 |
+
trainer.train()
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
# ==============================
|
| 156 |
+
# STEP 8: Save best model
|
| 157 |
+
# ==============================
|
| 158 |
+
best_model_dir = os.path.join(OUTPUT_DIR, "best_model")
|
| 159 |
+
trainer.save_model(best_model_dir)
|
| 160 |
+
tokenizer.save_pretrained(best_model_dir)
|
| 161 |
+
print(f"\nβ
Best model saved to: {best_model_dir}")
|
| 162 |
+
|
| 163 |
+
# Save final eval metrics to Evaluation_metrics folder
|
| 164 |
+
metrics = trainer.evaluate()
|
| 165 |
+
print(f"\nFinal Eval Metrics: {metrics}")
|
| 166 |
+
|
| 167 |
+
eval_dir = "Classification/Evaluation_metrics"
|
| 168 |
+
os.makedirs(eval_dir, exist_ok=True)
|
| 169 |
+
with open(os.path.join(eval_dir, "eval_metrics.json"), "w") as f:
|
| 170 |
+
json.dump(metrics, f, indent=2)
|
| 171 |
+
print(f"π Metrics saved to {eval_dir}/eval_metrics.json")
|
| 172 |
+
|
| 173 |
+
# Also save training history
|
| 174 |
+
log_history = trainer.state.log_history
|
| 175 |
+
with open(os.path.join(eval_dir, "training_log.json"), "w") as f:
|
| 176 |
+
json.dump(log_history, f, indent=2)
|
| 177 |
+
print(f"π Training log saved to {eval_dir}/training_log.json")
|
Classification/train_multilabel.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
train_multilabel.py β Fine-tune bert-base-uncased for Multi-Label NEET classification
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import json
|
| 6 |
+
import os
|
| 7 |
+
import numpy as np
|
| 8 |
+
from sklearn.model_selection import train_test_split
|
| 9 |
+
from sklearn.metrics import f1_score, accuracy_score
|
| 10 |
+
import torch
|
| 11 |
+
from transformers import (
|
| 12 |
+
AutoTokenizer,
|
| 13 |
+
AutoModelForSequenceClassification,
|
| 14 |
+
TrainingArguments,
|
| 15 |
+
Trainer,
|
| 16 |
+
EarlyStoppingCallback,
|
| 17 |
+
)
|
| 18 |
+
from Classification.dataset_multilabel import NEETMultiLabelDataset
|
| 19 |
+
|
| 20 |
+
# ==============================
|
| 21 |
+
# CONFIG
|
| 22 |
+
# ==============================
|
| 23 |
+
CONFIG_PATH = "Classification/config.json"
|
| 24 |
+
DATA_PATH = "Classification/data/multilabel_generated_questions.json"
|
| 25 |
+
LABEL_MAP = "Classification/data/label_map.json"
|
| 26 |
+
|
| 27 |
+
with open(CONFIG_PATH, encoding="utf-8") as f:
|
| 28 |
+
cfg = json.load(f)
|
| 29 |
+
|
| 30 |
+
MODEL_NAME = cfg["model_name"]
|
| 31 |
+
MAX_LENGTH = cfg["max_length"]
|
| 32 |
+
BATCH_SIZE = cfg["batch_size"]
|
| 33 |
+
LR = cfg["learning_rate"]
|
| 34 |
+
EPOCHS = cfg["num_epochs"]
|
| 35 |
+
OUTPUT_DIR = "Classification/checkpoints_multilabel"
|
| 36 |
+
SEED = cfg["seed"]
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
print("Loading label map...")
|
| 40 |
+
with open(LABEL_MAP, "r", encoding="utf-8") as f:
|
| 41 |
+
label_map = json.load(f)
|
| 42 |
+
num_labels = len(label_map)
|
| 43 |
+
cfg["num_labels"] = num_labels
|
| 44 |
+
|
| 45 |
+
print(f"Loading data from {DATA_PATH}...")
|
| 46 |
+
if not os.path.exists(DATA_PATH):
|
| 47 |
+
raise FileNotFoundError(f"Missing {DATA_PATH}. Generate the data first.")
|
| 48 |
+
|
| 49 |
+
with open(DATA_PATH, encoding="utf-8") as f:
|
| 50 |
+
all_data = json.load(f)
|
| 51 |
+
|
| 52 |
+
# Stratification is tricky for multi-label, simple split used here
|
| 53 |
+
train_data, val_data = train_test_split(all_data, test_size=0.2, random_state=SEED)
|
| 54 |
+
|
| 55 |
+
os.makedirs("Classification/data", exist_ok=True)
|
| 56 |
+
train_path = "Classification/data/train_split_multilabel.json"
|
| 57 |
+
val_path = "Classification/data/val_split_multilabel.json"
|
| 58 |
+
|
| 59 |
+
with open(train_path, "w", encoding="utf-8") as f:
|
| 60 |
+
json.dump(train_data, f, indent=2)
|
| 61 |
+
with open(val_path, "w", encoding="utf-8") as f:
|
| 62 |
+
json.dump(val_data, f, indent=2)
|
| 63 |
+
|
| 64 |
+
print(f"Train: {len(train_data)} | Val: {len(val_data)}")
|
| 65 |
+
|
| 66 |
+
print(f"Loading tokenizer: {MODEL_NAME}")
|
| 67 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
| 68 |
+
|
| 69 |
+
train_dataset = NEETMultiLabelDataset(train_path, tokenizer, num_labels, MAX_LENGTH)
|
| 70 |
+
val_dataset = NEETMultiLabelDataset(val_path, tokenizer, num_labels, MAX_LENGTH)
|
| 71 |
+
|
| 72 |
+
print(f"Loading {MODEL_NAME} for multi-label classification...")
|
| 73 |
+
model = AutoModelForSequenceClassification.from_pretrained(
|
| 74 |
+
MODEL_NAME,
|
| 75 |
+
num_labels=num_labels,
|
| 76 |
+
problem_type="multi_label_classification"
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
# Custom metric function
|
| 80 |
+
def compute_metrics(eval_pred):
|
| 81 |
+
logits, labels = eval_pred
|
| 82 |
+
|
| 83 |
+
# Apply sigmoid
|
| 84 |
+
sigmoid = torch.nn.Sigmoid()
|
| 85 |
+
probs = sigmoid(torch.Tensor(logits))
|
| 86 |
+
|
| 87 |
+
# Threshold at 0.5
|
| 88 |
+
preds = np.zeros(probs.shape)
|
| 89 |
+
preds[np.where(probs >= 0.5)] = 1
|
| 90 |
+
|
| 91 |
+
# Macro F1 is standard for multi-label
|
| 92 |
+
macro_f1 = f1_score(labels, preds, average='macro', zero_division=0)
|
| 93 |
+
acc = accuracy_score(labels, preds)
|
| 94 |
+
return {"accuracy": acc, "f1_macro": macro_f1}
|
| 95 |
+
|
| 96 |
+
training_args = TrainingArguments(
|
| 97 |
+
output_dir=OUTPUT_DIR,
|
| 98 |
+
num_train_epochs=EPOCHS,
|
| 99 |
+
per_device_train_batch_size=BATCH_SIZE,
|
| 100 |
+
per_device_eval_batch_size=BATCH_SIZE,
|
| 101 |
+
learning_rate=LR,
|
| 102 |
+
warmup_ratio=cfg["warmup_ratio"],
|
| 103 |
+
weight_decay=cfg["weight_decay"],
|
| 104 |
+
evaluation_strategy=cfg["evaluation_strategy"],
|
| 105 |
+
save_strategy=cfg["save_strategy"],
|
| 106 |
+
load_best_model_at_end=cfg["load_best_model_at_end"],
|
| 107 |
+
metric_for_best_model="f1_macro",
|
| 108 |
+
logging_steps=cfg["logging_steps"],
|
| 109 |
+
seed=SEED,
|
| 110 |
+
report_to="none",
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
trainer = Trainer(
|
| 114 |
+
model=model,
|
| 115 |
+
args=training_args,
|
| 116 |
+
train_dataset=train_dataset,
|
| 117 |
+
eval_dataset=val_dataset,
|
| 118 |
+
tokenizer=tokenizer,
|
| 119 |
+
compute_metrics=compute_metrics,
|
| 120 |
+
callbacks=[EarlyStoppingCallback(early_stopping_patience=2)],
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
print("\nStarting multi-label training...")
|
| 124 |
+
trainer.train()
|
| 125 |
+
|
| 126 |
+
best_model_dir = os.path.join(OUTPUT_DIR, "best_model")
|
| 127 |
+
trainer.save_model(best_model_dir)
|
| 128 |
+
tokenizer.save_pretrained(best_model_dir)
|
| 129 |
+
print(f"\nβ
Best multi-label model saved to: {best_model_dir}")
|
| 130 |
+
|
| 131 |
+
metrics = trainer.evaluate()
|
| 132 |
+
print(f"\nFinal Eval Metrics: {metrics}")
|
DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# π Deployment Guide β Railway (Backend) + Vercel (Frontend)
|
| 2 |
+
|
| 3 |
+
## β οΈ Key Constraint: BERT Model Size
|
| 4 |
+
The trained BERT model is **418 MB** (`model.safetensors`).
|
| 5 |
+
GitHub blocks files >100MB. We use **Git LFS** to handle this.
|
| 6 |
+
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
## PART 1: Setup Git LFS + Push to GitHub
|
| 10 |
+
|
| 11 |
+
### Step 1 β Install Git LFS
|
| 12 |
+
Download and install: https://git-lfs.com
|
| 13 |
+
Then in your terminal:
|
| 14 |
+
```bash
|
| 15 |
+
git lfs install
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
### Step 2 β Track large model file
|
| 19 |
+
```bash
|
| 20 |
+
cd "d:\Users\Pranil\Github Repos\Question_AndAnswerGeneration"
|
| 21 |
+
git lfs track "Classification/checkpoints/best_model/model.safetensors"
|
| 22 |
+
git add .gitattributes
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
### Step 3 β Stage and commit everything
|
| 26 |
+
```bash
|
| 27 |
+
git add .
|
| 28 |
+
git commit -m "Add deployment files + BERT model via LFS"
|
| 29 |
+
git push origin main
|
| 30 |
+
```
|
| 31 |
+
> β³ This will take a few minutes β the 418MB file uploads via LFS.
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## PART 2: Deploy Backend to Railway
|
| 36 |
+
|
| 37 |
+
### Step 4 β Create Railway account
|
| 38 |
+
Go to: https://railway.app
|
| 39 |
+
Sign up with **GitHub** account (easiest β auto-imports repos)
|
| 40 |
+
|
| 41 |
+
### Step 5 β Create new project
|
| 42 |
+
1. Click **"New Project"**
|
| 43 |
+
2. Choose **"Deploy from GitHub repo"**
|
| 44 |
+
3. Select your `Question_AndAnswerGeneration` repo
|
| 45 |
+
4. Railway auto-detects Python β click **"Deploy"**
|
| 46 |
+
|
| 47 |
+
### Step 6 β Set environment variables
|
| 48 |
+
In your Railway project β **Variables** tab β add these:
|
| 49 |
+
|
| 50 |
+
| Variable | Value |
|
| 51 |
+
|---|---|
|
| 52 |
+
| `SUPABASE_URL` | `https://your-project.supabase.co` |
|
| 53 |
+
| `SUPABASE_KEY` | `your-supabase-anon-key` |
|
| 54 |
+
| `GROQ_API_KEY` | `your-groq-api-key` |
|
| 55 |
+
| `GROQ_MODEL` | `llama-3.3-70b-versatile` |
|
| 56 |
+
| `EMBEDDING_MODEL` | `BAAI/bge-small-en-v1.5` |
|
| 57 |
+
|
| 58 |
+
### Step 7 β Get your backend URL
|
| 59 |
+
After deployment completes (3β8 mins):
|
| 60 |
+
Go to **Settings β Domains** β Copy your URL
|
| 61 |
+
It looks like: `https://question-andanswer-production.up.railway.app`
|
| 62 |
+
|
| 63 |
+
### Step 8 β Verify backend is live
|
| 64 |
+
Open in browser:
|
| 65 |
+
```
|
| 66 |
+
https://YOUR-RAILWAY-URL.up.railway.app/health
|
| 67 |
+
https://YOUR-RAILWAY-URL.up.railway.app/docs
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
---
|
| 71 |
+
|
| 72 |
+
## PART 3: Update Frontend with Backend URL
|
| 73 |
+
|
| 74 |
+
### Step 9 β Update API_BASE in app.js
|
| 75 |
+
Open `Frontend/app.js` and change line 14:
|
| 76 |
+
```javascript
|
| 77 |
+
// Before (local):
|
| 78 |
+
const API_BASE = "http://localhost:8000";
|
| 79 |
+
|
| 80 |
+
// After (production):
|
| 81 |
+
const API_BASE = "https://YOUR-RAILWAY-URL.up.railway.app";
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
### Step 10 β Commit the frontend update
|
| 85 |
+
```bash
|
| 86 |
+
git add Frontend/app.js
|
| 87 |
+
git commit -m "Update API_BASE to Railway URL"
|
| 88 |
+
git push origin main
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## PART 4: Deploy Frontend to Vercel
|
| 94 |
+
|
| 95 |
+
### Step 11 β Create Vercel account
|
| 96 |
+
Go to: https://vercel.com
|
| 97 |
+
Sign up with **GitHub** account
|
| 98 |
+
|
| 99 |
+
### Step 12 β Import project
|
| 100 |
+
1. Click **"New Project"**
|
| 101 |
+
2. Import your `Question_AndAnswerGeneration` repo
|
| 102 |
+
3. In **"Configure Project"**:
|
| 103 |
+
- **Root Directory**: `Frontend`
|
| 104 |
+
- **Framework Preset**: `Other` (it's vanilla HTML)
|
| 105 |
+
- Leave everything else default
|
| 106 |
+
4. Click **"Deploy"**
|
| 107 |
+
|
| 108 |
+
### Step 13 β Get your frontend URL
|
| 109 |
+
Vercel gives you: `https://question-andanswer.vercel.app`
|
| 110 |
+
|
| 111 |
+
---
|
| 112 |
+
|
| 113 |
+
## β
Final Test
|
| 114 |
+
|
| 115 |
+
1. Open your Vercel URL
|
| 116 |
+
2. Type a question: *"What is the role of cofactors in enzyme activity?"*
|
| 117 |
+
3. Click **π¬ Full Analysis**
|
| 118 |
+
4. Should classify β retrieve β answer in ~10 seconds
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
## π§ Troubleshooting
|
| 123 |
+
|
| 124 |
+
| Problem | Fix |
|
| 125 |
+
|---|---|
|
| 126 |
+
| Railway deploy fails | Check **Deploy Logs** in Railway dashboard |
|
| 127 |
+
| BERT model not found | Confirm `model.safetensors` was pushed via Git LFS |
|
| 128 |
+
| CORS error in browser | Verify Railway URL in `API_BASE` has no trailing slash |
|
| 129 |
+
| Supabase timeout | Check your Supabase project is not paused (free tier pauses after inactivity) |
|
| 130 |
+
| Railway out of memory | Upgrade to Hobby plan ($5/mo) β BERT needs ~1.5GB RAM |
|
| 131 |
+
|
| 132 |
+
---
|
| 133 |
+
|
| 134 |
+
## π° Cost Summary
|
| 135 |
+
|
| 136 |
+
| Service | Free Tier | Paid |
|
| 137 |
+
|---|---|---|
|
| 138 |
+
| **Railway** | 500MB RAM, limited hours | $5/mo Hobby |
|
| 139 |
+
| **Vercel** | Unlimited static hosting | Free |
|
| 140 |
+
| **Supabase** | 500MB DB, 2GB bandwidth | $25/mo Pro |
|
| 141 |
+
| **Groq** | Free tier (limited RPM) | Pay-per-use |
|
| 142 |
+
| **Git LFS** | 1GB free | $5/mo per 50GB |
|
| 143 |
+
|
| 144 |
+
> π‘ For a student project / demo: everything fits in free tiers.
|
| 145 |
+
> Railway free tier may sleep after inactivity (cold start ~30s on first request).
|
Dockerfile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use the official Python 3.10 image as base
|
| 2 |
+
FROM python:3.10-slim
|
| 3 |
+
|
| 4 |
+
# Set the working directory
|
| 5 |
+
WORKDIR /code
|
| 6 |
+
|
| 7 |
+
# Copy the requirements file into the container
|
| 8 |
+
COPY ./requirements.txt /code/requirements.txt
|
| 9 |
+
|
| 10 |
+
# Install the dependencies
|
| 11 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
| 12 |
+
|
| 13 |
+
# Copy the entire project into the container
|
| 14 |
+
# .dockerignore will prevent .venv and other large unnecessary files from being copied
|
| 15 |
+
COPY . /code
|
| 16 |
+
|
| 17 |
+
# Hugging Face Spaces exposes port 7860 by default
|
| 18 |
+
EXPOSE 7860
|
| 19 |
+
|
| 20 |
+
# Command to run the FastAPI application
|
| 21 |
+
CMD ["uvicorn", "Backend.main:app", "--host", "0.0.0.0", "--port", "7860"]
|
Frontend/app.js
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* app.js β Frontend logic for NEET Biology Q&A
|
| 3 |
+
*
|
| 4 |
+
* Handles:
|
| 5 |
+
* - API calls to FastAPI backend (classify, answer, full analysis)
|
| 6 |
+
* - Dynamic result rendering
|
| 7 |
+
* - Loading states and error handling
|
| 8 |
+
* - Health check polling
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
// ββ API Base URL βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 12 |
+
// Development: http://localhost:8000
|
| 13 |
+
// Production: Replace with your Railway URL after deployment
|
| 14 |
+
// e.g. const API_BASE = "https://your-app.up.railway.app";
|
| 15 |
+
const API_BASE = "http://localhost:8000";
|
| 16 |
+
|
| 17 |
+
// ==============================
|
| 18 |
+
// DOM REFERENCES
|
| 19 |
+
// ==============================
|
| 20 |
+
const questionInput = document.getElementById("questionInput");
|
| 21 |
+
const charCount = document.getElementById("charCount");
|
| 22 |
+
const btnClassify = document.getElementById("btnClassify");
|
| 23 |
+
const btnAnswer = document.getElementById("btnAnswer");
|
| 24 |
+
const btnFull = document.getElementById("btnFull");
|
| 25 |
+
|
| 26 |
+
const loadingSection = document.getElementById("loadingSection");
|
| 27 |
+
const loaderText = document.getElementById("loaderText");
|
| 28 |
+
const loaderSteps = document.getElementById("loaderSteps");
|
| 29 |
+
|
| 30 |
+
const resultsSection = document.getElementById("resultsSection");
|
| 31 |
+
const classificationCard = document.getElementById("classificationCard");
|
| 32 |
+
const answerCard = document.getElementById("answerCard");
|
| 33 |
+
const justificationCard = document.getElementById("justificationCard");
|
| 34 |
+
const sourcesCard = document.getElementById("sourcesCard");
|
| 35 |
+
|
| 36 |
+
const errorSection = document.getElementById("errorSection");
|
| 37 |
+
const errorMessage = document.getElementById("errorMessage");
|
| 38 |
+
|
| 39 |
+
const statusDot = document.getElementById("statusDot");
|
| 40 |
+
const statusText = document.getElementById("statusText");
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
// ==============================
|
| 44 |
+
// CHAR COUNT
|
| 45 |
+
// ==============================
|
| 46 |
+
questionInput.addEventListener("input", () => {
|
| 47 |
+
const len = questionInput.value.length;
|
| 48 |
+
charCount.textContent = `${len} / 500`;
|
| 49 |
+
});
|
| 50 |
+
|
| 51 |
+
// Enter key to submit (Shift+Enter for newline)
|
| 52 |
+
questionInput.addEventListener("keydown", (e) => {
|
| 53 |
+
if (e.key === "Enter" && !e.shiftKey) {
|
| 54 |
+
e.preventDefault();
|
| 55 |
+
handleFullAnalysis();
|
| 56 |
+
}
|
| 57 |
+
});
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
// ==============================
|
| 61 |
+
// HEALTH CHECK
|
| 62 |
+
// ==============================
|
| 63 |
+
async function checkHealth() {
|
| 64 |
+
try {
|
| 65 |
+
const res = await fetch(`${API_BASE}/health`);
|
| 66 |
+
if (res.ok) {
|
| 67 |
+
const data = await res.json();
|
| 68 |
+
statusDot.className = "status-dot online";
|
| 69 |
+
statusText.textContent = "Server Online";
|
| 70 |
+
return true;
|
| 71 |
+
}
|
| 72 |
+
} catch (e) {
|
| 73 |
+
// Server offline
|
| 74 |
+
}
|
| 75 |
+
statusDot.className = "status-dot offline";
|
| 76 |
+
statusText.textContent = "Server Offline";
|
| 77 |
+
return false;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
// Check on load, then every 30s
|
| 81 |
+
checkHealth();
|
| 82 |
+
setInterval(checkHealth, 30000);
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
// ==============================
|
| 86 |
+
// BUTTON HANDLERS
|
| 87 |
+
// ==============================
|
| 88 |
+
|
| 89 |
+
/** π·οΈ Classify Only */
|
| 90 |
+
async function handleClassify() {
|
| 91 |
+
const question = questionInput.value.trim();
|
| 92 |
+
if (!validate(question)) return;
|
| 93 |
+
|
| 94 |
+
setLoading(true, "Classifying your question...", [
|
| 95 |
+
"BERT analyzing question...",
|
| 96 |
+
"Extracting chapter & topics...",
|
| 97 |
+
]);
|
| 98 |
+
|
| 99 |
+
try {
|
| 100 |
+
const res = await fetch(`${API_BASE}/api/classify`, {
|
| 101 |
+
method: "POST",
|
| 102 |
+
headers: { "Content-Type": "application/json" },
|
| 103 |
+
body: JSON.stringify({ question }),
|
| 104 |
+
});
|
| 105 |
+
|
| 106 |
+
if (!res.ok) throw new Error(`Server error: ${res.status}`);
|
| 107 |
+
const data = await res.json();
|
| 108 |
+
|
| 109 |
+
setLoading(false);
|
| 110 |
+
renderClassificationOnly(data);
|
| 111 |
+
} catch (err) {
|
| 112 |
+
setLoading(false);
|
| 113 |
+
showError(err.message);
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
/** π Generate Answer (no classifier) */
|
| 119 |
+
async function handleAnswer() {
|
| 120 |
+
const question = questionInput.value.trim();
|
| 121 |
+
if (!validate(question)) return;
|
| 122 |
+
|
| 123 |
+
setLoading(true, "Generating answer...", [
|
| 124 |
+
"Retrieving NCERT context...",
|
| 125 |
+
"Generating answer via AI...",
|
| 126 |
+
"Verifying accuracy...",
|
| 127 |
+
]);
|
| 128 |
+
|
| 129 |
+
try {
|
| 130 |
+
const res = await fetch(`${API_BASE}/api/qa`, {
|
| 131 |
+
method: "POST",
|
| 132 |
+
headers: { "Content-Type": "application/json" },
|
| 133 |
+
body: JSON.stringify({ question, use_classifier: false }),
|
| 134 |
+
});
|
| 135 |
+
|
| 136 |
+
if (!res.ok) throw new Error(`Server error: ${res.status}`);
|
| 137 |
+
const data = await res.json();
|
| 138 |
+
|
| 139 |
+
setLoading(false);
|
| 140 |
+
renderQAResult(data, false);
|
| 141 |
+
} catch (err) {
|
| 142 |
+
setLoading(false);
|
| 143 |
+
showError(err.message);
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
/** π¬ Full Analysis (classify + answer) */
|
| 149 |
+
async function handleFullAnalysis() {
|
| 150 |
+
const question = questionInput.value.trim();
|
| 151 |
+
if (!validate(question)) return;
|
| 152 |
+
|
| 153 |
+
setLoading(true, "Running full analysis...", [
|
| 154 |
+
"BERT classifying chapter...",
|
| 155 |
+
"Extracting topics...",
|
| 156 |
+
"Retrieving NCERT context...",
|
| 157 |
+
"Generating answer via AI...",
|
| 158 |
+
"Verifying & scoring...",
|
| 159 |
+
]);
|
| 160 |
+
|
| 161 |
+
try {
|
| 162 |
+
const res = await fetch(`${API_BASE}/api/qa`, {
|
| 163 |
+
method: "POST",
|
| 164 |
+
headers: { "Content-Type": "application/json" },
|
| 165 |
+
body: JSON.stringify({ question, use_classifier: true }),
|
| 166 |
+
});
|
| 167 |
+
|
| 168 |
+
if (!res.ok) throw new Error(`Server error: ${res.status}`);
|
| 169 |
+
const data = await res.json();
|
| 170 |
+
|
| 171 |
+
setLoading(false);
|
| 172 |
+
renderQAResult(data, true);
|
| 173 |
+
} catch (err) {
|
| 174 |
+
setLoading(false);
|
| 175 |
+
showError(err.message);
|
| 176 |
+
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
// ==============================
|
| 181 |
+
// VALIDATION
|
| 182 |
+
// ==============================
|
| 183 |
+
function validate(question) {
|
| 184 |
+
if (!question || question.length < 5) {
|
| 185 |
+
showError("Please enter a question (at least 5 characters).");
|
| 186 |
+
return false;
|
| 187 |
+
}
|
| 188 |
+
return true;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
// ==============================
|
| 193 |
+
// LOADING STATE
|
| 194 |
+
// ==============================
|
| 195 |
+
function setLoading(show, text = "", steps = []) {
|
| 196 |
+
const allBtns = [btnClassify, btnAnswer, btnFull];
|
| 197 |
+
|
| 198 |
+
if (show) {
|
| 199 |
+
hideResults();
|
| 200 |
+
hideError();
|
| 201 |
+
loadingSection.style.display = "block";
|
| 202 |
+
loaderText.textContent = text;
|
| 203 |
+
loaderSteps.innerHTML = "";
|
| 204 |
+
|
| 205 |
+
// Animate steps appearing one by one
|
| 206 |
+
steps.forEach((step, i) => {
|
| 207 |
+
setTimeout(() => {
|
| 208 |
+
const el = document.createElement("div");
|
| 209 |
+
el.className = "loader-step";
|
| 210 |
+
el.innerHTML = `<span>β³</span> ${step}`;
|
| 211 |
+
el.style.animationDelay = `${i * 0.15}s`;
|
| 212 |
+
loaderSteps.appendChild(el);
|
| 213 |
+
}, i * 800);
|
| 214 |
+
});
|
| 215 |
+
|
| 216 |
+
allBtns.forEach((b) => (b.disabled = true));
|
| 217 |
+
} else {
|
| 218 |
+
loadingSection.style.display = "none";
|
| 219 |
+
allBtns.forEach((b) => (b.disabled = false));
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
// ==============================
|
| 225 |
+
// RENDER: Classification Only
|
| 226 |
+
// ==============================
|
| 227 |
+
function renderClassificationOnly(data) {
|
| 228 |
+
hideResults();
|
| 229 |
+
resultsSection.style.display = "flex";
|
| 230 |
+
|
| 231 |
+
const cls = data.classification;
|
| 232 |
+
if (cls) {
|
| 233 |
+
renderClassificationCard(cls);
|
| 234 |
+
classificationCard.style.display = "block";
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
// Hide QA cards
|
| 238 |
+
answerCard.style.display = "none";
|
| 239 |
+
justificationCard.style.display = "none";
|
| 240 |
+
sourcesCard.style.display = "none";
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
// ==============================
|
| 245 |
+
// RENDER: Full QA Result
|
| 246 |
+
// ==============================
|
| 247 |
+
function renderQAResult(data, showClassification) {
|
| 248 |
+
hideResults();
|
| 249 |
+
resultsSection.style.display = "flex";
|
| 250 |
+
|
| 251 |
+
// Check if question was rejected (low confidence)
|
| 252 |
+
if (data.rejected) {
|
| 253 |
+
if (data.classification) {
|
| 254 |
+
renderClassificationCard(data.classification);
|
| 255 |
+
classificationCard.style.display = "block";
|
| 256 |
+
}
|
| 257 |
+
// Show rejection as an error-style answer
|
| 258 |
+
answerCard.style.display = "block";
|
| 259 |
+
const badge = document.getElementById("verificationBadge");
|
| 260 |
+
badge.className = "verification-badge verified-false";
|
| 261 |
+
badge.textContent = "β Rejected";
|
| 262 |
+
document.getElementById("answerContent").textContent = data.answer;
|
| 263 |
+
justificationCard.style.display = "none";
|
| 264 |
+
sourcesCard.style.display = "none";
|
| 265 |
+
return;
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
// Classification
|
| 269 |
+
if (showClassification && data.classification) {
|
| 270 |
+
renderClassificationCard(data.classification);
|
| 271 |
+
classificationCard.style.display = "block";
|
| 272 |
+
} else {
|
| 273 |
+
classificationCard.style.display = "none";
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
// Answer
|
| 277 |
+
if (data.answer) {
|
| 278 |
+
renderAnswerCard(data);
|
| 279 |
+
answerCard.style.display = "block";
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
// Justification
|
| 283 |
+
if (data.justification && data.justification.length > 0) {
|
| 284 |
+
renderJustificationCard(data.justification);
|
| 285 |
+
justificationCard.style.display = "block";
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
// Sources
|
| 289 |
+
if (data.sources && data.sources.length > 0) {
|
| 290 |
+
renderSourcesCard(data.sources, data.confidence);
|
| 291 |
+
sourcesCard.style.display = "block";
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
// ==============================
|
| 297 |
+
// RENDER HELPERS
|
| 298 |
+
// ==============================
|
| 299 |
+
|
| 300 |
+
function renderClassificationCard(cls) {
|
| 301 |
+
// Chapter confidence badge & Name
|
| 302 |
+
const confEl = document.getElementById("chapterConfidence");
|
| 303 |
+
const chapterNameEl = document.getElementById("chapterName");
|
| 304 |
+
|
| 305 |
+
if (cls.rejected || cls.chapter_confidence < 0.45) {
|
| 306 |
+
chapterNameEl.textContent = "No Chapter Relevant";
|
| 307 |
+
confEl.className = "confidence-badge confidence-low";
|
| 308 |
+
|
| 309 |
+
let reasonStr = cls.rejection_reason || "Out of domain";
|
| 310 |
+
// If it simply failed the 45% check but wasn't explicitly OOD
|
| 311 |
+
if (!cls.rejected && cls.chapter_confidence < 0.45) {
|
| 312 |
+
reasonStr = "Confidence too low";
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
// Strip out the parentheses containing the actual numbers if we want to hide them completely
|
| 316 |
+
// e.g. "Top-1 confidence too low (0.43 < 0.55)" -> "Top-1 confidence too low"
|
| 317 |
+
const cleanReason = reasonStr.split("(")[0].trim();
|
| 318 |
+
confEl.textContent = `Rejected: ${cleanReason}`;
|
| 319 |
+
} else {
|
| 320 |
+
chapterNameEl.textContent = cls.chapter;
|
| 321 |
+
const confPct = (cls.chapter_confidence * 100).toFixed(1);
|
| 322 |
+
const confClass = cls.chapter_confidence >= 0.8 ? "confidence-high" :
|
| 323 |
+
cls.chapter_confidence >= 0.5 ? "confidence-medium" : "confidence-low";
|
| 324 |
+
confEl.className = `confidence-badge ${confClass}`;
|
| 325 |
+
confEl.textContent = `${confPct}% confidence`;
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
// Topics
|
| 329 |
+
const topicsList = document.getElementById("topicsList");
|
| 330 |
+
topicsList.innerHTML = "";
|
| 331 |
+
|
| 332 |
+
if (cls.topics && cls.topics.length > 0) {
|
| 333 |
+
cls.topics.forEach((t) => {
|
| 334 |
+
const item = document.createElement("div");
|
| 335 |
+
item.className = "topic-item";
|
| 336 |
+
item.innerHTML = `
|
| 337 |
+
<div class="topic-name">
|
| 338 |
+
<span class="topic-code">${escapeHtml(t.section_code)}</span>
|
| 339 |
+
<span class="topic-title">${escapeHtml(t.section_title)}</span>
|
| 340 |
+
</div>
|
| 341 |
+
<span class="topic-similarity">${(t.similarity * 100).toFixed(1)}% match</span>
|
| 342 |
+
`;
|
| 343 |
+
topicsList.appendChild(item);
|
| 344 |
+
});
|
| 345 |
+
} else {
|
| 346 |
+
topicsList.innerHTML = `<p style="color: var(--text-muted); font-size: 0.85rem;">No specific topics identified</p>`;
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
function renderAnswerCard(data) {
|
| 352 |
+
// Verification badge
|
| 353 |
+
const badge = document.getElementById("verificationBadge");
|
| 354 |
+
if (data.verified) {
|
| 355 |
+
badge.className = "verification-badge verified-true";
|
| 356 |
+
badge.textContent = "β Verified";
|
| 357 |
+
} else {
|
| 358 |
+
badge.className = "verification-badge verified-false";
|
| 359 |
+
badge.textContent = "β Unverified";
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
// Answer text
|
| 363 |
+
document.getElementById("answerContent").textContent = data.answer;
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
function renderJustificationCard(justification) {
|
| 368 |
+
const list = document.getElementById("justificationList");
|
| 369 |
+
list.innerHTML = "";
|
| 370 |
+
justification.forEach((step) => {
|
| 371 |
+
const li = document.createElement("li");
|
| 372 |
+
li.textContent = step;
|
| 373 |
+
list.appendChild(li);
|
| 374 |
+
});
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
function renderSourcesCard(sources, confidence) {
|
| 379 |
+
// Overall confidence
|
| 380 |
+
const confEl = document.getElementById("overallConfidence");
|
| 381 |
+
const confPct = (confidence * 100).toFixed(1);
|
| 382 |
+
const confClass = confidence >= 0.7 ? "confidence-high" :
|
| 383 |
+
confidence >= 0.4 ? "confidence-medium" : "confidence-low";
|
| 384 |
+
confEl.className = `confidence-badge ${confClass}`;
|
| 385 |
+
confEl.textContent = `${confPct}% confidence`;
|
| 386 |
+
|
| 387 |
+
// Source list
|
| 388 |
+
const list = document.getElementById("sourcesList");
|
| 389 |
+
list.innerHTML = "";
|
| 390 |
+
sources.forEach((s) => {
|
| 391 |
+
const item = document.createElement("div");
|
| 392 |
+
item.className = "source-item";
|
| 393 |
+
item.innerHTML = `
|
| 394 |
+
<div class="source-meta">
|
| 395 |
+
<span class="source-chapter">${escapeHtml(s.chapter || "")}</span>
|
| 396 |
+
<span class="source-section">${escapeHtml(s.section || "")} β ${escapeHtml(s.section_title || "")}</span>
|
| 397 |
+
<span class="source-similarity">${(s.similarity * 100).toFixed(1)}%</span>
|
| 398 |
+
</div>
|
| 399 |
+
<div class="source-text">${escapeHtml(s.text_content || "")}</div>
|
| 400 |
+
`;
|
| 401 |
+
list.appendChild(item);
|
| 402 |
+
});
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
// ==============================
|
| 407 |
+
// UTILITY
|
| 408 |
+
// ==============================
|
| 409 |
+
|
| 410 |
+
function hideResults() {
|
| 411 |
+
resultsSection.style.display = "none";
|
| 412 |
+
classificationCard.style.display = "none";
|
| 413 |
+
answerCard.style.display = "none";
|
| 414 |
+
justificationCard.style.display = "none";
|
| 415 |
+
sourcesCard.style.display = "none";
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
function showError(msg) {
|
| 419 |
+
hideResults();
|
| 420 |
+
errorSection.style.display = "block";
|
| 421 |
+
errorMessage.textContent = msg;
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
function hideError() {
|
| 425 |
+
errorSection.style.display = "none";
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
function escapeHtml(text) {
|
| 429 |
+
const div = document.createElement("div");
|
| 430 |
+
div.textContent = text;
|
| 431 |
+
return div.innerHTML;
|
| 432 |
+
}
|
Frontend/index.html
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>NEET Biology Q&A β AI Study Assistant</title>
|
| 7 |
+
<meta name="description" content="AI-powered NEET Biology question answering system using BERT classification and RAG pipeline with NCERT textbook context." />
|
| 8 |
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 9 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
| 10 |
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
| 11 |
+
<link rel="stylesheet" href="styles.css" />
|
| 12 |
+
</head>
|
| 13 |
+
<body>
|
| 14 |
+
<!-- ============ AMBIENT BACKGROUND ============ -->
|
| 15 |
+
<div class="ambient-bg">
|
| 16 |
+
<div class="orb orb-1"></div>
|
| 17 |
+
<div class="orb orb-2"></div>
|
| 18 |
+
<div class="orb orb-3"></div>
|
| 19 |
+
</div>
|
| 20 |
+
|
| 21 |
+
<!-- ============ NAVBAR ============ -->
|
| 22 |
+
<nav class="navbar" id="navbar">
|
| 23 |
+
<div class="nav-brand">
|
| 24 |
+
<span class="nav-icon">π§¬</span>
|
| 25 |
+
<span class="nav-title">NEET Bio <span class="gradient-text">AI</span></span>
|
| 26 |
+
</div>
|
| 27 |
+
<div class="nav-status">
|
| 28 |
+
<span class="status-dot" id="statusDot"></span>
|
| 29 |
+
<span class="status-text" id="statusText">Connecting...</span>
|
| 30 |
+
</div>
|
| 31 |
+
</nav>
|
| 32 |
+
|
| 33 |
+
<!-- ============ MAIN CONTENT ============ -->
|
| 34 |
+
<main class="main-container">
|
| 35 |
+
|
| 36 |
+
<!-- HERO SECTION -->
|
| 37 |
+
<section class="hero">
|
| 38 |
+
<h1 class="hero-title">
|
| 39 |
+
Your AI-Powered
|
| 40 |
+
<span class="gradient-text">NEET Biology</span>
|
| 41 |
+
Study Assistant
|
| 42 |
+
</h1>
|
| 43 |
+
<p class="hero-subtitle">
|
| 44 |
+
Ask any NCERT Biology question β get chapter classification, topic extraction,
|
| 45 |
+
and verified answers powered by BERT & RAG
|
| 46 |
+
</p>
|
| 47 |
+
</section>
|
| 48 |
+
|
| 49 |
+
<!-- INPUT SECTION -->
|
| 50 |
+
<section class="input-section">
|
| 51 |
+
<div class="input-card glass-card">
|
| 52 |
+
<div class="input-header">
|
| 53 |
+
<span class="input-icon">π‘</span>
|
| 54 |
+
<span class="input-label">Ask your question</span>
|
| 55 |
+
</div>
|
| 56 |
+
<textarea
|
| 57 |
+
id="questionInput"
|
| 58 |
+
class="question-textarea"
|
| 59 |
+
placeholder="e.g., What is the role of cofactors in enzyme activity?"
|
| 60 |
+
rows="3"
|
| 61 |
+
maxlength="500"
|
| 62 |
+
></textarea>
|
| 63 |
+
<div class="input-footer">
|
| 64 |
+
<span class="char-count" id="charCount">0 / 500</span>
|
| 65 |
+
<div class="action-buttons">
|
| 66 |
+
<button class="btn btn-classify" id="btnClassify" onclick="handleClassify()">
|
| 67 |
+
<span class="btn-icon">π·οΈ</span>
|
| 68 |
+
<span class="btn-text">Classify</span>
|
| 69 |
+
</button>
|
| 70 |
+
<button class="btn btn-answer" id="btnAnswer" onclick="handleAnswer()">
|
| 71 |
+
<span class="btn-icon">π</span>
|
| 72 |
+
<span class="btn-text">Generate Answer</span>
|
| 73 |
+
</button>
|
| 74 |
+
<button class="btn btn-full" id="btnFull" onclick="handleFullAnalysis()">
|
| 75 |
+
<span class="btn-icon">π¬</span>
|
| 76 |
+
<span class="btn-text">Full Analysis</span>
|
| 77 |
+
</button>
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
</div>
|
| 81 |
+
</section>
|
| 82 |
+
|
| 83 |
+
<!-- LOADING INDICATOR -->
|
| 84 |
+
<section class="loading-section" id="loadingSection" style="display: none;">
|
| 85 |
+
<div class="loader-card glass-card">
|
| 86 |
+
<div class="loader-spinner"></div>
|
| 87 |
+
<p class="loader-text" id="loaderText">Analyzing your question...</p>
|
| 88 |
+
<div class="loader-steps" id="loaderSteps"></div>
|
| 89 |
+
</div>
|
| 90 |
+
</section>
|
| 91 |
+
|
| 92 |
+
<!-- RESULTS SECTION -->
|
| 93 |
+
<section class="results-section" id="resultsSection" style="display: none;">
|
| 94 |
+
|
| 95 |
+
<!-- Classification Card -->
|
| 96 |
+
<div class="result-card glass-card" id="classificationCard" style="display: none;">
|
| 97 |
+
<div class="card-header">
|
| 98 |
+
<span class="card-icon">π·οΈ</span>
|
| 99 |
+
<h2 class="card-title">Classification</h2>
|
| 100 |
+
<span class="confidence-badge" id="chapterConfidence"></span>
|
| 101 |
+
</div>
|
| 102 |
+
<div class="classification-content">
|
| 103 |
+
<div class="chapter-info">
|
| 104 |
+
<span class="label">Chapter</span>
|
| 105 |
+
<span class="value" id="chapterName"></span>
|
| 106 |
+
</div>
|
| 107 |
+
<div class="topics-list" id="topicsList"></div>
|
| 108 |
+
</div>
|
| 109 |
+
</div>
|
| 110 |
+
|
| 111 |
+
<!-- Answer Card -->
|
| 112 |
+
<div class="result-card glass-card" id="answerCard" style="display: none;">
|
| 113 |
+
<div class="card-header">
|
| 114 |
+
<span class="card-icon">π</span>
|
| 115 |
+
<h2 class="card-title">Answer</h2>
|
| 116 |
+
<div class="verification-badge" id="verificationBadge"></div>
|
| 117 |
+
</div>
|
| 118 |
+
<div class="answer-content" id="answerContent"></div>
|
| 119 |
+
</div>
|
| 120 |
+
|
| 121 |
+
<!-- Justification Card -->
|
| 122 |
+
<div class="result-card glass-card" id="justificationCard" style="display: none;">
|
| 123 |
+
<div class="card-header">
|
| 124 |
+
<span class="card-icon">π</span>
|
| 125 |
+
<h2 class="card-title">Justification</h2>
|
| 126 |
+
</div>
|
| 127 |
+
<ol class="justification-list" id="justificationList"></ol>
|
| 128 |
+
</div>
|
| 129 |
+
|
| 130 |
+
<!-- Sources Card -->
|
| 131 |
+
<div class="result-card glass-card" id="sourcesCard" style="display: none;">
|
| 132 |
+
<div class="card-header">
|
| 133 |
+
<span class="card-icon">π</span>
|
| 134 |
+
<h2 class="card-title">NCERT Sources</h2>
|
| 135 |
+
<span class="confidence-badge" id="overallConfidence"></span>
|
| 136 |
+
</div>
|
| 137 |
+
<div class="sources-list" id="sourcesList"></div>
|
| 138 |
+
</div>
|
| 139 |
+
</section>
|
| 140 |
+
|
| 141 |
+
<!-- ERROR SECTION -->
|
| 142 |
+
<section class="error-section" id="errorSection" style="display: none;">
|
| 143 |
+
<div class="error-card glass-card">
|
| 144 |
+
<span class="error-icon">β οΈ</span>
|
| 145 |
+
<p class="error-message" id="errorMessage"></p>
|
| 146 |
+
<button class="btn btn-retry" onclick="hideError()">Try Again</button>
|
| 147 |
+
</div>
|
| 148 |
+
</section>
|
| 149 |
+
|
| 150 |
+
</main>
|
| 151 |
+
|
| 152 |
+
<!-- ============ FOOTER ============ -->
|
| 153 |
+
<footer class="footer">
|
| 154 |
+
<p>Built with <span class="gradient-text">BERT</span> + <span class="gradient-text">RAG</span> β’ NCERT Biology Chapters 1β31</p>
|
| 155 |
+
</footer>
|
| 156 |
+
|
| 157 |
+
<script src="app.js"></script>
|
| 158 |
+
</body>
|
| 159 |
+
</html>
|
Frontend/styles.css
ADDED
|
@@ -0,0 +1,723 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ============================================
|
| 2 |
+
NEET Biology Q&A β CSS Design System
|
| 3 |
+
Theme: Study Environment + Gradient Trust
|
| 4 |
+
============================================ */
|
| 5 |
+
|
| 6 |
+
/* ββ Reset & Variables ββββββββββββββββββββββββ */
|
| 7 |
+
*, *::before, *::after {
|
| 8 |
+
margin: 0;
|
| 9 |
+
padding: 0;
|
| 10 |
+
box-sizing: border-box;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
:root {
|
| 14 |
+
/* Classic Matte Blue Palette β Professional & Classy */
|
| 15 |
+
--bg-dark: #0f172a; /* Deep matte slate */
|
| 16 |
+
--bg-surface: #1e293b; /* Matte card bg */
|
| 17 |
+
--bg-card: #1e293b;
|
| 18 |
+
--bg-card-hover: #334155;
|
| 19 |
+
|
| 20 |
+
/* Accent colors (Solid matte instead of gradients) */
|
| 21 |
+
--color-primary: #2563eb; /* Classic Blue */
|
| 22 |
+
--color-secondary: #3b82f6;
|
| 23 |
+
--color-tertiary: #1e40af; /* Deep Blue */
|
| 24 |
+
|
| 25 |
+
/* Re-map specific components to solid colors */
|
| 26 |
+
--gradient-primary: var(--color-primary);
|
| 27 |
+
--gradient-classify: var(--color-primary);
|
| 28 |
+
--gradient-answer: var(--color-secondary);
|
| 29 |
+
--gradient-full: var(--color-tertiary);
|
| 30 |
+
--gradient-text: var(--color-primary);
|
| 31 |
+
--gradient-success: #15803d;
|
| 32 |
+
--gradient-warning: #b45309;
|
| 33 |
+
|
| 34 |
+
/* Text */
|
| 35 |
+
--text-primary: #f8fafc;
|
| 36 |
+
--text-secondary: #cbd5e1;
|
| 37 |
+
--text-muted: #94a3b8;
|
| 38 |
+
|
| 39 |
+
/* Borders (Solid matte instead of neon glow) */
|
| 40 |
+
--border-subtle: #334155;
|
| 41 |
+
--border-glow: #475569;
|
| 42 |
+
|
| 43 |
+
/* Effects (Flat/Soft shadow instead of glassmorphism) */
|
| 44 |
+
--glass-bg: #1e293b;
|
| 45 |
+
--glass-border: #334155;
|
| 46 |
+
--glass-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2), 0 2px 4px -1px rgba(0, 0, 0, 0.1);
|
| 47 |
+
|
| 48 |
+
/* Sizing */
|
| 49 |
+
--max-width: 820px;
|
| 50 |
+
--radius-sm: 6px;
|
| 51 |
+
--radius-md: 8px;
|
| 52 |
+
--radius-lg: 12px;
|
| 53 |
+
--radius-xl: 16px;
|
| 54 |
+
|
| 55 |
+
/* Transitions */
|
| 56 |
+
--transition-fast: 0.15s ease;
|
| 57 |
+
--transition-normal: 0.2s ease;
|
| 58 |
+
--transition-slow: 0.3s ease;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
body {
|
| 62 |
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
| 63 |
+
background: var(--bg-dark);
|
| 64 |
+
color: var(--text-primary);
|
| 65 |
+
min-height: 100vh;
|
| 66 |
+
overflow-x: hidden;
|
| 67 |
+
line-height: 1.6;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
/* ββ Ambient Background Orbs (Disabled for professional look) ββββββββββββββββ */
|
| 72 |
+
.ambient-bg {
|
| 73 |
+
display: none;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
/* ββ Navbar βββββββββββββββββββββββββββββββββ */
|
| 78 |
+
.navbar {
|
| 79 |
+
position: sticky;
|
| 80 |
+
top: 0;
|
| 81 |
+
z-index: 100;
|
| 82 |
+
display: flex;
|
| 83 |
+
align-items: center;
|
| 84 |
+
justify-content: space-between;
|
| 85 |
+
padding: 14px 28px;
|
| 86 |
+
background: rgba(10, 14, 26, 0.85);
|
| 87 |
+
backdrop-filter: blur(20px);
|
| 88 |
+
border-bottom: 1px solid var(--glass-border);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.nav-brand {
|
| 92 |
+
display: flex;
|
| 93 |
+
align-items: center;
|
| 94 |
+
gap: 10px;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
.nav-icon {
|
| 98 |
+
font-size: 1.5rem;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.nav-title {
|
| 102 |
+
font-size: 1.2rem;
|
| 103 |
+
font-weight: 700;
|
| 104 |
+
letter-spacing: -0.02em;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
.nav-status {
|
| 108 |
+
display: flex;
|
| 109 |
+
align-items: center;
|
| 110 |
+
gap: 8px;
|
| 111 |
+
font-size: 0.82rem;
|
| 112 |
+
color: var(--text-muted);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.status-dot {
|
| 116 |
+
width: 8px;
|
| 117 |
+
height: 8px;
|
| 118 |
+
border-radius: 50%;
|
| 119 |
+
background: #f59e0b;
|
| 120 |
+
animation: pulse 2s ease-in-out infinite;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.status-dot.online { background: #10b981; }
|
| 124 |
+
.status-dot.offline { background: #ef4444; animation: none; }
|
| 125 |
+
|
| 126 |
+
@keyframes pulse {
|
| 127 |
+
0%, 100% { opacity: 1; }
|
| 128 |
+
50% { opacity: 0.4; }
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
/* ββ Gradient Text (Flattened to solid color) ββββββββββββββββββββββββββ */
|
| 133 |
+
.gradient-text {
|
| 134 |
+
color: var(--color-secondary);
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
/* ββ Main Container βββββββββββββββββββββββββ */
|
| 139 |
+
.main-container {
|
| 140 |
+
position: relative;
|
| 141 |
+
z-index: 1;
|
| 142 |
+
max-width: var(--max-width);
|
| 143 |
+
margin: 0 auto;
|
| 144 |
+
padding: 0 20px 60px;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
/* ββ Hero Section βββββββββββββββββββββββββββ */
|
| 149 |
+
.hero {
|
| 150 |
+
text-align: center;
|
| 151 |
+
padding: 48px 0 36px;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.hero-title {
|
| 155 |
+
font-size: 2.4rem;
|
| 156 |
+
font-weight: 800;
|
| 157 |
+
letter-spacing: -0.03em;
|
| 158 |
+
line-height: 1.2;
|
| 159 |
+
margin-bottom: 14px;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
.hero-subtitle {
|
| 163 |
+
font-size: 1rem;
|
| 164 |
+
color: var(--text-secondary);
|
| 165 |
+
max-width: 560px;
|
| 166 |
+
margin: 0 auto;
|
| 167 |
+
line-height: 1.6;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
/* ββ Matte Card βββββββββββββββββββββββββββββ */
|
| 172 |
+
.glass-card {
|
| 173 |
+
background: var(--bg-card);
|
| 174 |
+
border: 1px solid var(--border-subtle);
|
| 175 |
+
border-radius: var(--radius-xl);
|
| 176 |
+
box-shadow: var(--glass-shadow);
|
| 177 |
+
transition: border-color var(--transition-normal);
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
.glass-card:hover {
|
| 181 |
+
border-color: var(--border-glow);
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
/* ββ Input Section ββββββββββββββββββββββββββ */
|
| 186 |
+
.input-section {
|
| 187 |
+
margin-bottom: 28px;
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
.input-card {
|
| 191 |
+
padding: 24px;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
.input-header {
|
| 195 |
+
display: flex;
|
| 196 |
+
align-items: center;
|
| 197 |
+
gap: 8px;
|
| 198 |
+
margin-bottom: 14px;
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
.input-icon {
|
| 202 |
+
font-size: 1.2rem;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
.input-label {
|
| 206 |
+
font-size: 0.9rem;
|
| 207 |
+
font-weight: 600;
|
| 208 |
+
color: var(--text-secondary);
|
| 209 |
+
text-transform: uppercase;
|
| 210 |
+
letter-spacing: 0.05em;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
.question-textarea {
|
| 214 |
+
width: 100%;
|
| 215 |
+
background: rgba(0, 0, 0, 0.3);
|
| 216 |
+
border: 1px solid var(--border-subtle);
|
| 217 |
+
border-radius: var(--radius-md);
|
| 218 |
+
padding: 16px;
|
| 219 |
+
color: var(--text-primary);
|
| 220 |
+
font-family: 'Inter', sans-serif;
|
| 221 |
+
font-size: 1rem;
|
| 222 |
+
line-height: 1.6;
|
| 223 |
+
resize: vertical;
|
| 224 |
+
transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
|
| 225 |
+
outline: none;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
.question-textarea::placeholder {
|
| 229 |
+
color: var(--text-muted);
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
.question-textarea:focus {
|
| 233 |
+
border-color: var(--color-primary);
|
| 234 |
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
.input-footer {
|
| 238 |
+
display: flex;
|
| 239 |
+
align-items: center;
|
| 240 |
+
justify-content: space-between;
|
| 241 |
+
margin-top: 16px;
|
| 242 |
+
flex-wrap: wrap;
|
| 243 |
+
gap: 12px;
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
.char-count {
|
| 247 |
+
font-size: 0.8rem;
|
| 248 |
+
color: var(--text-muted);
|
| 249 |
+
font-family: 'JetBrains Mono', monospace;
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
/* ββ Action Buttons βββββββββββββββββββββββββ */
|
| 254 |
+
.action-buttons {
|
| 255 |
+
display: flex;
|
| 256 |
+
gap: 10px;
|
| 257 |
+
flex-wrap: wrap;
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
.btn {
|
| 261 |
+
display: inline-flex;
|
| 262 |
+
align-items: center;
|
| 263 |
+
gap: 6px;
|
| 264 |
+
padding: 10px 18px;
|
| 265 |
+
border: none;
|
| 266 |
+
border-radius: var(--radius-md);
|
| 267 |
+
font-family: 'Inter', sans-serif;
|
| 268 |
+
font-size: 0.88rem;
|
| 269 |
+
font-weight: 600;
|
| 270 |
+
cursor: pointer;
|
| 271 |
+
transition: all var(--transition-normal);
|
| 272 |
+
color: white;
|
| 273 |
+
position: relative;
|
| 274 |
+
overflow: hidden;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
.btn::before {
|
| 278 |
+
content: '';
|
| 279 |
+
position: absolute;
|
| 280 |
+
inset: 0;
|
| 281 |
+
opacity: 0;
|
| 282 |
+
background: rgba(0, 0, 0, 0.1); /* Darken instead of glowing light on hover */
|
| 283 |
+
transition: opacity var(--transition-fast);
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
.btn:hover::before { opacity: 1; }
|
| 287 |
+
|
| 288 |
+
.btn:active {
|
| 289 |
+
transform: translateY(1px); /* More solid matte feel */
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
.btn:disabled {
|
| 293 |
+
opacity: 0.5;
|
| 294 |
+
cursor: not-allowed;
|
| 295 |
+
transform: none;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
.btn:disabled::before { opacity: 0; }
|
| 299 |
+
|
| 300 |
+
.btn-classify { background: var(--gradient-classify); }
|
| 301 |
+
.btn-answer { background: var(--gradient-answer); }
|
| 302 |
+
.btn-full { background: var(--gradient-full); }
|
| 303 |
+
.btn-retry {
|
| 304 |
+
background: var(--gradient-primary);
|
| 305 |
+
margin-top: 12px;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
.btn-icon {
|
| 309 |
+
font-size: 1rem;
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
/* ββ Loading Section ββββββββββββββββββββββββ */
|
| 314 |
+
.loading-section {
|
| 315 |
+
margin-bottom: 28px;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
.loader-card {
|
| 319 |
+
padding: 32px;
|
| 320 |
+
text-align: center;
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
.loader-spinner {
|
| 324 |
+
width: 44px;
|
| 325 |
+
height: 44px;
|
| 326 |
+
margin: 0 auto 16px;
|
| 327 |
+
border: 3px solid var(--border-subtle);
|
| 328 |
+
border-top-color: var(--color-primary);
|
| 329 |
+
border-radius: 50%;
|
| 330 |
+
animation: spin 0.8s linear infinite;
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
@keyframes spin {
|
| 334 |
+
to { transform: rotate(360deg); }
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
.loader-text {
|
| 338 |
+
font-size: 1rem;
|
| 339 |
+
font-weight: 500;
|
| 340 |
+
color: var(--text-secondary);
|
| 341 |
+
margin-bottom: 12px;
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
.loader-steps {
|
| 345 |
+
display: flex;
|
| 346 |
+
flex-direction: column;
|
| 347 |
+
gap: 6px;
|
| 348 |
+
font-size: 0.82rem;
|
| 349 |
+
color: var(--text-muted);
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
.loader-step {
|
| 353 |
+
display: flex;
|
| 354 |
+
align-items: center;
|
| 355 |
+
justify-content: center;
|
| 356 |
+
gap: 6px;
|
| 357 |
+
opacity: 0;
|
| 358 |
+
animation: fadeIn 0.4s ease forwards;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
.loader-step.done {
|
| 362 |
+
color: #10b981;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
@keyframes fadeIn {
|
| 366 |
+
to { opacity: 1; }
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
/* ββ Result Cards βββββββββββββββββββββββββββ */
|
| 371 |
+
.results-section {
|
| 372 |
+
display: flex;
|
| 373 |
+
flex-direction: column;
|
| 374 |
+
gap: 20px;
|
| 375 |
+
animation: slideUp 0.5s ease;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
@keyframes slideUp {
|
| 379 |
+
from { opacity: 0; transform: translateY(20px); }
|
| 380 |
+
to { opacity: 1; transform: translateY(0); }
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
.result-card {
|
| 384 |
+
padding: 24px;
|
| 385 |
+
animation: slideUp 0.5s ease;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
.card-header {
|
| 389 |
+
display: flex;
|
| 390 |
+
align-items: center;
|
| 391 |
+
gap: 10px;
|
| 392 |
+
margin-bottom: 18px;
|
| 393 |
+
padding-bottom: 14px;
|
| 394 |
+
border-bottom: 1px solid var(--border-subtle);
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
.card-icon {
|
| 398 |
+
font-size: 1.2rem;
|
| 399 |
+
}
|
| 400 |
+
|
| 401 |
+
.card-title {
|
| 402 |
+
font-size: 1.1rem;
|
| 403 |
+
font-weight: 700;
|
| 404 |
+
flex: 1;
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
/* ββ Confidence Badge βββββββββββββββββββββββ */
|
| 409 |
+
.confidence-badge {
|
| 410 |
+
display: inline-flex;
|
| 411 |
+
align-items: center;
|
| 412 |
+
gap: 5px;
|
| 413 |
+
padding: 4px 12px;
|
| 414 |
+
border-radius: 20px;
|
| 415 |
+
font-size: 0.78rem;
|
| 416 |
+
font-weight: 600;
|
| 417 |
+
font-family: 'JetBrains Mono', monospace;
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
.confidence-high {
|
| 421 |
+
background: rgba(16, 185, 129, 0.15);
|
| 422 |
+
color: #34d399;
|
| 423 |
+
border: 1px solid rgba(16, 185, 129, 0.25);
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
.confidence-medium {
|
| 427 |
+
background: rgba(245, 158, 11, 0.15);
|
| 428 |
+
color: #fbbf24;
|
| 429 |
+
border: 1px solid rgba(245, 158, 11, 0.25);
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
.confidence-low {
|
| 433 |
+
background: rgba(239, 68, 68, 0.15);
|
| 434 |
+
color: #f87171;
|
| 435 |
+
border: 1px solid rgba(239, 68, 68, 0.25);
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
|
| 439 |
+
/* ββ Classification Content βββββββββββββββββ */
|
| 440 |
+
.classification-content {
|
| 441 |
+
display: flex;
|
| 442 |
+
flex-direction: column;
|
| 443 |
+
gap: 14px;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
.chapter-info {
|
| 447 |
+
display: flex;
|
| 448 |
+
align-items: center;
|
| 449 |
+
gap: 12px;
|
| 450 |
+
padding: 12px 16px;
|
| 451 |
+
background: rgba(37, 99, 235, 0.05); /* very soft blue */
|
| 452 |
+
border-radius: var(--radius-md);
|
| 453 |
+
border: 1px solid rgba(37, 99, 235, 0.15);
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
.chapter-info .label {
|
| 457 |
+
font-size: 0.78rem;
|
| 458 |
+
font-weight: 600;
|
| 459 |
+
color: var(--color-secondary);
|
| 460 |
+
text-transform: uppercase;
|
| 461 |
+
letter-spacing: 0.06em;
|
| 462 |
+
white-space: nowrap;
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
.chapter-info .value {
|
| 466 |
+
font-size: 1rem;
|
| 467 |
+
font-weight: 600;
|
| 468 |
+
color: var(--text-primary);
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
.topics-list {
|
| 472 |
+
display: flex;
|
| 473 |
+
flex-direction: column;
|
| 474 |
+
gap: 8px;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
.topic-item {
|
| 478 |
+
display: flex;
|
| 479 |
+
align-items: center;
|
| 480 |
+
justify-content: space-between;
|
| 481 |
+
padding: 10px 14px;
|
| 482 |
+
background: var(--bg-surface);
|
| 483 |
+
border-radius: var(--radius-sm);
|
| 484 |
+
border: 1px solid var(--border-subtle);
|
| 485 |
+
transition: background var(--transition-fast);
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
.topic-item:hover {
|
| 489 |
+
background: var(--bg-card-hover);
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
.topic-name {
|
| 493 |
+
display: flex;
|
| 494 |
+
align-items: center;
|
| 495 |
+
gap: 8px;
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
.topic-code {
|
| 499 |
+
font-family: 'JetBrains Mono', monospace;
|
| 500 |
+
font-size: 0.78rem;
|
| 501 |
+
font-weight: 500;
|
| 502 |
+
color: var(--color-secondary);
|
| 503 |
+
background: rgba(37, 99, 235, 0.1);
|
| 504 |
+
padding: 2px 8px;
|
| 505 |
+
border-radius: 4px;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
.topic-title {
|
| 509 |
+
font-size: 0.9rem;
|
| 510 |
+
color: var(--text-primary);
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
.topic-similarity {
|
| 514 |
+
font-family: 'JetBrains Mono', monospace;
|
| 515 |
+
font-size: 0.78rem;
|
| 516 |
+
color: var(--text-muted);
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
|
| 520 |
+
/* ββ Answer Content βββββββββββββββββββββββββ */
|
| 521 |
+
.answer-content {
|
| 522 |
+
font-size: 0.95rem;
|
| 523 |
+
line-height: 1.8;
|
| 524 |
+
color: var(--text-primary);
|
| 525 |
+
white-space: pre-wrap;
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
/* ββ Verification Badge βββββββββββββββββββββ */
|
| 530 |
+
.verification-badge {
|
| 531 |
+
display: inline-flex;
|
| 532 |
+
align-items: center;
|
| 533 |
+
gap: 5px;
|
| 534 |
+
padding: 4px 12px;
|
| 535 |
+
border-radius: 20px;
|
| 536 |
+
font-size: 0.78rem;
|
| 537 |
+
font-weight: 600;
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
.verified-true {
|
| 541 |
+
background: rgba(16, 185, 129, 0.15);
|
| 542 |
+
color: #34d399;
|
| 543 |
+
border: 1px solid rgba(16, 185, 129, 0.25);
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
.verified-false {
|
| 547 |
+
background: rgba(239, 68, 68, 0.15);
|
| 548 |
+
color: #f87171;
|
| 549 |
+
border: 1px solid rgba(239, 68, 68, 0.25);
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
|
| 553 |
+
/* ββ Justification List βββββββββββββββββββββ */
|
| 554 |
+
.justification-list {
|
| 555 |
+
list-style: none;
|
| 556 |
+
counter-reset: step;
|
| 557 |
+
display: flex;
|
| 558 |
+
flex-direction: column;
|
| 559 |
+
gap: 10px;
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
.justification-list li {
|
| 563 |
+
counter-increment: step;
|
| 564 |
+
display: flex;
|
| 565 |
+
gap: 12px;
|
| 566 |
+
font-size: 0.9rem;
|
| 567 |
+
color: var(--text-secondary);
|
| 568 |
+
line-height: 1.6;
|
| 569 |
+
padding: 10px 14px;
|
| 570 |
+
background: rgba(0, 0, 0, 0.2);
|
| 571 |
+
border-radius: var(--radius-sm);
|
| 572 |
+
border-left: 3px solid;
|
| 573 |
+
border-image: var(--gradient-primary) 1;
|
| 574 |
+
}
|
| 575 |
+
|
| 576 |
+
.justification-list li::before {
|
| 577 |
+
content: counter(step);
|
| 578 |
+
display: flex;
|
| 579 |
+
align-items: center;
|
| 580 |
+
justify-content: center;
|
| 581 |
+
min-width: 24px;
|
| 582 |
+
height: 24px;
|
| 583 |
+
background: var(--gradient-primary);
|
| 584 |
+
color: white;
|
| 585 |
+
border-radius: 50%;
|
| 586 |
+
font-size: 0.72rem;
|
| 587 |
+
font-weight: 700;
|
| 588 |
+
flex-shrink: 0;
|
| 589 |
+
}
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
/* ββ Sources List βββββββββββββββββββββββββββ */
|
| 593 |
+
.sources-list {
|
| 594 |
+
display: flex;
|
| 595 |
+
flex-direction: column;
|
| 596 |
+
gap: 10px;
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
.source-item {
|
| 600 |
+
padding: 14px;
|
| 601 |
+
background: var(--bg-surface);
|
| 602 |
+
border-radius: var(--radius-md);
|
| 603 |
+
border: 1px solid var(--border-subtle);
|
| 604 |
+
transition: border-color var(--transition-fast);
|
| 605 |
+
}
|
| 606 |
+
|
| 607 |
+
.source-item:hover {
|
| 608 |
+
border-color: var(--border-glow);
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
.source-meta {
|
| 612 |
+
display: flex;
|
| 613 |
+
align-items: center;
|
| 614 |
+
gap: 8px;
|
| 615 |
+
margin-bottom: 8px;
|
| 616 |
+
flex-wrap: wrap;
|
| 617 |
+
}
|
| 618 |
+
|
| 619 |
+
.source-chapter {
|
| 620 |
+
font-size: 0.78rem;
|
| 621 |
+
font-weight: 600;
|
| 622 |
+
color: var(--color-secondary);
|
| 623 |
+
background: rgba(37, 99, 235, 0.1);
|
| 624 |
+
padding: 2px 8px;
|
| 625 |
+
border-radius: 4px;
|
| 626 |
+
}
|
| 627 |
+
|
| 628 |
+
.source-section {
|
| 629 |
+
font-size: 0.78rem;
|
| 630 |
+
color: var(--text-muted);
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
.source-similarity {
|
| 634 |
+
font-family: 'JetBrains Mono', monospace;
|
| 635 |
+
font-size: 0.72rem;
|
| 636 |
+
color: var(--text-muted);
|
| 637 |
+
margin-left: auto;
|
| 638 |
+
}
|
| 639 |
+
|
| 640 |
+
.source-text {
|
| 641 |
+
font-size: 0.85rem;
|
| 642 |
+
color: var(--text-secondary);
|
| 643 |
+
line-height: 1.6;
|
| 644 |
+
display: -webkit-box;
|
| 645 |
+
-webkit-line-clamp: 3;
|
| 646 |
+
line-clamp: 3;
|
| 647 |
+
-webkit-box-orient: vertical;
|
| 648 |
+
overflow: hidden;
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
|
| 652 |
+
/* ββ Error Section ββββββββββββββββββββββββββ */
|
| 653 |
+
.error-card {
|
| 654 |
+
padding: 28px;
|
| 655 |
+
text-align: center;
|
| 656 |
+
border: 1px solid rgba(239, 68, 68, 0.25);
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
.error-icon {
|
| 660 |
+
font-size: 2rem;
|
| 661 |
+
display: block;
|
| 662 |
+
margin-bottom: 10px;
|
| 663 |
+
}
|
| 664 |
+
|
| 665 |
+
.error-message {
|
| 666 |
+
color: #f87171;
|
| 667 |
+
font-size: 0.95rem;
|
| 668 |
+
margin-bottom: 4px;
|
| 669 |
+
}
|
| 670 |
+
|
| 671 |
+
|
| 672 |
+
/* ββ Footer ββββββββββββββββββββββββββοΏ½οΏ½οΏ½ββββββ */
|
| 673 |
+
.footer {
|
| 674 |
+
position: relative;
|
| 675 |
+
z-index: 1;
|
| 676 |
+
text-align: center;
|
| 677 |
+
padding: 24px;
|
| 678 |
+
font-size: 0.82rem;
|
| 679 |
+
color: var(--text-muted);
|
| 680 |
+
border-top: 1px solid var(--glass-border);
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
/* ββ Responsive βββββββββββββββββββββββββββββ */
|
| 685 |
+
@media (max-width: 640px) {
|
| 686 |
+
.hero-title {
|
| 687 |
+
font-size: 1.6rem;
|
| 688 |
+
}
|
| 689 |
+
|
| 690 |
+
.hero-subtitle {
|
| 691 |
+
font-size: 0.88rem;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
.action-buttons {
|
| 695 |
+
width: 100%;
|
| 696 |
+
}
|
| 697 |
+
|
| 698 |
+
.btn {
|
| 699 |
+
flex: 1;
|
| 700 |
+
justify-content: center;
|
| 701 |
+
padding: 10px 12px;
|
| 702 |
+
font-size: 0.82rem;
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
.input-footer {
|
| 706 |
+
flex-direction: column;
|
| 707 |
+
align-items: stretch;
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
.char-count {
|
| 711 |
+
text-align: right;
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
.topic-item {
|
| 715 |
+
flex-direction: column;
|
| 716 |
+
align-items: flex-start;
|
| 717 |
+
gap: 6px;
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
.source-similarity {
|
| 721 |
+
margin-left: 0;
|
| 722 |
+
}
|
| 723 |
+
}
|
Procfile
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
web: uvicorn Backend.main:app --host 0.0.0.0 --port $PORT
|
README.md
CHANGED
|
@@ -1,12 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 𧬠NEET Biology Q&A β AI Study Assistant
|
| 2 |
+
|
| 3 |
+
An AI-powered Question Answering system for NEET Biology built with **BERT classification**, **RAG pipeline**, and **NCERT textbook context**.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## ποΈ Architecture
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
User Question
|
| 11 |
+
β
|
| 12 |
+
βΌ
|
| 13 |
+
ββββββββββββββββββββββββββ
|
| 14 |
+
β BERT Classifier β β Predicts NCERT chapter (31 classes, 91.7% F1)
|
| 15 |
+
β (bert-base-uncased) β β Extracts 1-3 relevant topics/subtopics
|
| 16 |
+
ββββββββββ¬ββββββββββββββββ
|
| 17 |
+
β
|
| 18 |
+
βΌ
|
| 19 |
+
ββββββββββββββββββββββββββ
|
| 20 |
+
β Supabase pgvector β β Retrieves top-k text chunks filtered by chapter
|
| 21 |
+
β (BGE-small-en-v1.5) β β Cosine similarity search on NCERT embeddings
|
| 22 |
+
ββββββββββ¬ββββββββββββββββ
|
| 23 |
+
β
|
| 24 |
+
βΌ
|
| 25 |
+
ββββββββββββββββββββββββββ
|
| 26 |
+
β Groq LLM (Llama 3) β β Generates answer from retrieved context
|
| 27 |
+
β RAG Pipeline β β Justifies with step-by-step reasoning
|
| 28 |
+
β β β Verifies answer accuracy
|
| 29 |
+
ββββββββββ¬ββββββββββββββββ
|
| 30 |
+
β
|
| 31 |
+
βΌ
|
| 32 |
+
JSON Response β Frontend
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
---
|
| 36 |
+
|
| 37 |
+
## π Project Structure
|
| 38 |
+
|
| 39 |
+
```
|
| 40 |
+
Question_AndAnswerGeneration/
|
| 41 |
+
β
|
| 42 |
+
βββ Backend/ # FastAPI REST API
|
| 43 |
+
β βββ main.py # App entrypoint, CORS, model preloading
|
| 44 |
+
β βββ schemas.py # Pydantic request/response models
|
| 45 |
+
β βββ routers/
|
| 46 |
+
β βββ qa.py # POST /api/qa, POST /api/classify
|
| 47 |
+
β
|
| 48 |
+
βββ Frontend/ # Vanilla HTML/CSS/JS UI
|
| 49 |
+
β βββ index.html
|
| 50 |
+
β βββ styles.css
|
| 51 |
+
β βββ app.js
|
| 52 |
+
β
|
| 53 |
+
βββ Classification/ # BERT Chapter Classifier
|
| 54 |
+
β βββ config.json # Training hyperparameters
|
| 55 |
+
β βββ dataset.py # PyTorch Dataset class
|
| 56 |
+
β βββ train.py # Fine-tuning script
|
| 57 |
+
β βββ predict.py # Inference wrapper
|
| 58 |
+
β βββ classify_and_extract.py # BERT + topic extraction orchestrator
|
| 59 |
+
β βββ checkpoints/
|
| 60 |
+
β β βββ best_model/ # Trained BERT weights
|
| 61 |
+
β βββ data/
|
| 62 |
+
β β βββ generated_questions.json # 5,673 labeled questions
|
| 63 |
+
β β βββ label_map.json # chapter_id β chapter_name
|
| 64 |
+
β βββ Evaluation_metrics/
|
| 65 |
+
β βββ eval_metrics.json
|
| 66 |
+
β βββ training_log.json
|
| 67 |
+
β
|
| 68 |
+
βββ rag/ # RAG Pipeline
|
| 69 |
+
β βββ retriever.py # Supabase vector search
|
| 70 |
+
β βββ prompt_builder.py # LLM prompt templates
|
| 71 |
+
β βββ generator.py # Groq API calls
|
| 72 |
+
β βββ confidence.py # Confidence scoring
|
| 73 |
+
β βββ pipeline.py # Full orchestrator
|
| 74 |
+
β
|
| 75 |
+
βββ pdf_to_embedding/ # Data Ingestion
|
| 76 |
+
βββ clean_pdf_to_json.py # PDF β cleaned JSON chunks
|
| 77 |
+
βββ embed_and_upload.py # JSON β embeddings β Supabase
|
| 78 |
+
βββ supabase_schema.sql # Database schema + RPC function
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## π Quick Start
|
| 84 |
+
|
| 85 |
+
### Prerequisites
|
| 86 |
+
|
| 87 |
+
- Python 3.10+
|
| 88 |
+
- Supabase account (with pgvector enabled)
|
| 89 |
+
- Groq API key
|
| 90 |
+
|
| 91 |
+
### 1. Clone & Setup
|
| 92 |
+
|
| 93 |
+
```bash
|
| 94 |
+
git clone https://github.com/PranilBankar/Question_AndAnswerGeneration.git
|
| 95 |
+
cd Question_AndAnswerGeneration
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
### 2. Create Virtual Environment
|
| 99 |
+
|
| 100 |
+
```bash
|
| 101 |
+
python -m venv .venv
|
| 102 |
+
|
| 103 |
+
# Windows
|
| 104 |
+
.venv\Scripts\Activate.ps1
|
| 105 |
+
|
| 106 |
+
# macOS/Linux
|
| 107 |
+
source .venv/bin/activate
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
### 3. Install Dependencies
|
| 111 |
+
|
| 112 |
+
```bash
|
| 113 |
+
pip install torch transformers sentence-transformers scikit-learn
|
| 114 |
+
pip install fastapi uvicorn
|
| 115 |
+
pip install supabase python-dotenv
|
| 116 |
+
pip install groq numpy
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
### 4. Environment Variables
|
| 120 |
+
|
| 121 |
+
Create `pdf_to_embedding/.env`:
|
| 122 |
+
|
| 123 |
+
```env
|
| 124 |
+
SUPABASE_URL=https://your-project.supabase.co
|
| 125 |
+
SUPABASE_KEY=your-anon-key
|
| 126 |
+
GROQ_API_KEY=your-groq-api-key
|
| 127 |
+
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
---
|
| 131 |
+
|
| 132 |
+
## βΆοΈ Running the Project
|
| 133 |
+
|
| 134 |
+
### Start the Backend (Terminal 1)
|
| 135 |
+
|
| 136 |
+
```bash
|
| 137 |
+
cd Question_AndAnswerGeneration
|
| 138 |
+
.venv\Scripts\Activate.ps1
|
| 139 |
+
uvicorn Backend.main:app --reload --port 8000
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
Wait for: `β
All models loaded β server ready!`
|
| 143 |
+
|
| 144 |
+
### Start the Frontend (Terminal 2)
|
| 145 |
+
|
| 146 |
+
```bash
|
| 147 |
+
cd Question_AndAnswerGeneration
|
| 148 |
+
python -m http.server 5500 --directory Frontend
|
| 149 |
+
```
|
| 150 |
+
|
| 151 |
+
### Open in Browser
|
| 152 |
+
|
| 153 |
+
```
|
| 154 |
+
Frontend: http://localhost:5500
|
| 155 |
+
Swagger: http://localhost:8000/docs
|
| 156 |
+
Health: http://localhost:8000/health
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
## π API Endpoints
|
| 162 |
+
|
| 163 |
+
| Method | Endpoint | Description |
|
| 164 |
+
|--------|----------|-------------|
|
| 165 |
+
| `POST` | `/api/qa` | Full pipeline: classify β retrieve β answer β verify |
|
| 166 |
+
| `POST` | `/api/classify` | BERT classification + topic extraction only |
|
| 167 |
+
| `GET` | `/health` | Health check (server + model status) |
|
| 168 |
+
| `GET` | `/docs` | Swagger UI (auto-generated) |
|
| 169 |
+
|
| 170 |
+
### Example: POST /api/qa
|
| 171 |
+
|
| 172 |
+
```bash
|
| 173 |
+
curl -X POST http://localhost:8000/api/qa \
|
| 174 |
+
-H "Content-Type: application/json" \
|
| 175 |
+
-d '{"question": "What is the role of cofactors in enzyme activity?"}'
|
| 176 |
+
```
|
| 177 |
+
|
| 178 |
+
### Example: POST /api/classify
|
| 179 |
+
|
| 180 |
+
```bash
|
| 181 |
+
curl -X POST http://localhost:8000/api/classify \
|
| 182 |
+
-H "Content-Type: application/json" \
|
| 183 |
+
-d '{"question": "What is the role of cofactors in enzyme activity?"}'
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
---
|
| 187 |
|
| 188 |
+
## π§ Tech Stack
|
| 189 |
+
|
| 190 |
+
| Component | Technology |
|
| 191 |
+
|-----------|------------|
|
| 192 |
+
| Classifier | BERT (bert-base-uncased), PyTorch, HuggingFace Transformers |
|
| 193 |
+
| Embeddings | BGE-small-en-v1.5 (384-dim), Sentence Transformers |
|
| 194 |
+
| Vector DB | Supabase PostgreSQL + pgvector (HNSW index) |
|
| 195 |
+
| LLM | Groq API (Llama 3) |
|
| 196 |
+
| Backend | FastAPI + Uvicorn |
|
| 197 |
+
| Frontend | Vanilla HTML/CSS/JS |
|
| 198 |
+
| Data Source | NCERT Biology Class 11 & 12 (31 chapters) |
|
| 199 |
+
|
| 200 |
+
---
|
| 201 |
+
|
| 202 |
+
## π Model Performance
|
| 203 |
+
|
| 204 |
+
| Metric | Score |
|
| 205 |
+
|--------|-------|
|
| 206 |
+
| Accuracy | 91.19% |
|
| 207 |
+
| F1 (macro) | 91.68% |
|
| 208 |
+
| Classes | 31 chapters |
|
| 209 |
+
| Training Data | 5,673 questions |
|
| 210 |
+
| Training Time | 8 min 30 sec (CPU) |
|
| 211 |
+
|
| 212 |
+
---
|
| 213 |
+
|
| 214 |
+
## π License
|
| 215 |
+
|
| 216 |
+
This project is for educational purposes.
|
pdf_to_embedding/.env.example
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
SUPABASE_URL="https://your-project-id.supabase.co"
|
| 2 |
+
SUPABASE_KEY="your-supabase-service-role-key-or-anon-key"
|
| 3 |
+
|
| 4 |
+
# Groq LLM API
|
| 5 |
+
GROQ_API_KEY="your-groq-api-key-here"
|
| 6 |
+
GROQ_MODEL="llama-3.3-70b-versatile"
|
| 7 |
+
|
| 8 |
+
# Embedding model (local, no API key needed)
|
| 9 |
+
MBEDDING_MODEL="BAAI/bge-small-en-v1.5"
|
| 10 |
+
E
|
pdf_to_embedding/clean_pdf_to_json.py
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
import json
|
| 3 |
+
import fitz
|
| 4 |
+
from transformers import AutoTokenizer
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
|
| 7 |
+
# ==============================
|
| 8 |
+
# CONFIG
|
| 9 |
+
# ==============================
|
| 10 |
+
|
| 11 |
+
PDF_PATH = r"D:\Users\Pranil\Github Repos\NLP_pdfDataset\11th Ncert\kebo109.pdf"
|
| 12 |
+
OUTPUT_JSON = "biology_embedding_ready_final.json"
|
| 13 |
+
SUBJECT = "Biology"
|
| 14 |
+
MAX_TOKENS = 220
|
| 15 |
+
TOKENIZER_MODEL = "bert-base-uncased"
|
| 16 |
+
|
| 17 |
+
REMOVE_SUMMARY = True # Optional toggle
|
| 18 |
+
|
| 19 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 20 |
+
TOKENIZER_MODEL,
|
| 21 |
+
clean_up_tokenization_spaces=True
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# ==============================
|
| 25 |
+
# STEP 1: Extract Raw Text
|
| 26 |
+
# ==============================
|
| 27 |
+
|
| 28 |
+
def extract_text(pdf_path):
|
| 29 |
+
doc = fitz.open(pdf_path)
|
| 30 |
+
text = ""
|
| 31 |
+
for page in doc:
|
| 32 |
+
text += page.get_text("text") + "\n"
|
| 33 |
+
return text
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# ==============================
|
| 37 |
+
# STEP 2: Clean Raw Text
|
| 38 |
+
# ==============================
|
| 39 |
+
|
| 40 |
+
def clean_text(text):
|
| 41 |
+
|
| 42 |
+
# Remove page numbers
|
| 43 |
+
text = re.sub(r"^\d+\s*$", "", text, flags=re.MULTILINE)
|
| 44 |
+
|
| 45 |
+
# Remove headers
|
| 46 |
+
text = re.sub(r"\nBIOLOGY\n", "\n", text, flags=re.IGNORECASE)
|
| 47 |
+
# text = re.sub(r"\nBIOMOLECULES\n", "\n", text, flags=re.IGNORECASE)
|
| 48 |
+
|
| 49 |
+
# Remove reprint line
|
| 50 |
+
text = re.sub(r"Reprint.*?\n", "", text)
|
| 51 |
+
|
| 52 |
+
# Remove weird unicode arrows
|
| 53 |
+
text = re.sub(r"[βο§\uf8e7]+", "", text)
|
| 54 |
+
|
| 55 |
+
# Remove everything after EXERCISES
|
| 56 |
+
text = re.split(r"\nEXERCISES", text)[0]
|
| 57 |
+
|
| 58 |
+
# Optionally remove summary
|
| 59 |
+
if REMOVE_SUMMARY:
|
| 60 |
+
text = re.split(r"\nSUMMARY", text)[0]
|
| 61 |
+
|
| 62 |
+
# Normalize spacing
|
| 63 |
+
text = re.sub(r"\n{2,}", "\n", text)
|
| 64 |
+
text = re.sub(r"\s{2,}", " ", text)
|
| 65 |
+
|
| 66 |
+
return text.strip()
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
# ==============================
|
| 70 |
+
# STEP 3: Extract Chapter Info
|
| 71 |
+
# ==============================
|
| 72 |
+
|
| 73 |
+
def extract_chapter_info(text):
|
| 74 |
+
|
| 75 |
+
lines = text.split("\n")
|
| 76 |
+
lines = [l.strip() for l in lines if l.strip()]
|
| 77 |
+
|
| 78 |
+
chapter_number = "Unknown"
|
| 79 |
+
chapter_title = "Unknown"
|
| 80 |
+
|
| 81 |
+
for i, line in enumerate(lines):
|
| 82 |
+
match = re.search(r"CHAPTER\s+(\d+)", line, re.IGNORECASE)
|
| 83 |
+
if match:
|
| 84 |
+
chapter_number = match.group(1)
|
| 85 |
+
|
| 86 |
+
# Look ABOVE for true title (skip long sentences)
|
| 87 |
+
for j in range(i - 1, -1, -1):
|
| 88 |
+
if len(lines[j].split()) <= 5: # short line = likely title
|
| 89 |
+
chapter_title = lines[j].title()
|
| 90 |
+
break
|
| 91 |
+
|
| 92 |
+
break
|
| 93 |
+
|
| 94 |
+
return chapter_number, chapter_title
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
# ==============================
|
| 98 |
+
# STEP 4: Detect Real Sections
|
| 99 |
+
# ==============================
|
| 100 |
+
def split_real_sections(text, chapter_number):
|
| 101 |
+
|
| 102 |
+
section_pattern = rf"\n({chapter_number}\.\d+)\s*\n?([A-Za-z][^\n]+)"
|
| 103 |
+
|
| 104 |
+
matches = list(re.finditer(section_pattern, text))
|
| 105 |
+
|
| 106 |
+
sections = []
|
| 107 |
+
|
| 108 |
+
for i, match in enumerate(matches):
|
| 109 |
+
|
| 110 |
+
section_number = match.group(1)
|
| 111 |
+
section_title = match.group(2).strip().title()
|
| 112 |
+
|
| 113 |
+
start = match.end()
|
| 114 |
+
|
| 115 |
+
# Look ahead up to next match or end
|
| 116 |
+
end = matches[i + 1].start() if i + 1 < len(matches) else len(text)
|
| 117 |
+
|
| 118 |
+
section_text = text[start:end].strip()
|
| 119 |
+
|
| 120 |
+
# ----------------------------
|
| 121 |
+
# π₯ CRITICAL FILTER
|
| 122 |
+
# ----------------------------
|
| 123 |
+
|
| 124 |
+
# Reject sidebar / TOC matches
|
| 125 |
+
if len(section_text) < 500:
|
| 126 |
+
continue
|
| 127 |
+
|
| 128 |
+
# Must contain real sentences
|
| 129 |
+
if section_text.count(".") < 3:
|
| 130 |
+
continue
|
| 131 |
+
|
| 132 |
+
# Must not look like menu list
|
| 133 |
+
if re.search(r"\n9\.\d\n", section_text):
|
| 134 |
+
continue
|
| 135 |
+
|
| 136 |
+
sections.append({
|
| 137 |
+
"section_number": section_number,
|
| 138 |
+
"section_title": section_title,
|
| 139 |
+
"text": section_text
|
| 140 |
+
})
|
| 141 |
+
|
| 142 |
+
return sections
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
# ==============================
|
| 146 |
+
# STEP 5: Chunking
|
| 147 |
+
# ==============================
|
| 148 |
+
|
| 149 |
+
def chunk_text(text):
|
| 150 |
+
|
| 151 |
+
# Remove repeated heading inside text
|
| 152 |
+
text = re.sub(r"^\d+\.\d+\s+[A-Za-z\s]+", "", text)
|
| 153 |
+
|
| 154 |
+
sentences = re.split(r'(?<=[.!?]) +', text)
|
| 155 |
+
|
| 156 |
+
chunks = []
|
| 157 |
+
current_chunk = ""
|
| 158 |
+
|
| 159 |
+
for sentence in sentences:
|
| 160 |
+
|
| 161 |
+
candidate = current_chunk + " " + sentence
|
| 162 |
+
token_count = len(tokenizer(candidate)["input_ids"])
|
| 163 |
+
|
| 164 |
+
if token_count <= MAX_TOKENS:
|
| 165 |
+
current_chunk = candidate
|
| 166 |
+
else:
|
| 167 |
+
if len(tokenizer(current_chunk)["input_ids"]) > 40:
|
| 168 |
+
chunks.append(current_chunk.strip())
|
| 169 |
+
current_chunk = sentence
|
| 170 |
+
|
| 171 |
+
if len(tokenizer(current_chunk)["input_ids"]) > 40:
|
| 172 |
+
chunks.append(current_chunk.strip())
|
| 173 |
+
|
| 174 |
+
return chunks
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
# ==============================
|
| 178 |
+
# MAIN PIPELINE
|
| 179 |
+
# ==============================
|
| 180 |
+
|
| 181 |
+
def process_pdf():
|
| 182 |
+
|
| 183 |
+
print("Extracting text...")
|
| 184 |
+
raw_text = extract_text(PDF_PATH)
|
| 185 |
+
|
| 186 |
+
print("Cleaning text...")
|
| 187 |
+
cleaned_text = clean_text(raw_text)
|
| 188 |
+
|
| 189 |
+
print("Extracting chapter info...")
|
| 190 |
+
chapter_number, chapter_title = extract_chapter_info(cleaned_text)
|
| 191 |
+
|
| 192 |
+
print(f"Detected Chapter {chapter_number}: {chapter_title}")
|
| 193 |
+
|
| 194 |
+
print("Detecting real sections...")
|
| 195 |
+
sections = split_real_sections(cleaned_text, chapter_number)
|
| 196 |
+
|
| 197 |
+
print(f"Valid sections detected: {len(sections)}")
|
| 198 |
+
|
| 199 |
+
all_chunks = []
|
| 200 |
+
global_index = 0
|
| 201 |
+
|
| 202 |
+
for section in tqdm(sections):
|
| 203 |
+
|
| 204 |
+
section_number = section["section_number"]
|
| 205 |
+
section_title = section["section_title"]
|
| 206 |
+
|
| 207 |
+
chunks = chunk_text(section["text"])
|
| 208 |
+
|
| 209 |
+
for chunk in chunks:
|
| 210 |
+
|
| 211 |
+
chunk_id = f"bio_ch{chapter_number}_{section_number}_{global_index:04}"
|
| 212 |
+
|
| 213 |
+
all_chunks.append({
|
| 214 |
+
"id": chunk_id,
|
| 215 |
+
"subject": SUBJECT,
|
| 216 |
+
"chapter": chapter_title,
|
| 217 |
+
"chapter_number": chapter_number,
|
| 218 |
+
"section": section_number,
|
| 219 |
+
"section_title": section_title,
|
| 220 |
+
"text": chunk,
|
| 221 |
+
})
|
| 222 |
+
|
| 223 |
+
global_index += 1
|
| 224 |
+
|
| 225 |
+
print(f"\nGenerated {len(all_chunks)} clean embedding-ready chunks.")
|
| 226 |
+
|
| 227 |
+
with open(OUTPUT_JSON, "w", encoding="utf-8") as f:
|
| 228 |
+
json.dump(all_chunks, f, indent=2)
|
| 229 |
+
|
| 230 |
+
print(f"Saved to {OUTPUT_JSON}")
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
if __name__ == "__main__":
|
| 234 |
+
process_pdf()
|
pdf_to_embedding/embed_and_upload.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import glob
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
from supabase import create_client, Client
|
| 6 |
+
from sentence_transformers import SentenceTransformer
|
| 7 |
+
from tqdm import tqdm
|
| 8 |
+
|
| 9 |
+
# ==============================
|
| 10 |
+
# CONFIG
|
| 11 |
+
# ==============================
|
| 12 |
+
JSON_OUTPUT_DIR = r"D:\Users\Pranil\Github Repos\Question_AndAnswerGeneration\pdf_to_embedding"
|
| 13 |
+
EMBEDDING_MODEL_NAME = "BAAI/bge-small-en-v1.5"
|
| 14 |
+
|
| 15 |
+
# Batch size for Supabase insertion to avoid payload too large errors
|
| 16 |
+
BATCH_SIZE = 100
|
| 17 |
+
|
| 18 |
+
# ==============================
|
| 19 |
+
# INITIALIZATION
|
| 20 |
+
# ==============================
|
| 21 |
+
# Load environment variables from .env
|
| 22 |
+
load_dotenv()
|
| 23 |
+
|
| 24 |
+
SUPABASE_URL = os.getenv("SUPABASE_URL")
|
| 25 |
+
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
|
| 26 |
+
|
| 27 |
+
if not SUPABASE_URL or not SUPABASE_KEY:
|
| 28 |
+
raise ValueError("Missing SUPABASE_URL or SUPABASE_KEY in .env file.")
|
| 29 |
+
|
| 30 |
+
# Initialize Supabase client
|
| 31 |
+
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 32 |
+
|
| 33 |
+
# Initialize Embedding Model
|
| 34 |
+
print(f"Loading embedding model: {EMBEDDING_MODEL_NAME}")
|
| 35 |
+
model = SentenceTransformer(EMBEDDING_MODEL_NAME)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def process_and_upload():
|
| 39 |
+
# Find all JSON files recursively in the output directory
|
| 40 |
+
json_files = glob.glob(os.path.join(JSON_OUTPUT_DIR, "**", "*.json"), recursive=True)
|
| 41 |
+
|
| 42 |
+
if not json_files:
|
| 43 |
+
print(f"No JSON files found in {JSON_OUTPUT_DIR}")
|
| 44 |
+
return
|
| 45 |
+
|
| 46 |
+
print(f"Found {len(json_files)} JSON files to process.")
|
| 47 |
+
|
| 48 |
+
for json_path in json_files:
|
| 49 |
+
print(f"\nProcessing file: {json_path}")
|
| 50 |
+
|
| 51 |
+
with open(json_path, 'r', encoding='utf-8') as f:
|
| 52 |
+
try:
|
| 53 |
+
chunks = json.load(f)
|
| 54 |
+
except json.JSONDecodeError:
|
| 55 |
+
print(f"Error decoding JSON in {json_path}. Skipping.")
|
| 56 |
+
continue
|
| 57 |
+
|
| 58 |
+
if not chunks:
|
| 59 |
+
continue
|
| 60 |
+
|
| 61 |
+
print(f"Loaded {len(chunks)} chunks.")
|
| 62 |
+
|
| 63 |
+
# Process in batches
|
| 64 |
+
for i in tqdm(range(0, len(chunks), BATCH_SIZE), desc="Uploading Batches"):
|
| 65 |
+
batch_chunks = chunks[i:i + BATCH_SIZE]
|
| 66 |
+
|
| 67 |
+
# Extract texts for embedding
|
| 68 |
+
texts_to_embed = [chunk["text"] for chunk in batch_chunks]
|
| 69 |
+
|
| 70 |
+
# Generate embeddings
|
| 71 |
+
embeddings = model.encode(texts_to_embed, normalize_embeddings=True)
|
| 72 |
+
|
| 73 |
+
# Prepare data for Supabase
|
| 74 |
+
supabase_payload = []
|
| 75 |
+
for j, chunk in enumerate(batch_chunks):
|
| 76 |
+
supabase_payload.append({
|
| 77 |
+
"chunk_id": chunk.get("id"),
|
| 78 |
+
"subject": chunk.get("subject", "Biology"),
|
| 79 |
+
"chapter": chunk.get("chapter", "Unknown"),
|
| 80 |
+
"chapter_number": str(chunk.get("chapter_number", "")),
|
| 81 |
+
"section": str(chunk.get("section", "")),
|
| 82 |
+
"section_title": chunk.get("section_title", ""),
|
| 83 |
+
"text_content": chunk.get("text", ""),
|
| 84 |
+
"embedding": embeddings[j].tolist() # Convert NumPy array to list
|
| 85 |
+
})
|
| 86 |
+
|
| 87 |
+
# Insert into Supabase
|
| 88 |
+
try:
|
| 89 |
+
# Upsert is safer in case of rerun (based on chunk_id if we specify it as unique, but we let uuid handle primary id)
|
| 90 |
+
# However, chunk_id is marked as unique in schema, so we should handle conflicts or just insert
|
| 91 |
+
response = supabase.table("ncert_knowledge_chunks").upsert(
|
| 92 |
+
supabase_payload,
|
| 93 |
+
on_conflict="chunk_id"
|
| 94 |
+
).execute()
|
| 95 |
+
|
| 96 |
+
except Exception as e:
|
| 97 |
+
print(f"Error inserting batch into Supabase: {e}")
|
| 98 |
+
|
| 99 |
+
print("\nβ
All embeddings uploaded successfully!")
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
if __name__ == "__main__":
|
| 103 |
+
process_and_upload()
|
pdf_to_embedding/json_ouput/11th Ncert output/Kebo101.json
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "bio_ch1_1.0_0001",
|
| 4 |
+
"subject": "Biology",
|
| 5 |
+
"chapter": "The Living World",
|
| 6 |
+
"chapter_number": "1",
|
| 7 |
+
"section": "1.0",
|
| 8 |
+
"section_title": "Introduction to Diversity in the Living World",
|
| 9 |
+
"text": "Biology is the science of life forms and living processes. The living world comprises an amazing diversity of living organisms. Early man could easily perceive the difference between inanimate matter and living organisms. Early man deified some of the inanimate matter (wind, sea, fire etc.) and some among the animals and plants. A common feature of all such forms of inanimate and animate objects was the sense of awe or fear that they evoked. The description of living organisms including human beings began much later in human history. Societies which indulged in anthropocentric view of biology could register limited progress in biological knowledge. Systematic and monumental description of life forms brought in, out of necessity, detailed systems of identification, nomenclature and classification. The biggest spin off of such studies was the recognition of the sharing of similarities among living organisms both horizontally and vertically. That all present day living organisms are related to each other and also to all organisms that ever lived on this earth, was a revelation which humbled man and led to cultural movements for conservation of biodiversity. In the following chapters of this unit, you will get a description, including classification, of animals and plants from a taxonomistβs perspective."
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"id": "bio_ch1_1.0_0002",
|
| 13 |
+
"subject": "Biology",
|
| 14 |
+
"chapter": "The Living World",
|
| 15 |
+
"chapter_number": "1",
|
| 16 |
+
"section": "1.0",
|
| 17 |
+
"section_title": "Ernst Mayr Biography",
|
| 18 |
+
"text": "Born on 5 July 1904, in Kempten, Germany, Ernst Mayr, the Harvard University evolutionary biologist who has been called βThe Darwin of the 20th centuryβ, was one of the 100 greatest scientists of all time. Mayr joined Harvardβs Faculty of Arts and Sciences in 1953 and retired in 1975, assuming the title Alexander Agassiz Professor of Zoology Emeritus. Throughout his nearly 80-year career, his research spanned ornithology, taxonomy, zoogeography, evolution, systematics, and the history and philosophy of biology. He almost single-handedly made the origin of species diversity the central question of evolutionary biology that it is today. He also pioneered the currently accepted definition of a biological species. Mayr was awarded the three prizes widely regarded as the triple crown of biology: the Balzan Prize in 1983, the International Prize for Biology in 1994, and the Crafoord Prize in 1999. Mayr died at the age of 100 in the year 2004."
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"id": "bio_ch1_1.1_0003",
|
| 22 |
+
"subject": "Biology",
|
| 23 |
+
"chapter": "The Living World",
|
| 24 |
+
"chapter_number": "1",
|
| 25 |
+
"section": "1.1",
|
| 26 |
+
"section_title": "Diversity in the Living World",
|
| 27 |
+
"text": "How wonderful is the living world! The wide range of living types is amazing. The extraordinary habitats in which we find living organisms, be it cold mountains, deciduous forests, oceans, fresh water lakes, deserts or hot springs, leave us speechless. The beauty of a galloping horse, of the migrating birds, the valley of flowers or the attacking shark evokes awe and a deep sense of wonder. The ecological conflict and cooperation among members of a population and among populations of a community or even the molecular traffic inside a cell make us deeply reflect on β what indeed is life? This question has two implicit questions within it. The first is a technical one and seeks answer to what living is as opposed to the non-living, and the second is a philosophical one, and seeks answer to what the purpose of life is. As scientists, we shall not attempt answering the second question. We will try to reflect on β what is living? If you look around you will see a large variety of living organisms, be it potted plants, insects, birds, your pets or other animals and plants."
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"id": "bio_ch1_1.1_0004",
|
| 31 |
+
"subject": "Biology",
|
| 32 |
+
"chapter": "The Living World",
|
| 33 |
+
"chapter_number": "1",
|
| 34 |
+
"section": "1.1",
|
| 35 |
+
"section_title": "Diversity in the Living World",
|
| 36 |
+
"text": "There are also several organisms that you cannot see with your naked eye but they are all around you. If you were to increase the area that you make observations in, the range and variety of organisms that you see would increase. Obviously, if you were to visit a dense forest, you would probably see a much greater number and kinds of living organisms in it. Each different kind of plant, animal or organism that you see, represents a species. The number of species that are known and described range between 1.7-1.8 million. This refers to biodiversity or the number and types of organisms present on earth. We should remember here that as we explore new areas, and even old ones, new organisms are continuously being identified. As stated earlier, there are millions of plants and animals in the world; we know the plants and animals in our own area by their local names. These local names would vary from place to place, even within a country. Probably you would recognise the confusion that would be created if we did not find ways and means to talk to each other, to refer to organisms we are talking about."
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"id": "bio_ch1_1.1_0005",
|
| 40 |
+
"subject": "Biology",
|
| 41 |
+
"chapter": "The Living World",
|
| 42 |
+
"chapter_number": "1",
|
| 43 |
+
"section": "1.1",
|
| 44 |
+
"section_title": "Diversity in the Living World",
|
| 45 |
+
"text": "Hence, there is a need to standardise the naming of living organisms such that a particular organism is known by the same name all over the world. This process is called nomenclature. Obviously, nomenclature or naming is only possible when the organism is described correctly and we know to what organism the name is attached to. This is identification. In order to facilitate the study, number of scientists have established procedures to assign a scientific name to each known organism. This is acceptable to biologists all over the world. For plants, scientific names are based on agreed principles and criteria, which are provided in International Code for Botanical Nomenclature (ICBN). Animal taxonomists have evolved International Code of Zoological Nomenclature (ICZN). The scientific names ensure that each organism has only one name. Description of any organism should enable the people to arrive at the same name. They also ensure that such a name has not been used for any other known organism."
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"id": "bio_ch1_1.1_0006",
|
| 49 |
+
"subject": "Biology",
|
| 50 |
+
"chapter": "The Living World",
|
| 51 |
+
"chapter_number": "1",
|
| 52 |
+
"section": "1.1",
|
| 53 |
+
"section_title": "Diversity in the Living World",
|
| 54 |
+
"text": "Biologists follow universally accepted principles to provide scientific names to known organisms. Each name has two components β the Generic name and the specific epithet. This system of providing a name with two components is called Binomial nomenclature. This naming system given by Carolus Linnaeus is being practised by biologists all over the world. This naming system using a two word format was found convenient. Let us take the example of mango to understand the way of providing scientific names better. The scientific name of mango is written as Mangifera indica. In this name Mangifera represents the genus while indica, is a particular species, or a specific epithet. Biological names are generally in Latin and written in italics. They are Latinised or derived from Latin irrespective of their origin. The first word in a biological name represents the genus while the second component denotes the specific epithet. Both the words in a biological name, when handwritten, are separately underlined, or printed in italics to indicate their Latin origin. The first word denoting the genus starts with a capital letter while the specific epithet starts with a small letter."
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"id": "bio_ch1_1.1_0007",
|
| 58 |
+
"subject": "Biology",
|
| 59 |
+
"chapter": "The Living World",
|
| 60 |
+
"chapter_number": "1",
|
| 61 |
+
"section": "1.1",
|
| 62 |
+
"section_title": "Diversity in the Living World",
|
| 63 |
+
"text": "Since it is nearly impossible to study all the living organisms, it is necessary to devise some means to make this possible. This process is classification. Classification is the process by which anything is grouped into convenient categories based on some easily observable characters. For example, we easily recognise groups such as plants or animals or dogs, cats or insects. The moment we use any of these terms, we associate certain characters with the organism in that group. These convenient categories we use to study organisms are scientifically termed as taxa. Here you must recognise that taxa can indicate categories at very different levels. βPlantsβ β also form a taxa. βWheatβ is also a taxa. Similarly, βanimalsβ, βmammalsβ, βdogsβ are all taxa β but you know that a dog is a mammal and mammals are animals. Therefore, βanimalsβ, βmammalsβ and βdogsβ represent taxa at different levels. Hence, based on characteristics, all living organisms can be classified into different taxa. This process of classification is taxonomy."
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"id": "bio_ch1_1.1_0008",
|
| 67 |
+
"subject": "Biology",
|
| 68 |
+
"chapter": "The Living World",
|
| 69 |
+
"chapter_number": "1",
|
| 70 |
+
"section": "1.1",
|
| 71 |
+
"section_title": "Diversity in the Living World",
|
| 72 |
+
"text": "External and internal structure, along with the structure of cell, development process and ecological information of organisms are essential and form the basis of modern taxonomic studies. Hence, characterisation, identification, classification and nomenclature are the processes that are basic to taxonomy. Human beings were, since long, not only interested in knowing more about different kinds of organisms and their diversities, but also the relationships among them. This branch of study was referred to as systematics. The word systematics is derived from the Latin word βsystemaβ which means systematic arrangement of organisms. Linnaeus used Systema Naturae as the title of his publication. The scope of systematics was later enlarged to include identification, nomenclature and classification. Systematics takes into account evolutionary relationships between organisms. Classification is not a single step process but involves hierarchy of steps in which each step represents a rank or category. Since the category is a part of overall taxonomic arrangement, it is called the taxonomic category and all categories together constitute the taxonomic hierarchy."
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"id": "bio_ch1_1.2_0009",
|
| 76 |
+
"subject": "Biology",
|
| 77 |
+
"chapter": "The Living World",
|
| 78 |
+
"chapter_number": "1",
|
| 79 |
+
"section": "1.2",
|
| 80 |
+
"section_title": "Taxonomic Categories",
|
| 81 |
+
"text": "Each category, referred to as a unit of classification, in fact, represents a rank and is commonly termed as taxon (pl.: taxa). Taxonomic categories and hierarchy can be illustrated by an example. Insects represent a group of organisms sharing common features like three pairs of jointed legs. It means insects are recognisable concrete objects which can be classified, and thus were given a rank or category. Category further denotes rank. Each rank or taxon, in fact, represents a unit of classification. These taxonomic groups/categories are distinct biological entities and not merely morphological aggregates. Taxonomical studies of all known organisms have led to the development of common categories such as kingdom, phylum or division (for plants), class, order, family, genus and species. All organisms, including those in the plant and animal kingdoms have species as the lowest category. The basic requirement is the knowledge of characters of an individual or group of organisms. This helps in identifying similarities and dissimilarities among the individuals of the same kind of organisms as well as of other kinds of organisms."
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"id": "bio_ch1_1.2.1_0010",
|
| 85 |
+
"subject": "Biology",
|
| 86 |
+
"chapter": "The Living World",
|
| 87 |
+
"chapter_number": "1",
|
| 88 |
+
"section": "1.2.1",
|
| 89 |
+
"section_title": "Species",
|
| 90 |
+
"text": "Taxonomic studies consider a group of individual organisms with fundamental similarities as a species. One should be able to distinguish one species from the other closely related species based on the distinct morphological differences. Let us consider Mangifera indica, Solanum tuberosum (potato) and Panthera leo (lion). All the three names, indica, tuberosum and leo, represent the specific epithets, while the first words Mangifera, Solanum and Panthera are genera and represents another higher level of taxon or category. Each genus may have one or more than one specific epithets representing different organisms, but having morphological similarities. For example, Panthera has another specific epithet called tigris and Solanum includes species like nigrum and melongena. Human beings belong to the species sapiens which is grouped in the genus Homo. The scientific name thus, for human being, is written as Homo sapiens."
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"id": "bio_ch1_1.2.2_0011",
|
| 94 |
+
"subject": "Biology",
|
| 95 |
+
"chapter": "The Living World",
|
| 96 |
+
"chapter_number": "1",
|
| 97 |
+
"section": "1.2.2",
|
| 98 |
+
"section_title": "Genus",
|
| 99 |
+
"text": "Genus comprises a group of related species which has more characters in common in comparison to species of other genera. We can say that genera are aggregates of closely related species. For example, potato and brinjal are two different species but both belong to the genus Solanum. Lion (Panthera leo), leopard (P. pardus) and tiger (P. tigris) with several common features, are all species of the genus Panthera. This genus differs from another genus Felis which includes cats. The next category, Family, has a group of related genera with still less number of similarities as compared to genus and species. Families are characterised on the basis of both vegetative and reproductive features of plant species. Among plants for example, three different genera Solanum, Petunia and Datura are placed in the family Solanaceae. Among animals for example, genus Panthera, comprising lion, tiger, leopard is put along with genus Felis (cats) in the family Felidae. Similarly, if you observe the features of a cat and a dog, you will find some similarities and some differences. They are separated into two different families β Felidae and Canidae, respectively."
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"id": "bio_ch1_1.2.4_0012",
|
| 103 |
+
"subject": "Biology",
|
| 104 |
+
"chapter": "The Living World",
|
| 105 |
+
"chapter_number": "1",
|
| 106 |
+
"section": "1.2.4",
|
| 107 |
+
"section_title": "Order, Class, and Phylum",
|
| 108 |
+
"text": "Generally, order and other higher taxonomic categories are identified based on the aggregates of characters. Order being a higher category, is the assemblage of families which exhibit a few similar characters. The similar characters are less in number as compared to different genera included in a family. Plant families like Convolvulaceae and Solanaceae are included in the order Polymoniales mainly based on the floral characters. The animal order, Carnivora, includes families like Felidae and Canidae. The category Class includes related orders. For example, order Primata comprising monkey, gorilla and gibbon is placed in class Mammalia along with order Carnivora that includes animals like tiger, cat and dog. Classes comprising animals like fishes, amphibians, reptiles, birds along with mammals constitute the next higher category called Phylum. All these, based on the common features like presence of notochord and dorsal hollow neural system, are included in phylum Chordata. In case of plants, classes with a few similar characters are assigned to a higher category called Division."
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"id": "bio_ch1_1.2.7_0013",
|
| 112 |
+
"subject": "Biology",
|
| 113 |
+
"chapter": "The Living World",
|
| 114 |
+
"chapter_number": "1",
|
| 115 |
+
"section": "1.2.7",
|
| 116 |
+
"section_title": "Kingdom",
|
| 117 |
+
"text": "All animals belonging to various phyla are assigned to the highest category called Kingdom Animalia in the classification system of animals. The Kingdom Plantae, on the other hand, is distinct, and comprises all plants from various divisions. The taxonomic categories from species to kingdom are broad categories. However, taxonomists have also developed sub-categories in this hierarchy to facilitate more sound and scientific placement of various taxa. As we go higher from species to kingdom, the number of common characteristics goes on decreasing. Lower the taxa, more are the characteristics that the members within the taxon share. Higher the category, greater is the difficulty of determining the relationship to other taxa at the same level. Hence, the problem of classification becomes more complex."
|
| 118 |
+
}
|
| 119 |
+
]
|
pdf_to_embedding/json_ouput/11th Ncert output/Kebo102.json
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"id": "bio_ch2_2.0_0001",
|
| 4 |
+
"subject": "Biology",
|
| 5 |
+
"chapter": "Biological Classification",
|
| 6 |
+
"chapter_number": "2",
|
| 7 |
+
"section": "2.0",
|
| 8 |
+
"section_title": "Introduction to Biological Classification",
|
| 9 |
+
"text": "Since the dawn of civilisation, there have been many attempts to classify living organisms. It was done instinctively not using criteria that were scientific but borne out of a need to use organisms for our own use β for food, shelter and clothing. Aristotle was the earliest to attempt a more scientific basis for classification. He used simple morphological characters to classify plants into trees, shrubs and herbs. He also divided animals into two groups, those which had red blood and those that did not. In Linnaeus' time a Two Kingdom system of classification with Plantae and Animalia kingdoms was developed that included all plants and animals respectively. This system did not distinguish between the eukaryotes and prokaryotes, unicellular and multicellular organisms and photosynthetic (green algae) and non-photosynthetic (fungi) organisms. Classification of organisms into plants and animals was easily done and was easy to understand, but, a large number of organisms did not fall into either category."
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"id": "bio_ch2_2.0_0002",
|
| 13 |
+
"subject": "Biology",
|
| 14 |
+
"chapter": "Biological Classification",
|
| 15 |
+
"chapter_number": "2",
|
| 16 |
+
"section": "2.0",
|
| 17 |
+
"section_title": "Development of the Five Kingdom System",
|
| 18 |
+
"text": "The two kingdom classification used for a long time was found inadequate. Besides gross morphology, a need was also felt for including other characteristics like cell structure, nature of wall, mode of nutrition, habitat, methods of reproduction, evolutionary relationships, etc. Classification systems for the living organisms have hence, undergone several changes over the time. Though plant and animal kingdoms have been a constant under all different systems, the understanding of what groups/organisms be included under these kingdoms have been changing. R.H. Whittaker (1969) proposed a Five Kingdom Classification. The kingdoms defined by him were named Monera, Protista, Fungi, Plantae and Animalia. The main criteria for classification used by him include cell structure, body organisation, mode of nutrition, reproduction and phylogenetic relationships. The three-domain system has also been proposed that divides the Kingdom Monera into two domains, leaving the remaining eukaryotic kingdoms in the third domain and thereby a six kingdom classification."
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"id": "bio_ch2_2.0_0003",
|
| 22 |
+
"subject": "Biology",
|
| 23 |
+
"chapter": "Biological Classification",
|
| 24 |
+
"chapter_number": "2",
|
| 25 |
+
"section": "2.0",
|
| 26 |
+
"section_title": "Rationalization of Kingdom Classification",
|
| 27 |
+
"text": "Earlier classification systems included bacteria, blue green algae, fungi, mosses, ferns, gymnosperms and the angiosperms under βPlantsβ. The character that unified this whole kingdom was that all the organisms included had a cell wall in their cells. This placed together groups which widely differed in other characteristics. It brought together the prokaryotic bacteria and the blue green algae (cyanobacteria) with other groups which were eukaryotic. It also grouped together the unicellular organisms and the multicellular ones, say, for example, Chlamydomonas and Spirogyra were placed together under algae. The classification did not differentiate between the heterotrophic group β fungi, and the autotrophic green plants, though they also showed a characteristic difference in their walls composition β the fungi had chitin in their walls while the green plants had a cellulosic cell wall. When such characteristics were considered, the fungi were placed in a separate kingdom β Kingdom Fungi. All prokaryotic organisms were grouped together under Kingdom Monera and the unicellular eukaryotic organisms were placed in Kingdom Protista."
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"id": "bio_ch2_2.1_0004",
|
| 31 |
+
"subject": "Biology",
|
| 32 |
+
"chapter": "Biological Classification",
|
| 33 |
+
"chapter_number": "2",
|
| 34 |
+
"section": "2.1",
|
| 35 |
+
"section_title": "Kingdom Monera",
|
| 36 |
+
"text": "Bacteria are the sole members of the Kingdom Monera. They are the most abundant micro-organisms. Bacteria occur almost everywhere. Hundreds of bacteria are present in a handful of soil. They also live in extreme habitats such as hot springs, deserts, snow and deep oceans where very few other life forms can survive. Many of them live in or on other organisms as parasites. Bacteria are grouped under four categories based on their shape: the spherical Coccus, the rod-shaped Bacillus, the comma-shaped Vibrium and the spiral Spirillum. Though the bacterial structure is very simple, they are very complex in behaviour. Compared to many other organisms, bacteria as a group show the most extensive metabolic diversity. Some of the bacteria are autotrophic, i.e., they synthesise their own food from inorganic substrates. They may be photosynthetic autotrophic or chemosynthetic autotrophic. The vast majority of bacteria are heterotrophs, i.e., they depend on other organisms or on dead organic matter for food."
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"id": "bio_ch2_2.1.1_0005",
|
| 40 |
+
"subject": "Biology",
|
| 41 |
+
"chapter": "Biological Classification",
|
| 42 |
+
"chapter_number": "2",
|
| 43 |
+
"section": "2.1.1",
|
| 44 |
+
"section_title": "Archaebacteria and Eubacteria",
|
| 45 |
+
"text": "Archaebacteria are special since they live in some of the most harsh habitats such as extreme salty areas (halophiles), hot springs (thermoacidophiles) and marshy areas (methanogens). Archaebacteria differ from other bacteria in having a different cell wall structure and this feature is responsible for their survival in extreme conditions. Methanogens are present in the gut of several ruminant animals such as cows and buffaloes and they are responsible for the production of methane (biogas) from the dung of these animals. There are thousands of different eubacteria or βtrue bacteriaβ. They are characterised by the presence of a rigid cell wall, and if motile, a flagellum. The cyanobacteria (also referred to as blue-green algae) have chlorophyll a similar to green plants and are photosynthetic autotrophs. The cyanobacteria are unicellular, colonial or filamentous, freshwater/marine or terrestrial algae. The colonies are generally surrounded by gelatinous sheath. They often form blooms in polluted water bodies."
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"id": "bio_ch2_2.1.2_0006",
|
| 49 |
+
"subject": "Biology",
|
| 50 |
+
"chapter": "Biological Classification",
|
| 51 |
+
"chapter_number": "2",
|
| 52 |
+
"section": "2.1.2",
|
| 53 |
+
"section_title": "Metabolic Diversity and Reproduction in Monera",
|
| 54 |
+
"text": "Some cyanobacteria can fix atmospheric nitrogen in specialised cells called heterocysts, e.g., Nostoc and Anabaena. Chemosynthetic autotrophic bacteria oxidise various inorganic substances such as nitrates, nitrites and ammonia and use the released energy for their ATP production. They play a great role in recycling nutrients like nitrogen, phosphorous, iron and sulphur. Heterotrophic bacteria are most abundant in nature. The majority are important decomposers. Many of them have a significant impact on human affairs. They are helpful in making curd from milk, production of antibiotics, and fixing nitrogen in legume roots. Some are pathogens causing damage to human beings, crops, farm animals and pets. Cholera, typhoid, tetanus, citrus canker are well known diseases caused by different bacteria. Bacteria reproduce mainly by fission. Sometimes, under unfavourable conditions, they produce spores. They also reproduce by a sort of sexual reproduction by adopting a primitive type of DNA transfer from one bacterium to the other. The Mycoplasma are organisms that completely lack a cell wall. They are the smallest living cells known and can survive without oxygen."
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
"id": "bio_ch2_2.2_0007",
|
| 58 |
+
"subject": "Biology",
|
| 59 |
+
"chapter": "Biological Classification",
|
| 60 |
+
"chapter_number": "2",
|
| 61 |
+
"section": "2.2",
|
| 62 |
+
"section_title": "Kingdom Protista",
|
| 63 |
+
"text": "All single-celled eukaryotes are placed under Protista, but the boundaries of this kingdom are not well defined. What may be βa photosynthetic protistanβ to one biologist may be βa plantβ to another. In this book we include Chrysophytes, Dinoflagellates, Euglenoids, Slime moulds and Protozoans under Protista. Members of Protista are primarily aquatic. This kingdom forms a link with the others dealing with plants, animals and fungi. Being eukaryotes, the protistan cell body contains a well defined nucleus and other membrane-bound organelles. Some have flagella or cilia. Protists reproduce asexually and sexually by a process involving cell fusion and zygote formation. Chrysophytes include diatoms and golden algae (desmids). They are found in fresh water as well as in marine environments. They are microscopic and float passively in water currents (plankton). Most of them are photosynthetic. In diatoms the cell walls form two thin overlapping shells, which fit together as in a soap box. The walls are embedded with silica and thus the walls are indestructible. diatoms have left behind large amount of cell wall deposits in their habitat; this accumulation is referred to as βdiatomaceous earthβ."
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"id": "bio_ch2_2.2.2_0008",
|
| 67 |
+
"subject": "Biology",
|
| 68 |
+
"chapter": "Biological Classification",
|
| 69 |
+
"chapter_number": "2",
|
| 70 |
+
"section": "2.2.2",
|
| 71 |
+
"section_title": "Dinoflagellates, Euglenoids, and Slime Moulds",
|
| 72 |
+
"text": "Dinoflagellates are mostly marine and photosynthetic. They appear yellow, green, brown, blue or red depending on the main pigments present in their cells. The cell wall has stiff cellulose plates on the outer surface. Most of them have two flagella. Very often, red dinoflagellates (Example: Gonyaulax) undergo such rapid multiplication that they make the sea appear red (red tides). Euglenoids are mostly fresh water organisms found in stagnant water. Instead of a cell wall, they have a protein rich layer called pellicle which makes their body flexible. They have two flagella, a short and a long one. Though they are photosynthetic in the presence of sunlight, when deprived of sunlight they behave like heterotrophs by predating on other smaller organisms. Slime moulds are saprophytic protists. The body moves along decaying twigs and leaves engulfing organic material. Under suitable conditions, they form an aggregation called plasmodium. During unfavourable conditions, the plasmodium differentiates and forms fruiting bodies bearing spores at their tips. The spores possess true walls and are extremely resistant."
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"id": "bio_ch2_2.2.5_0009",
|
| 76 |
+
"subject": "Biology",
|
| 77 |
+
"chapter": "Biological Classification",
|
| 78 |
+
"chapter_number": "2",
|
| 79 |
+
"section": "2.2.5",
|
| 80 |
+
"section_title": "Protozoans",
|
| 81 |
+
"text": "All protozoans are heterotrophs and live as predators or parasites. They are believed to be primitive relatives of animals. There are four major groups of protozoans. Amoeboid protozoans live in fresh water, sea water or moist soil. They move and capture their prey by putting out pseudopodia (false feet) as in Amoeba. Flagellated protozoans are either free-living or parasitic. They have flagella. The parasitic forms cause diseases such as sleeping sickness, e.g., Trypanosoma. Ciliated protozoans are aquatic, actively moving organisms because of the presence of thousands of cilia. They have a cavity (gullet) that opens to the outside of the cell surface. The coordinated movement of rows of cilia causes the water laden with food to be steered into the gullet, e.g., Paramoecium. Sporozoans include diverse organisms that have an infectious spore-like stage in their life cycle. The most notorious is Plasmodium (malarial parasite) which causes malaria, a disease which has a staggering effect on human population."
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"id": "bio_ch2_2.3_0010",
|
| 85 |
+
"subject": "Biology",
|
| 86 |
+
"chapter": "Biological Classification",
|
| 87 |
+
"chapter_number": "2",
|
| 88 |
+
"section": "2.3",
|
| 89 |
+
"section_title": "Kingdom Fungi",
|
| 90 |
+
"text": "The fungi constitute a unique kingdom of heterotrophic organisms. They show a great diversity in morphology and habitat. Fungi are cosmopolitan and occur in air, water, soil and on animals and plants. They prefer to grow in warm and humid places. With the exception of yeasts which are unicellular, fungi are filamentous. Their bodies consist of long, slender thread-like structures called hyphae. The network of hyphae is known as mycelium. Some hyphae are continuous tubes filled with multinucleated cytoplasm β these are called coenocytic hyphae. Others have septae or cross walls in their hyphae. The cell walls of fungi are composed of chitin and polysaccharides. Most fungi are heterotrophic and absorb soluble organic matter from dead substrates and hence are called saprophytes. Those that depend on living plants and animals are called parasites. They can also live as symbionts β in association with algae as lichens and with roots of higher plants as mycorrhiza. Reproduction in fungi can take place by vegetative means β fragmentation, fission and budding."
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"id": "bio_ch2_2.3_0011",
|
| 94 |
+
"subject": "Biology",
|
| 95 |
+
"chapter": "Biological Classification",
|
| 96 |
+
"chapter_number": "2",
|
| 97 |
+
"section": "2.3",
|
| 98 |
+
"section_title": "Fungal Life Cycle and Classification Basis",
|
| 99 |
+
"text": "Asexual reproduction in fungi is by spores called conidia or sporangiospores or zoospores, and sexual reproduction is by oospores, ascospores and basidiospores. The various spores are produced in distinct structures called fruiting bodies. The sexual cycle involves three steps: Fusion of protoplasms between two motile or non-motile gametes called plasmogamy; Fusion of two nuclei called karyogamy; and Meiosis in zygote resulting in haploid spores. When a fungus reproduces sexually, two haploid hyphae of compatible mating types come together and fuse. In some fungi, the fusion of two haploid cells immediately results in diploid cells (2n). However, in ascomycetes and basidiomycetes, an intervening dikaryotic stage (n + n, i.e., two nuclei per cell) occurs; such a condition is called a dikaryon and the phase is called dikaryophase. Later, the parental nuclei fuse and the cells become diploid. The fungi form fruiting bodies in which reduction division occurs, leading to formation of haploid spores. The morphology of the mycelium, mode of spore formation and fruiting bodies form the basis for the division of the kingdom into various classes."
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"id": "bio_ch2_2.3.1_0012",
|
| 103 |
+
"subject": "Biology",
|
| 104 |
+
"chapter": "Biological Classification",
|
| 105 |
+
"chapter_number": "2",
|
| 106 |
+
"section": "2.3.1",
|
| 107 |
+
"section_title": "Classes of Fungi",
|
| 108 |
+
"text": "Phycomycetes are found in aquatic habitats and on decaying wood in moist and damp places or as obligate parasites on plants. The mycelium is aseptate and coenocytic. Asexual reproduction takes place by zoospores (motile) or by aplanospores (non-motile). These spores are endogenously produced in sporangium. A zygospore is formed by fusion of two gametes. Ascomycetes, commonly known as sac-fungi, are mostly multicellular, e.g., Penicillium, or rarely unicellular, e.g., yeast. They are saprophytic, decomposers, parasitic or coprophilous. Mycelium is branched and septate. The asexual spores are conidia produced exogenously on special mycelium called conidiophores. Sexual spores are called ascospores which are produced endogenously in sac like asci. Basidiomycetes include mushrooms, bracket fungi or puffballs. They grow in soil, on logs and tree stumps. The mycelium is branched and septate. Asexual spores are generally not found, but vegetative reproduction by fragmentation is common. Deuteromycetes are known as imperfect fungi because only the asexual or vegetative phases are known. Once the sexual stage is discovered, they are moved to ascomycetes or basidiomycetes."
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"id": "bio_ch2_2.4_0013",
|
| 112 |
+
"subject": "Biology",
|
| 113 |
+
"chapter": "Biological Classification",
|
| 114 |
+
"chapter_number": "2",
|
| 115 |
+
"section": "2.4",
|
| 116 |
+
"section_title": "Kingdoms Plantae and Animalia",
|
| 117 |
+
"text": "Kingdom Plantae includes all eukaryotic chlorophyll-containing organisms commonly called plants. A few members are partially heterotrophic such as the insectivorous plants (Bladderwort, Venus fly trap) or parasites (Cuscuta). The plant cells have an eukaryotic structure with prominent chloroplasts and a cell wall mainly made of cellulose. Plantae includes algae, bryophytes, pteridophytes, gymnosperms and angiosperms. The life cycle of plants has two distinct phases β the diploid sporophytic and the haploid gametophytic β that alternate with each other. This phenomenon is called alternation of generations. Kingdom Animalia is characterised by heterotrophic eukaryotic organisms that are multicellular and their cells lack cell walls. They directly or indirectly depend on plants for food. They digest their food in an internal cavity and store food reserves as glycogen or fat. Their mode of nutrition is holozoic β by ingestion of food. They follow a definite growth pattern and grow into adults that have a definite shape and size. Most of them are capable of locomotion."
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"id": "bio_ch2_2.6_0014",
|
| 121 |
+
"subject": "Biology",
|
| 122 |
+
"chapter": "Biological Classification",
|
| 123 |
+
"chapter_number": "2",
|
| 124 |
+
"section": "2.6",
|
| 125 |
+
"section_title": "Viruses, Viroids, and Prions",
|
| 126 |
+
"text": "In the five kingdom classification of Whittaker there is no mention of lichens and some acellular organisms like viruses, viroids and prions. Viruses did not find a place in classification since they are not considered truly βlivingβ, as they do not have a cell structure. They are non-cellular organisms characterised by having an inert crystalline structure outside the living cell. Once they infect a cell, they take over the machinery of the host cell to replicate themselves. Dmitri Ivanowsky (1892) recognised certain microbes as causal organism of the mosaic disease of tobacco. M.W. Beijerinck (1898) demonstrated that the extract of the infected plants of tobacco could cause infection in healthy plants and called the fluid Contagium vivum fluidum. W.M. Stanley (1935) showed that viruses could be crystallised and crystals consist largely of proteins. A virus is a nucleoprotein and the genetic material is infectious. No virus contains both RNA and DNA. In general, viruses that infect plants have single stranded RNA and viruses that infect animals have either single or double stranded RNA or double stranded DNA."
|
| 127 |
+
},
|
| 128 |
+
{
|
| 129 |
+
"id": "bio_ch2_2.6_0015",
|
| 130 |
+
"subject": "Biology",
|
| 131 |
+
"chapter": "Biological Classification",
|
| 132 |
+
"chapter_number": "2",
|
| 133 |
+
"section": "2.6",
|
| 134 |
+
"section_title": "Viroids, Prions, and Lichens",
|
| 135 |
+
"text": "In 1971, T.O. Diener discovered a new infectious agent called a viroid that was smaller than viruses and caused potato spindle tuber disease. It was found to be a free RNA lacking the protein coat found in viruses. The RNA of the viroid was of low molecular weight. In modern medicine, certain infectious neurological diseases were found to be transmitted by an agent consisting of abnormally folded protein called prions. The agent was similar in size to viruses. The most notable diseases caused by prions are bovine spongiform encephalopathy (BSE) in cattle and CreutzfeldtβJacob disease (CJD) in humans. Lichens are symbiotic associations between algae and fungi. The algal component is known as phycobiont and fungal component as mycobiont, which are autotrophic and heterotrophic, respectively. Algae prepare food for fungi and fungi provide shelter and absorb mineral nutrients and water for its partner. Lichens are very good pollution indicators β they do not grow in polluted areas."
|
| 136 |
+
}
|
| 137 |
+
]
|
pdf_to_embedding/json_ouput/11th Ncert output/Kebo103.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
[
|
| 3 |
+
{
|
| 4 |
+
"id": "bio_ch3_3.0_0001",
|
| 5 |
+
"subject": "Biology",
|
| 6 |
+
"chapter": "Plant Kingdom",
|
| 7 |
+
"chapter_number": "3",
|
| 8 |
+
"section": "3.0",
|
| 9 |
+
"section_title": "Introduction to Plant Classification",
|
| 10 |
+
"text": "Our understanding of the plant kingdom has changed over time. Fungi, and members of the Monera and Protista having cell walls have now been excluded from Plantae though earlier classifications placed them in the same kingdom. So, the cyanobacteria that are also referred to as blue green algae are not βalgaeβ any more. In this chapter, we will describe Algae, Bryophytes, Pteridophytes, Gymnosperms and Angiosperms under Plantae. The earliest systems of classification used only gross superficial morphological characters such as habit, colour, number and shape of leaves, etc. They were based mainly on vegetative characters or on the androecium structure. Such systems were artificial; they separated the closely related species since they were based on a few characteristics. Also, the artificial systems gave equal weightage to vegetative and sexual characteristics; this is not acceptable since we know that often the vegetative characters are more easily affected by environment. As against this, natural classification systems developed, which were based on natural affinities among the organisms and consider, not only the external features, but also internal features, like ultra structure, anatomy, embryology and phytochemistry."
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"id": "bio_ch3_3.0_0002",
|
| 14 |
+
"subject": "Biology",
|
| 15 |
+
"chapter": "Plant Kingdom",
|
| 16 |
+
"chapter_number": "3",
|
| 17 |
+
"section": "3.0",
|
| 18 |
+
"section_title": "Modern Taxonomic Approaches",
|
| 19 |
+
"text": "At present phylogenetic classification systems based on evolutionary relationships between the various organisms are acceptable. This assumes that organisms belonging to the same taxa have a common ancestor. We now use information from many other sources too to help resolve difficulties in classification. These become more important when there is no supporting fossil evidence. Numerical Taxonomy which is now easily carried out using computers is based on all observable characteristics. Number and codes are assigned to all the characters and the data are then processed. In this way each character is given equal importance and at the same time hundreds of characters can be considered. Cytotaxonomy, that is based on cytological information like chromosome number, structure, behaviour and chemotaxonomy, that uses the chemical constituents of the plant to resolve confusions, are also used by taxonomists these days."
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"id": "bio_ch3_3.1_0003",
|
| 23 |
+
"subject": "Biology",
|
| 24 |
+
"chapter": "Plant Kingdom",
|
| 25 |
+
"chapter_number": "3",
|
| 26 |
+
"section": "3.1",
|
| 27 |
+
"section_title": "Algae Characteristics and Reproduction",
|
| 28 |
+
"text": "Algae are chlorophyll-bearing, simple, thalloid, autotrophic and largely aquatic organisms. They occur in a variety of other habitats: moist stones, soils and wood. Some of them also occur in association with fungi (lichen) and animals. The form and size of algae is highly variable, ranging from colonial forms like Volvox and the filamentous forms like Ulothrix and Spirogyra. A few of the marine forms such as kelps, form massive plant bodies. The algae reproduce by vegetative, asexual and sexual methods. Vegetative reproduction is by fragmentation. Asexual reproduction is by the production of different types of spores, the most common being the zoospores. They are flagellated (motile) and on germination gives rise to new plants. Sexual reproduction takes place through fusion of two gametes. These gametes can be flagellated and similar in size or non-flagellated but similar in size. Such reproduction is called isogamous. Fusion of two gametes dissimilar in size is termed as anisogamous. Fusion between one large, non-motile female gamete and a smaller, motile male gamete is termed oogamous."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"id": "bio_ch3_3.1_0004",
|
| 32 |
+
"subject": "Biology",
|
| 33 |
+
"chapter": "Plant Kingdom",
|
| 34 |
+
"chapter_number": "3",
|
| 35 |
+
"section": "3.1",
|
| 36 |
+
"section_title": "Economic Importance of Algae",
|
| 37 |
+
"text": "Algae are useful to man in a variety of ways. At least a half of the total carbon dioxide fixation on earth is carried out by algae through photosynthesis. Being photosynthetic, they increase the level of dissolved oxygen in their immediate environment. They are of paramount importance as primary producers of energy-rich compounds which form the basis of the food cycles of all aquatic animals. Many species of Porphyra, Laminaria and Sargassum are among the 70 species of marine algae used as food. Certain marine brown and red algae produce large amounts of hydrocolloids (water holding substances), e.g., algin (brown algae) and carrageen (red algae) which are used commercially. Agar, one of the commercial products obtained from Gelidium and Gracilaria are used to grow microbes and in preparations of ice-creams and jellies. Chlorella, a unicellular alga rich in proteins, is used as food supplement even by space travellers. The algae are divided into three main classes: Chlorophyceae, Phaeophyceae and Rhodophyceae."
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"id": "bio_ch3_3.1.1_0005",
|
| 41 |
+
"subject": "Biology",
|
| 42 |
+
"chapter": "Plant Kingdom",
|
| 43 |
+
"chapter_number": "3",
|
| 44 |
+
"section": "3.1.1",
|
| 45 |
+
"section_title": "Chlorophyceae (Green Algae)",
|
| 46 |
+
"text": "The members of chlorophyceae are commonly called green algae. The plant body may be unicellular, colonial or filamentous. They are usually grass green due to the dominance of pigments chlorophyll a and b. The pigments are localised in definite chloroplasts. The chloroplasts may be discoid, plate-like, reticulate, cup-shaped, spiral or ribbon-shaped in different species. Most of the members have one or more storage bodies called pyrenoids located in the chloroplasts. Pyrenoids contain protein besides starch. Some algae may store food in the form of oil droplets. Green algae usually have a rigid cell wall made of an inner layer of cellulose and an outer layer of pectose. Vegetative reproduction usually takes place by fragmentation. Asexual reproduction is by flagellated zoospores produced in zoosporangia. The sexual reproduction shows considerable variation in the type and formation of sex cells and it may be isogamous, anisogamous or oogamous. Some commonly found green algae are: Chlamydomonas, Volvox, Ulothrix, Spirogyra and Chara."
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"id": "bio_ch3_3.1.2_0006",
|
| 50 |
+
"subject": "Biology",
|
| 51 |
+
"chapter": "Plant Kingdom",
|
| 52 |
+
"chapter_number": "3",
|
| 53 |
+
"section": "3.1.2",
|
| 54 |
+
"section_title": "Phaeophyceae (Brown Algae)",
|
| 55 |
+
"text": "The members of phaeophyceae or brown algae are found primarily in marine habitats. They range from simple branched, filamentous forms to profusely branched forms as represented by kelps, which may reach a height of 100 metres. They possess chlorophyll a, c, carotenoids and xanthophylls. They vary in colour from olive green to various shades of brown depending upon the amount of the xanthophyll pigment, fucoxanthin. Food is stored as complex carbohydrates, which may be in the form of laminarin or mannitol. The vegetative cells have a cellulosic wall usually covered on the outside by a gelatinous coating of algin. The plant body is usually attached to the substratum by a holdfast, and has a stalk, the stipe and leaf like photosynthetic organ β the frond. Asexual reproduction in most brown algae is by biflagellate zoospores that are pear-shaped and have two unequal laterally attached flagella. Sexual reproduction may be isogamous, anisogamous or oogamous. Common forms are Ectocarpus, Dictyota, Laminaria, Sargassum and Fucus."
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"id": "bio_ch3_3.1.3_0007",
|
| 59 |
+
"subject": "Biology",
|
| 60 |
+
"chapter": "Plant Kingdom",
|
| 61 |
+
"chapter_number": "3",
|
| 62 |
+
"section": "3.1.3",
|
| 63 |
+
"section_title": "Rhodophyceae (Red Algae)",
|
| 64 |
+
"text": "The members of rhodophyceae are commonly called red algae because of the predominance of the red pigment, r-phycoerythrin. Majority of the red algae are marine with greater concentrations found in the warmer areas. They occur in both well-lighted regions close to the surface of water and also at great depths in oceans where relatively little light penetrates. The red thalli of most of the red algae are multicellular. Some of them have complex body organisation. The food is stored as floridean starch which is very similar to amylopectin and glycogen in structure. The red algae usually reproduce vegetatively by fragmentation. They reproduce asexually by non-motile spores and sexually by non-motile gametes. Sexual reproduction is oogamous and accompanied by complex post fertilisation developments. The common members are: Polysiphonia, Porphyra, Gracilaria and Gelidium."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"id": "bio_ch3_3.2_0008",
|
| 68 |
+
"subject": "Biology",
|
| 69 |
+
"chapter": "Plant Kingdom",
|
| 70 |
+
"chapter_number": "3",
|
| 71 |
+
"section": "3.2",
|
| 72 |
+
"section_title": "Bryophytes Overview and Life Cycle",
|
| 73 |
+
"text": "Bryophytes include the various mosses and liverworts that are found commonly growing in moist shaded areas in the hills. Bryophytes are also called amphibians of the plant kingdom because these plants can live in soil but are dependent on water for sexual reproduction. They play an important role in plant succession on bare rocks/soil. The plant body of bryophytes is more differentiated than that of algae. It is thallus-like and prostrate or erect, and attached to the substratum by unicellular or multicellular rhizoids. They lack true roots, stem or leaves. They may possess root-like, leaf-like or stem-like structures. The main plant body of the bryophyte is haploid. It produces gametes, hence is called a gametophyte. The sex organs in bryophytes are multicellular. The male sex organ is called antheridium. They produce biflagellate antherozoids. The female sex organ called archegonium is flask-shaped and produces a single egg. An antherozoid fuses with the egg to produce the zygote. Zygotes produce a multicellular body called a sporophyte."
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"id": "bio_ch3_3.2_0009",
|
| 77 |
+
"subject": "Biology",
|
| 78 |
+
"chapter": "Plant Kingdom",
|
| 79 |
+
"chapter_number": "3",
|
| 80 |
+
"section": "3.2",
|
| 81 |
+
"section_title": "Economic and Ecological Importance of Bryophytes",
|
| 82 |
+
"text": "The sporophyte is not free-living but attached to the photosynthetic gametophyte and derives nourishment from it. Some cells of the sporophyte undergo reduction division (meiosis) to produce haploid spores. These spores germinate to produce gametophyte. Bryophytes in general are of little economic importance but some mosses provide food for herbaceous mammals, birds and other animals. Species of Sphagnum provide peat that have long been used as fuel, and as packing material for trans-shipment of living material because of their capacity to hold water. Mosses along with lichens are the first organisms to colonise rocks and hence, are of great ecological importance. They decompose rocks making the substrate suitable for the growth of higher plants. Since mosses form dense mats on the soil, they reduce the impact of falling rain and prevent soil erosion. The bryophytes are divided into liverworts and mosses."
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"id": "bio_ch3_3.2.1_0010",
|
| 86 |
+
"subject": "Biology",
|
| 87 |
+
"chapter": "Plant Kingdom",
|
| 88 |
+
"chapter_number": "3",
|
| 89 |
+
"section": "3.2.1",
|
| 90 |
+
"section_title": "Liverworts and Mosses",
|
| 91 |
+
"text": "The liverworts grow usually in moist, shady habitats such as banks of streams, marshy ground, damp soil, bark of trees and deep in the woods. The plant body of a liverwort is thalloid, e.g., Marchantia. Asexual reproduction in liverworts takes place by fragmentation of thalli, or by the formation of specialised structures called gemmae. Gemmae are green, multicellular, asexual buds, which develop in small receptacles called gemma cups located on the thalli. The predominant stage of the life cycle of a moss is the gametophyte which consists of two stages: the protonema stage and the leafy stage. The first stage develops directly from a spore. The second stage develops from the secondary protonema as a lateral bud and consists of upright axes bearing spirally arranged leaves. Mosses have an elaborate mechanism of spore dispersal. Common examples of mosses are Funaria, Polytrichum and Sphagnum."
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"id": "bio_ch3_3.3_0011",
|
| 95 |
+
"subject": "Biology",
|
| 96 |
+
"chapter": "Plant Kingdom",
|
| 97 |
+
"chapter_number": "3",
|
| 98 |
+
"section": "3.3",
|
| 99 |
+
"section_title": "Pteridophytes: Vascular Non-Seeded Plants",
|
| 100 |
+
"text": "The Pteridophytes include horsetails and ferns. Pteridophytes are used for medicinal purposes and as soil-binders. They are also frequently grown as ornamentals. Evolutionarily, they are the first terrestrial plants to possess vascular tissues β xylem and phloem. The pteridophytes are found in cool, damp, shady places. In pteridophytes, the dominant phase in the life cycle is the sporophyte which is differentiated into true root, stem and leaves. These organs possess well-differentiated vascular tissues. The leaves in pteridophyta are small (microphylls) as in Selaginella or large (macrophylls) as in ferns. The sporophytes bear sporangia that are subtended by leaf-like appendages called sporophylls. In some cases sporophylls may form distinct compact structures called strobili or cones. The sporangia produce spores by meiosis in spore mother cells. The spores germinate to give rise to inconspicuous, small but multicellular, free-living, mostly photosynthetic thalloid gametophytes called prothallus."
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"id": "bio_ch3_3.3_0012",
|
| 104 |
+
"subject": "Biology",
|
| 105 |
+
"chapter": "Plant Kingdom",
|
| 106 |
+
"chapter_number": "3",
|
| 107 |
+
"section": "3.3",
|
| 108 |
+
"section_title": "Pteridophyte Reproduction and Classification",
|
| 109 |
+
"text": "Pteridophyte gametophytes require cool, damp, shady places to grow. Because of this specific restricted requirement and the need for water for fertilisation, the spread of living pteridophytes is limited and restricted to narrow geographical regions. The gametophytes bear male and female sex organs called antheridia and archegonia, respectively. Water is required for transfer of antherozoids to the mouth of archegonium. Fusion of male gamete with the egg result in the formation of zygote. Zygote thereafter produces a multicellular well-differentiated sporophyte which is the dominant phase. In majority of the pteridophytes all the spores are of similar kinds; such plants are called homosporous. Genera like Selaginella and Salvinia which produce two kinds of spores, macro and micro spores, are known as heterosporous. The development of the zygotes into young embryos take place within the female gametophytes. This event is a precursor to the seed habit. The pteridophytes are classified into four classes: Psilopsida, Lycopsida, Sphenopsida and Pteropsida."
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"id": "bio_ch3_3.4_0013",
|
| 113 |
+
"subject": "Biology",
|
| 114 |
+
"chapter": "Plant Kingdom",
|
| 115 |
+
"chapter_number": "3",
|
| 116 |
+
"section": "3.4",
|
| 117 |
+
"section_title": "Gymnosperms Characteristics",
|
| 118 |
+
"text": "The gymnosperms are plants in which the ovules are not enclosed by any ovary wall and remain exposed, both before and after fertilisation. The seeds that develop post-fertilisation, are not covered. Gymnosperms include medium-sized trees or tall trees and shrubs. One of the gymnosperms, the giant redwood tree Sequoia is one of the tallest tree species. The roots are generally tap roots. Roots in some genera have fungal association in the form of mycorrhiza, while in some others small specialised roots called coralloid roots are associated with nitrogen-fixing cyanobacteria. The stems are unbranched or branched. The leaves may be simple or compound. The leaves in gymnosperms are well-adapted to withstand extremes of temperature, humidity and wind. In conifers, the needle-like leaves reduce the surface area. Their thick cuticle and sunken stomata also help to reduce water loss."
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"id": "bio_ch3_3.4_0014",
|
| 122 |
+
"subject": "Biology",
|
| 123 |
+
"chapter": "Plant Kingdom",
|
| 124 |
+
"chapter_number": "3",
|
| 125 |
+
"section": "3.4",
|
| 126 |
+
"section_title": "Gymnosperm Reproduction",
|
| 127 |
+
"text": "The gymnosperms are heterosporous; they produce haploid microspores and megaspores. The two kinds of spores are produced within sporangia that are borne on sporophylls which are arranged spirally along an axis to form lax or compact strobili or cones. The strobili bearing microsporophylls are called male strobili. The microspores develop into a highly reduced male gametophyte called a pollen grain. The cones bearing megasporophylls with ovules are called female strobili. The megaspore mother cell divides meiotically to form four megaspores. One of the megaspores develops into a multicellular female gametophyte that bears two or more archegonia. Unlike bryophytes and pteridophytes, in gymnosperms, the male and the female gametophytes do not have an independent free-living existence. They remain within the sporangia retained on the sporophytes. The pollen grain is released and carried in air currents to come in contact with the opening of the ovules. Following fertilisation, zygote develops into an embryo and the ovules into seeds."
|
| 128 |
+
},
|
| 129 |
+
{
|
| 130 |
+
"id": "bio_ch3_3.5_0015",
|
| 131 |
+
"subject": "Biology",
|
| 132 |
+
"chapter": "Plant Kingdom",
|
| 133 |
+
"chapter_number": "3",
|
| 134 |
+
"section": "3.5",
|
| 135 |
+
"section_title": "Angiosperms: Flowering Plants",
|
| 136 |
+
"text": "Unlike the gymnosperms where the ovules are naked, in the angiosperms or flowering plants, the pollen grains and ovules are developed in specialised structures called flowers. In angiosperms, the seeds are enclosed in fruits. The angiosperms are an exceptionally large group of plants occurring in wide range of habitats. They range in size from the smallest Wolffia to tall trees of Eucalyptus. They provide us with food, fodder, fuel, medicines and several other commercially important products. They are divided into two classes: the dicotyledons and the monocotyledons. The dicotyledons are characterised by having two cotyledons in their seeds while the monocotyledons have only one. In angiosperms, the male sex organ in a flower is the stamen and the female sex organ is the pistil or the carpel. The pollen grains are produced in the anthers, while the ovary at the base of the pistil contains ovules. Following double fertilisation, the ovules develop into seeds and the ovaries develop into fruits."
|
| 137 |
+
}
|
| 138 |
+
]
|
pdf_to_embedding/json_ouput/11th Ncert output/Kebo104.json
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
[
|
| 3 |
+
{
|
| 4 |
+
"id": "bio_ch4_4.1_0000",
|
| 5 |
+
"subject": "Biology",
|
| 6 |
+
"chapter": "Animal Kingdom",
|
| 7 |
+
"chapter_number": "4",
|
| 8 |
+
"section": "4.1",
|
| 9 |
+
"section_title": "Basis of Classification and Levels of Organisation",
|
| 10 |
+
"text": "When you look around, you will observe different animals with different structures and forms. As over a million species of animals have been described till now, the need for classification becomes all the more important. The classification also helps in assigning a systematic position to newly described species. Inspite of differences in structure and form of different animals, there are fundamental features common to various individuals in relation to the arrangement of cells, body symmetry, nature of coelom, patterns of digestive, circulatory or reproductive systems. These features are used as the basis of animal classification. Though all members of Animalia are multicellular, all of them do not exhibit the same pattern of organisation of cells. For example, in sponges, the cells are arranged as loose cell aggregates, i.e., they exhibit cellular level of organisation. Some division of labour (activities) occur among the cells. In coelenterates, the arrangement of cells is more complex. Here the cells performing the same function are arranged into tissues, hence is called tissue level of organisation. A still higher level of organisation, i.e., organ level is exhibited by members of Platyhelminthes and other higher phyla where tissues are grouped together to form organs, each specialised for a particular function."
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"id": "bio_ch4_4.1.1_0001",
|
| 14 |
+
"subject": "Biology",
|
| 15 |
+
"chapter": "Animal Kingdom",
|
| 16 |
+
"chapter_number": "4",
|
| 17 |
+
"section": "4.1.1",
|
| 18 |
+
"section_title": "Organ Systems and Body Symmetry",
|
| 19 |
+
"text": "In animals like Annelids, Arthropods, Molluscs, Echinoderms and Chordates, organs have associated to form functional systems, each system concerned with a specific physiological function. This pattern is called organ system level of organisation. Organ systems in different groups of animals exhibit various patterns of complexities. For example, the digestive system in Platyhelminthes has only a single opening to the outside of the body that serves as both mouth and anus, and is hence called incomplete. A complete digestive system has two openings, mouth and anus. Similarly, the circulatory system may be of two types: (i) open type in which the blood is pumped out of the heart and the cells and tissues are directly bathed in it and (ii) closed type in which the blood is circulated through a series of vessels of varying diameters (arteries, veins and capillaries). Animals can be categorised on the basis of their symmetry. Sponges are mostly asymmetrical, i.e., any plane that passes through the centre does not divide them into equal halves. When any plane passing through the central axis of the body divides the organism into two identical halves, it is called radial symmetry. Coelenterates, ctenophores and echinoderms have this kind of body plan. Animals like annelids, arthropods, etc., where the body can be divided into identical left and right halves in only one plane, exhibit bilateral symmetry."
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"id": "bio_ch4_4.1.3_0002",
|
| 23 |
+
"subject": "Biology",
|
| 24 |
+
"chapter": "Animal Kingdom",
|
| 25 |
+
"chapter_number": "4",
|
| 26 |
+
"section": "4.1.3",
|
| 27 |
+
"section_title": "Germinal Layers and Coelom",
|
| 28 |
+
"text": "Animals in which the cells are arranged in two embryonic layers, an external ectoderm and an internal endoderm, are called diploblastic animals, e.g., coelenterates. An undifferentiated layer, mesoglea, is present in between the ectoderm and the endoderm. Those animals in which the developing embryo has a third germinal layer, mesoderm, in between the ectoderm and endoderm, are called triploblastic animals (platyhelminthes to chordates). Presence or absence of a cavity between the body wall and the gut wall is very important in classification. The body cavity, which is lined by mesoderm is called coelom. Animals possessing coelom are called coelomates, e.g., annelids, molluscs, arthropods, echinoderms, hemichordates and chordates. In some animals, the body cavity is not lined by mesoderm, instead, the mesoderm is present as scattered pouches in between the ectoderm and endoderm. Such a body cavity is called pseudocoelom and the animals possessing them are called pseudocoelomates, e.g., aschelminthes. The animals in which the body cavity is absent are called acoelomates, e.g., platyhelminthes."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"id": "bio_ch4_4.1.5_0003",
|
| 32 |
+
"subject": "Biology",
|
| 33 |
+
"chapter": "Animal Kingdom",
|
| 34 |
+
"chapter_number": "4",
|
| 35 |
+
"section": "4.1.5",
|
| 36 |
+
"section_title": "Segmentation and Notochord",
|
| 37 |
+
"text": "In some animals, the body is externally and internally divided into segments with a serial repetition of at least some organs. For example, in earthworm, the body shows this pattern called metameric segmentation and the phenomenon is known as metamerism. Notochord is a mesodermally derived rod-like structure formed on the dorsal side during embryonic development in some animals. Animals with notochord are called chordates and those animals which do not form this structure are called non-chordates, e.g., porifera to echinoderms. The broad classification of Animalia, based on common fundamental features such as levels of organisation, symmetry, and the nature of the coelom, provides a systematic framework for understanding the diverse phyla described in biological studies."
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"id": "bio_ch4_4.2.1_0004",
|
| 41 |
+
"subject": "Biology",
|
| 42 |
+
"chapter": "Animal Kingdom",
|
| 43 |
+
"chapter_number": "4",
|
| 44 |
+
"section": "4.2.1",
|
| 45 |
+
"section_title": "Phylum β Porifera",
|
| 46 |
+
"text": "Members of this phylum are commonly known as sponges. They are generally marine and mostly asymmetrical animals. These are primitive multicellular animals and have cellular level of organisation. Sponges have a water transport or canal system. Water enters through minute pores (ostia) in the body wall into a central cavity, spongocoel, from where it goes out through the osculum. This pathway of water transport is helpful in food gathering, respiratory exchange and removal of waste. Choanocytes or collar cells line the spongocoel and the canals. Digestion is intracellular. The body is supported by a skeleton made up of spicules or spongin fibres. Sexes are not separate (hermaphrodite), i.e., eggs and sperms are produced by the same individual. Sponges reproduce asexually by fragmentation and sexually by formation of gametes. Fertilisation is internal and development is indirect having a larval stage which is morphologically distinct from the adult. Examples: Sycon (Scypha), Spongilla (Fresh water sponge) and Euspongia (Bath sponge)."
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"id": "bio_ch4_4.2.2_0005",
|
| 50 |
+
"subject": "Biology",
|
| 51 |
+
"chapter": "Animal Kingdom",
|
| 52 |
+
"chapter_number": "4",
|
| 53 |
+
"section": "4.2.2",
|
| 54 |
+
"section_title": "Phylum β Coelenterata (Cnidaria)",
|
| 55 |
+
"text": "They are aquatic, mostly marine, sessile or free-swimming, radially symmetrical animals. The name cnidaria is derived from the cnidoblasts or cnidocytes (which contain the stinging capsules or nematocysts) present on the tentacles and the body. Cnidoblasts are used for anchorage, defense and for the capture of prey. Cnidarians exhibit tissue level of organisation and are diploblastic. They have a central gastro-vascular cavity with a single opening, mouth on hypostome. Digestion is extracellular and intracellular. Some of the cnidarians, e.g., corals have a skeleton composed of calcium carbonate. Cnidarians exhibit two basic body forms called polyp and medusa. The former is a sessile and cylindrical form like Hydra, Adamsia, etc. whereas, the latter is umbrella-shaped and free-swimming like Aurelia or jelly fish. Those cnidarians which exist in both forms exhibit alternation of generations (Metagenesis), i.e., polyps produce medusae asexually and medusae form the polyps sexually (e.g., Obelia). Examples: Physalia (Portuguese man-of-war), Adamsia (Sea anemone), Pennatula (Sea-pen), Gorgonia (Sea-fan) and Meandrina (Brain coral)."
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"id": "bio_ch4_4.2.3_0006",
|
| 59 |
+
"subject": "Biology",
|
| 60 |
+
"chapter": "Animal Kingdom",
|
| 61 |
+
"chapter_number": "4",
|
| 62 |
+
"section": "4.2.3",
|
| 63 |
+
"section_title": "Phyla β Ctenophora and Platyhelminthes",
|
| 64 |
+
"text": "Ctenophores, commonly known as sea walnuts or comb jellies are exclusively marine, radially symmetrical, diploblastic organisms with tissue level of organisation. The body bears eight external rows of ciliated comb plates, which help in locomotion. Digestion is both extracellular and intracellular. Bioluminescence (the property of a living organism to emit light) is well-marked in ctenophores. Sexes are not separate. Reproduction takes place only by sexual means. Fertilisation is external with indirect development. Examples: Pleurobrachia and Ctenoplana. Platyhelminthes have dorso-ventrally flattened body, hence are called flatworms. These are mostly endoparasites found in animals including human beings. Flatworms are bilaterally symmetrical, triploblastic and acoelomate animals with organ level of organisation. Hooks and suckers are present in the parasitic forms. Some of them absorb nutrients from the host directly through their body surface. Specialised cells called flame cells help in osmoregulation and excretion. Sexes are not separate. Fertilisation is internal and development is through many larval stages. Some members like Planaria possess high regeneration capacity. Examples: Taenia (Tapeworm), Fasciola (Liver fluke)."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"id": "bio_ch4_4.2.5_0007",
|
| 68 |
+
"subject": "Biology",
|
| 69 |
+
"chapter": "Animal Kingdom",
|
| 70 |
+
"chapter_number": "4",
|
| 71 |
+
"section": "4.2.5",
|
| 72 |
+
"section_title": "Phyla β Aschelminthes and Annelida",
|
| 73 |
+
"text": "The body of the aschelminthes is circular in cross-section, hence, the name roundworms. They may be freeliving, aquatic and terrestrial or parasitic in plants and animals. Roundworms have organ-system level of body organisation. They are bilaterally symmetrical, triploblastic and pseudocoelomate animals. Alimentary canal is complete with a well-developed muscular pharynx. An excretory tube removes body wastes from the body cavity through the excretory pore. Sexes are separate (dioecious), i.e., males and females are distinct. Often females are longer than males. Fertilisation is internal and development may be direct (the young ones resemble the adult) or indirect. Examples : Ascaris (Roundworm), Wuchereria (Filaria worm), Ancylostoma (Hookworm). Annelids may be aquatic or terrestrial; free-living, and sometimes parasitic. They exhibit organ-system level of body organisation and bilateral symmetry. They are triploblastic, metamerically segmented and coelomate animals. Their body surface is distinctly marked out into segments or metameres. They possess longitudinal and circular muscles which help in locomotion. Aquatic annelids like Nereis possess lateral appendages, parapodia, which help in swimming. A closed circulatory system is present. Nephridia help in osmoregulation and excretion. Neural system consists of paired ganglia connected by lateral nerves to a double ventral nerve cord. Nereis is dioecious, but earthworms and leeches are monoecious. Reproduction is sexual. Examples : Nereis, Pheretima (Earthworm) and Hirudinaria (Blood sucking leech)."
|
| 74 |
+
},
|
| 75 |
+
{
|
| 76 |
+
"id": "bio_ch4_4.2.7_0008",
|
| 77 |
+
"subject": "Biology",
|
| 78 |
+
"chapter": "Animal Kingdom",
|
| 79 |
+
"chapter_number": "4",
|
| 80 |
+
"section": "4.2.7",
|
| 81 |
+
"section_title": "Phylum β Arthropoda",
|
| 82 |
+
"text": "This is the largest phylum of Animalia which includes insects. Over two-thirds of all named species on earth are arthropods. They have organ-system level of organisation. They are bilaterally symmetrical, triploblastic, segmented and coelomate animals. The body of arthropods is covered by chitinous exoskeleton. The body consists of head, thorax and abdomen. They have jointed appendages. Respiratory organs are gills, book gills, book lungs or tracheal system. Circulatory system is of open type. Sensory organs like antennae, eyes (compound and simple), statocysts or balancing organs are present. Excretion takes place through malpighian tubules. They are mostly dioecious. Fertilisation is usually internal. They are mostly oviparous. Development may be direct or indirect. Examples: Economically important insects β Apis (Honey bee), Bombyx (Silkworm), Laccifer (Lac insect). Vectors β Anopheles, Culex and Aedes (Mosquitoes). Gregarious pest β Locusta (Locust). Living fossil β Limulus (King crab)."
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"id": "bio_ch4_4.2.8_0009",
|
| 86 |
+
"subject": "Biology",
|
| 87 |
+
"chapter": "Animal Kingdom",
|
| 88 |
+
"chapter_number": "4",
|
| 89 |
+
"section": "4.2.8",
|
| 90 |
+
"section_title": "Phylum β Mollusca",
|
| 91 |
+
"text": "This is the second largest animal phylum. Molluscs are terrestrial or aquatic (marine or fresh water) having an organ-system level of organisation. They are bilaterally symmetrical, triploblastic and coelomate animals. Body is covered by a calcareous shell and is unsegmented with a distinct head, muscular foot and visceral hump. A soft and spongy layer of skin forms a mantle over the visceral hump. The space between the hump and the mantle is called the mantle cavity in which feather like gills are present. They have respiratory and excretory functions. The anterior head region has sensory tentacles. The mouth contains a file-like rasping organ for feeding, called radula. They are usually dioecious and oviparous with indirect development. Examples: Pila (Apple snail), Pinctada (Pearl oyster), Sepia (Cuttlefish), Loligo (Squid), Octopus (Devil fish), Aplysia (Sea hare), Dentalium (Tusk shell) and Chaetopleura (Chiton)."
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"id": "bio_ch4_4.2.9_0010",
|
| 95 |
+
"subject": "Biology",
|
| 96 |
+
"chapter": "Animal Kingdom",
|
| 97 |
+
"chapter_number": "4",
|
| 98 |
+
"section": "4.2.9",
|
| 99 |
+
"section_title": "Phyla β Echinodermata and Hemichordata",
|
| 100 |
+
"text": "Echinoderms have an endoskeleton of calcareous ossicles and, hence, the name Echinodermata (Spiny bodied). All are marine with organ-system level of organisation. The adult echinoderms are radially symmetrical but larvae are bilaterally symmetrical. They are triploblastic and coelomate animals. Digestive system is complete with mouth on the lower (ventral) side and anus on the upper (dorsal) side. The most distinctive feature of echinoderms is the presence of water vascular system which helps in locomotion, capture and transport of food and respiration. An excretory system is absent. Sexes are separate. Reproduction is sexual. Fertilisation is usually external. Development is indirect with free-swimming larva. Examples: Asterias (Star fish), Echinus (Sea urchin). Hemichordata was earlier considered as a sub-phylum under phylum Chordata but is now a separate phylum. Hemichordates have a rudimentary structure in the collar region called stomochord, similar to notochord. This phylum consists of a small group of worm-like marine animals with organ-system level of organisation. They are bilaterally symmetrical, triploblastic and coelomate animals. The body is cylindrical and composed of an anterior proboscis, a collar and a long trunk. Circulatory system is of open type. Respiration takes place through gills. Excretory organ is proboscis gland. Sexes are separate. Fertilisation is external. Examples: Balanoglossus and Saccoglossus."
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"id": "bio_ch4_4.2.11_0011",
|
| 104 |
+
"subject": "Biology",
|
| 105 |
+
"chapter": "Animal Kingdom",
|
| 106 |
+
"chapter_number": "4",
|
| 107 |
+
"section": "4.2.11",
|
| 108 |
+
"section_title": "Phylum β Chordata and Subphyla",
|
| 109 |
+
"text": "Animals belonging to phylum Chordata are fundamentally characterised by the presence of a notochord, a dorsal hollow nerve cord and paired pharyngeal gill slits. These are bilaterally symmetrical, triploblastic, coelomate with organ-system level of organisation. They possess a post anal tail and a closed circulatory system. Phylum Chordata is divided into three subphyla: Urochordata or Tunicata, Cephalochordata and Vertebrata. Subphyla Urochordata and Cephalochordata are often referred to as protochordates and are exclusively marine. In Urochordata, notochord is present only in larval tail, while in Cephalochordata, it extends from head to tail region and is persistent throughout their life. Examples: Urochordata β Ascidia, Salpa, Doliolum; Cephalochordata β Branchiostoma (Amphioxus or Lancelet). The members of subphylum Vertebrata possess notochord during the embryonic period. The notochord is replaced by a cartilaginous or bony vertebral column in the adult. Thus all vertebrates are chordates but all chordates are not vertebrates. Besides the basic chordate characters, vertebrates have a ventral muscular heart with two, three or four chambers, kidneys for excretion and osmoregulation and paired appendages which may be fins or limbs."
|
| 110 |
+
},
|
| 111 |
+
{
|
| 112 |
+
"id": "bio_ch4_4.2.11.1_0012",
|
| 113 |
+
"subject": "Biology",
|
| 114 |
+
"chapter": "Animal Kingdom",
|
| 115 |
+
"chapter_number": "4",
|
| 116 |
+
"section": "4.2.11.1",
|
| 117 |
+
"section_title": "Class β Cyclostomata",
|
| 118 |
+
"text": "All living members of the class Cyclostomata are ectoparasites on some fishes. They have an elongated body bearing 6-15 pairs of gill slits for respiration. Cyclostomes have a sucking and circular mouth without jaws. Their body is devoid of scales and paired fins. Cranium and vertebral column are cartilaginous. Circulation is of closed type. Cyclostomes are marine but migrate for spawning to fresh water. After spawning, within a few days, they die. Their larvae, after metamorphosis, return to the ocean. Examples: Petromyzon (Lamprey) and Myxine (Hagfish). This class represents the most primitive living vertebrates, characterized by their parasitic lifestyle and lack of traditional vertebrate features such as jaws or scales."
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"id": "bio_ch4_4.2.11.2_0013",
|
| 122 |
+
"subject": "Biology",
|
| 123 |
+
"chapter": "Animal Kingdom",
|
| 124 |
+
"chapter_number": "4",
|
| 125 |
+
"section": "4.2.11.2",
|
| 126 |
+
"section_title": "Class β Chondrichthyes",
|
| 127 |
+
"text": "Chondrichthyes are marine animals with streamlined body and have cartilaginous endoskeleton. Mouth is located ventrally. Notochord is persistent throughout life. Gill slits are separate and without operculum (gill cover). The skin is tough, containing minute placoid scales. Teeth are modified placoid scales which are backwardly directed. Their jaws are very powerful. These animals are predaceous. Due to the absence of air bladder, they have to swim constantly to avoid sinking. Heart is two-chambered (one auricle and one ventricle). Some of them have electric organs (e.g., Torpedo) and some possess poison sting (e.g., Trygon). They are cold-blooded (poikilothermous) animals, i.e., they lack the capacity to regulate their body temperature. Sexes are separate. In males pelvic fins bear claspers. They have internal fertilisation and many of them are viviparous. Examples: Scoliodon (Dog fish), Pristis (Saw fish), Carcharodon (Great white shark), Trygon (Sting ray)."
|
| 128 |
+
},
|
| 129 |
+
{
|
| 130 |
+
"id": "bio_ch4_4.2.11.3_0014",
|
| 131 |
+
"subject": "Biology",
|
| 132 |
+
"chapter": "Animal Kingdom",
|
| 133 |
+
"chapter_number": "4",
|
| 134 |
+
"section": "4.2.11.3",
|
| 135 |
+
"section_title": "Class β Osteichthyes",
|
| 136 |
+
"text": "Osteichthyes includes both marine and fresh water fishes with bony endoskeleton. Their body is streamlined. Mouth is mostly terminal. They have four pairs of gills which are covered by an operculum on each side. Skin is covered with cycloid/ctenoid scales. Air bladder is present which regulates buoyancy. Heart is two-chambered (one auricle and one ventricle). They are cold-blooded animals. Sexes are separate. Fertilisation is usually external. They are mostly oviparous and development is direct. These fishes represent a diverse group adapted to various aquatic environments, utilizing their bony structure and buoyancy control for efficient swimming. Examples: Marine β Exocoetus (Flying fish), Hippocampus (Sea horse); Freshwater β Labeo (Rohu), Catla (Katla), Clarias (Magur); Aquarium β Betta (Fighting fish), Pterophyllum (Angel fish)."
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"id": "bio_ch4_4.2.11.4_0015",
|
| 140 |
+
"subject": "Biology",
|
| 141 |
+
"chapter": "Animal Kingdom",
|
| 142 |
+
"chapter_number": "4",
|
| 143 |
+
"section": "4.2.11.4",
|
| 144 |
+
"section_title": "Class β Amphibia",
|
| 145 |
+
"text": "As the name indicates, amphibians can live in aquatic as well as terrestrial habitats. Most of them have two pairs of limbs. Body is divisible into head and trunk. Tail may be present in some. The amphibian skin is moist (without scales). The eyes have eyelids. A tympanum represents the ear. Alimentary canal, urinary and reproductive tracts open into a common chamber called cloaca which opens to the exterior. Respiration is by gills, lungs and through skin. The heart is three-chambered (two auricles and one ventricle). These are cold-blooded animals. Sexes are separate. Fertilisation is external. They are oviparous and development is indirect. They represent a significant evolutionary step as animals that bridges the gap between aquatic and terrestrial lifestyles. Examples: Bufo (Toad), Rana (Frog), Hyla (Tree frog), Salamandra (Salamander), Ichthyophis (Limbless amphibia)."
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"id": "bio_ch4_4.2.11.5_0016",
|
| 149 |
+
"subject": "Biology",
|
| 150 |
+
"chapter": "Animal Kingdom",
|
| 151 |
+
"chapter_number": "4",
|
| 152 |
+
"section": "4.2.11.5",
|
| 153 |
+
"section_title": "Class β Reptilia",
|
| 154 |
+
"text": "The class name refers to their creeping or crawling mode of locomotion. They are mostly terrestrial animals and their body is covered by dry and cornified skin, epidermal scales or scutes. They do not have external ear openings. Tympanum represents ear. Limbs, when present, are two pairs. Heart is usually three-chambered, but four-chambered in crocodiles. Reptiles are poikilotherms. Snakes and lizards shed their scales as skin cast. Sexes are separate. Fertilisation is internal. They are oviparous and development is direct. This group is well-adapted for survival on land with their specialized skin and reproductive strategies. Examples: Chelone (Turtle), Testudo (Tortoise), Chameleon (Tree lizard), Calotes (Garden lizard), Crocodilus (Crocodile), Alligator (Alligator), Hemidactylus (Wall lizard), Poisonous snakes β Naja (Cobra), Bangarus (Krait), Vipera (Viper)."
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"id": "bio_ch4_4.2.11.6_0017",
|
| 158 |
+
"subject": "Biology",
|
| 159 |
+
"chapter": "Animal Kingdom",
|
| 160 |
+
"chapter_number": "4",
|
| 161 |
+
"section": "4.2.11.6",
|
| 162 |
+
"section_title": "Class β Aves",
|
| 163 |
+
"text": "The characteristic features of Aves (birds) are the presence of feathers and most of them can fly except flightless birds (e.g., Ostrich). They possess beak. The forelimbs are modified into wings. The hind limbs generally have scales and are modified for walking, swimming or clasping the tree branches. Skin is dry without glands except the oil gland at the base of the tail. Endoskeleton is fully ossified (bony) and the long bones are hollow with air cavities (pneumatic). The digestive tract of birds has additional chambers, the crop and gizzard. Heart is completely four-chambered. They are warm-blooded (homoiothermous) animals, i.e., they are able to maintain a constant body temperature. Respiration is by lungs. Air sacs connected to lungs supplement respiration. Sexes are separate. Fertilisation is internal. They are oviparous and development is direct. Examples : Corvus (Crow), Columba (Pigeon), Psittacula (Parrot), Struthio (Ostrich), Pavo (Peacock), Aptenodytes (Penguin), Neophron (Vulture)."
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"id": "bio_ch4_4.2.11.7_0018",
|
| 167 |
+
"subject": "Biology",
|
| 168 |
+
"chapter": "Animal Kingdom",
|
| 169 |
+
"chapter_number": "4",
|
| 170 |
+
"section": "4.2.11.7",
|
| 171 |
+
"section_title": "Class β Mammalia",
|
| 172 |
+
"text": "They are found in a variety of habitats β polar ice caps, deserts, mountains, forests, grasslands and dark caves. Some of them have adapted to fly or live in water. The most unique mammalian characteristic is the presence of milk producing glands (mammary glands) by which the young ones are nourished. They have two pairs of limbs, adapted for walking, running, climbing, burrowing, swimming or flying. The skin of mammals is unique in possessing hair. External ears or pinnae are present. Different types of teeth are present in the jaw. Heart is four-chambered. They are homoiothermous. Respiration is by lungs. Sexes are separate and fertilisation is internal. They are viviparous with few exceptions and development is direct. Examples: Oviparous-Ornithorhynchus (Platypus); Viviparous - Macropus (Kangaroo), Pteropus (Flying fox), Camelus (Camel), Macaca (Monkey), Rattus (Rat), Canis (Dog), Felis (Cat), Elephas (Elephant), Equus (Horse), Delphinus (Common dolphin), Balaenoptera (Blue whale), Panthera tigris (Tiger), Panthera leo (Lion)."
|
| 173 |
+
}
|
| 174 |
+
]
|