Download Backend/routers/qa.py from PranilB/Question_Answering_Classification: direct link, hf CLI and curl.
- Browser
- Download file 6.11 kB
-
https://huggingface.co/spaces/PranilB/Question_Answering_Classification/resolve/main/Backend/routers/qa.py
- Command line
-
hf download hf://spaces/PranilB/Question_Answering_Classification/Backend/routers/qa.py
-
curl -L -o qa.py https://huggingface.co/spaces/PranilB/Question_Answering_Classification/resolve/main/Backend/routers/qa.py
6.11 kB
| """ | |
| qa.py β Question Answering API router | |
| Endpoints: | |
| POST /qa β Full RAG pipeline (classify + retrieve + answer + verify) | |
| POST /classify β Classification only (BERT chapter + topic extraction) | |
| """ | |
| import traceback | |
| from fastapi import APIRouter, HTTPException | |
| from Backend.schemas import ( | |
| QuestionRequest, | |
| QAResponse, | |
| ClassifyOnlyRequest, | |
| ClassifyOnlyResponse, | |
| ClassificationResult, | |
| TopicInfo, | |
| SourceChunk, | |
| IsNeetBioRequest, | |
| IsNeetBioResponse | |
| ) | |
| from rag.pipeline import run_pipeline | |
| from Classification.classify_and_extract import classify_question, get_predictor | |
| router = APIRouter(prefix="/api", tags=["Question Answering"]) | |
| # ============================== | |
| # POST /api/qa | |
| # ============================== | |
| async def answer_question(req: QuestionRequest): | |
| """ | |
| Full Q&A pipeline: | |
| 1. BERT β chapter prediction + topic extraction | |
| 2. Supabase β retrieve NCERT chunks (filtered by chapter) | |
| 3. Groq LLM β generate answer + justification | |
| 4. Groq LLM β verify answer | |
| 5. Compute confidence score | |
| """ | |
| try: | |
| result = run_pipeline( | |
| question=req.question, | |
| chapter_filter=req.chapter_filter, | |
| top_k=req.top_k, | |
| use_classifier=req.use_classifier, | |
| ) | |
| # Build classification model if present | |
| classification = None | |
| if result.get("classification"): | |
| raw = result["classification"] | |
| classification = ClassificationResult( | |
| chapter=raw["chapter"], | |
| chapter_id=raw["chapter_id"], | |
| chapter_confidence=raw["chapter_confidence"], | |
| rejected=raw.get("rejected", False), | |
| rejection_reason=raw.get("rejection_reason", ""), | |
| entropy=raw.get("entropy", 0.0), | |
| margin=raw.get("margin", 0.0), | |
| topics=[ | |
| TopicInfo( | |
| section_code=t["section_code"], | |
| section_title=t["section_title"], | |
| similarity=t["similarity"], | |
| ) | |
| for t in raw.get("topics", []) | |
| ], | |
| ) | |
| # Build sources | |
| sources = [ | |
| SourceChunk( | |
| chapter=s.get("chapter"), | |
| section=s.get("section"), | |
| section_title=s.get("section_title"), | |
| text_content=s.get("text_content"), | |
| similarity=s.get("similarity", 0.0), | |
| ) | |
| for s in result.get("sources", []) | |
| ] | |
| return QAResponse( | |
| question=result["question"], | |
| classification=classification, | |
| answer=result["answer"], | |
| justification=result.get("justification", []), | |
| sources=sources, | |
| confidence=result.get("confidence", 0.0), | |
| verified=result.get("verified", False), | |
| verifier_note=result.get("verifier_note", ""), | |
| ) | |
| except Exception as e: | |
| traceback.print_exc() | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Pipeline error: {str(e)}", | |
| ) | |
| # ============================== | |
| # POST /api/classify | |
| # ============================== | |
| async def classify_only(req: ClassifyOnlyRequest): | |
| """ | |
| Classification only (no RAG): | |
| 1. BERT β chapter prediction | |
| 2. Supabase retrieval β topic extraction | |
| """ | |
| try: | |
| raw = classify_question(req.question) | |
| classification = ClassificationResult( | |
| chapter=raw["chapter"], | |
| chapter_id=raw["chapter_id"], | |
| chapter_confidence=raw["chapter_confidence"], | |
| rejected=raw.get("rejected", False), | |
| rejection_reason=raw.get("rejection_reason", ""), | |
| entropy=raw.get("entropy", 0.0), | |
| margin=raw.get("margin", 0.0), | |
| topics=[ | |
| TopicInfo( | |
| section_code=t["section_code"], | |
| section_title=t["section_title"], | |
| similarity=t["similarity"], | |
| ) | |
| for t in raw.get("topics", []) | |
| ], | |
| ) | |
| return ClassifyOnlyResponse( | |
| question=req.question, | |
| classification=classification, | |
| ) | |
| except Exception as e: | |
| traceback.print_exc() | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Classification error: {str(e)}", | |
| ) | |
| # ============================== | |
| # POST /api/is-neet-bio | |
| # ============================== | |
| async def is_neet_bio(req: IsNeetBioRequest): | |
| """ | |
| Runs only the BERT classifier prediction to check OOD (Out-Of-Domain) logic. | |
| Fast path validation for frontend to prevent garbage from triggering the RAG pipeline. | |
| """ | |
| try: | |
| predictor = get_predictor() | |
| bert_result = predictor.predict(req.question) | |
| rejected = bert_result.get("rejected", False) | |
| reason = bert_result.get("rejection_reason", "") | |
| return IsNeetBioResponse( | |
| is_valid=not rejected, | |
| rejected=rejected, | |
| reason=reason | |
| ) | |
| except Exception as e: | |
| traceback.print_exc() | |
| raise HTTPException( | |
| status_code=500, | |
| detail=f"Validation error: {str(e)}", | |
| ) | |