Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Node / Wrangler
node_modules/
.wrangler/
dist/

# Python
__pycache__/
*.py[cod]
*.pyo
.venv/
venv/
env/
*.egg-info/
.pytest_cache/
htmlcov/
.coverage

# OS
.DS_Store
Thumbs.db
144 changes: 142 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,142 @@
# quantalab
Interactive virtual laboratory where students can explore physics, chemistry, and biology experiments in simulation. Guided by an AI mentor that explains concepts, answers questions, and suggests experiments. Designed to make scientific exploration accessible, safe, and engaging through hands-on digital experimentation.
# ⚗️ QuantaLab

**Interactive virtual laboratory** where students explore physics, chemistry, and biology experiments through simulation. Guided by an **AI mentor** (powered by Cloudflare Workers AI) that explains concepts, answers questions, and suggests experiments. Designed to make scientific exploration accessible, safe, and engaging through hands-on digital experimentation.

---

## ✨ Features

| Domain | Experiments |
|---|---|
| ⚛️ **Physics** | Simple Pendulum, Projectile Motion, Ohm's Law |
| 🧪 **Chemistry** | Acid–Base Reactions, Boyle's Law, Acid–Base Titration |
| 🧬 **Biology** | Mitosis, Natural Selection, Photosynthesis |

- **Real-time simulations** rendered on an HTML5 Canvas with live parameter controls
- **AI Mentor** chat powered by `@cf/meta/llama-3.1-8b-instruct` via Cloudflare Workers AI
- **Interactive controls** — sliders to adjust experiment parameters and instantly see results
- **Live measurements** panel with calculated metrics for each experiment
- Fully serverless — runs as a **Cloudflare Python Worker** with static assets

---

## 🏗 Project Structure

```
quantalab/
├── wrangler.toml # Cloudflare Workers configuration
├── src/
│ ├── index.py # Python Worker — HTTP router
│ ├── experiments.py # Experiment catalogue (data + helpers)
│ └── ai_mentor.py # Cloudflare AI integration
├── static/
│ ├── index.html # Single-page application shell
│ ├── style.css # Dark-theme responsive styles
│ └── app.js # Simulation engine + chat client
├── tests/
│ └── test_experiments.py # Pytest unit tests
└── requirements.txt # Local dev dependencies
```

---

## 🚀 Getting Started

### Prerequisites

- [Node.js](https://nodejs.org/) ≥ 18 (for Wrangler CLI)
- [Wrangler](https://developers.cloudflare.com/workers/wrangler/) ≥ 3.x
- A Cloudflare account with **Workers AI** enabled

```bash
npm install -g wrangler
```

### Local Development

```bash
# Clone the repo
git clone https://github.com/alphaonelabs/quantalab.git
cd quantalab

# Install local test dependencies
pip install -r requirements.txt

# Run tests
pytest tests/ -v

# Start the local dev server (Wrangler)
wrangler dev
```

Open `http://localhost:8787` in your browser.

> **Note:** The AI Mentor requires a Cloudflare Workers AI binding which is automatically available in both `wrangler dev` and production deployments.

### Deploy to Cloudflare Workers

```bash
wrangler deploy
```

Wrangler will output a `*.workers.dev` URL for your deployment.

---

## 🔌 API Reference

| Method | Path | Description |
|---|---|---|
| `GET` | `/` | Serve the SPA (index.html) |
| `GET` | `/api/health` | Health-check — returns `{"status":"ok"}` |
| `GET` | `/api/experiments` | List all experiments across all domains |
| `GET` | `/api/experiments/{domain}` | List experiments for a specific domain |
| `GET` | `/api/experiments/{domain}/{id}` | Get details for a single experiment |
| `POST` | `/api/mentor` | Ask the AI mentor a question |

### POST `/api/mentor`

**Request body:**
```json
{
"message": "Why does a longer pendulum have a longer period?",
"history": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}],
"domain": "physics",
"experiment": "pendulum"
}
```

**Response:**
```json
{
"response": "Great question! The period of a pendulum depends on..."
}
```

---

## 🧪 Running Tests

```bash
pip install -r requirements.txt
pytest tests/ -v
```

---

## 🛠 Technology Stack

| Layer | Technology |
|---|---|
| Runtime | Cloudflare Python Workers (Pyodide) |
| AI | Cloudflare Workers AI (`@cf/meta/llama-3.1-8b-instruct`) |
| Frontend | Vanilla HTML5/CSS3/JavaScript + Canvas API |
| Fonts | Inter + JetBrains Mono (Google Fonts) |
| Testing | pytest + pytest-asyncio |
| Deployment | Cloudflare Workers (via Wrangler) |

---

## 📄 License

[MIT](LICENSE)
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Runtime dependencies for Cloudflare Python Workers are provided by the platform.
# The packages below are used for local testing only.
pytest>=8.0.0
pytest-asyncio>=0.23.0
62 changes: 62 additions & 0 deletions src/ai_mentor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
AI Mentor module — wraps Cloudflare Workers AI to power QuantaLab's
in-lab science tutor.
"""

import json

# System prompt that shapes the AI mentor's persona and behaviour
_SYSTEM_PROMPT = """You are QuantaMentor, an enthusiastic and patient AI science tutor for QuantaLab,
an interactive virtual laboratory. Your role is to:

1. Explain scientific concepts clearly, adapting your language to the student's apparent level.
2. Guide students through experiments with hints, not direct answers.
3. Celebrate curiosity and correct misconceptions gently.
4. Suggest follow-up experiments when a student has mastered the current one.
5. Always relate abstract theory to real-world examples.

Keep answers concise (2–4 sentences unless a deeper explanation is clearly needed).
Use simple Markdown (bold, bullet lists) to structure longer answers.
Do NOT solve homework or give direct answers to exam questions — guide instead.
"""


async def ask_mentor(env, user_message: str, history: list[dict], domain: str = "", experiment: str = "") -> str:
"""
Send a message to the AI mentor and return the response text.

Args:
env: Cloudflare Worker environment (provides env.AI binding).
user_message: The student's question or input.
history: Previous turns as [{"role": "user"|"assistant", "content": "..."}].
domain: Current science domain (e.g. "physics").
experiment: Current experiment id (e.g. "pendulum").

Returns:
The mentor's reply as a plain string.
"""
context_note = ""
if domain and experiment:
context_note = f"\n\n[Context: student is working on the '{experiment}' experiment in {domain}.]"

messages = [
{"role": "system", "content": _SYSTEM_PROMPT + context_note},
*history[-10:], # keep the last 10 turns to stay within context limits
{"role": "user", "content": user_message},
]

response = await env.AI.run(
"@cf/meta/llama-3.1-8b-instruct",
{"messages": messages},
)

# The Workers AI response object exposes .response for text models
if hasattr(response, "response"):
return str(response.response)

# Fallback: try parsing as JSON-like object
try:
data = json.loads(str(response))
return data.get("response", str(response))
except Exception:
return str(response)
Loading