finalize mcq and add test cases

parent 923f5898
...@@ -361,53 +361,71 @@ class AgentService: ...@@ -361,53 +361,71 @@ class AgentService:
def get_dynamic_quiz( def get_dynamic_quiz(
self, grade: int, subject: str, unit: str, concept: str, is_arabic: bool, count: int self, grade: int, subject: str, unit: str, concept: str, is_arabic: bool, count: int
) -> List[Dict]: ) -> List[Dict]:
""" """
Generates a dynamic quiz of 'count' questions for a specific topic. Generates a dynamic quiz of 'count' questions using a hybrid approach:
It ensures a portion of the questions are newly generated. 1. Always generates a "freshness batch" of new questions.
2. Retrieves all questions and checks if the total meets the 'count'.
3. If not, generates the remaining number of questions needed.
""" """
if not self.pgvector: if not self.pgvector:
raise HTTPException(status_code=503, detail="Vector service is not available for this feature.") raise HTTPException(status_code=503, detail="Vector service is not available for this feature.")
# 1. Calculate how many new questions to generate # --- PART 1: Follow the original logic to ensure freshness ---
# Logic: at least 1, up to 1/3 of the quiz size, with a max cap of 5.
num_new_questions = min(max(1, math.floor(count / 3)), 5) # 1. Calculate how many new questions to generate for freshness.
logger.info(f"Request for {count} questions. Will generate {num_new_questions} new ones.") num_fresh_questions = min(max(1, math.floor(count / 3)), 5)
logger.info(f"Request for {count} questions. Step 1: Generating {num_fresh_questions} new 'freshness' questions.")
# 2. Generate and store the new questions # 2. Generate and store these new "freshness" questions.
try: try:
self.generate_and_store_mcqs( self.generate_and_store_mcqs(
grade=grade, grade=grade, subject=subject, unit=unit, concept=concept,
subject=subject, is_arabic=is_arabic, num_questions=num_fresh_questions
unit=unit,
concept=concept,
is_arabic=is_arabic,
num_questions=num_new_questions
) )
except Exception as e: except Exception as e:
# If generation fails, we can still proceed with existing questions. logger.warning(f"Could not generate 'freshness' questions for the quiz due to an error: {e}")
logger.warning(f"Could not generate new questions for the quiz due to an error: {e}")
# --- PART 2: Check for a shortfall and generate more if needed ---
# 3. Retrieve ALL available questions for the topic from the database
all_mcqs = self.pgvector.get_mcqs( # 3. Retrieve ALL available questions for the topic from the database.
grade=grade, all_mcqs_after_freshness = self.pgvector.get_mcqs(
subject=subject, grade=grade, subject=subject, unit=unit, concept=concept,
unit=unit, is_arabic=is_arabic, limit=None
concept=concept,
is_arabic=is_arabic,
limit=None # Retrieve all
) )
if not all_mcqs: # 4. Calculate if there is still a shortfall.
questions_still_needed = count - len(all_mcqs_after_freshness)
# 5. If we still need more questions, generate the exact number missing.
if questions_still_needed > 0:
logger.info(f"After freshness batch, have {len(all_mcqs_after_freshness)} questions. Generating {questions_still_needed} more to meet count of {count}.")
# Cap this second generation step as a safeguard.
num_to_generate_gap = min(questions_still_needed, 10)
try:
self.generate_and_store_mcqs(
grade=grade, subject=subject, unit=unit, concept=concept,
is_arabic=is_arabic, num_questions=num_to_generate_gap
)
except Exception as e:
logger.warning(f"Could not generate the remaining {num_to_generate_gap} questions due to an error: {e}")
# --- PART 3: Final Assembly and Return ---
# 6. Retrieve the final, complete list of ALL questions.
final_pool = self.pgvector.get_mcqs(
grade=grade, subject=subject, unit=unit, concept=concept,
is_arabic=is_arabic, limit=None
)
if not final_pool:
raise HTTPException(status_code=404, detail="No questions could be found or generated for this topic.") raise HTTPException(status_code=404, detail="No questions could be found or generated for this topic.")
# 4. Randomly select the desired number of questions from the full pool # 7. Randomly select the desired number of questions from the final pool.
# First, shuffle the entire list of questions random.shuffle(final_pool)
random.shuffle(all_mcqs) final_quiz = final_pool[:count]
# Then, return a slice of the list with the requested count
# This gracefully handles cases where we have fewer questions than requested.
final_quiz = all_mcqs[:count]
logger.info(f"Returning a dynamic quiz of {len(final_quiz)} questions for '{concept}'.") logger.info(f"Returning a dynamic quiz of {len(final_quiz)} questions for '{concept}'.")
return final_quiz return final_quiz
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment