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
11 changes: 7 additions & 4 deletions backend/Generator/llm_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import re
import threading
from llama_cpp import Llama

from .output_validator import validate_mcq, validate_shortq, validate_boolq

class LLMQuestionGenerator:
"""Generates various types of questions using Qwen3-0.6B via llama.cpp.
Expand Down Expand Up @@ -73,7 +73,8 @@ def generate_short_questions(self, input_text, max_questions=4):
return []

raw = choices[0].get("message", {}).get("content", "")
return self._parse_response(raw, max_questions)
parsed_questions = self._parse_response(raw, max_questions)
return validate_shortq(parsed_questions)

except (AttributeError, TypeError, ValueError):
return []
Expand Down Expand Up @@ -113,7 +114,8 @@ def generate_mcq_questions(self, input_text, max_questions=4):
return []

raw = choices[0].get("message", {}).get("content", "")
return self._parse_mcq_response(raw, max_questions)
parsed_questions = self._parse_mcq_response(raw, max_questions)
return validate_mcq(parsed_questions)

except (AttributeError, TypeError, ValueError):
return []
Expand Down Expand Up @@ -152,7 +154,8 @@ def generate_boolean_questions(self, input_text, max_questions=4):
return []

raw = choices[0].get("message", {}).get("content", "")
return self._parse_bool_response(raw, max_questions)
parsed_questions = self._parse_bool_response(raw, max_questions)
return validate_boolq(parsed_questions)

except (AttributeError, TypeError, ValueError):
return []
Expand Down
131 changes: 131 additions & 0 deletions backend/Generator/output_validator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
Output validation for LLM-generated questions.
Ensures that only well-formed, complete questions are returned to API consumers.
"""


def validate_mcq(questions):
"""
Validate multiple-choice questions.

Args:
questions: List of MCQ question dictionaries

Returns:
List of valid MCQ questions (filtered)

Validation Rules:
- question field must exist and be non-empty string
- options field must exist and be a list with at least 2 elements
- correct_answer field must exist and be non-empty string
"""
if not questions:
return []

valid_questions = []

for q in questions:
if not isinstance(q, dict):
continue

# Check question field
question = q.get("question")
if not question or not isinstance(question, str) or not question.strip():
continue

# Check options field
options = q.get("options")
if not options or not isinstance(options, list) or len(options) < 2:
continue

# Verify all options are non-empty strings
if not all(isinstance(opt, str) and opt.strip() for opt in options):
continue

# Check correct_answer field
correct_answer = q.get("correct_answer")
if not correct_answer or not isinstance(correct_answer, str) or not correct_answer.strip():
continue

# All checks passed - this is a valid question
valid_questions.append(q)

return valid_questions


def validate_shortq(questions):
"""
Validate short answer questions.

Args:
questions: List of short answer question dictionaries

Returns:
List of valid short answer questions (filtered)

Validation Rules:
- question field must exist and be non-empty string
- answer field must exist and be non-empty string
"""
if not questions:
return []

valid_questions = []

for q in questions:
if not isinstance(q, dict):
continue

# Check question field
question = q.get("question")
if not question or not isinstance(question, str) or not question.strip():
continue

# Check answer field
answer = q.get("answer")
if not answer or not isinstance(answer, str) or not answer.strip():
continue

# All checks passed - this is a valid question
valid_questions.append(q)

return valid_questions


def validate_boolq(questions):
"""
Validate boolean (true/false) questions.

Args:
questions: List of boolean question dictionaries

Returns:
List of valid boolean questions (filtered)

Validation Rules:
- question field must exist and be non-empty string
- answer field must exist and be boolean type (True or False)
"""
if not questions:
return []

valid_questions = []

for q in questions:
if not isinstance(q, dict):
continue

# Check question field
question = q.get("question")
if not question or not isinstance(question, str) or not question.strip():
continue

# Check answer field - must be boolean type, not string or int
answer = q.get("answer")
if not isinstance(answer, bool):
continue

# All checks passed - this is a valid question
valid_questions.append(q)

return valid_questions