Inspiration
What it does
How I built it
Challenges I ran into
Accomplishments that I'm proud of
What I learned
What's next for Study Mind Ai
StudyMind AI: Bridging the Gap Between AI Tutoring and Real-World Accountability Inspiration The inspiration for StudyMind AI came from observing a fundamental flaw in modern education: the gap between access to information and actual learning. Students have access to thousands of PDFs, textbooks, and videos, yet they still struggle. Why? Because learning is an active process, and reading a PDF is passive.
I was also deeply fascinated by the Ebbinghaus Forgetting Curve, which illustrates how memory retention declines over time if there is no attempt to retain it. The formula for memory retention is generally expressed as:
R(t)=e − S t
Where R is memory retention, t is time, and S is the relative strength of memory.
I realized that to combat this exponential decay, students need two things:
Interactive Guidance: Someone to explain complex concepts step-by-step, right when they are reading them. Real Stakes: A reason to study today, rather than procrastinating until tomorrow. This led to the core thesis of StudyMind AI: Combine a ChatGPT-like AI tutor with the real-world accountability of monetary penalties and competitive leaderboards.
How I Built It StudyMind AI is an Android-native application built entirely with Kotlin and Jetpack Compose. I designed the UI to strictly follow Material Design 3 (MD3) Expressive guidelines, utilizing vibrant color tokens (deep purples, expressive limes, and corals), large rounded shapes, and a floating "Liquid Glass" navigation bar.
The architecture follows a strict MVVM (Model-View-ViewModel) pattern.
The AI Engine: The core of the app is a real-time chat interface. Instead of waiting for the backend LLM to generate an entire response, I implemented a WebSocket connection using OkHttp. This allows the backend to push word-by-word chunks to the app.
To mathematically model the user's "Honor Score" and ensure fairness in competitions, I designed a composite metric that weighs consistency heavily against penalties:
H=∑ i=1 N (w c ⋅c i +w t ⋅t i )−λ∑ j=1 M p j
Where:
H = Total Honor Score c i
= Consistency points for day i
- t i
= Task completion points for day i
- p j
= Penalty paid for missed task j
- w c ,w t ,λ = Tuning weights for the algorithm Key Features Implemented:
PDF Insight Agent: Users upload PDFs via Android's Storage Access Framework. The app reads the file, sends it to the backend, and the AI generates topics without locking the user into a linear path. Adaptive Practice: The AI dynamically generates multiple-choice questions based on the user's chosen difficulty. Penalty System: A scheduling system where missed tasks result in actual monetary deductions, tracked via a PostgreSQL database. Challenges I Faced Building a real-time, heavily interactive UI in Compose presented several significant technical hurdles.
- The UI Freeze: State vs. SharedFlow Initially, I used a standard mutableStateOf for the streaming chat text. When the WebSocket received data, I appended it like this: streamingMessage.value += chunk.
Because LLMs generate tokens rapidly, this triggered hundreds of Compose recompositions per second. The Main Thread froze, and the app threw silent NullPointerExceptions.
The Solution: I replaced the State with a Kotlin Channel paired with a SharedFlow. The WebSocket now sends chunks into a Channel on a background Dispatchers.Default thread. The SharedFlow conflates the data, meaning if the UI is busy drawing, it drops intermediate text frames and only renders the latest string. This completely eliminated the UI lag, creating a perfectly smooth, ChatGPT-like typing effect.
- Android's File Security Sandbox When implementing the PDF upload, I encountered a persistent NullPointerException inside openInputStream. In HTML, is easy; in Android, you receive a temporary content:// URI. If the activity changes or the app loses focus, the URI permission expires.
The Solution: I switched from GetContent() to ActivityResultContracts.OpenDocument(). I explicitly called takePersistableUriPermission() to force Android to grant my app long-term read access. To prevent crashing the UI thread with heavy I/O, I used withContext(Dispatchers.IO) to copy the URI stream into a local java.io.File in the app's cacheDir before sending it to the backend via Retrofit as a MultipartBody.Part.
- Aligning Asynchronous Agent Histories The app features "Insight Icons" (Tips, Tricks, Questions). The backend streams these alongside the main text. When loading a previous session, I struggled to attach these agent responses to the correct AI message, as their timestamps didn't perfectly align, and chatMessageId was often null.
The Solution: I implemented a robust date-parsing fallback using SimpleDateFormat. If the chatMessageId was missing, I converted the createdAt strings of both messages and agents into Date objects. I then used a lastOrNull comparison to find the AI message that occurred immediately before the agent response was generated, ensuring perfect historical alignment.
What I Learned This project was a masterclass in both advanced Android development and behavioral economics in software design.
Reactive Programming: I learned the hard way that Compose is incredibly sensitive to rapid state mutations. Understanding when to use StateFlow for UI state versus SharedFlow for high-frequency event streams was a breakthrough. Android Privacy Mechanics: I gained a deep appreciation for how strictly Android sandboxes file access. Designing robust I/O operations that respect temporary URI permissions while keeping the Main thread unblocked was highly educational. Gamification Design: I learned that to truly modify user behavior, rewards aren't enough—there must be real, quantifiable stakes. Designing the penalty pool system taught me how to balance risk and reward to keep users engaged without making the app feel overly punitive.
Built With
- android
- chromadb
- fastapi
- fireworks
- langchain
- langgraph
- postgresql
Log in or sign up for Devpost to join the conversation.