Spaces:
Paused
Paused
| """Expanded mock task generator with many families and multiple difficulty levels.""" | |
| import random | |
| from typing import List, Tuple | |
| from interfaces import Task, TaskGeneratorInterface | |
| class MockTaskGenerator(TaskGeneratorInterface): | |
| """ | |
| Expanded task generator with: | |
| - 15+ topic families | |
| - 5-7 difficulty levels (higher = multi-step) | |
| - Procedural task generation | |
| """ | |
| def __init__(self, seed: int = 42): | |
| self.rng = random.Random(seed) | |
| self.task_counter = 0 | |
| # Expanded topic families (15+ topics) | |
| self.topics = [ | |
| 'history', 'science', 'literature', 'geography', 'current_events', | |
| 'mathematics', 'programming', 'philosophy', 'art', 'music', | |
| 'biology', 'chemistry', 'physics', 'economics', 'psychology' | |
| ] | |
| # Expanded difficulty levels (5-7 levels) | |
| # Higher levels involve multi-step reasoning | |
| self.difficulties = [ | |
| 'trivial', # 0: Single fact recall | |
| 'easy', # 1: Simple understanding | |
| 'medium', # 2: Application of concepts | |
| 'hard', # 3: Analysis and reasoning (2-3 steps) | |
| 'expert', # 4: Complex multi-step (3-4 steps) | |
| 'master', # 5: Advanced multi-step (4-5 steps) | |
| 'grandmaster' # 6: Expert-level synthesis (5+ steps) | |
| ] | |
| # Template structure for each topic | |
| self._init_templates() | |
| def _init_templates(self): | |
| """Initialize template structures for procedural generation.""" | |
| # Templates store base patterns, not fixed questions | |
| self.template_patterns = { | |
| topic: { | |
| 'base_concepts': self._get_base_concepts(topic), | |
| 'relationships': self._get_relationships(topic), | |
| 'complexity_factors': self._get_complexity_factors(topic) | |
| } | |
| for topic in self.topics | |
| } | |
| def _get_base_concepts(self, topic: str) -> List[str]: | |
| """Get base concepts for a topic.""" | |
| concept_map = { | |
| 'history': ['dates', 'events', 'causes', 'effects', 'figures'], | |
| 'science': ['principles', 'laws', 'experiments', 'observations'], | |
| 'literature': ['themes', 'symbols', 'characters', 'plot', 'style'], | |
| 'geography': ['locations', 'features', 'climate', 'resources'], | |
| 'current_events': ['trends', 'issues', 'policies', 'impacts'], | |
| 'mathematics': ['operations', 'equations', 'patterns', 'proofs'], | |
| 'programming': ['syntax', 'algorithms', 'data structures', 'patterns'], | |
| 'philosophy': ['concepts', 'arguments', 'theories', 'ethics'], | |
| 'art': ['styles', 'techniques', 'movements', 'artists'], | |
| 'music': ['theory', 'instruments', 'genres', 'composers'], | |
| 'biology': ['cells', 'systems', 'processes', 'evolution'], | |
| 'chemistry': ['elements', 'reactions', 'bonding', 'mechanisms'], | |
| 'physics': ['forces', 'energy', 'fields', 'particles'], | |
| 'economics': ['markets', 'policies', 'indicators', 'theories'], | |
| 'psychology': ['behavior', 'cognition', 'theories', 'methods'] | |
| } | |
| return concept_map.get(topic, ['concept1', 'concept2', 'concept3']) | |
| def _get_relationships(self, topic: str) -> List[str]: | |
| """Get relationship types for multi-step reasoning.""" | |
| return ['causes', 'enables', 'requires', 'leads_to', 'depends_on', 'influences'] | |
| def _get_complexity_factors(self, topic: str) -> List[str]: | |
| """Get factors that increase complexity.""" | |
| return ['context', 'exceptions', 'interactions', 'historical', 'contemporary'] | |
| def get_available_topics(self) -> List[str]: | |
| """Return list of available topics.""" | |
| return self.topics.copy() | |
| def get_available_difficulties(self) -> List[str]: | |
| """Return list of available difficulties.""" | |
| return self.difficulties.copy() | |
| def _get_steps_for_difficulty(self, difficulty: str) -> int: | |
| """Determine number of reasoning steps for a difficulty level.""" | |
| step_map = { | |
| 'trivial': 1, | |
| 'easy': 1, | |
| 'medium': 2, | |
| 'hard': 3, | |
| 'expert': 4, | |
| 'master': 5, | |
| 'grandmaster': 6 | |
| } | |
| return step_map.get(difficulty, 1) | |
| def _generate_multi_step_question(self, topic: str, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """ | |
| Generate a question with multiple reasoning steps. | |
| Returns: | |
| (passage, question, [correct, distractor1, distractor2, distractor3]) | |
| """ | |
| steps = self._get_steps_for_difficulty(difficulty) | |
| concepts = self.template_patterns[topic]['base_concepts'] | |
| relationships = self.template_patterns[topic]['relationships'] | |
| # Select concepts and relationships based on difficulty | |
| selected_concepts = self.rng.sample(concepts, min(steps, len(concepts))) | |
| selected_relationships = self.rng.sample(relationships, steps - 1) if steps > 1 else [] | |
| # Generate passage with multi-step reasoning | |
| passage_parts = [] | |
| question_context = [] | |
| for i, concept in enumerate(selected_concepts): | |
| if i == 0: | |
| passage_parts.append(f"In {topic}, {concept} is fundamental.") | |
| question_context.append(concept) | |
| else: | |
| rel = selected_relationships[i-1] if i-1 < len(selected_relationships) else 'relates to' | |
| passage_parts.append(f"{concept} {rel} {selected_concepts[i-1]}.") | |
| question_context.append(f"{rel} {concept}") | |
| passage = " ".join(passage_parts) | |
| # Generate question that requires multi-step reasoning | |
| if steps == 1: | |
| question = f"What is the primary {selected_concepts[0]} in {topic}?" | |
| correct = f"Primary {selected_concepts[0]}" | |
| elif steps == 2: | |
| question = f"Given that {selected_concepts[0]} {selected_relationships[0]} {selected_concepts[1]}, what is the result?" | |
| correct = f"{selected_concepts[0]} β {selected_concepts[1]}" | |
| elif steps == 3: | |
| question = f"If {selected_concepts[0]} leads to {selected_concepts[1]}, and {selected_concepts[1]} influences {selected_concepts[2] if len(selected_concepts) > 2 else selected_concepts[0]}, what is the final outcome?" | |
| correct = f"Chain: {selected_concepts[0]} β {selected_concepts[1]} β {selected_concepts[min(2, len(selected_concepts)-1)]}" | |
| else: | |
| # Complex multi-step | |
| question = f"Considering the relationship chain: {' β '.join(selected_concepts[:steps])}, what synthesis emerges?" | |
| correct = f"Synthesis from {steps} steps" | |
| # Generate distractors | |
| distractors = [ | |
| f"Alternative {selected_concepts[0] if selected_concepts else 'answer'}", | |
| f"Unrelated concept", | |
| f"Reverse relationship" | |
| ] | |
| return passage, question, [correct] + distractors | |
| def generate_task(self, topic: str, difficulty: str) -> Task: | |
| """Generate a task for the given topic and difficulty.""" | |
| if topic not in self.topics: | |
| raise ValueError(f"Unknown topic: {topic}. Available: {self.topics}") | |
| if difficulty not in self.difficulties: | |
| raise ValueError(f"Unknown difficulty: {difficulty}. Available: {self.difficulties}") | |
| # Try topic-specific generator first, fall back to generic | |
| templates = { | |
| 'history': self._generate_history_question, | |
| 'science': self._generate_science_question, | |
| 'mathematics': self._generate_math_question, | |
| 'programming': self._generate_programming_question, | |
| } | |
| generator = templates.get(topic) | |
| if generator: | |
| passage, question, choices_list = generator(difficulty) | |
| else: | |
| passage, question, choices_list = self._generate_multi_step_question(topic, difficulty) | |
| # Shuffle choices | |
| correct_answer = choices_list[0] # First is always correct | |
| self.rng.shuffle(choices_list) | |
| correct_idx = choices_list.index(correct_answer) | |
| # Create task ID | |
| self.task_counter += 1 | |
| task_id = f"{topic}_{difficulty}_{self.task_counter}" | |
| return Task( | |
| passage=passage, | |
| question=question, | |
| choices=choices_list, | |
| answer=correct_idx, | |
| topic=topic, | |
| difficulty=difficulty, | |
| task_id=task_id | |
| ) | |
| def _generate_topic_specific_question(self, topic: str, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Generate topic-specific question templates for more realistic tasks.""" | |
| templates = { | |
| 'history': self._generate_history_question, | |
| 'science': self._generate_science_question, | |
| 'mathematics': self._generate_math_question, | |
| 'programming': self._generate_programming_question, | |
| } | |
| generator = templates.get(topic, self._generate_generic_question) | |
| return generator(difficulty) | |
| def _generate_history_question(self, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Generate history-specific questions.""" | |
| events = [ | |
| ("Industrial Revolution", "Britain", "late 18th century"), | |
| ("World War II", "1939-1945", "global conflict"), | |
| ("Renaissance", "Italy", "14th-17th century"), | |
| ("French Revolution", "1789", "socio-political upheaval"), | |
| ("Cold War", "1947-1991", "ideological conflict") | |
| ] | |
| event = self.rng.choice(events) | |
| steps = self._get_steps_for_difficulty(difficulty) | |
| if steps == 1: | |
| passage = f"The {event[0]} began in {event[1]}." | |
| question = f"When did the {event[0]} occur?" | |
| correct = event[1] if 'century' in event[1] or len(event[1]) > 4 else event[2] | |
| elif steps == 2: | |
| passage = f"The {event[0]} started in {event[1]} and led to {event[2]}." | |
| question = f"What was a major consequence of the {event[0]}?" | |
| correct = event[2] | |
| else: | |
| passage = f"The {event[0]} began in {event[1]}, caused {event[2]}, and influenced subsequent historical developments." | |
| question = f"What sequence of effects did the {event[0]} create?" | |
| correct = f"{event[1]} β {event[2]} β Historical changes" | |
| distractors = [ | |
| f"Alternative historical period", | |
| f"Different region", | |
| f"Unrelated event" | |
| ] | |
| return passage, question, [correct] + distractors | |
| def _generate_science_question(self, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Generate science-specific questions.""" | |
| concepts = [ | |
| ("Photosynthesis", "converts light to glucose", "requires CO2 and H2O"), | |
| ("Evolution", "natural selection", "genetic variation"), | |
| ("Gravity", "attracts mass", "affects motion") | |
| ] | |
| concept = self.rng.choice(concepts) | |
| steps = self._get_steps_for_difficulty(difficulty) | |
| if steps == 1: | |
| passage = f"{concept[0]} is a fundamental process." | |
| question = f"What does {concept[0]} do?" | |
| correct = concept[1] | |
| elif steps == 2: | |
| passage = f"{concept[0]} {concept[1]} and {concept[2]}." | |
| question = f"How does {concept[0]} work?" | |
| correct = f"{concept[1]} using {concept[2]}" | |
| else: | |
| passage = f"{concept[0]} {concept[1]}. This process {concept[2]}, which enables further biological processes." | |
| question = f"What is the complete mechanism of {concept[0]}?" | |
| correct = f"{concept[1]} β {concept[2]} β Biological outcomes" | |
| distractors = [ | |
| "Different mechanism", | |
| "Incorrect process", | |
| "Unrelated concept" | |
| ] | |
| return passage, question, [correct] + distractors | |
| def _generate_math_question(self, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Generate mathematics questions with varying complexity.""" | |
| steps = self._get_steps_for_difficulty(difficulty) | |
| if steps == 1: | |
| a, b = self.rng.randint(1, 10), self.rng.randint(1, 10) | |
| passage = f"Consider the numbers {a} and {b}." | |
| question = f"What is {a} + {b}?" | |
| correct = str(a + b) | |
| elif steps == 2: | |
| a, b, c = self.rng.randint(1, 10), self.rng.randint(1, 10), self.rng.randint(1, 10) | |
| passage = f"Given: x = {a}, y = {b}, z = {c}." | |
| question = f"What is (x + y) * z?" | |
| correct = str((a + b) * c) | |
| elif steps == 3: | |
| a, b, c, d = [self.rng.randint(1, 5) for _ in range(4)] | |
| passage = f"Given: a={a}, b={b}, c={c}, d={d}. Compute: a*b, then add c, then multiply by d." | |
| question = f"What is the final result?" | |
| correct = str((a * b + c) * d) | |
| else: | |
| # Multi-step algebraic chain | |
| values = [self.rng.randint(1, 5) for _ in range(steps + 1)] | |
| passage = f"Given values: {', '.join([f'v{i}={values[i]}' for i in range(len(values))])}" | |
| question = f"Compute: v0 * v1 + v2 * v3 - v4 (if applicable)" | |
| result = values[0] * values[1] + (values[2] * values[3] if len(values) > 3 else 0) - (values[4] if len(values) > 4 else 0) | |
| correct = str(result) | |
| distractors = [ | |
| str(self.rng.randint(0, 100)), | |
| str(self.rng.randint(0, 100)), | |
| str(self.rng.randint(0, 100)) | |
| ] | |
| return passage, question, [correct] + distractors | |
| def _generate_programming_question(self, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Generate programming questions.""" | |
| steps = self._get_steps_for_difficulty(difficulty) | |
| if steps == 1: | |
| passage = "In Python, list indexing starts at 0." | |
| question = "What is the first index of a list?" | |
| correct = "0" | |
| elif steps == 2: | |
| passage = "Consider: arr = [1, 2, 3, 4, 5]. First, get arr[1:3], then access the last element." | |
| question = "What is the result?" | |
| correct = "3" | |
| elif steps == 3: | |
| passage = "Code: x = [1, 2, 3]; y = x[1:]; z = y[-1] + x[0]" | |
| question = "What is z?" | |
| correct = "4" # y[-1] = 3, x[0] = 1, so 3+1=4 | |
| else: | |
| # Multi-step: a = [1,2,3,4]; b = a[1:3]; c = sum(b); d = c * a[0] | |
| # a[1:3] = [2,3], sum(b) = 5, a[0] = 1, so d = 5 * 1 = 5 | |
| passage = "Multi-step: a = [1,2,3,4]; b = a[1:3]; c = sum(b); d = c * a[0]" | |
| question = "What is d?" | |
| correct = "5" # a[1:3]=[2,3], sum=5, 5*1=5 | |
| distractors = ["0", "1", "2"] | |
| return passage, question, [correct] + distractors | |
| def _generate_generic_question(self, difficulty: str) -> Tuple[str, str, List[str]]: | |
| """Fallback generic question generator.""" | |
| return self._generate_multi_step_question(self.rng.choice(self.topics), difficulty) | |