arnaucube
arnaucube/study-labPublic Self-hosted repository
study-lab/README.md
README.mdRaw
  1# Study Lab
  2
  3Study Lab 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- can branch off any previous answer
 10- select a chunk of text from an answer and ask about it
 11- vim-like shortcuts
 12- plain js + html + css
 13- session info (api token & history) stays local on your browser, questions go through openai's api
 14- you see token usage and cost estimations
 15
 16other:
 17- branching conversation tree with clickable question nodes
 18- root-to-current-branch conversation view
 19- ask about selected answer text with suggested or custom follow-ups
 20- streaming responses
 21- markdown, fenced code blocks, and LaTeX rendering through KaTeX
 22- persistent sessions and API settings in `localStorage`
 23- lightweight vanilla HTML, CSS, and JavaScript
 24- responsive concept map for desktop and small screens
 25- persistent light/dark theme with system-theme detection
 26- monthly token tracking with per-model details and a local billing estimate
 27- independent chat-history clearing and per-conversation deletion
 28- multiple persistent maps with a browsable conversation sidebar
 29- per-map PDF context for books and papers, uploaded once through the Files API
 30- debounced search across map titles, questions, answers, and PDF names
 31- collapsible, zoomable concept trees with active-path highlighting
 32- vim-style keyboard navigation for nodes, maps, search, and the composer
 33- large-answer optimizations: throttled stream painting and `content-visibility`
 34
 35![Study Lab main view showing a branching conversation](screenshots/main%20view.png)
 36
 37## Run locally
 38
 39You 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).
 40
 41From this directory, start any static file server. Python is commonly preinstalled:
 42
 43```bash
 44python3 -m http.server 8080
 45```
 46
 47Then open <http://localhost:8080>.
 48
 49Alternatively, with Node.js:
 50
 51```bash
 52npx --yes serve .
 53```
 54
 55Open the local URL printed by `serve`.
 56
 571. Choose **Settings**.
 582. Paste an OpenAI API key.
 593. Keep `gpt-5-mini`, or enter another model available to your API project.
 604. Save and ask a question.
 61
 62To ask about a book or paper, choose **+ PDF** beside the composer and select one or more PDFs. The files are attached to the current map and included with every new question in that map, including questions asked from older branches. Each file must be under 50 MB, and all attached files in a map must total under 50 MB.
 63
 64The 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.
 65
 66## How branching works
 67
 68Each 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.
 69
 70The 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.
 71
 72![Using Go deeper to ask a focused follow-up about selected text](screenshots/go%20deeper.png)
 73
 74## Multiple maps
 75
 76Choose **New map** in the header or conversation sidebar to open a blank map. The current map is retained automatically. Use the left **Conversations** sidebar to switch between saved maps; each entry shows its title, node count, and last activity date. Use ✎ to rename a map or × to delete its entire conversation. A custom title remains unchanged as new questions are added; submitting a blank title restores automatic naming. Existing sessions from the original single-map storage format are migrated automatically.
 77
 78**Settings → Clear chat history** is the explicit destructive action that removes all saved maps. It does not remove the API key, other settings, or the separate API-usage ledger.
 79
 80## Search and navigation
 81
 82Use the search field in the conversation sidebar—or press `/` outside an input—to search all saved map titles, questions, answers, and PDF names. Results link directly to the matching map or question node. Search is debounced and capped at 60 displayed results to keep large workspaces responsive.
 83
 84The concept-map toolbar can expand or collapse all branches and zoom the tree from 80% to 140%. Individual branches have disclosure arrows, and their collapsed state persists with the map. The current root-to-node path remains highlighted.
 85
 86![Study Lab tree and conversation navigation](screenshots/tree%20navbar.png)
 87
 88Vim-style shortcuts work whenever a text field or dialog control is not focused:
 89
 90- `j` / `k` — next / previous visible concept node
 91- `h` / `l` — parent / first child; `l` expands a collapsed active node first
 92- `gg` / `G` — first / last visible node
 93- `J` / `K` — next / previous conversation
 94- `Space` — collapse or expand the active node
 95- `/` — focus cross-conversation search
 96- `i` — focus the question composer
 97- `Esc` — leave input or search mode
 98- `?` — open the in-app shortcut reference
 99
100![In-app reference for Vim-style keyboard shortcuts](screenshots/vim%20shortcuts.png)
101
102## PDF context
103
104PDFs are uploaded directly from the browser to the Files endpoint derived from the configured Responses API URL. Only their file IDs, names, and sizes are stored in `localStorage`; the PDF bytes are not copied into browser storage. Page images use low visual detail to reduce token use, while extracted PDF text remains available to the model. Use a vision-capable model that supports PDF inputs.
105
106PDF parsing adds extracted text and page images to the prompt, so large books can consume substantial input tokens on every question. The header usage tracker includes tokens reported for these requests. For very large collections or frequent querying, OpenAI recommends retrieval with File Search; this lightweight local app intentionally uses direct PDF input and does not create vector stores.
107
108Removing a PDF chip or clearing local chat history detaches the file locally but does **not** delete the uploaded copy from OpenAI. Delete retained files separately through your OpenAI account if needed. Custom API providers must expose a compatible `/files` endpoint next to their configured `/responses` endpoint.
109
110## Storage and security
111
112The browser stores these local keys:
113
114- `study-lab:v1` — multi-map conversation workspace, PDF file references, collapsed branches, and active-map selection
115- `study-lab:settings:v1` — API key, model, endpoint, and system instructions
116- `study-lab:usage:v1` — token usage and estimated request costs recorded by this browser
117- `study-lab:theme` — light/dark theme preference
118- `study-lab:tree-zoom` — concept-map zoom preference
119
120Data saved by releases before the rename is copied into the new storage namespace automatically on first load.
121
122The 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.
123
124![API usage details with token and cost estimates](screenshots/api%20usage.png)
125
126This 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:
127
128- Run the app only from files you trust.
129- Do not publish or host this version as a public multi-user site.
130- Prefer a restricted OpenAI project key with appropriate spend limits.
131- Use **Settings → Forget key** before sharing the browser profile or local origin.
132- Using a different port creates a different browser origin and therefore a separate session.
133
134For a public deployment, put API calls behind an authenticated backend and keep the key in a server environment variable.
135
136## Performance notes
137
138Only 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.
139
140Very 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.
141
142## Browser support
143
144Use 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.
145
146## API reference
147
148The 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).