refactor: implement core and server dir to split the library and endpoints for testing
This commit is contained in:
17
math_problems_structure/core/__init__.py
Normal file
17
math_problems_structure/core/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from math_problems_structure.core.problems.grade_1 import (
|
||||
compose_and_decompose_numbers,
|
||||
join_corresponding_sums,
|
||||
join_pictures_with_quantity,
|
||||
subtract_with_image_reference,
|
||||
sum_with_image_reference,
|
||||
where_are_more_items,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"compose_and_decompose_numbers",
|
||||
"join_corresponding_sums",
|
||||
"join_pictures_with_quantity",
|
||||
"subtract_with_image_reference",
|
||||
"sum_with_image_reference",
|
||||
"where_are_more_items",
|
||||
]
|
||||
0
math_problems_structure/core/problems/__init__.py
Normal file
0
math_problems_structure/core/problems/__init__.py
Normal file
27
math_problems_structure/core/problems/grade_1/__init__.py
Normal file
27
math_problems_structure/core/problems/grade_1/__init__.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from math_problems_structure.core.problems.grade_1.compose_and_decompose_numbers import (
|
||||
compose_and_decompose_numbers,
|
||||
)
|
||||
from math_problems_structure.core.problems.grade_1.join_corresponding_sums import (
|
||||
join_corresponding_sums,
|
||||
)
|
||||
from math_problems_structure.core.problems.grade_1.join_pictures_with_quantity import (
|
||||
join_pictures_with_quantity,
|
||||
)
|
||||
from math_problems_structure.core.problems.grade_1.subtract_with_image_reference import (
|
||||
subtract_with_image_reference,
|
||||
)
|
||||
from math_problems_structure.core.problems.grade_1.sum_with_image_reference import (
|
||||
sum_with_image_reference,
|
||||
)
|
||||
from math_problems_structure.core.problems.grade_1.where_are_more_items import (
|
||||
where_are_more_items,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"compose_and_decompose_numbers",
|
||||
"join_corresponding_sums",
|
||||
"join_pictures_with_quantity",
|
||||
"subtract_with_image_reference",
|
||||
"sum_with_image_reference",
|
||||
"where_are_more_items",
|
||||
]
|
||||
@@ -0,0 +1,42 @@
|
||||
import random
|
||||
|
||||
from math_problems_structure.core.schemas.grade_1.compose_and_decompose_numbers import (
|
||||
ComposeAndDecomposeNumbersProblem,
|
||||
DecompositionRow,
|
||||
PictureAsset,
|
||||
)
|
||||
|
||||
|
||||
def compose_and_decompose_numbers(
|
||||
picture: dict,
|
||||
whole: int = 10,
|
||||
randomize_rows: bool = False,
|
||||
seed: int | None = None,
|
||||
) -> dict:
|
||||
"""Generate number decomposition rows for one picture asset."""
|
||||
if whole < 2:
|
||||
raise ValueError("whole must be at least 2")
|
||||
|
||||
selected_picture = PictureAsset.model_validate(picture)
|
||||
pairs = [(first_part, whole - first_part) for first_part in range(whole - 1, 0, -1)]
|
||||
|
||||
if randomize_rows:
|
||||
rng = random.Random(seed)
|
||||
rng.shuffle(pairs)
|
||||
|
||||
problem = ComposeAndDecomposeNumbersProblem(
|
||||
whole=whole,
|
||||
picture=selected_picture,
|
||||
rows=[
|
||||
DecompositionRow(
|
||||
position=index + 1,
|
||||
whole=whole,
|
||||
first_part=first_part,
|
||||
second_part=second_part,
|
||||
picture=selected_picture,
|
||||
)
|
||||
for index, (first_part, second_part) in enumerate(pairs)
|
||||
],
|
||||
)
|
||||
|
||||
return problem.model_dump()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 411 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 328 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 333 KiB |
@@ -0,0 +1,96 @@
|
||||
import random
|
||||
|
||||
from math_problems_structure.core.schemas.grade_1.join_corresponding_sums import (
|
||||
AdditionExpression,
|
||||
JoinCorrespondingSumsProblem,
|
||||
SumConnection,
|
||||
)
|
||||
|
||||
|
||||
def join_corresponding_sums(
|
||||
pair_count: int = 3,
|
||||
min_sum: int = 2,
|
||||
max_sum: int = 10,
|
||||
min_addend: int = 1,
|
||||
max_addend: int = 9,
|
||||
seed: int | None = None,
|
||||
) -> dict:
|
||||
"""Generate addition expressions that students connect by equal sums."""
|
||||
if pair_count < 1:
|
||||
raise ValueError("pair_count must be at least 1")
|
||||
if min_sum > max_sum:
|
||||
raise ValueError("min_sum must be less than or equal to max_sum")
|
||||
if min_addend > max_addend:
|
||||
raise ValueError("min_addend must be less than or equal to max_addend")
|
||||
|
||||
expressions_by_total: dict[int, list[tuple[int, int]]] = {}
|
||||
for total in range(min_sum, max_sum + 1):
|
||||
expressions = []
|
||||
for first_addend in range(min_addend, max_addend + 1):
|
||||
second_addend = total - first_addend
|
||||
if min_addend <= second_addend <= max_addend:
|
||||
expressions.append((first_addend, second_addend))
|
||||
|
||||
if len(expressions) >= 2:
|
||||
expressions_by_total[total] = expressions
|
||||
|
||||
available_totals = list(expressions_by_total)
|
||||
if len(available_totals) < pair_count:
|
||||
raise ValueError("sum and addend ranges must contain enough matchable sums")
|
||||
|
||||
rng = random.Random(seed)
|
||||
selected_totals = rng.sample(available_totals, pair_count)
|
||||
left_items: list[dict] = []
|
||||
right_items: list[dict] = []
|
||||
|
||||
for total in selected_totals:
|
||||
left_expression, right_expression = rng.sample(expressions_by_total[total], 2)
|
||||
match_id = f"sum-{total}"
|
||||
left_items.append(
|
||||
{
|
||||
"first_addend": left_expression[0],
|
||||
"second_addend": left_expression[1],
|
||||
"total": total,
|
||||
"match_id": match_id,
|
||||
}
|
||||
)
|
||||
right_items.append(
|
||||
{
|
||||
"first_addend": right_expression[0],
|
||||
"second_addend": right_expression[1],
|
||||
"total": total,
|
||||
"match_id": match_id,
|
||||
}
|
||||
)
|
||||
|
||||
rng.shuffle(left_items)
|
||||
rng.shuffle(right_items)
|
||||
|
||||
left_expressions = [
|
||||
AdditionExpression(position=index + 1, **item)
|
||||
for index, item in enumerate(left_items)
|
||||
]
|
||||
right_expressions = [
|
||||
AdditionExpression(position=index + 1, **item)
|
||||
for index, item in enumerate(right_items)
|
||||
]
|
||||
right_positions_by_match_id = {
|
||||
expression.match_id: expression.position for expression in right_expressions
|
||||
}
|
||||
answer_key = [
|
||||
SumConnection(
|
||||
match_id=expression.match_id,
|
||||
total=expression.total,
|
||||
left_position=expression.position,
|
||||
right_position=right_positions_by_match_id[expression.match_id],
|
||||
)
|
||||
for expression in left_expressions
|
||||
]
|
||||
|
||||
problem = JoinCorrespondingSumsProblem(
|
||||
left_expressions=left_expressions,
|
||||
right_expressions=right_expressions,
|
||||
answer_key=answer_key,
|
||||
)
|
||||
|
||||
return problem.model_dump()
|
||||
@@ -0,0 +1,73 @@
|
||||
import random
|
||||
|
||||
from math_problems_structure.core.schemas.grade_1.join_pictures_with_quantity import (
|
||||
JoinPicturesWithQuantityProblem,
|
||||
NumberCard,
|
||||
PictureAsset,
|
||||
PictureContainer,
|
||||
)
|
||||
|
||||
|
||||
def join_pictures_with_quantity(
|
||||
available_pictures: list[dict],
|
||||
container_count_per_side: int = 5,
|
||||
min_quantity: int = 1,
|
||||
max_quantity: int = 10,
|
||||
seed: int | None = None,
|
||||
) -> dict:
|
||||
"""Generate a count-and-match picture problem.
|
||||
|
||||
The caller only provides the picture assets that exist in the project. The
|
||||
function chooses unique quantities, assigns pictures to the left and right
|
||||
containers, and returns a JSON-ready validated problem structure.
|
||||
|
||||
Each picture must have: id, name, image_path.
|
||||
"""
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
|
||||
pictures = [PictureAsset.model_validate(picture) for picture in available_pictures]
|
||||
available_quantities = list(range(min_quantity, max_quantity + 1))
|
||||
|
||||
if container_count_per_side < 1:
|
||||
raise ValueError("container_count_per_side must be at least 1")
|
||||
|
||||
if len(available_quantities) < container_count_per_side:
|
||||
raise ValueError(
|
||||
"quantity range must contain at least container_count_per_side values"
|
||||
)
|
||||
|
||||
required_picture_count = container_count_per_side * 2
|
||||
if len(pictures) < required_picture_count:
|
||||
raise ValueError(
|
||||
f"available_pictures must contain at least {required_picture_count} pictures"
|
||||
)
|
||||
|
||||
number_card_values = random.sample(available_quantities, container_count_per_side)
|
||||
left_quantities = random.sample(number_card_values, len(number_card_values))
|
||||
right_quantities = random.sample(number_card_values, len(number_card_values))
|
||||
selected_pictures = random.sample(pictures, required_picture_count)
|
||||
|
||||
left_pictures = selected_pictures[:container_count_per_side]
|
||||
right_pictures = selected_pictures[container_count_per_side:]
|
||||
|
||||
problem = JoinPicturesWithQuantityProblem(
|
||||
left_containers=[
|
||||
PictureContainer(
|
||||
position=index + 1, quantity=quantity, picture=left_pictures[index]
|
||||
)
|
||||
for index, quantity in enumerate(left_quantities)
|
||||
],
|
||||
number_cards=[
|
||||
NumberCard(position=index + 1, value=value)
|
||||
for index, value in enumerate(number_card_values)
|
||||
],
|
||||
right_containers=[
|
||||
PictureContainer(
|
||||
position=index + 1, quantity=quantity, picture=right_pictures[index]
|
||||
)
|
||||
for index, quantity in enumerate(right_quantities)
|
||||
],
|
||||
)
|
||||
|
||||
return problem.model_dump()
|
||||
@@ -0,0 +1,49 @@
|
||||
from math_problems_structure.core.schemas.grade_1.subtract_with_image_reference import (
|
||||
FigureGroup,
|
||||
PictureAsset,
|
||||
SubtractWithImageReferenceProblem,
|
||||
SubtractionEquation,
|
||||
)
|
||||
|
||||
|
||||
def subtract_with_image_reference(
|
||||
object_name: str,
|
||||
initial_quantity: int,
|
||||
removed_quantity: int,
|
||||
figure: dict,
|
||||
actor_name: str = "Diego",
|
||||
) -> dict:
|
||||
"""Generate a subtraction story problem with remaining and removed groups."""
|
||||
if removed_quantity > initial_quantity:
|
||||
raise ValueError("removed_quantity must be less than or equal to initial_quantity")
|
||||
|
||||
selected_figure = PictureAsset.model_validate(figure)
|
||||
remaining_quantity = initial_quantity - removed_quantity
|
||||
question = (
|
||||
f"Hay {initial_quantity} {object_name}. "
|
||||
f"{actor_name} sacó {removed_quantity} {object_name}. "
|
||||
f"¿Cuántos {object_name} quedan?"
|
||||
)
|
||||
problem = SubtractWithImageReferenceProblem(
|
||||
question=question,
|
||||
object_name=object_name,
|
||||
actor_name=actor_name,
|
||||
figure=selected_figure,
|
||||
remaining_group=FigureGroup(
|
||||
label="quedan",
|
||||
quantity=remaining_quantity,
|
||||
picture=selected_figure,
|
||||
),
|
||||
subtracted_group=FigureGroup(
|
||||
label="sacó",
|
||||
quantity=removed_quantity,
|
||||
picture=selected_figure,
|
||||
),
|
||||
equation=SubtractionEquation(
|
||||
initial_quantity=initial_quantity,
|
||||
removed_quantity=removed_quantity,
|
||||
remaining_quantity=remaining_quantity,
|
||||
),
|
||||
)
|
||||
|
||||
return problem.model_dump()
|
||||
@@ -0,0 +1,92 @@
|
||||
import random
|
||||
|
||||
from math_problems_structure.core.schemas.grade_1.sum_with_image_reference import (
|
||||
AddendGroup,
|
||||
FigureGroup,
|
||||
ImageOption,
|
||||
PictureAsset,
|
||||
SumWithImageReferenceProblem,
|
||||
)
|
||||
|
||||
|
||||
def sum_with_image_reference(
|
||||
first_quantity: int,
|
||||
second_quantity: int,
|
||||
first_description: str,
|
||||
second_description: str,
|
||||
common_object: str,
|
||||
first_picture: dict,
|
||||
second_picture: dict,
|
||||
option_count: int = 3,
|
||||
min_option_quantity: int = 1,
|
||||
max_option_quantity: int = 20,
|
||||
seed: int | None = None,
|
||||
) -> dict:
|
||||
"""Generate an addition question with image answer options."""
|
||||
if option_count < 2:
|
||||
raise ValueError("option_count must be at least 2")
|
||||
|
||||
total = first_quantity + second_quantity
|
||||
option_values = list(range(max(2, min_option_quantity), max_option_quantity + 1))
|
||||
|
||||
if total not in option_values:
|
||||
raise ValueError("option quantity range must include the correct total")
|
||||
|
||||
distractor_values = [value for value in option_values if value != total]
|
||||
if len(distractor_values) < option_count - 1:
|
||||
raise ValueError("option quantity range must contain enough distractor values")
|
||||
|
||||
rng = random.Random(seed)
|
||||
selected_values = rng.sample(distractor_values, option_count - 1) + [total]
|
||||
rng.shuffle(selected_values)
|
||||
first_option_picture = PictureAsset.model_validate(first_picture)
|
||||
second_option_picture = PictureAsset.model_validate(second_picture)
|
||||
question = (
|
||||
f"Hay {first_quantity} {first_description} y "
|
||||
f"{second_quantity} {second_description}, "
|
||||
f"¿cuántas {common_object} hay en total?"
|
||||
)
|
||||
options: list[ImageOption] = []
|
||||
|
||||
for index, quantity in enumerate(selected_values):
|
||||
if quantity == total:
|
||||
option_first_quantity = first_quantity
|
||||
option_second_quantity = second_quantity
|
||||
else:
|
||||
option_first_quantity = rng.randint(1, quantity - 1)
|
||||
option_second_quantity = quantity - option_first_quantity
|
||||
|
||||
options.append(
|
||||
ImageOption(
|
||||
position=index + 1,
|
||||
quantity=quantity,
|
||||
first_group=FigureGroup(
|
||||
quantity=option_first_quantity,
|
||||
description=first_description,
|
||||
picture=first_option_picture,
|
||||
),
|
||||
second_group=FigureGroup(
|
||||
quantity=option_second_quantity,
|
||||
description=second_description,
|
||||
picture=second_option_picture,
|
||||
),
|
||||
is_correct=quantity == total,
|
||||
)
|
||||
)
|
||||
|
||||
problem = SumWithImageReferenceProblem(
|
||||
question=question,
|
||||
first_group=AddendGroup(
|
||||
quantity=first_quantity,
|
||||
description=first_description,
|
||||
),
|
||||
second_group=AddendGroup(
|
||||
quantity=second_quantity,
|
||||
description=second_description,
|
||||
),
|
||||
common_object=common_object,
|
||||
total=total,
|
||||
options=options,
|
||||
)
|
||||
|
||||
return problem.model_dump()
|
||||
@@ -0,0 +1,55 @@
|
||||
import random
|
||||
|
||||
from math_problems_structure.core.schemas.grade_1.where_are_more_items import (
|
||||
ItemGroup,
|
||||
MoreItemsComparison,
|
||||
PictureAsset,
|
||||
WhereAreMoreItemsProblem,
|
||||
)
|
||||
|
||||
|
||||
def where_are_more_items(
|
||||
available_pictures: list[dict],
|
||||
comparison_count: int = 3,
|
||||
min_quantity: int = 1,
|
||||
max_quantity: int = 10,
|
||||
seed: int | None = None,
|
||||
) -> dict:
|
||||
"""Generate comparison cards where students choose the group with more items."""
|
||||
pictures = [PictureAsset.model_validate(picture) for picture in available_pictures]
|
||||
|
||||
if len(pictures) < 2:
|
||||
raise ValueError("available_pictures must contain at least 2 pictures")
|
||||
|
||||
if min_quantity >= max_quantity:
|
||||
raise ValueError("max_quantity must be greater than min_quantity")
|
||||
|
||||
rng = random.Random(seed)
|
||||
quantity_values = list(range(min_quantity, max_quantity + 1))
|
||||
comparisons: list[MoreItemsComparison] = []
|
||||
|
||||
for index in range(comparison_count):
|
||||
left_picture, right_picture = rng.sample(pictures, 2)
|
||||
left_quantity, right_quantity = rng.sample(quantity_values, 2)
|
||||
answer_side = "left" if left_quantity > right_quantity else "right"
|
||||
|
||||
comparisons.append(
|
||||
MoreItemsComparison(
|
||||
position=index + 1,
|
||||
left_group=ItemGroup(
|
||||
side="left",
|
||||
picture=left_picture,
|
||||
quantity=left_quantity,
|
||||
),
|
||||
right_group=ItemGroup(
|
||||
side="right",
|
||||
picture=right_picture,
|
||||
quantity=right_quantity,
|
||||
),
|
||||
answer_side=answer_side,
|
||||
)
|
||||
)
|
||||
|
||||
problem = WhereAreMoreItemsProblem(comparisons=comparisons)
|
||||
|
||||
return problem.model_dump()
|
||||
0
math_problems_structure/core/schemas/__init__.py
Normal file
0
math_problems_structure/core/schemas/__init__.py
Normal file
39
math_problems_structure/core/schemas/grade_1/__init__.py
Normal file
39
math_problems_structure/core/schemas/grade_1/__init__.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from math_problems_structure.core.schemas.grade_1.compose_and_decompose_numbers import (
|
||||
ComposeAndDecomposeNumbersProblem,
|
||||
ComposeAndDecomposeNumbersRequest,
|
||||
)
|
||||
from math_problems_structure.core.schemas.grade_1.join_corresponding_sums import (
|
||||
JoinCorrespondingSumsProblem,
|
||||
JoinCorrespondingSumsRequest,
|
||||
)
|
||||
from math_problems_structure.core.schemas.grade_1.join_pictures_with_quantity import (
|
||||
JoinPicturesWithQuantityProblem,
|
||||
JoinPicturesWithQuantityRequest,
|
||||
)
|
||||
from math_problems_structure.core.schemas.grade_1.subtract_with_image_reference import (
|
||||
SubtractWithImageReferenceProblem,
|
||||
SubtractWithImageReferenceRequest,
|
||||
)
|
||||
from math_problems_structure.core.schemas.grade_1.sum_with_image_reference import (
|
||||
SumWithImageReferenceProblem,
|
||||
SumWithImageReferenceRequest,
|
||||
)
|
||||
from math_problems_structure.core.schemas.grade_1.where_are_more_items import (
|
||||
WhereAreMoreItemsProblem,
|
||||
WhereAreMoreItemsRequest,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"ComposeAndDecomposeNumbersProblem",
|
||||
"ComposeAndDecomposeNumbersRequest",
|
||||
"JoinCorrespondingSumsProblem",
|
||||
"JoinCorrespondingSumsRequest",
|
||||
"JoinPicturesWithQuantityProblem",
|
||||
"JoinPicturesWithQuantityRequest",
|
||||
"SubtractWithImageReferenceProblem",
|
||||
"SubtractWithImageReferenceRequest",
|
||||
"SumWithImageReferenceProblem",
|
||||
"SumWithImageReferenceRequest",
|
||||
"WhereAreMoreItemsProblem",
|
||||
"WhereAreMoreItemsRequest",
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
from pydantic import BaseModel, Field, PositiveInt
|
||||
|
||||
|
||||
class PictureAsset(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
image_path: str = Field(min_length=1)
|
||||
|
||||
|
||||
class DecompositionRow(BaseModel):
|
||||
position: PositiveInt
|
||||
whole: PositiveInt
|
||||
first_part: PositiveInt
|
||||
second_part: PositiveInt
|
||||
picture: PictureAsset
|
||||
has_answer_boxes: bool = True
|
||||
|
||||
|
||||
class ComposeAndDecomposeNumbersProblem(BaseModel):
|
||||
instructions: str = "Compón y descompón el número."
|
||||
whole: PositiveInt
|
||||
picture: PictureAsset
|
||||
rows: list[DecompositionRow]
|
||||
|
||||
|
||||
class ComposeAndDecomposeNumbersRequest(BaseModel):
|
||||
picture: PictureAsset
|
||||
whole: PositiveInt = 10
|
||||
randomize_rows: bool = False
|
||||
seed: int | None = None
|
||||
@@ -0,0 +1,32 @@
|
||||
from pydantic import BaseModel, Field, PositiveInt
|
||||
|
||||
|
||||
class AdditionExpression(BaseModel):
|
||||
position: PositiveInt
|
||||
first_addend: PositiveInt
|
||||
second_addend: PositiveInt
|
||||
total: PositiveInt
|
||||
match_id: str = Field(min_length=1)
|
||||
|
||||
|
||||
class SumConnection(BaseModel):
|
||||
match_id: str = Field(min_length=1)
|
||||
total: PositiveInt
|
||||
left_position: PositiveInt
|
||||
right_position: PositiveInt
|
||||
|
||||
|
||||
class JoinCorrespondingSumsProblem(BaseModel):
|
||||
instructions: str = "Conecta."
|
||||
left_expressions: list[AdditionExpression]
|
||||
right_expressions: list[AdditionExpression]
|
||||
answer_key: list[SumConnection]
|
||||
|
||||
|
||||
class JoinCorrespondingSumsRequest(BaseModel):
|
||||
pair_count: PositiveInt = 3
|
||||
min_sum: PositiveInt = 2
|
||||
max_sum: PositiveInt = 10
|
||||
min_addend: PositiveInt = 1
|
||||
max_addend: PositiveInt = 9
|
||||
seed: int | None = None
|
||||
@@ -0,0 +1,35 @@
|
||||
from pydantic import BaseModel, Field, PositiveInt
|
||||
|
||||
|
||||
class PictureAsset(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
image_path: str = Field(min_length=1)
|
||||
|
||||
|
||||
class PictureContainer(BaseModel):
|
||||
position: PositiveInt
|
||||
quantity: PositiveInt
|
||||
picture: PictureAsset
|
||||
|
||||
|
||||
class NumberCard(BaseModel):
|
||||
position: PositiveInt
|
||||
value: PositiveInt
|
||||
shows_blocks: bool = True
|
||||
has_answer_box: bool = True
|
||||
|
||||
|
||||
class JoinPicturesWithQuantityProblem(BaseModel):
|
||||
instructions: str = "Cuenta las imágenes y une cada grupo con el número correcto."
|
||||
left_containers: list[PictureContainer]
|
||||
number_cards: list[NumberCard]
|
||||
right_containers: list[PictureContainer]
|
||||
|
||||
|
||||
class JoinPicturesWithQuantityRequest(BaseModel):
|
||||
available_pictures: list[PictureAsset] = Field(min_length=1)
|
||||
container_count_per_side: PositiveInt = 5
|
||||
min_quantity: PositiveInt = 1
|
||||
max_quantity: PositiveInt = 10
|
||||
seed: int | None = None
|
||||
@@ -0,0 +1,40 @@
|
||||
from pydantic import BaseModel, Field, NonNegativeInt, PositiveInt
|
||||
|
||||
|
||||
class PictureAsset(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
image_path: str = Field(min_length=1)
|
||||
|
||||
|
||||
class SubtractionEquation(BaseModel):
|
||||
initial_quantity: PositiveInt
|
||||
removed_quantity: PositiveInt
|
||||
remaining_quantity: NonNegativeInt
|
||||
symbol: str = "-"
|
||||
equals_symbol: str = "="
|
||||
|
||||
|
||||
class FigureGroup(BaseModel):
|
||||
label: str = Field(min_length=1)
|
||||
quantity: NonNegativeInt
|
||||
picture: PictureAsset
|
||||
|
||||
|
||||
class SubtractWithImageReferenceProblem(BaseModel):
|
||||
title: str = "¿Cuántos quedan?"
|
||||
question: str
|
||||
object_name: str = Field(min_length=1)
|
||||
actor_name: str = Field(min_length=1)
|
||||
figure: PictureAsset
|
||||
remaining_group: FigureGroup
|
||||
subtracted_group: FigureGroup
|
||||
equation: SubtractionEquation
|
||||
|
||||
|
||||
class SubtractWithImageReferenceRequest(BaseModel):
|
||||
object_name: str = Field(min_length=1)
|
||||
initial_quantity: PositiveInt
|
||||
removed_quantity: PositiveInt
|
||||
figure: PictureAsset
|
||||
actor_name: str = Field(default="Diego", min_length=1)
|
||||
@@ -0,0 +1,51 @@
|
||||
from pydantic import BaseModel, Field, PositiveInt
|
||||
|
||||
|
||||
class PictureAsset(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
image_path: str = Field(min_length=1)
|
||||
|
||||
|
||||
class AddendGroup(BaseModel):
|
||||
quantity: PositiveInt
|
||||
description: str = Field(min_length=1)
|
||||
|
||||
|
||||
class FigureGroup(BaseModel):
|
||||
quantity: PositiveInt
|
||||
description: str = Field(min_length=1)
|
||||
picture: PictureAsset
|
||||
|
||||
|
||||
class ImageOption(BaseModel):
|
||||
position: PositiveInt
|
||||
quantity: PositiveInt
|
||||
first_group: FigureGroup
|
||||
second_group: FigureGroup
|
||||
is_correct: bool
|
||||
has_answer_box: bool = True
|
||||
|
||||
|
||||
class SumWithImageReferenceProblem(BaseModel):
|
||||
question: str
|
||||
instructions: str = "Escoge la imagen en la próxima página."
|
||||
first_group: AddendGroup
|
||||
second_group: AddendGroup
|
||||
common_object: str = Field(min_length=1)
|
||||
total: PositiveInt
|
||||
options: list[ImageOption]
|
||||
|
||||
|
||||
class SumWithImageReferenceRequest(BaseModel):
|
||||
first_quantity: PositiveInt
|
||||
second_quantity: PositiveInt
|
||||
first_description: str = Field(min_length=1)
|
||||
second_description: str = Field(min_length=1)
|
||||
common_object: str = Field(min_length=1)
|
||||
first_picture: PictureAsset
|
||||
second_picture: PictureAsset
|
||||
option_count: PositiveInt = 3
|
||||
min_option_quantity: PositiveInt = 1
|
||||
max_option_quantity: PositiveInt = 20
|
||||
seed: int | None = None
|
||||
@@ -0,0 +1,36 @@
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, Field, PositiveInt
|
||||
|
||||
|
||||
class PictureAsset(BaseModel):
|
||||
id: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
image_path: str = Field(min_length=1)
|
||||
|
||||
|
||||
class ItemGroup(BaseModel):
|
||||
side: Literal["left", "right"]
|
||||
picture: PictureAsset
|
||||
quantity: PositiveInt
|
||||
|
||||
|
||||
class MoreItemsComparison(BaseModel):
|
||||
position: PositiveInt
|
||||
left_group: ItemGroup
|
||||
right_group: ItemGroup
|
||||
answer_side: Literal["left", "right"]
|
||||
has_answer_box: bool = True
|
||||
|
||||
|
||||
class WhereAreMoreItemsProblem(BaseModel):
|
||||
instructions: str = "Marca dónde hay más."
|
||||
comparisons: list[MoreItemsComparison]
|
||||
|
||||
|
||||
class WhereAreMoreItemsRequest(BaseModel):
|
||||
available_pictures: list[PictureAsset] = Field(min_length=1)
|
||||
comparison_count: PositiveInt = 3
|
||||
min_quantity: PositiveInt = 1
|
||||
max_quantity: PositiveInt = 10
|
||||
seed: int | None = None
|
||||
Reference in New Issue
Block a user