Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import random
|
| 4 |
+
import google.generativeai as genai
|
| 5 |
+
from typing import List, Dict, Any
|
| 6 |
+
|
| 7 |
+
# Configure Gemini API
|
| 8 |
+
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
|
| 9 |
+
|
| 10 |
+
# IB Math topics list
|
| 11 |
+
IB_TOPICS = [
|
| 12 |
+
"SL 1.1 - Operations with numbers in the form a Γ 10k where 1 < a < 10 and k is an integer.",
|
| 13 |
+
"SL 1.2 - Arithmetic sequences and series. Use of the formulae for the nth term and the sum of the first n terms of the sequence. Use of sigma notation for sums of arithmetic sequences. Applications. Analysis, interpretation and prediction where a model is not perfectly arithmetic in real life.",
|
| 14 |
+
"SL 1.3 - Geometric sequences and series. Use of the formulae for the n th term and the sum of the first n terms of the sequence. Use of sigma notation for the sums of geometric sequences. Applications.",
|
| 15 |
+
"SL 1.4 - Financial applications of geometric sequences and series: compound interest, annual depreciation.",
|
| 16 |
+
"SL 1.5 - Laws of exponents with integer exponents. Introduction to logarithms with base 10 and e. Numerical evaluation of logarithms using technology.",
|
| 17 |
+
"SL 1.6 - Simple deductive proof, numerical and algebraic; how to lay out a left-hand side to right-hand side (LHS to RHS) proof. The symbols and notation for equality and identity.",
|
| 18 |
+
"SL 1.7 - Laws of exponents with rational exponents. Laws of logarithms. logaxy = logax + logay, loga(x/y) = logax-logay, logaxm = mlogax for a, x, y > 0. Change of base of a logarithm. Solving exponential equations, including using logarithms.",
|
| 19 |
+
"SL 1.8 - Sum of infinite convergent geometric sequences.",
|
| 20 |
+
"SL 1.9 - The binomial theorem: expansion of (a + b)n, n β N. Use of Pascal's triangle and nCr.",
|
| 21 |
+
"AHL 1.10 - Counting principles, including permutations and combinations. Extension of the binomial theorem to fractional and negative indices, ie (a + b)n, nβQ.",
|
| 22 |
+
"AHL 1.11 - Partial fractions.",
|
| 23 |
+
"AHL 1.12 - Complex numbers: the number i, where iΒ² = β 1. Cartesian form z = a + bi; the terms real part, imaginary part, conjugate, modulus and argument. The complex plane.",
|
| 24 |
+
"AHL 1.13 - Modulus-argument (polar) form: z = r(cosΞΈ + isinΞΈ) = rcisΞΈ. Euler form: z = reiΞΈ. Sums, products and quotients in Cartesian, polar or Euler forms and their geometric interpretation.",
|
| 25 |
+
"AHL 1.14 - Complex conjugate roots of quadratic and polynomial equations with real coefficients. De Moivre's theorem and its extension to rational exponents. Powers and roots of complex numbers.",
|
| 26 |
+
"AHL 1.15 - Proof by mathematical induction. Proof by contradiction. Use of a counterexample to show that a statement is not always true.",
|
| 27 |
+
"AHL 1.16 - Solutions of systems of linear equations (a maximum of three equations in three unknowns), including cases where there is a unique solution, an infinite number of solutions or no solution.",
|
| 28 |
+
"SL 2.1 - Different forms of the equation of a straight line. Gradient; intercepts. Lines with gradients mβ and mβ. Parallel lines mβ = mβ. Perpendicular lines mβ Γ mβ = β 1.",
|
| 29 |
+
"SL 2.2 - Concept of a function, domain, range and graph. Function notation, for example f(x), v(t), C(n). The concept of a function as a mathematical model. Informal concept that an inverse function reverses or undoes the effect of a function. Inverse function as a reflection in the line y = x, and the notation fβ»ΒΉ(x).",
|
| 30 |
+
"SL 2.3 - The graph of a function; its equation y = f(x). Creating a sketch from information given or a context, including transferring a graph from screen to paper. Using technology to graph functions including their sums and differences.",
|
| 31 |
+
"SL 2.4 - Determine key features of graphs. Finding the point of intersection of two curves or lines using technology.",
|
| 32 |
+
"SL 2.5 - Composite functions. Identity function. Finding the inverse function fβ»ΒΉ(x).",
|
| 33 |
+
"SL 2.6 - The quadratic function f(x) = axΒ² + bx + c: its graph, y -intercept (0, c). Axis of symmetry. The form f(x) = a(x β p)(x β q), x-intercepts (p, 0) and (q, 0). The form f(x) = a (x β h)Β² + k, vertex (h, k).",
|
| 34 |
+
"SL 2.7 - Solution of quadratic equations and inequalities. The quadratic formula. The discriminant Ξ = bΒ² - 4ac and the nature of the roots, that is, two distinct real roots, two equal real roots, no real roots.",
|
| 35 |
+
"SL 2.8 - The reciprocal function f(x) = 1/x, xβ 0: its graph and self-inverse nature. Rational functions of the form f(x) = (ax + b)/(cx + d) and their graphs. Equations of vertical and horizontal asymptotes.",
|
| 36 |
+
"SL 2.9 - Exponential functions and their graphs: f(x) = aΛ£, a > 0, f(x) = eΛ£. Logarithmic functions and their graphs: f(x) = logβx, x > 0, f(x) = lnx, x > 0.",
|
| 37 |
+
"SL 2.10 - Solving equations, both graphically and analytically. Use of technology to solve a variety of equations, including those where there is no appropriate analytic approach. Applications of graphing skills and solving equations that relate to real-life situations.",
|
| 38 |
+
"SL 2.11 - Transformations of graphs. Translations: y = f(x) + b; y = f(x β a). Reflections (in both axes): y = β f(x); y = f(-x). Vertical stretch with scale factor p: y = pf(x). Horizontal stretch with scale factor 1/q: y = f(qx). Composite transformations.",
|
| 39 |
+
"AHL 2.12 - Polynomial functions, their graphs and equations; zeros, roots and factors. The factor and remainder theorems. Sum and product of the roots of polynomial equations.",
|
| 40 |
+
"AHL 2.13 - Rational functions of the form f(x) = (ax + b)/(cxΒ² + dx + e), and f(x) = (axΒ² + bx + c)/(dx + e).",
|
| 41 |
+
"AHL 2.14 - Odd and even functions. Finding the inverse function, fβ»ΒΉ(x), including domain restriction. Self-inverse functions.",
|
| 42 |
+
"AHL 2.15 - Solutions of g(x) β₯ f(x), both graphically and analytically.",
|
| 43 |
+
"AHL 2.16 - The graphs of the functions, y = |f(x)| and y = f(|x)|, y = 1/f(x), y = f(ax + b), y = [f(x)]Β². Solution of modulus equations and inequalities.",
|
| 44 |
+
"SL 3.1 - The distance between two points in three-dimensional space, and their midpoint. Volume and surface area of three-dimensional solids including right-pyramid, right cone, sphere, hemisphere and combinations of these solids. The size of an angle between two intersecting lines or between a line and a plane.",
|
| 45 |
+
"SL 3.2 - Use of sine, cosine and tangent ratios to find the sides and angles of right-angled triangles. The sine rule. The cosine rule. Area of a triangle.",
|
| 46 |
+
"SL 3.3 - Applications of right and non-right angled trigonometry, including Pythagoras's theorem. Angles of elevation and depression. Construction of labelled diagrams from written statements.",
|
| 47 |
+
"SL 3.4 - The circle: radian measure of angles; length of an arc; area of a sector.",
|
| 48 |
+
"SL 3.5 - Definition of cosΞΈ, sinΞΈ in terms of the unit circle. Definition of tanΞΈ as sinΞΈ/cosΞΈ. Exact values of trigonometric ratios of 0, Ο/6, Ο/4, Ο/3, Ο/2 and their multiples. Extension of the sine rule to the ambiguous case.",
|
| 49 |
+
"SL 3.6 - The Pythagorean identity cosΒ²ΞΈ + sinΒ²ΞΈ = 1. Double angle identities for sine and cosine. The relationship between trigonometric ratios.",
|
| 50 |
+
"SL 3.7 - The circular functions sinx, cosx, and tanx; amplitude, their periodic nature, and their graphs. Composite functions of the form f(x) = asin(b(x + c)) + d. Transformations. Real-life contexts.",
|
| 51 |
+
"SL 3.8 - Solving trigonometric equations in a finite interval, both graphically and analytically. Equations leading to quadratic equations in sinx, cosx or tanx.",
|
| 52 |
+
"AHL 3.9 - Definition of the reciprocal trigonometric ratios secΞΈ, cosecΞΈ and cotΞΈ. Pythagorean identities: 1 + tanΒ²ΞΈ = secΒ²ΞΈ, 1 + cotΒ²ΞΈ = cosecΒ²ΞΈ. The inverse functions f(x) = arcsinx, f(x) = arccosx, f(x) = arctanx; their domains and ranges; their graphs.",
|
| 53 |
+
"AHL 3.10 - Compound angle identities. Double angle identity for tan.",
|
| 54 |
+
"AHL 3.11 - Relationships between trigonometric functions and the symmetry properties of their graphs.",
|
| 55 |
+
"AHL 3.12 - Concept of a vector; position vectors; displacement vectors. Representation of vectors using directed line segments. Base vectors i, j, k. Components of a vector. Algebraic and geometric approaches to: the sum and difference of two vectors, the zero vector, the vector -v, multiplication by a scalar, parallel vectors, magnitude of a vector, unit vectors, position vectors, displacement vector. Proofs of geometrical properties using vectors.",
|
| 56 |
+
"AHL 3.13 - The definition of the scalar product of two vectors. The angle between two vectors. Perpendicular vectors; parallel vectors.",
|
| 57 |
+
"AHL 3.14 - Vector equation of a line in two and three dimensions: r = a + Ξ»b. The angle between two lines. Simple applications to kinematics.",
|
| 58 |
+
"AHL 3.15 - Coincident, parallel, intersecting and skew lines, distinguishing between these cases. Points of intersection.",
|
| 59 |
+
"AHL 3.16 - The definition of the vector product of two vectors. Properties of the vector product. Geometric interpretation of | v x w |.",
|
| 60 |
+
"AHL 3.17 - Vector equations of a plane. Cartesian equation of a plane.",
|
| 61 |
+
"AHL 3.18 - Intersections of: a line with a plane; two planes; three planes. Angle between: a line and a plane; two planes.",
|
| 62 |
+
"SL 4.1 - Concepts of population, sample, random sample, discrete and continuous data. Reliability of data sources and bias in sampling. Interpretation of outliers. Sampling techniques and their effectiveness.",
|
| 63 |
+
"SL 4.2 - Presentation of data (discrete and continuous): frequency distributions (tables). Histograms. Cumulative frequency; cumulative frequency graphs; use to find median, quartiles, percentiles, range and interquartile range (IQR). Production and understanding of box and whisker diagrams.",
|
| 64 |
+
"SL 4.3 - Measures of central tendency (mean, median and mode). Estimation of mean from grouped data. Modal class. Measures of dispersion (interquartile range, standard deviation and variance). Effect of constant changes on the original data. Quartiles of discrete data.",
|
| 65 |
+
"SL 4.4 - Linear correlation of bivariate data. Pearson's product-moment correlation coefficient, r. Scatter diagrams; lines of best fit, by eye, passing through the mean point. Equation of the regression line of y on x. Use of the equation of the regression line for prediction purposes. Interpret the meaning of the parameters, a and b, in a linear regression y = ax + b.",
|
| 66 |
+
"SL 4.5 - Concepts of trial, outcome, equally likely outcomes, relative frequency, sample space (U) and event. The probability of an event A. The complementary events A and A'. Expected number of occurrences.",
|
| 67 |
+
"SL 4.6 - Use of Venn diagrams, tree diagrams, sample space diagrams and tables of outcomes to calculate probabilities. Combined events. Mutually exclusive events. Conditional probability. Independent events.",
|
| 68 |
+
"SL 4.7 - Concept of discrete random variables and their probability distributions. Expected value (mean), for discrete data. Applications.",
|
| 69 |
+
"SL 4.8 - Binomial distribution. Mean and variance of the binomial distribution.",
|
| 70 |
+
"SL 4.9 - The normal distribution and curve. Properties of the normal distribution. Diagrammatic representation. Normal probability calculations. Inverse normal calculations.",
|
| 71 |
+
"SL 4.10 - Equation of the regression line of x on y. Use of the equation for prediction purposes.",
|
| 72 |
+
"SL 4.11 - Formal definition and use of the formulae for conditional probabilities, and for independent events.",
|
| 73 |
+
"SL 4.12 - Standardization of normal variables (z- values). Inverse normal calculations where mean and standard deviation are unknown.",
|
| 74 |
+
"AHL 4.13 - Use of Bayes' theorem for a maximum of three events.",
|
| 75 |
+
"AHL 4.14 - Variance of a discrete random variable. Continuous random variables and their probability density functions. Mode and median of continuous random variables. Mean, variance and standard deviation of both discrete and continuous random variables. The effect of linear transformations of X.",
|
| 76 |
+
"SL 5.1 - Introduction to the concept of a limit. Derivative interpreted as gradient function and as rate of change.",
|
| 77 |
+
"SL 5.2 - Increasing and decreasing functions. Graphical interpretation of f'(x) > 0, f'(x) = 0, f'(x) < 0.",
|
| 78 |
+
"SL 5.3 - Derivative of f(x) = axβΏ is f'(x) = anxβΏβ»ΒΉ, n β Z. The derivative of functions of the form f(x) = axβΏ + bxβΏβ»ΒΉ ... where all exponents are integers.",
|
| 79 |
+
"SL 5.4 - Tangents and normals at a given point, and their equations.",
|
| 80 |
+
"SL 5.5 - Introduction to integration as anti-differentiation of functions of the form f(x) = axβΏ + bxβΏβ»ΒΉ + ...., where n β Z, nβ -1. Anti-differentiation with a boundary condition to determine the constant term. Definite integrals using technology. Area of a region enclosed by a curve y = f(x) and the x -axis, where f(x) > 0.",
|
| 81 |
+
"SL 5.6 - Derivative of xβΏ (n β Q), sinx, cosx, eΛ£ and lnx. Differentiation of a sum and a multiple of these functions. The chain rule for composite functions. The product and quotient rules.",
|
| 82 |
+
"SL 5.7 - The second derivative. Graphical behaviour of functions, including the relationship between the graphs of f, f' and f''.",
|
| 83 |
+
"SL 5.8 - Local maximum and minimum points. Testing for maximum and minimum. Optimization. Points of inflexion with zero and non-zero gradients.",
|
| 84 |
+
"SL 5.9 - Kinematic problems involving displacement s, velocity v, acceleration a and total distance travelled.",
|
| 85 |
+
"SL 5.10 - Indefinite integral of xβΏ (n β Q), sinx, cosx, 1/x and eΛ£. The composites of any of these with the linear function ax + b. Integration by inspection (reverse chain rule) or by substitution for expressions of the form: β«kg'(x)f(g(x))dx.",
|
| 86 |
+
"SL 5.11 - Definite integrals, including analytical approach. Areas of a region enclosed by a curve y = f(x) and the x-axis, where f(x) can be positive or negative, without the use of technology. Areas between curves.",
|
| 87 |
+
"AHL 5.12 - Informal understanding of continuity and differentiability of a function at a point. Understanding of limits (convergence and divergence). Definition of derivative from first principles. Higher derivatives.",
|
| 88 |
+
"AHL 5.13 - The evaluation of limits of the form lim f(x)/g(x) using l'HΓ΄pital's rule or the Maclaurin series. Repeated use of l'HΓ΄pital's rule.",
|
| 89 |
+
"AHL 5.14 - Implicit differentiation. Related rates of change. Optimisation problems.",
|
| 90 |
+
"AHL 5.15 - Derivatives of tanx, secx, cosecx, cotx, aΛ£, logβx, arcsinx, arccosx, arctanx. Indefinite integrals of the derivatives of any of the above functions. The composites of any of these with a linear function. Use of partial fractions to rearrange the integrand.",
|
| 91 |
+
"AHL 5.16 - Integration by substitution. Integration by parts. Repeated integration by parts.",
|
| 92 |
+
"AHL 5.17 - Area of the region enclosed by a curve and the y-axis in a given interval. Volumes of revolution about the x-axis or y-axis.",
|
| 93 |
+
"AHL 5.18 - First order differential equations. Numerical solution of dy/dx = f(x, y) using Euler's method. Variables separable. Homogeneous differential equation. Solution of y' + P(x)y = Q(x), using the integrating factor.",
|
| 94 |
+
"AHL 5.19 - Maclaurin series to obtain expansions for eΛ£, sinx, cosx, ln(1+x), (1+x)α΅, pβQ. Use of simple substitution, products, integration and differentiation to obtain other series. Maclaurin series developed from differential equations"
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
def create_model():
|
| 98 |
+
"""Create Gemini model with error handling."""
|
| 99 |
+
try:
|
| 100 |
+
model = genai.GenerativeModel("gemini-2.0-flash-exp", generation_config={"temperature": 0})
|
| 101 |
+
return model
|
| 102 |
+
except Exception as e:
|
| 103 |
+
try:
|
| 104 |
+
model = genai.GenerativeModel("gemini-1.5-flash", generation_config={"temperature": 0})
|
| 105 |
+
return model
|
| 106 |
+
except Exception as e2:
|
| 107 |
+
raise Exception(f"Failed to create Gemini model: {e2}")
|
| 108 |
+
|
| 109 |
+
def identify_topics_with_gemini(qp_content: str, graded_as: str) -> Dict[str, Any]:
|
| 110 |
+
"""
|
| 111 |
+
Send QP content and grading results to Gemini to identify topics for each question.
|
| 112 |
+
"""
|
| 113 |
+
model = create_model()
|
| 114 |
+
|
| 115 |
+
topics_list = "\n".join([f"- {topic}" for topic in IB_TOPICS])
|
| 116 |
+
|
| 117 |
+
prompt = f"""You are an IB Mathematics expert. Analyze the following question paper content and grading results to identify the specific IB Math topic for each question.
|
| 118 |
+
|
| 119 |
+
QUESTION PAPER CONTENT:
|
| 120 |
+
{qp_content}
|
| 121 |
+
|
| 122 |
+
GRADING RESULTS:
|
| 123 |
+
{graded_as}
|
| 124 |
+
|
| 125 |
+
IB MATH TOPICS LIST:
|
| 126 |
+
{topics_list}
|
| 127 |
+
|
| 128 |
+
For each question in the question paper, identify which specific topic from the list above it belongs to. Return your analysis in JSON format:
|
| 129 |
+
|
| 130 |
+
{{
|
| 131 |
+
"topic_analysis": [
|
| 132 |
+
{{
|
| 133 |
+
"question_id": "1",
|
| 134 |
+
"topic": "SL 2.6",
|
| 135 |
+
"confidence": "high",
|
| 136 |
+
"reasoning": "Question involves quadratic functions and finding vertex form"
|
| 137 |
+
}},
|
| 138 |
+
{{
|
| 139 |
+
"question_id": "2",
|
| 140 |
+
"topic": "SL 4.7",
|
| 141 |
+
"confidence": "medium",
|
| 142 |
+
"reasoning": "Question deals with discrete probability distributions"
|
| 143 |
+
}}
|
| 144 |
+
],
|
| 145 |
+
"incorrect_topics": ["SL 2.6", "SL 4.7"],
|
| 146 |
+
"correct_topics": ["SL 1.2", "SL 3.4"]
|
| 147 |
+
}}
|
| 148 |
+
|
| 149 |
+
Focus on:
|
| 150 |
+
1. Identifying the exact topic code from the provided list
|
| 151 |
+
2. Determining which questions were answered incorrectly vs correctly based on the grading
|
| 152 |
+
3. Providing clear reasoning for topic identification
|
| 153 |
+
"""
|
| 154 |
+
|
| 155 |
+
try:
|
| 156 |
+
response = model.generate_content(prompt)
|
| 157 |
+
response_text = response.text
|
| 158 |
+
|
| 159 |
+
# Extract JSON from response
|
| 160 |
+
import re
|
| 161 |
+
json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
|
| 162 |
+
if json_match:
|
| 163 |
+
return json.loads(json_match.group())
|
| 164 |
+
else:
|
| 165 |
+
raise ValueError("No JSON found in response")
|
| 166 |
+
|
| 167 |
+
except Exception as e:
|
| 168 |
+
print(f"Error in topic identification: {e}")
|
| 169 |
+
return {"topic_analysis": [], "incorrect_topics": [], "correct_topics": []}
|
| 170 |
+
|
| 171 |
+
def load_questions_database(file_path: str = "merged_gemini_output.txt") -> List[Dict]:
|
| 172 |
+
"""
|
| 173 |
+
Load questions from the database file.
|
| 174 |
+
Expected format: JSON objects with year, month, question_number, topic, content fields.
|
| 175 |
+
"""
|
| 176 |
+
questions = []
|
| 177 |
+
|
| 178 |
+
if not os.path.exists(file_path):
|
| 179 |
+
print(f"Warning: Questions database file '{file_path}' not found.")
|
| 180 |
+
return questions
|
| 181 |
+
|
| 182 |
+
try:
|
| 183 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 184 |
+
content = f.read()
|
| 185 |
+
|
| 186 |
+
# Parse the content - assuming it contains JSON objects
|
| 187 |
+
# Handle the format described in the prompt
|
| 188 |
+
import re
|
| 189 |
+
json_objects = re.findall(r'\{[^}]+\}', content)
|
| 190 |
+
|
| 191 |
+
for json_str in json_objects:
|
| 192 |
+
try:
|
| 193 |
+
question = json.loads(json_str)
|
| 194 |
+
questions.append(question)
|
| 195 |
+
except json.JSONDecodeError:
|
| 196 |
+
continue
|
| 197 |
+
|
| 198 |
+
except Exception as e:
|
| 199 |
+
print(f"Error loading questions database: {e}")
|
| 200 |
+
|
| 201 |
+
return questions
|
| 202 |
+
|
| 203 |
+
def generate_smart_test(topic_analysis: Dict[str, Any], questions_db: List[Dict]) -> Dict[str, Any]:
|
| 204 |
+
"""
|
| 205 |
+
Generate a smart test based on the topic analysis and available questions.
|
| 206 |
+
|
| 207 |
+
Recommended composition (8-question example):
|
| 208 |
+
1. 4 remediation items - each tied to specific concepts the student got wrong
|
| 209 |
+
- 2 items that are near-transfer (very similar to original wrong items, scaffolded)
|
| 210 |
+
- 2 items that are far-transfer/applied (same concept but in new context)
|
| 211 |
+
2. 2 retention items - on topics the student got right (check for forgetting)
|
| 212 |
+
3. 1 synthesis/higher-order item - combine multiple concepts
|
| 213 |
+
4. 1 quick confidence/metacognition item
|
| 214 |
+
"""
|
| 215 |
+
|
| 216 |
+
incorrect_topics = topic_analysis.get("incorrect_topics", [])
|
| 217 |
+
correct_topics = topic_analysis.get("correct_topics", [])
|
| 218 |
+
|
| 219 |
+
# Group questions by topic
|
| 220 |
+
questions_by_topic = {}
|
| 221 |
+
for question in questions_db:
|
| 222 |
+
topic = question.get("topic", "")
|
| 223 |
+
if topic not in questions_by_topic:
|
| 224 |
+
questions_by_topic[topic] = []
|
| 225 |
+
questions_by_topic[topic].append(question)
|
| 226 |
+
|
| 227 |
+
test_questions = []
|
| 228 |
+
|
| 229 |
+
# 1. Remediation items (4 questions from incorrect topics)
|
| 230 |
+
remediation_questions = []
|
| 231 |
+
for topic in incorrect_topics[:2]: # Focus on first 2 incorrect topics
|
| 232 |
+
if topic in questions_by_topic:
|
| 233 |
+
available = questions_by_topic[topic]
|
| 234 |
+
if len(available) >= 2:
|
| 235 |
+
# 1 near-transfer, 1 far-transfer per topic
|
| 236 |
+
selected = random.sample(available, min(2, len(available)))
|
| 237 |
+
remediation_questions.extend(selected)
|
| 238 |
+
|
| 239 |
+
# Ensure we have 4 remediation questions
|
| 240 |
+
while len(remediation_questions) < 4 and incorrect_topics:
|
| 241 |
+
for topic in incorrect_topics:
|
| 242 |
+
if topic in questions_by_topic and len(remediation_questions) < 4:
|
| 243 |
+
available = [q for q in questions_by_topic[topic] if q not in remediation_questions]
|
| 244 |
+
if available:
|
| 245 |
+
remediation_questions.append(random.choice(available))
|
| 246 |
+
|
| 247 |
+
test_questions.extend(remediation_questions[:4])
|
| 248 |
+
|
| 249 |
+
# 2. Retention items (2 questions from correct topics)
|
| 250 |
+
retention_questions = []
|
| 251 |
+
for topic in correct_topics[:2]:
|
| 252 |
+
if topic in questions_by_topic:
|
| 253 |
+
available = [q for q in questions_by_topic[topic] if q not in test_questions]
|
| 254 |
+
if available:
|
| 255 |
+
retention_questions.append(random.choice(available))
|
| 256 |
+
|
| 257 |
+
test_questions.extend(retention_questions[:2])
|
| 258 |
+
|
| 259 |
+
# 3. Synthesis question (1 question combining concepts)
|
| 260 |
+
# For now, pick a complex question from available topics
|
| 261 |
+
synthesis_candidates = []
|
| 262 |
+
all_topics = list(set(incorrect_topics + correct_topics))
|
| 263 |
+
for topic in all_topics:
|
| 264 |
+
if topic in questions_by_topic:
|
| 265 |
+
available = [q for q in questions_by_topic[topic] if q not in test_questions]
|
| 266 |
+
synthesis_candidates.extend(available)
|
| 267 |
+
|
| 268 |
+
if synthesis_candidates:
|
| 269 |
+
test_questions.append(random.choice(synthesis_candidates))
|
| 270 |
+
|
| 271 |
+
# 4. Metacognition item (create a simple confidence question)
|
| 272 |
+
metacognition_question = {
|
| 273 |
+
"question_number": "META",
|
| 274 |
+
"topic": "Metacognition",
|
| 275 |
+
"content": "Rate your confidence level (1-5) for each of the questions above and briefly explain your reasoning for one question where you felt least confident.",
|
| 276 |
+
"year": "N/A",
|
| 277 |
+
"month": "N/A"
|
| 278 |
+
}
|
| 279 |
+
test_questions.append(metacognition_question)
|
| 280 |
+
|
| 281 |
+
return {
|
| 282 |
+
"test_questions": test_questions,
|
| 283 |
+
"composition": {
|
| 284 |
+
"remediation_items": len(remediation_questions),
|
| 285 |
+
"retention_items": len(retention_questions),
|
| 286 |
+
"synthesis_items": 1,
|
| 287 |
+
"metacognition_items": 1,
|
| 288 |
+
"total_questions": len(test_questions)
|
| 289 |
+
},
|
| 290 |
+
"focus_topics": {
|
| 291 |
+
"incorrect_topics": incorrect_topics,
|
| 292 |
+
"correct_topics": correct_topics
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
def format_test_output(smart_test: Dict[str, Any]) -> str:
|
| 297 |
+
"""Format the generated test for display."""
|
| 298 |
+
output = []
|
| 299 |
+
output.append("# SMART ADAPTIVE TEST")
|
| 300 |
+
output.append("=" * 50)
|
| 301 |
+
output.append("")
|
| 302 |
+
|
| 303 |
+
# Test composition summary
|
| 304 |
+
comp = smart_test["composition"]
|
| 305 |
+
output.append("## Test Composition:")
|
| 306 |
+
output.append(f"- Remediation items: {comp['remediation_items']}")
|
| 307 |
+
output.append(f"- Retention items: {comp['retention_items']}")
|
| 308 |
+
output.append(f"- Synthesis items: {comp['synthesis_items']}")
|
| 309 |
+
output.append(f"- Metacognition items: {comp['metacognition_items']}")
|
| 310 |
+
output.append(f"- Total questions: {comp['total_questions']}")
|
| 311 |
+
output.append("")
|
| 312 |
+
|
| 313 |
+
# Focus topics
|
| 314 |
+
focus = smart_test["focus_topics"]
|
| 315 |
+
output.append("## Focus Areas:")
|
| 316 |
+
output.append("### Topics to remediate:")
|
| 317 |
+
for topic in focus["incorrect_topics"]:
|
| 318 |
+
output.append(f"- {topic}")
|
| 319 |
+
output.append("")
|
| 320 |
+
output.append("### Topics to retain:")
|
| 321 |
+
for topic in focus["correct_topics"]:
|
| 322 |
+
output.append(f"- {topic}")
|
| 323 |
+
output.append("")
|
| 324 |
+
|
| 325 |
+
# Questions
|
| 326 |
+
output.append("## Test Questions:")
|
| 327 |
+
output.append("")
|
| 328 |
+
|
| 329 |
+
for i, question in enumerate(smart_test["test_questions"], 1):
|
| 330 |
+
output.append(f"### Question {i}")
|
| 331 |
+
output.append(f"**Topic:** {question.get('topic', 'N/A')}")
|
| 332 |
+
if question.get('year') != 'N/A':
|
| 333 |
+
output.append(f"**Source:** {question.get('month', '')} {question.get('year', '')}")
|
| 334 |
+
output.append("")
|
| 335 |
+
output.append(question.get('content', ''))
|
| 336 |
+
output.append("")
|
| 337 |
+
output.append("-" * 30)
|
| 338 |
+
output.append("")
|
| 339 |
+
|
| 340 |
+
return "\n".join(output)
|
| 341 |
+
|
| 342 |
+
def smart_test_pipeline(qp_content: str, graded_as: str) -> str:
|
| 343 |
+
"""
|
| 344 |
+
Main pipeline function that takes QP content and grading results,
|
| 345 |
+
identifies topics, and generates a smart adaptive test.
|
| 346 |
+
"""
|
| 347 |
+
print("π Starting smart test generation...")
|
| 348 |
+
|
| 349 |
+
# Step 1: Identify topics using Gemini
|
| 350 |
+
print("π Analyzing topics with Gemini...")
|
| 351 |
+
topic_analysis = identify_topics_with_gemini(qp_content, graded_as)
|
| 352 |
+
|
| 353 |
+
if not topic_analysis.get("topic_analysis"):
|
| 354 |
+
return "β Error: Could not analyze topics from the provided content."
|
| 355 |
+
|
| 356 |
+
print(f"β
Identified {len(topic_analysis.get('incorrect_topics', []))} incorrect topics and {len(topic_analysis.get('correct_topics', []))} correct topics")
|
| 357 |
+
|
| 358 |
+
# Step 2: Load questions database
|
| 359 |
+
print("π Loading questions database...")
|
| 360 |
+
questions_db = load_questions_database()
|
| 361 |
+
|
| 362 |
+
if not questions_db:
|
| 363 |
+
return "β Error: No questions database found. Please ensure 'merged_gemini_output.txt' exists."
|
| 364 |
+
|
| 365 |
+
print(f"β
Loaded {len(questions_db)} questions from database")
|
| 366 |
+
|
| 367 |
+
# Step 3: Generate smart test
|
| 368 |
+
print("π― Generating adaptive test...")
|
| 369 |
+
smart_test = generate_smart_test(topic_analysis, questions_db)
|
| 370 |
+
|
| 371 |
+
# Step 4: Format output
|
| 372 |
+
formatted_test = format_test_output(smart_test)
|
| 373 |
+
|
| 374 |
+
print("β
Smart test generated successfully!")
|
| 375 |
+
return formatted_test
|
| 376 |
+
|
| 377 |
+
if __name__ == "__main__":
|
| 378 |
+
# Example usage
|
| 379 |
+
sample_qp = """
|
| 380 |
+
Question 1: Solve the quadratic equation xΒ² + 5x + 6 = 0
|
| 381 |
+
Question 2: A discrete random variable X has the probability distribution P(X = x) = cx(5-x) for x = 1,2,3,4. Find the value of c.
|
| 382 |
+
"""
|
| 383 |
+
|
| 384 |
+
sample_graded = """
|
| 385 |
+
Question 1: Incorrect - Student got x = -2, -4 instead of x = -2, -3
|
| 386 |
+
Question 2: Correct - Student correctly found c = 1/30
|
| 387 |
+
"""
|
| 388 |
+
|
| 389 |
+
result = smart_test_pipeline(sample_qp, sample_graded)
|
| 390 |
+
print(result)
|