File size: 6,013 Bytes
5775a1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
175
176
# modules/mcq_generator.py
"""Enhanced MCQ Quiz Generator Module"""

import random
from typing import Dict, List, Tuple
from modules.api_utils import (
    fetch_wikipedia_summary,
    search_wikipedia,
    fetch_related_topics,
    fetch_wikipedia_categories,
)


def generate_smart_distractors(

    correct_answer: str, topic: str, context: str

) -> List[str]:
    """Generate intelligent distractor options"""
    distractors = set()

    # Get related topics
    related = fetch_related_topics(topic, 10)
    distractors.update(related)

    # Get categories and use them for distractors
    categories = fetch_wikipedia_categories(topic)
    if categories:
        # Search for other items in the same categories
        for category in categories[:2]:
            similar_items = search_wikipedia(category, 5)
            distractors.update(similar_items)

    # Remove the correct answer and topic
    distractors.discard(correct_answer)
    distractors.discard(topic)

    # Convert to list and shuffle
    distractor_list = list(distractors)
    random.shuffle(distractor_list)

    # If not enough distractors, add generic ones
    if len(distractor_list) < 3:
        generic_distractors = [
            "Scientific Theory",
            "Historical Event",
            "Mathematical Concept",
            "Geographical Location",
            "Literary Work",
            "Technological Innovation",
            "Cultural Phenomenon",
            "Economic System",
            "Political Movement",
        ]
        distractor_list.extend(generic_distractors)

    return distractor_list[:3]


def generate_question_types(topic: str, summary_data: Dict, difficulty: str) -> Dict:
    """Generate different types of questions based on difficulty"""
    title = summary_data.get("title", topic)
    extract = summary_data.get("extract", "")
    description = summary_data.get("description", "")

    question_templates = {
        "Easy": [
            f"What is {title}?",
            f"Which of the following best describes {title}?",
            f"What category does {title} belong to?",
        ],
        "Medium": [
            f"What is the primary characteristic of {title}?",
            f"How is {title} commonly defined?",
            f"Which statement about {title} is most accurate?",
        ],
        "Hard": [
            f"What distinguishes {title} from related concepts?",
            f"In what context is {title} most significant?",
            f"What is the key principle underlying {title}?",
        ],
    }

    # Select appropriate question
    questions = question_templates.get(difficulty, question_templates["Easy"])
    question = random.choice(questions)

    # For harder difficulties, extract a more specific answer from the text
    if difficulty == "Easy":
        correct_answer = title
    elif difficulty == "Medium":
        # Try to find a defining characteristic
        sentences = extract.split(".")
        if len(sentences) > 1:
            correct_answer = description if description else title
        else:
            correct_answer = title
    else:  # Hard
        # Use a more complex answer
        correct_answer = description if description else title

    return {"question": question, "correct_answer": correct_answer, "context": extract}


def generate_mcq(topic: str, difficulty: str) -> Dict:
    """Generate an enhanced multiple choice question"""
    summary_data = fetch_wikipedia_summary(topic)

    if not summary_data:
        # Try searching for the topic
        search_results = search_wikipedia(topic, 3)
        if search_results:
            # Try the first search result
            topic = search_results[0]
            summary_data = fetch_wikipedia_summary(topic)

        if not summary_data:
            return {
                "error": "Topic not found on Wikipedia. Try a different topic or check spelling.",
                "status": False,
                "suggestions": search_results if search_results else [],
            }

    # Generate question based on difficulty
    question_data = generate_question_types(topic, summary_data, difficulty)

    # Generate smart distractors
    distractors = generate_smart_distractors(
        question_data["correct_answer"], topic, question_data["context"]
    )

    # Create options
    options = [question_data["correct_answer"]] + distractors[:3]
    random.shuffle(options)

    # Create explanation
    extract = summary_data.get("extract", "")
    explanation = extract[:300] + "..." if len(extract) > 300 else extract

    return {
        "question": question_data["question"],
        "options": options,
        "correct_answer": question_data["correct_answer"],
        "explanation": explanation,
        "topic": summary_data.get("title", topic),
        "difficulty": difficulty,
        "status": True,
    }


def generate_quiz_set(

    topic: str, difficulty: str, num_questions: int = 5

) -> List[Dict]:
    """Generate a set of questions for a complete quiz"""
    questions = []
    used_topics = set()

    # Get related topics for variety
    related_topics = [topic] + fetch_related_topics(topic, 10)

    for i in range(num_questions):
        # Try to use different related topics
        for related_topic in related_topics:
            if related_topic not in used_topics:
                question = generate_mcq(related_topic, difficulty)
                if question.get("status"):
                    questions.append(question)
                    used_topics.add(related_topic)
                    break

        # If we couldn't get enough questions, try the main topic again
        if len(questions) <= i:
            question = generate_mcq(topic, difficulty)
            if question.get("status"):
                questions.append(question)

    return questions