from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import StreamingResponse from pydantic import BaseModel, Field from typing import List, Optional from llama_index.llms.ollama import Ollama from llama_index.core import PromptTemplate from llama_index.llms.groq import Groq import os import dotenv from enum import Enum dotenv.load_dotenv() app = FastAPI() # Enable CORS for all origins (for development purposes) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Load LLM model # llm = Ollama(model="llama3", request_timeout=120.0) # llama3-70b-8192 llm = Groq(model="llama-3.3-70b-versatile", api_key="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", ) class Options(BaseModel): """A quiz with a title and a list of questions.""" questions: List[str] = Field(..., description="List of questions in the quiz") class Quiz(BaseModel): """An album inspired by a movie, containing an artist and a list of songs.""" question: str = Field(..., description="The question to be answered") correct_answer: str = Field(..., description="The correct answer to the question") options: List[Options] = Field(..., description="List of options for the question") class Difficulty(str, Enum): easy = "Easy" medium = "Medium" hard = "Hard" class QuizFormat(str, Enum): multiple_choice = "Multiple Choice" open_ended = "Open ended" true_false = "True/False" class QuizRequest(BaseModel): topic: str = Field(..., description="Topic of the quiz") subject: str = Field(..., description="Subject of the quiz") grade_level: str = Field(..., description="Grade level (e.g., Primary 3, JSS 1)") description: Optional[str] = Field(None, description="Brief description of the quiz (optional)") difficulty: Difficulty = Field(..., description="Difficulty level") format: QuizFormat = Field(..., description="Format of the quiz") num_questions: int = Field(..., gt=0, le=50, description="Number of questions (1-50)") language: str = Field(..., description="Language to translate the quiz into") # Define the prompt template for quiz generation PROMPT_TEMPLATE = """ Generate a set of quizzes that align with the given requirements: Topic: {topic} Subject: {subject} Grade Level: {grade_level} {description_part} Difficulty: {difficulty} Format: {format} Number of Questions: {num_questions} Ensure the format follows and ensure its in json format. No extra information just your response please and make it well formatted: [ {{ "question": "Question text here?", "correct_answer": "Correct answer", "options": ["Option 1", "Option 2", "Option 3", "Option 4"] }}, ] """ FORMAT_PROMPT_TEMPLATE = """ You are a formatting assistant. Your ONLY job is to format quizzes into a structured, teacher-friendly format. STRICT INSTRUCTIONS: 1. Do NOT include any explanations, introductions, or thought processes. Output ONLY the formatted quiz. 2. Do NOT add or remove content from questions, answers, or options. 3. Format each quiz as follows: - Start with the question number (e.g., "1. Question text here?"). - On the next line, write "Answer: " followed by the correct answer. - On the next line, write "Options: " followed by the list of options, each on a new line with a bullet point. 4. Separate each quiz with two blank lines for clarity. 5. Use STRICTLY these HTML tags for proper formatting: - `
` for line breaks. - `

` for paragraphs. - `