A personal AI tutor for technical-interview prep. Pick a topic, work through its subtopics with a chatbot, upload academic papers for it to quiz you on, and generate entirely new topics.
Personal-use project. The Claude API is called directly from the browser (
dangerouslyAllowBrowser: true), which means the API key is visible to anyone with devtools access to this app. That's fine for local/private use but must move behind a backend proxy before any public deployment.
- Study topics — each topic has a syllabus of subtopics (key concepts + learning objectives). Chat with Claude one subtopic at a time; it tracks your progress (
not-started/in-progress/completed) automatically via tool calls. - Create a topic from a prompt — type a short instruction and Claude generates a full syllabus, which you preview and approve before it's saved.
- Readings — upload a PDF on a topic page; Claude extracts title/authors/year/summary, tags it to relevant subtopics, and flags anything that looks off-topic before saving. The tutor can pull up the actual PDF mid-conversation to discuss and quiz you on it.
- Cost tracking — every API call (tutoring turns, reading analysis, topic generation) logs its token usage and cost to a
/costspage, broken down by topic. - Google Sign-In — all data (progress, conversations, readings, topics, costs) is private per-user in Firestore/Storage.
- Vite + React 19 + React Router + Tailwind CSS
- Firebase: Auth (Google Sign-In), Firestore, Storage
- Anthropic Claude API (
@anthropic-ai/sdk) — tutoring chat, PDF metadata extraction, and syllabus generation each use their own model/prompt
src/lib/aiClient.jsis the only file that touches@anthropic-ai/sdk— swapping to a backend proxy later means changing this file only, not its call sites.src/lib/tools.jsholds every tool schema (progress updates, reading-metadata extraction, syllabus generation) used in forced tool-call requests.src/services/*.jsare the Firestore/Storage data-access layer (progressService,conversationService,readingsService,costService,topicsService) — one file per collection.src/context/TopicsContext.jsxandsrc/context/AuthContext.jsxprovide live app-wide state (topics, auth) viaonSnapshot/onAuthStateChanged.- Conversations are scoped per-subtopic (
conversations/{uid}/topics/{topicId}/subtopics/{subtopicId}) — each subtopic has one persistent conversation, navigated to directly.