api / app.py
datavorous's picture
Update app.py
50a9258 verified
from fastapi import FastAPI, HTTPException, Query
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import sqlite3
from typing import List, Dict
import random
from pydantic import BaseModel
app = FastAPI()
# Configure CORS to allow only specific domains
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # Restrict to specific domains in production
allow_credentials=True,
allow_methods=["*"], # Allows all HTTP methods
allow_headers=["*"], # Allows all headers
)
# Database connection utility
def get_db_connection():
connection = sqlite3.connect("questions.db")
connection.row_factory = sqlite3.Row
# refer to this SO thread: https://stackoverflow.com/questions/44009452/what-is-the-purpose-of-the-row-factory-method-of-an-sqlite3-connection-object
return connection
# API endpoints
@app.get("/")
def get_image():
return {
"message": "success",
"repository": "https://github.com/qpump/api"
}
@app.get("/questions")
def filter_questions(
subject: str = None,
chapter: str = None,
topic: str = None,
question_type: str = None,
paper_id: str = None,
offset: int = Query(0, ge=0, description="Offset for pagination"),
limit: int = Query(10, ge=1, le=100, description="Limit for pagination")
):
"""Filter questions based on various parameters."""
query = "SELECT * FROM questions WHERE 1=1"
params = []
if subject:
query += " AND subject = ?"
params.append(subject)
if chapter:
query += " AND chapter = ?"
params.append(chapter)
if topic:
query += " AND topic = ?"
params.append(topic)
if question_type:
query += " AND question_type = ?"
params.append(question_type)
if paper_id:
query += " AND paper_id = ?"
params.append(paper_id)
query += " LIMIT ? OFFSET ?"
params.extend([limit, offset])
connection = get_db_connection()
cursor = connection.execute(query, params)
questions = cursor.fetchall()
connection.close()
if not questions:
raise HTTPException(status_code=404, detail="No questions found with the given filters.")
return [dict(question) for question in questions]
@app.get("/questions/{question_id}")
def get_question_by_id(question_id: str):
"""Get question details based on question ID."""
connection = get_db_connection()
query = "SELECT * FROM questions WHERE question_id = ?"
question = connection.execute(query, (question_id,)).fetchone()
connection.close()
if not question:
raise HTTPException(status_code=404, detail="Question not found.")
return dict(question)
@app.get("/{subject}")
def list_chapters(subject: str):
"""
Return list of chapters for a given subject along with the count of questions in each chapter.
Also includes the total number of questions in the subject.
"""
connection = get_db_connection()
query = "SELECT chapter, COUNT(*) as question_count FROM questions WHERE subject = ? GROUP BY chapter"
cursor = connection.execute(query, (subject,))
chapters = cursor.fetchall()
connection.close()
if not chapters:
raise HTTPException(status_code=404, detail="Subject not found or no chapters available.")
return {
"subject": subject,
"chapters": [dict(chapter) for chapter in chapters]
}
@app.get("/{subject}/{chapter}")
def list_topics(subject: str, chapter: str):
"""
Return list of topics for a given chapter along with the count of questions in each topic.
Also includes the total number of questions in the chapter.
"""
connection = get_db_connection()
query = "SELECT topic, COUNT(*) as question_count FROM questions WHERE subject = ? AND chapter = ? GROUP BY topic"
cursor = connection.execute(query, (subject, chapter))
topics = cursor.fetchall()
connection.close()
if not topics:
raise HTTPException(status_code=404, detail="Chapter not found or no topics available.")
return {
"subject": subject,
"chapter": chapter,
"topics": [dict(topic) for topic in topics]
}
@app.get("/{subject}/{chapter}/{topic}")
def list_questions(subject: str, chapter: str, topic: str):
"""
Return list of questions for a given topic.
"""
connection = get_db_connection()
query = "SELECT * FROM questions WHERE subject = ? AND chapter = ? AND topic = ?"
cursor = connection.execute(query, (subject, chapter, topic))
questions = cursor.fetchall()
connection.close()
if not questions:
raise HTTPException(status_code=404, detail="Topic not found or no questions available.")
return {
"subject": subject,
"chapter": chapter,
"topic": topic,
"questions": [dict(question) for question in questions]
}
#import logging
#logging.basicConfig(level=logging.DEBUG)
class TestParameters(BaseModel):
subjects: List[str] = None
chapters: List[str] = None
topics: List[str] = None
num_questions: int = 10
total_time: int = 60
@app.post("/generate-test")
def generate_test(test_params: TestParameters):
num_questions = test_params.num_questions # Number of questions per subject
total_time = test_params.total_time
subjects = test_params.subjects
chapters = test_params.chapters
topics = test_params.topics
# Connect to the database
connection = get_db_connection()
# Prepare the result for the test
test = {
"total_questions": num_questions * len(subjects), # Total number of questions = num_questions per subject * number of subjects
"total_time": total_time,
"questions": []
}
# Fetch questions for each subject
for subject in subjects:
query = "SELECT * FROM questions WHERE subject = ?"
params = [subject]
# Apply additional filters if provided
if chapters:
query += " AND chapter IN ({})".format(','.join(['?'] * len(chapters)))
params.extend(chapters)
if topics:
query += " AND topic IN ({})".format(','.join(['?'] * len(topics)))
params.extend(topics)
cursor = connection.execute(query, params)
questions = cursor.fetchall()
# If no questions found for this subject, raise an error
if not questions:
raise HTTPException(status_code=404, detail=f"No questions found for subject: {subject}")
# If not enough questions are available for this subject, raise an error
if len(questions) < num_questions:
raise HTTPException(
status_code=400,
detail=f"Not enough questions available for subject {subject}. Requested {num_questions}, but found {len(questions)}."
)
# Randomly select the requested number of questions for the subject
selected_questions = random.sample(questions, num_questions)
# Add the selected questions to the test
test['questions'].extend([dict(q) for q in selected_questions])
connection.close()
# Return the generated test
return test