study-lab/README.md
README.mdRaw
1# Study Pal
2
3Study Pal is a local-first, branching AI chat for exploring technical concepts. Every question becomes a node in a concept map. Select any earlier node to continue from that point, or select text inside an answer and ask a focused follow-up.
4
5The app is intentionally frontend-only: there is no build step, package manager, backend, or database. Conversations and settings persist in the browser's `localStorage`, while responses stream directly from OpenAI's Responses API.
6
7## Features
8
9- Branching conversation tree with clickable question nodes
10- Root-to-current-branch conversation view
11- Ask about selected answer text with suggested or custom follow-ups
12- Streaming responses
13- Markdown, fenced code blocks, and LaTeX rendering through KaTeX
14- Persistent sessions and API settings in `localStorage`
15- Lightweight vanilla HTML, CSS, and JavaScript
16- Responsive concept map for desktop and small screens
17- Persistent light/dark theme with system-theme detection
18- Monthly token tracking with per-model details and a local billing estimate
19- Large-answer optimizations: throttled stream painting and `content-visibility`
20
21## Run locally
22
23You need a modern browser, an internet connection, and an OpenAI API key. A ChatGPT subscription/password is not an API key; create a project key in the [OpenAI dashboard](https://platform.openai.com/api-keys).
24
25From this directory, start any static file server. Python is commonly preinstalled:
26
27```bash
28python3 -m http.server 8080
29```
30
31Then open <http://localhost:8080>.
32
33Alternatively, with Node.js:
34
35```bash
36npx --yes serve .
37```
38
39Open the local URL printed by `serve`.
40
411. Choose **Settings**.
422. Paste an OpenAI API key.
433. Keep `gpt-5-mini`, or enter another model available to your API project.
444. Save and ask a question.
45
46The endpoint is configurable under **Advanced**, which is useful for an OpenAI-compatible Responses API. Compatibility depends on whether that provider implements the Responses API and browser CORS.
47
48## How branching works
49
50Each node stores its parent ID. Clicking a node makes it the active context and displays only the path from the root to that node. The next question becomes its child. Selecting text within an answer and choosing **Ask** creates a child of the answer's node, even if another branch was active.
51
52The complete parent-path conversation is sent with each request. This makes every branch self-contained and avoids coupling local history to provider-side response IDs.
53
54## Storage and security
55
56The browser stores three local keys:
57
58- `study-pal:v1` — conversation nodes
59- `study-pal:settings:v1` — API key, model, endpoint, and system instructions
60- `study-pal:usage:v1` — token usage and estimated request costs recorded by this browser
61
62The usage button in the header counts tokens reported by completed Responses API requests made from this browser. Its estimated USD amount uses a local pricing table and is not an invoice: it cannot see other browsers or applications, historical requests made before tracking was added, credits, taxes, or special pricing. Use the linked OpenAI usage dashboard as the source of truth for billing.
63
64This design is convenient for a private tool on your own laptop, but browser storage is not a secure secret vault. Any JavaScript executing on the same origin can read it. Therefore:
65
66- Run the app only from files you trust.
67- Do not publish or host this version as a public multi-user site.
68- Prefer a restricted OpenAI project key with appropriate spend limits.
69- Use **Settings → Forget key** before sharing the browser profile or local origin.
70- Using a different port creates a different browser origin and therefore a separate session.
71
72For a public deployment, put API calls behind an authenticated backend and keep the key in a server environment variable.
73
74## Performance notes
75
76Only the active branch is added to the main document; sibling branches remain compact data in `localStorage`. Streaming UI updates are batched roughly every 70 ms instead of rerendering for every token. Off-screen messages use CSS `content-visibility`, and the concept map is built with a single document-fragment update.
77
78Very large sessions are ultimately limited by the browser's `localStorage` quota (usually a few megabytes). Start a new map when the saved tree becomes unusually large.
79
80## Browser support
81
82Use a current version of Chrome, Edge, Firefox, or Safari. LaTeX loads from the jsDelivr CDN; if it cannot load, equations remain visible as plain source text. The OpenAI API must allow requests from your local browser origin. If a corporate browser policy or custom endpoint blocks CORS, a small local proxy backend would be required.
83
84## API reference
85
86The app uses `POST /v1/responses` with `stream: true` and reads Server-Sent Events. See the official [OpenAI streaming Responses documentation](https://developers.openai.com/api/docs/guides/streaming-responses).