Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ app.*.map.json
/android/app/release
backend/.env
backend/node_modules
my-question-app/node_modules
my-question-app/node_modules
backend\fastapi-backend\.env
**/.env
Binary file added backend/fastapi-backend.zip
Binary file not shown.
5 changes: 0 additions & 5 deletions backend/fastapi-backend/.env

This file was deleted.

11 changes: 11 additions & 0 deletions backend/fastapi-backend/models/mailrouter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pydantic import BaseModel,EmailStr
from typing import List
# class EmailRequest(BaseModel):
# to:str
# subject:str
# body:str
class EmailRequest(BaseModel):
to: List[EmailStr] # List of emails
student_id: List[str] # List of student IDs
user_id: str # Single user ID
class_id: str
2 changes: 1 addition & 1 deletion backend/fastapi-backend/questions.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"questions": [{"id": 1, "type": "multiple_choice", "question": "The force that keeps the moon in its orbit around the Earth is called:", "options": ["Centripetal force", "Gravitational force", "Frictional force", "Tension force"], "answer": "Centripetal force"}, {"id": 2, "type": "multiple_choice", "question": "According to the universal law of gravitation, the force between two objects is directly proportional to the:", "options": ["Distance between the objects", "Square of the distance between the objects", "Product of their masses", "Ratio of their masses"], "answer": "Product of their masses"}, {"id": 3, "type": "multiple_choice", "question": "What is the SI unit of the universal gravitational constant (G)?", "options": ["N", "m/s\u00c2\u00b2", "N m\u00c2\u00b2/kg\u00c2\u00b2", "kg m/s\u00c2\u00b2"], "answer": "N m\u00c2\u00b2/kg\u00c2\u00b2"}, {"id": 4, "type": "numerical", "question": "If the mass of an object is 10 kg, and the acceleration due to gravity is 9.8 m/s\u00c2\u00b2, what is the weight of the object?", "answer": "98 N"}, {"id": 5, "type": "numerical", "question": "An object is thrown vertically upwards and rises to a height of 5 m. Calculate the initial velocity with which the object was thrown upwards. (g = 9.8 m/s\u00c2\u00b2)", "answer": "9.9 m/s"}]}
{"questions": [{"id": 1, "type": "multiple_choice", "question": "The force that keeps a body moving along a circular path is called:", "options": ["Gravitational force", "Centripetal force", "Frictional force", "Tension force"], "answer": "Centripetal force"}, {"id": 2, "type": "multiple_choice", "question": "The SI unit of the universal gravitational constant (G) is:", "options": ["N m/kg", "N m\u00c2\u00b2 / kg\u00c2\u00b2", "kg m/s\u00c2\u00b2", "m/s\u00c2\u00b2"], "answer": "N m\u00c2\u00b2 / kg\u00c2\u00b2"}, {"id": 3, "type": "numerical", "question": "An object has a mass of 10 kg. What is its weight on Earth if g = 9.8 m/s\u00c2\u00b2?", "answer": "98 N"}, {"id": 4, "type": "numerical", "question": "If the weight of an object on Earth is 60 N, what would be its approximate weight on the Moon?", "answer": "10 N"}]}
107 changes: 98 additions & 9 deletions backend/fastapi-backend/routers/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
status,
HTTPException,
File,
UploadFile
UploadFile,Request
)
from fastapi.responses import (
RedirectResponse
RedirectResponse,JSONResponse
)
import smtplib
from datetime import datetime
from pydantic import BaseModel
from email.message import EmailMessage

import json
import asyncio
Expand All @@ -20,7 +24,12 @@
import uuid
import cv2
import os
from dotenv import load_dotenv
load_dotenv()
EMAIL_USER = os.getenv("EMAIL_USER")
EMAIL_PASS = os.getenv("EMAIL_PASS")
from models.question_generate_model import QuestionGenerationRequest
from models.mailrouter import EmailRequest
PDF_STORAGE_DIR="uploaded_pdfs"
os.makedirs(PDF_STORAGE_DIR,exist_ok=True)
router = APIRouter()
Expand Down Expand Up @@ -100,16 +109,36 @@ async def upload_image(file: UploadFile = File(...)):
detail=f"Unexpected error: {str(e)}"
)

# @router.post("/api/upload-pdf")
# async def upload_pdf(pdf_file:UploadFile=File(...)):
# file_id = str(uuid.uuid4())
# file_path = os.path.join(PDF_STORAGE_DIR, f"{file_id}.pdf")


# with open(file_path, "wb") as f:
# f.write(await pdf_file.read())

