A Next.js 14 application that provides a streaming chat UI for LM Studio, including model management helpers, OpenSCAD previews, and one-click code downloads.
- Streaming chat against LM Studio's REST (
/api/v0) or OpenAI-compatible (/v1) endpoints. - Multiple LM Studio servers: point the UI at any reachable LM Studio instance without rebuilding.
- Learning-focused prompt presets: quick system prompts for Arduino, general Python, Xcode/iOS, OpenSCAD, Python Data Science, and JavaScript game experiments.
- OpenSCAD assistant tools: inject OpenSCAD prompt scaffolds and render returned code to STL directly in the browser.
- Interactive code helpers: run JavaScript/TypeScript directly in the browser or execute Python via Pyodide without leaving the chat.
- Code snippet downloads: every fenced code block can be exported as a zipped file with sensible extensions.
- Conversation search: full-text search over stored conversations using SQLite FTS5.
- Modern stack: Next.js 14 (App Router), React 18, Tailwind CSS, TypeScript.
- Node.js 18 or newer (Node 20+ recommended).
- npm (bundled with Node.js).
- LM Studio 0.3.6 or later with the REST server enabled (
lms server start) or the desktop GUI running with "OpenAI Compatibility" enabled. - macOS, Linux, or Windows environment with SQLite available (bundled via
better-sqlite3).
npm install
npm run devThe app starts on http://localhost:5173 by default.
- Launch LM Studio (or
lms server start). - Load your preferred model in LM Studio.
- Copy the base URL (for example
http://127.0.0.1:1234/v1). - In the chat app, paste this URL into the "Server" field and click Connect. The app polls
/api/v0/modelsfirst, falling back to/v1/models. The drop-down updates once the server responds.
| Variable | Default | Description |
|---|---|---|
LM_STUDIO_BASE_URL |
http://localhost:1234/v1 |
Fallback LM Studio URL if the client has not set one manually. |
LM_STUDIO_MODEL |
(empty) | Optional default model id used if a conversation does not specify one. |
LM_STUDIO_API_KEY |
(empty) | Sent as a Bearer token for LM Studio servers that enforce authentication. |
.env.sample contains reasonable defaults. Duplicate it to .env.local if you need to customise anything globally.
| Script | Description |
|---|---|
npm run dev |
Runs Next.js in development mode (refresh + HMR) on port 5173. |
npm run build |
Builds the production bundle. Useful to validate TypeScript. |
npm start |
Serves the built app (next start -p 5173). |
- Use the top-left server selector to configure a target LM Studio instance.
- The app stores the last-used URL in
localStorageso each refresh reuses the same host. - Refresh models triggers a live fetch from the currently selected host.
- The New button creates a conversation with default system prompt & model.
- Sending a message with no active conversation automatically creates one.
- The sidebar lists existing conversations (newest first) with quick search.
- Messages stream from LM Studio using the REST endpoint first (
/api/v0/chat/completions). - If REST streaming returns
404or is unavailable, the app falls back to/v1/chat/completions. - If the model is not yet loaded, the server typically returns
404or "not loaded"; the app polls/api/v0/modelsuntil the model reportsstate: "loaded"and then retries automatically.
- Assistant messages are scanned for fenced Markdown (```language).
- Each code block receives a Download button. Clicking it POSTs to
/api/zip, which returns a.ziparchive containing the snippet as a file (language-aware extension). - Downloads do not require page reloads and work with multiple snippets simultaneously.
- "Python Data" mentors young adults through approachable data science tasks (pandas, visualization, real world datasets).
- "JS Games" supports browser game experiments with clear game-loop explanations.
- Classic presets (Arduino, Python, Xcode/iOS, OpenSCAD) remain available.
- JavaScript / TypeScript blocks include a Run button; TS is transpiled in the browser before execution.
- Python blocks spin up Pyodide on demand (
runPythonAsync) and stream stdout/stderr back into the transcript. - Outputs (including console logs) appear immediately beneath the code block.
- The Helper panel contains an "OpenSCAD" preset to seed system prompts.
- When the assistant replies with an OpenSCAD code block, a Render STL widget appears.
- Rendering POSTs the code to
/api/openscad/render, compiles it viaopenscad-wasm, displays an interactive Three.js preview, and offers STL download.
| Route | Method | Purpose |
|---|---|---|
/api/models |
GET | Proxies /api/v0/models or /v1/models. Accepts baseUrl query for per-request overrides. |
/api/chat/stream |
POST | Streams chat replies. Body { conversationId, userText, baseUrl? }. Handles model load polling + REST/OpenAI fallback. |
/api/conversations |
GET/POST | Lists or creates conversations (SQLite). |
/api/conversations/[id] |
GET/PATCH | Retrieve or update conversation metadata. |
/api/search |
GET | Full-text search across conversation history. |
/api/openscad/render |
POST | Compiles OpenSCAD code to STL via openscad-wasm. |
/api/zip |
POST | Returns a zip archive for code snippet downloads. |
- SQLite database (
chat.db) lives in the project root and is created on first run. messagestable holds chat history.messages_ftsprovides FTS5 search.- The DB is opened with WAL mode and 5 second busy timeout for parallel access.
- System prompt presets: Modify
PROMPT_TEMPLATESinapp/page.tsxto add your own. - Default model: Set
LM_STUDIO_MODELin.env.localif you always start with a particular model. - Styling: Tailwind is configured via
tailwind.config.tsandapp/globals.css.
| Issue | Possible Fix |
|---|---|
404 from /api/v0/chat/completions |
Make sure the REST server is started (lms server start) and the model is loaded. The app auto-retries but only if the server reports state loaded. |
| Conversation shows "LM Studio returned no content" | Usually means the endpoint returned an error without body. Check the server logs and ensure the active model matches the dropdown. |
| OpenSCAD preview fails | Verify the code is valid OpenSCAD, and the response includes a fenced block labelled ```openscad`. |
| Downloads blocked | Some browsers block multiple downloads per click; confirm pop-up/ download permissions. |
- The project uses the Next.js App Router. API routes live under
app/api. - TypeScript is optional for components but enabled for pages.
postcss.config.jsandtailwind.config.tsconfigure styling. Tailwind is loaded globally throughapp/globals.css.jsziphandles server-side zipping; adjust/api/zipto bundle multiple files if required.
- Multi-select downloads (bundle an entire message into one archive).
- Conversation export/import.
- Authentication & role-based access for multi-user setups.
- Model state monitoring / notifications for asynchronous loads.
This project is provided without an explicit license; adapt or extend according to your organisation's policies.