Shreya2005-2005's picture
fix: use clamp() in scoring formulas, remove score_range, use exclusive bounds
dd41132
|
Raw History Blame Contribute Delete
5.34 kB
---
title: Smart Study Session Optimizer
emoji: πŸ“š
colorFrom: blue
colorTo: green
sdk: docker
pinned: false
---
# Smart Study Session Optimizer
## Why I Built This
Okay so honestly this project started from a very relatable place β€” I used to study for 4-5 hours straight
during exam prep, and by the third hour I was basically just staring at my notes without retaining anything.
I knew I was supposed to take breaks but it felt like "wasting time". Turns out I was doing it completely wrong.
I came across some research on the Pomodoro Technique and ultradian rhythms, and I got curious: could you
actually *learn* the optimal study break pattern using reinforcement learning? The environment models a simplified
version of mental energy and focus, and lets an RL agent figure out when to grind and when to rest.
It's not a perfect simulation of human cognition (not even close), but it's a fun approximation and it
passed all the hackathon criteria, so I'm calling it a win.
---
## Project Structure
```
study-optimizer/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ models.py # Pydantic models (Observation, Action, StepResult)
β”‚ β”œβ”€β”€ environment.py # Core RL environment logic
β”‚ └── client.py # HTTP client for the environment API
β”œβ”€β”€ server/
β”‚ └── app.py # FastAPI server
β”œβ”€β”€ inference.py # Main script: LLM agent runs an episode
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ requirements.txt
└── openenv.yaml # OpenEnv spec compliance
```
---
## How It Works
The environment simulates a study session. At each step, the agent sees:
- **Energy** (0–100): how much mental stamina is left
- **Focus** (0–100): current concentration level
- **Time studied**: cumulative minutes of studying
- **Session elapsed**: total minutes including breaks
- **Consecutive study minutes**: streak without a break (focus drops fast here)
- **Break count**: how many breaks taken
- **Productive minutes**: minutes where focus was above 60
The agent picks one of 3 actions:
- `0` β†’ **Study** (5 min, drains energy & focus)
- `1` β†’ **Short break** (10 min, moderate recovery)
- `2` β†’ **Long break** (20 min, full recovery but costs time)
---
## The 3 Tasks
| Task ID | Goal | Score Formula |
|---------|------|---------------|
| `survive_8_hours` | Keep energy > 0 for 480 min | `clamp(energy_remaining / 100, 0.01, 0.99)` |
| `maximize_productivity` | Max productive minutes in 240 min | `clamp(productive_minutes / 240, 0.01, 0.99)` |
| `smart_break_taker` | Only break when energy < 40% | `clamp(good_breaks / total_breaks, 0.01, 0.99)` |
---
## Quick Start
### 1. Install dependencies
```bash
pip install -r requirements.txt
```
### 2. Run the server
```bash
uvicorn server.app:app --host 0.0.0.0 --port 7860 --reload
```
### 3. Run inference (LLM agent plays the game)
```bash
# Set env vars first
export API_BASE_URL="https://api.openai.com/v1"
export MODEL_NAME="gpt-4o-mini"
export HF_TOKEN="your_hf_token"
python inference.py --task maximize_productivity
```
### 4. Try it manually with curl
```bash
# Start an episode
curl -X POST http://localhost:7860/reset \
-H "Content-Type: application/json" \
-d '{"task_id": "maximize_productivity"}'
# Study for 5 minutes
curl -X POST http://localhost:7860/step \
-H "Content-Type: application/json" \
-d '{"action": 0}'
# Health check
curl http://localhost:7860/health
```
---
## Docker
```bash
# Build
docker build -t study-optimizer .
# Run
docker run -p 7860:7860 study-optimizer
# With env vars for inference
docker run -p 7860:7860 \
-e API_BASE_URL="https://api.openai.com/v1" \
-e MODEL_NAME="gpt-4o-mini" \
-e HF_TOKEN="your_token" \
study-optimizer
```
---
## Environment Variables
| Variable | Description | Required |
|----------|-------------|----------|
| `API_BASE_URL` | Base URL for OpenAI-compatible LLM API | Yes (for inference) |
| `MODEL_NAME` | Model identifier (e.g. `gpt-4o-mini`) | Yes (for inference) |
| `HF_TOKEN` | HuggingFace API token | Yes (for HF Spaces) |
| `PORT` | Server port (default: 7860) | No |
---
## OpenEnv Compliance
This environment follows the OpenEnv spec:
- `POST /reset` β†’ returns initial observation
- `POST /step` β†’ takes action, returns `{observation, reward, done, info}`
- `GET /health` β†’ returns `{"status": "ok"}`
- `GET /state` β†’ returns full env state
- `openenv.yaml` β†’ spec definition file
---
## Reward Design
Reward at each step:
- Studying with high energy + focus: **+1.0**
- Studying with just energy (focus low): **+0.3**
- Studying while exhausted: **-0.5**
- Smart break (energy < 40): **+0.5 to +1.0**
- Unnecessary break: **-0.3 to -0.6**
- Terminal reward at end varies by task
The reward shaping is intentionally conservative β€” it's meant to guide the agent
without being so prescriptive that it removes the need to learn anything interesting.
---
## Known Limitations / TODOs
- The energy drain model is simplified (doesn't account for circadian rhythms, caffeine, etc.)
- No persistence β€” session state resets on server restart
- Haven't tried training a proper PPO agent yet, only tested with LLM inference
- Should add a WebSocket endpoint for real-time streaming
---
*Built for the Meta PyTorch OpenEnv Hackathon by Scaler School of Technology*