# return {"file_id": file_id, "message": "PDF uploaded successfully"}
@router.post("/api/upload-pdf")
async def upload_pdf(pdf_file:UploadFile=File(...)):
async def upload_pdf(request: Request):
form = await request.form()

# Try both possible field names
pdf_file: UploadFile | None = form.get("pdf_file") or form.get("file")

if not pdf_file:
return JSONResponse(
status_code=422,
content={"message": "No PDF file found in request under 'pdf_file' or 'file'"},
)

file_id = str(uuid.uuid4())
file_path = os.path.join(PDF_STORAGE_DIR, f"{file_id}.pdf")


with open(file_path, "wb") as f:
f.write(await pdf_file.read())

return {"file_id": file_id, "message": "PDF uploaded successfully"}
return {"file_id": file_id, "message": "uploaded successfully"}
@router.post("/api/generate-questions")
async def generate_questions(request: QuestionGenerationRequest):
file_path = os.path.join(PDF_STORAGE_DIR, f"{request.file_id}.pdf")
Expand All @@ -134,14 +163,15 @@ def extract_text():
)
try:
raw = output.content
logger.info(raw)

# Step 1: Convert escaped characters into proper string (e.g., "\n" to actual newline)

raw = raw.encode('utf-8').decode('unicode_escape')

# Step 2: Remove markdown syntax like ```json ... ```

cleaned = raw.strip().replace("```json", "").replace("```", "").strip()

# Step 3: Now it's safe to parse as JSON

parsed = json.loads(cleaned)
async with aiofiles.open(DATA_FILE, "w") as f:
await f.write(json.dumps(parsed))
Expand All @@ -158,4 +188,63 @@ def extract_text():
# "class_level": request.class_level,
# "chapter_background": request.chapter_background
# }
# this text along with input stuff will be passed to the llm
# this text along with input stuff will be passed to the llm
### MAIL SENDING SERVICE
# @router.post("/send-mail")
# def send_mail(req: EmailRequest):
# try:
# msg = EmailMessage()
# msg['Subject'] = req.subject
# msg['From'] = EMAIL_USER
# msg['To'] = req.to
# msg.set_content(req.body)
# with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
# smtp.login(EMAIL_USER, EMAIL_PASS)
# smtp.send_message(msg)

# return {"status": "sent"}

# except Exception as e:
# raise HTTPException(status_code=500, detail=f"Email failed: {str(e)}")
@router.post("/send-mail")
def send_mail(req: EmailRequest):
if len(req.to) != len(req.student_id):
raise HTTPException(status_code=400, detail="Emails and student IDs must match in length.")

try:
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
smtp.login(EMAIL_USER, EMAIL_PASS)

for email, student_id in zip(req.to, req.student_id):

test_link = f"http://localhost:5173?userId={req.user_id}&&classid={req.class_id}&&studentId={student_id}"


subject = "📝 Your GradeGenius Test Link"
body = f"""
Hi there,

You've been invited to take your quiz on GradeGenius. Please use the following secure link to access your test:

👉 {test_link}

This link is unique to you. Make sure you don't share it with anyone else.

Best of luck!
GradeGenius Team
""".strip()


msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = EMAIL_USER
msg['To'] = email
msg.set_content(body)


smtp.send_message(msg)

return {"status": "All emails sent successfully"}

except Exception as e:
raise HTTPException(status_code=500, detail=f"Email failed: {str(e)}")
Binary file not shown.
Binary file not shown.
Binary file not shown.
47 changes: 47 additions & 0 deletions backend2/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from fastapi import FastAPI, Request
from pydantic import BaseModel
import aiofiles
import json
from datetime import datetime

app = FastAPI()


class AnswerSubmission(BaseModel):
answers: dict
studentId: str


class ScoreSubmission(BaseModel):
studentId: str
score: int


# 📝 Save answers asynchronously
@router.post("/submit")
async def submit_answers(payload: AnswerSubmission):
record = {
"timestamp": datetime.utcnow().isoformat(),
"studentId": payload.studentId,
"answers": payload.answers
}

async with aiofiles.open("answers.jsonl", mode="a") as f:
await f.write(json.dumps(record) + "\n")

return {"message": "Answers submitted successfully"}


# 📝 Save score asynchronously
@router.post("/api/submit-scores")
async def submit_score(payload: ScoreSubmission):
record = {
"timestamp": datetime.utcnow().isoformat(),
"studentId": payload.studentId,
"score": payload.score
}

async with aiofiles.open("scores.jsonl", mode="a") as f:
await f.write(json.dumps(record) + "\n")

return {"message": "Score submitted successfully"}
Loading