Skip to content
Open
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,6 @@ dist
.pnp.*

.DS_Store
src/.DS_Store
src/.DS_Store

.env
482 changes: 201 additions & 281 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
"@babel/runtime": "^7.28.4",
"@radix-ui/react-slider": "^1.3.6",
"@tailwindcss/vite": "^4.1.10",
"cors": "^2.8.5",
"d3": "^7.9.0",
"dotenv": "^17.2.3",
"express": "^5.1.0",
"openai": "^6.9.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"svgo": "^4.0.0",
Expand Down
20 changes: 20 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import express from "express";
import "dotenv/config";
import gradeCompareRouter from "./routes/gradeCompare.js";
import cors from "cors";

const app = express();

app.use(cors());
app.use(express.json());
app.use("/api/grade-compare", gradeCompareRouter);

const PORT = process.env.PORT || 3001;

app.get("/api/health", (req, res) => {
res.json({ message: "hello world" });
});

app.listen(PORT, () => {
console.log(`Backend running on port ${PORT}`);
});
61 changes: 61 additions & 0 deletions server/routes/gradeCompare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { difference } from "d3";
import express from "express";
import OpenAI from "openai";

const router = express.Router();

const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});

router.post("/", async (req, res) => {
try {
const { countryA, countryB, studentAnswer } = req.body;
const prompt = `
Grade an AP World History compare-and-contrast response out of 5:
Country A: ${countryA}
Country B: ${countryB}
Student answer: ${studentAnswer}
Rubric:
- 1 valid similarity with evidence
- 1 valid difference with evidence
- Accuracy
- Historical Reasoning
- Clarity

Return ONLY valid JSON with this exact structure:
{
"score": number,
"similarity": string,
"difference": string,
"strengths": string,
"areasToImprove": string
}
`;

const result = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
});

let json;
try {
json = JSON.parse(result.choices[0].message.content);
} catch {
json = {
score: -1,
similarity: "",
difference: "",
strengths: "",
areasToImprove: result.choices[0].message.content
}
}

res.json(json);
} catch (err) {
console.error(err);
res.status(500).json({ error: "AI grading failed" });
}
});

export default router;
26 changes: 20 additions & 6 deletions src/components/TimeSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const TimeSliderContext = createContext<TimeSliderProps | undefined>(undefined);
export const useTimeSliderContext = () => {
const context = useContext(TimeSliderContext);
if (!context) {
throw new Error("useTimeSliderContext must be used within a TimeSliderProvider");
throw new Error(
"useTimeSliderContext must be used within a TimeSliderProvider"
);
}
return context;
};
Expand All @@ -22,7 +24,9 @@ interface TimeSliderProviderProps {
children: React.ReactNode;
}

export const TimeSliderProvider: React.FC<TimeSliderProviderProps> = ({ children }) => {
export const TimeSliderProvider: React.FC<TimeSliderProviderProps> = ({
children,
}) => {
const [selectedTime, setSelectedTime] = useState<number>(1200);

return (
Expand Down Expand Up @@ -52,12 +56,22 @@ export const TimeSlider = () => {

{/* Marks */}
{timePeriods.map((mark) => {
const left = ((mark - timePeriods[0]) /
(timePeriods[timePeriods.length - 1] - timePeriods[0])) * 100;
const left =
((mark - timePeriods[0]) /
(timePeriods[timePeriods.length - 1] - timePeriods[0])) *
100;
return (
<div key={mark} className="absolute -top-1" style={{ left: `${left}%` }} role="presentation">
<div
key={mark}
className="absolute -top-1"
style={{ left: `${left}%` }}
role="presentation"
>
<div className="w-[2px] h-4 bg-gray-600" aria-hidden="true"></div>
<div className="text-xs text-gray-200 text-center mt-1 -translate-x-1/2" aria-hidden="true">
<div
className="text-xs text-gray-200 text-center mt-1 -translate-x-1/2"
aria-hidden="true"
>
{mark}
</div>
</div>
Expand Down
80 changes: 80 additions & 0 deletions src/notes/quiz-notes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
export interface ValidComparison {
timePeriod: [number, number],
country1: string,
country2: string,
similarities?: string[],
differences?: string[]
}

export const comparisons : ValidComparison[] = [
{
timePeriod: [1450, 1750],
country1: "Ottoman Empire",
country2: "Mughal Empire",
similarities: [
"Gunpowder empires using firearms to expand and maintain control",
"Religious tolerance toward diverse subject populations",
"Strong centralized rule under powerful monarchs"
],
differences: [
"Ottomans were primarily Sunni Muslim rulers of a Mediterranean empire, while Mughals ruled a largely Hindu population in South Asia",
"The Ottomans developed a large naval presence, while the Mughals focused more on land-based control"
]
},
{
timePeriod: [1450, 1750],
country1: "Spain",
country2: "Portugal",
similarities: [
"Early leaders in maritime exploration",
"Established overseas colonial empires",
"Used colonies to extract wealth through mercantilist policies"
],
differences: [
"Spain focused on large territorial empires in the Americas, while Portugal emphasized trade posts in Africa and Asia",
"Spain relied heavily on silver mining, whereas Portugal focused more on spice and slave trades"
]
},
{
timePeriod: [1750, 1900],
country1: "Great Britain",
country2: "Japan",
similarities: [
"Underwent rapid industrialization",
"Expanded state power through modernization",
"Used new technologies to strengthen military capabilities"
],
differences: [
"Britain industrialized gradually through private enterprise, while Japan industrialized rapidly through state-led reforms",
"Britain already possessed a global empire, while Japan pursued imperial expansion later in the period"
]
},
{
timePeriod: [1750, 1900],
country1: "China (Qing Dynasty)",
country2: "Ottoman Empire",
similarities: [
"Faced internal rebellions and external pressure from European powers",
"Struggled to modernize traditional political and economic systems",
"Lost territorial and economic sovereignty during the 19th century"
],
differences: [
"China experienced significant population growth that strained resources, while the Ottoman Empire faced ethnic nationalism",
"Ottoman reforms were more centralized, whereas Qing reforms were uneven and resisted by elites"
]
},
{
timePeriod: [1900, 2000],
country1: "United States",
country2: "Soviet Union",
similarities: [
"Emergence as global superpowers after World War II",
"Engaged in ideological competition during the Cold War",
"Invested heavily in military and technological development"
],
differences: [
"The United States promoted capitalism and democratic governance, while the Soviet Union promoted communism and one-party rule",
"The U.S. economy was market-based, while the Soviet economy was centrally planned"
]
}
]
Loading