Spaces:
Sleeping
Sleeping
File size: 6,396 Bytes
4908bf3 03d1c7c 4908bf3 b0f8eb8 4908bf3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
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:
- `<br>` for line breaks.
- `<p>` for paragraphs.
- `<ul>` and `<li>` for lists.
Output ONLY the formatted quiz. No extra text.
Here is the input JSON:
{quiz_json}
"""
# Define the prompt template for translation
TRANSLATION_PROMPT_TEMPLATE = """
Translate the following text into {target_language}. Ensure the translation is accurate and maintains the original meaning:
{text}
"""
def format_quiz_stream(prompt: str):
"""Stream responses from the LLM for formatting"""
response = llm.complete(prompt)
if hasattr(response, "text"):
for chunk in response.text.split("\n"):
yield chunk
elif hasattr(response, "content"):
for chunk in response.content.split("\n"):
yield chunk
else:
raise AttributeError("Response does not contain text content.")
def translate_text(text: str, target_language: str) -> str:
"""Translate text to the desired language using the LLM"""
translation_prompt = TRANSLATION_PROMPT_TEMPLATE.format(
target_language=target_language,
text=text
)
translation_response = llm.complete(translation_prompt)
return translation_response.text
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.post("/generate-quizzes/")
def generate_quiz(quiz_request: QuizRequest):
print(quiz_request)
"""Generates quizzes dynamically based on user input"""
try:
# Handle optional description
description_part = f"Description: {quiz_request.description}" if quiz_request.description else ""
# Step 1: Generate the raw quiz JSON using the first LLM
prompt = PROMPT_TEMPLATE.format(
topic=quiz_request.topic,
subject=quiz_request.subject,
grade_level=quiz_request.grade_level,
format=quiz_request.format,
description_part=description_part, # This avoids adding "Description: None" if it's not provided
difficulty=quiz_request.difficulty,
num_questions=quiz_request.num_questions
)
# Generate the raw quiz JSON
raw_quiz_response = llm.complete(prompt).text
# Step 2: Translate the raw quiz JSON into the desired language
translated_quiz_response = translate_text(raw_quiz_response, quiz_request.language)
# Step 3: Format the translated quizzes into a teacher-friendly format
format_prompt = FORMAT_PROMPT_TEMPLATE.format(
quiz_json=translated_quiz_response,
)
# Return the formatted quizzes as a streaming response
return StreamingResponse(format_quiz_stream(format_prompt), media_type="text/plain")
except Exception as e:
print(e)
raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(e)}") |