Phase 7: MIT license, portfolio README, Docker, cross-platform start

- LICENSE: MIT
- README: rewritten as portfolio-grade docs (features with code pointers,
  architecture, Docker/Windows/macOS quick starts, BYO-model table)
- Dockerfile (3-stage: SPA build, pip wheels, slim runtime) + compose with
  a /data volume; .dockerignore keeps secrets and local data out
- database.py: AIDND_DB_PATH env override so deployments can relocate the
  SQLite file; documented in backend/.env.example
- start.sh: macOS/Linux dev script with first-run setup

Verified locally: production SPA build served by the backend (deep links
OK), DB created at the override path. Docker image itself untested here
(Docker not installed); flagged in plan/07.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
This commit is contained in:
parththakkar106
2026-07-06 16:51:48 +05:30
co-authored by Claude Fable 5
parent 466d7bc0e4
commit 22630c8411
9 changed files with 256 additions and 50 deletions
+19
View File
@@ -0,0 +1,19 @@
.git
.claude
plan
*.md
LICENSE
start.ps1
start.sh
# Secrets & local data — never in the image
*.env
backend/openrouter_key.env
*.db
# Build/runtime artifacts rebuilt inside the image
backend/.venv
**/__pycache__
**/*.pyc
frontend/node_modules
frontend/dist
+35
View File
@@ -0,0 +1,35 @@
# Stage 1 — build the React SPA
FROM node:22-alpine AS frontend-build
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# Stage 2 — build Python wheels (quickjs compiles from source if no wheel
# matches, so keep the toolchain out of the final image)
FROM python:3.12-slim AS python-build
RUN apt-get update && apt-get install -y --no-install-recommends gcc make \
&& rm -rf /var/lib/apt/lists/*
COPY backend/requirements.txt /tmp/requirements.txt
RUN pip wheel --no-cache-dir -r /tmp/requirements.txt -w /wheels
# Stage 3 — runtime
FROM python:3.12-slim
WORKDIR /app
COPY --from=python-build /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
# Layout mirrors the repo: main.py finds the SPA at ../../frontend/dist
# relative to backend/app/main.py.
COPY backend/app /app/backend/app
COPY --from=frontend-build /build/dist /app/frontend/dist
# Database lives on a volume; parent dir is created by the app if missing.
ENV AIDND_DB_PATH=/data/data.db
VOLUME /data
EXPOSE 8000
WORKDIR /app/backend
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Parth Thakkar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+99 -34
View File
@@ -1,54 +1,119 @@
# AI D&D — local AI Dungeon-style storytelling app
# AI D&D
Python (FastAPI + SQLite) backend, React (Vite) frontend, connectable to any
OpenAI-compatible AI endpoint (Ollama, LM Studio, OpenAI, OpenRouter, …).
An AI Dungeon-style interactive storytelling app you can run entirely on your own machine —
with your own AI model. Create scenarios, play open-ended adventures where an LLM narrates the
world, and extend the engine with **JavaScript scripts compatible with real AI Dungeon
scripting**.
Plan: see [`plan/00-OVERVIEW.md`](plan/00-OVERVIEW.md). Currently completed: **Phase 4** (AI Dungeon-compatible scripting).
Built with FastAPI + SQLite on the backend and React (Vite) on the frontend. Works with **any
OpenAI-compatible endpoint**: Ollama and LM Studio locally, or OpenRouter / OpenAI / Groq / vLLM
in the cloud — endpoint, key, and model are all runtime settings, and OpenRouter's free-tier
models make the whole experience $0.
## Run
> 📸 *Screenshots and a demo GIF are coming; for now the fastest tour is running it — one
> command with Docker.*
## Features
- **The full play loop** — Do / Say / Story / Continue actions, streamed AI responses (SSE),
retry, undo, and edit. Reasoning models supported: "thinking" streams into a collapsible 💭
panel with its own token budget.
- **AI Dungeon-compatible context engine** — memory, author's note, and story cards (world
info) triggered by keywords in recent story text, assembled under a token budget
(`backend/app/context/builder.py`).
- **Insights: total prompt transparency** — every turn stores the exact prompt sent to the
model; open 🔍 on any AI action to see each context component and why it was included.
- **JavaScript scripting, AI Dungeon-compatible** — `onInput` / `onModelContext` / `onOutput`
modifiers with shared `state` and a `worldEntries` API, executed in an embedded quickjs
sandbox (`backend/app/scripting/`). Real AI Dungeon scripts import and run. In-app
CodeMirror editor included.
- **Auto-summarization + Memory Bank** — the modern AI Dungeon memory system: AI-generated
memories every few actions, a running story summary, and embedding-based retrieval that
pulls old-but-relevant facts back into context, with similarity scores visible in Insights
(`backend/app/memorybank.py`).
- **Import/export** — AI Dungeon-compatible formats for scripts and scenarios; JSON for
everything.
## Quick start
### Docker (any OS)
```sh
docker compose up --build
```
Open http://localhost:8000. Your data persists in a named volume across restarts.
### Windows
```powershell
cd backend; python -m venv .venv; .\.venv\Scripts\pip.exe install -r requirements.txt; cd ..
cd frontend; npm install; cd ..
.\start.ps1
```
Then open http://localhost:5173. Backend API docs at http://localhost:8000/docs.
Open http://localhost:5173 (dev servers; API docs at http://localhost:8000/docs).
Or manually, in two terminals:
### macOS / Linux
```powershell
# Terminal 1 — backend
cd backend
.\.venv\Scripts\uvicorn.exe app.main:app --port 8000 --reload
# Terminal 2 — frontend
cd frontend
npm run dev
```sh
./start.sh # creates the venv and installs dependencies on first run
```
## First-time setup
Open http://localhost:5173.
```powershell
cd backend
python -m venv .venv
.\.venv\Scripts\pip.exe install -r requirements.txt
## Connect a model
cd ..\frontend
npm install
Open **Settings** in the app and point it at any OpenAI-compatible endpoint:
| Provider | Endpoint URL | Notes |
|---|---|---|
| Ollama (local) | `http://localhost:11434/v1` | free, private; also serves embedding models for the Memory Bank (e.g. `nomic-embed-text`) |
| LM Studio (local) | `http://localhost:1234/v1` | free, private |
| OpenRouter | `https://openrouter.ai/api/v1` | `:free` models cost nothing (no embeddings on the free tier) |
| OpenAI / Groq / vLLM / … | provider's `/v1` URL | anything speaking `/v1/chat/completions` |
Model name, API key, generation parameters, and (optionally) summary/embedding models for the
Memory Bank are all configured there too — no config files, no rebuild.
## How a turn works
```
player input
→ onInput script modifier
→ assemble context: [AI instructions] + [plot essentials] + [story summary]
+ [retrieved memories] + [triggered story cards]
+ [story history, token-budgeted] + [author's note] + [player action]
→ onModelContext script modifier
→ snapshot context (Insights)
→ provider adapter → AI (streamed)
→ onOutput script modifier
→ store & render
```
## Production-ish serving (single port)
## Architecture
Build the frontend, then the backend serves it statically:
```powershell
cd frontend
npm run build
# then run the backend and open http://localhost:8000
```
frontend/ React + Vite SPA ──HTTP/SSE──► backend/ FastAPI
├─ routers/ scenarios, adventures, story cards, scripts, settings, debug
├─ models.py SQLAlchemy: Scenario, Adventure, Action, StoryCard, Script, Settings, Memory
├─ context/ prompt assembly under a token budget
├─ scripting/ quickjs sandbox + AI Dungeon API surface
├─ memorybank.py auto-summarization + embedding retrieval
├─ providers/ OpenAI-compatible adapter, streaming
└─ data.db SQLite (path overridable via AIDND_DB_PATH)
```
## Layout
In production the backend serves the built SPA from one port (see `Dockerfile`); in
development Vite proxies `/api` to FastAPI.
- `backend/app/` — FastAPI app: `models.py` (SQLAlchemy), `schemas.py` (Pydantic), `routers/`
- `backend/data.db` — SQLite database (created on first run)
- `frontend/src/` — React SPA: `pages/`, `api.js`
- `plan/` — phased implementation plan
## Repo notes
- `plan/` — the phased implementation plan this was built from, kept as a build log
(phases 1–6 complete; 7–10 cover the public release).
- `backend/.env.example` — the few environment variables the backend reads.
- `CODE_REVIEW_FINDINGS.md` — notes from a self-review pass.
## License
[MIT](LICENSE)
+17
View File
@@ -0,0 +1,17 @@
# Environment variables read by the backend.
#
# NOTE: the app reads real environment variables — it does NOT auto-load this
# file. Set them in your shell, in docker-compose.yml, or in your host's
# dashboard. This file is documentation (and a template for deploy configs).
# Absolute path for the SQLite database file. Parent directory is created if
# missing. Default when unset: backend/data.db
# Docker compose sets this to /data/data.db (a named volume).
AIDND_DB_PATH=
# --- Coming in later phases (documented here as they land) ---
# Phase 8/9 will add: SECRET_KEY, MULTI_USER, DEMO_API_KEY, DEMO_ENDPOINT_URL,
# DEMO_MODEL_WHITELIST, DEMO_TURNS_PER_DAY, CORS_ORIGINS.
#
# The AI endpoint/API key/model are NOT env vars — they are configured at
# runtime in the app's Settings page and stored in the database.
+10 -1
View File
@@ -1,9 +1,18 @@
import os
from pathlib import Path
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, sessionmaker
DB_PATH = Path(__file__).resolve().parent.parent / "data.db"
# AIDND_DB_PATH lets deployments (Docker volume, hosted disk) relocate the
# database; default stays backend/data.db for local runs.
_env_db_path = os.environ.get("AIDND_DB_PATH")
DB_PATH = (
Path(_env_db_path).resolve()
if _env_db_path
else Path(__file__).resolve().parent.parent / "data.db"
)
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
engine = create_engine(
f"sqlite:///{DB_PATH}",
+11
View File
@@ -0,0 +1,11 @@
services:
ai-dnd:
build: .
ports:
- "8000:8000"
volumes:
- ai-dnd-data:/data
restart: unless-stopped
volumes:
ai-dnd-data:
+21 -15
View File
@@ -10,36 +10,42 @@ immediately usable on a resume — before any hosted-deployment work.
| License | **MIT** |
| README media (screenshots/GIF) | **Skip for now** — text-only README; visuals in a later pass |
**Ask before implementing:** GitHub repo name (default suggestion: `ai-dnd`) and whether the
existing local commit history/message is fine to publish as-is.
**Repo name (decided): `AI-DnD`.** Ask before publishing: whether the existing commit
history/messages are fine to publish as-is.
## Repo hygiene
- [ ] Add `LICENSE` (MIT, current year, Parth Thakkar).
- [ ] Verify no secrets or user data are tracked (`openrouter_key.env`, `data.db` — already
- [x] Add `LICENSE` (MIT, current year, Parth Thakkar).
- [x] Verify no secrets or user data are tracked (`openrouter_key.env`, `data.db` — already
gitignored and never committed; re-verify before push).
- [ ] Add `backend/.env.example` documenting every env var the app reads (grows in Phase 9).
- [ ] Decide what to do with `CODE_REVIEW_FINDINGS.md` and `plan/` — keep (shows process, good
- [x] Add `backend/.env.example` documenting every env var the app reads (grows in Phase 9).
(Currently just `AIDND_DB_PATH`, added to `database.py` for Docker/hosted volumes.)
- [x] Decide what to do with `CODE_REVIEW_FINDINGS.md` and `plan/` — keep (shows process, good
for a portfolio) — just give them a one-line mention in the README.
## README rewrite (portfolio-grade, text-only)
- [ ] Pitch paragraph: what it is, what makes it interesting (AI Dungeon-compatible scripting,
- [x] Pitch paragraph: what it is, what makes it interesting (AI Dungeon-compatible scripting,
memory bank with embeddings, full prompt transparency/Insights, provider-agnostic).
- [ ] Feature list with pointers into the code (scripting engine, context builder, memory bank).
- [ ] Architecture diagram (reuse/refresh the one in `plan/00-OVERVIEW.md`).
- [ ] Setup instructions for **Windows (start.ps1), macOS/Linux (manual), and Docker**.
- [ ] "Bring your own model" section: Ollama / LM Studio / OpenRouter free models — emphasize it
- [x] Feature list with pointers into the code (scripting engine, context builder, memory bank).
- [x] Architecture diagram (reuse/refresh the one in `plan/00-OVERVIEW.md`).
- [x] Setup instructions for **Windows (start.ps1), macOS/Linux (manual), and Docker**.
- [x] "Bring your own model" section: Ollama / LM Studio / OpenRouter free models — emphasize it
runs fully free.
- [ ] Placeholder section for screenshots/GIF (added in a later pass).
- [x] Placeholder section for screenshots/GIF (added in a later pass).
## Docker (one-command run for non-Windows users)
- [ ] `Dockerfile`: multi-stage — build frontend (`npm run build`), then Python image serving
- [x] `Dockerfile`: multi-stage — build frontend (`npm run build`), then Python image serving
FastAPI with the built SPA mounted (SPA fallback already exists in `app/main.py`).
- [ ] `docker-compose.yml`: single service, volume for `data.db`, port mapping.
- [ ] `start.sh` for macOS/Linux dev parity with `start.ps1` (optional, nice-to-have).
(3 stages: node build → pip wheel build with gcc for quickjs → slim runtime.)
- [x] `docker-compose.yml`: single service, named volume mounted at `/data`
(`AIDND_DB_PATH=/data/data.db`), port mapping.
- [x] `start.sh` for macOS/Linux dev parity with `start.ps1` (optional, nice-to-have).
- [ ] Test: `docker compose up` from a clean clone → app works at `http://localhost:8000`.
**Blocked locally: Docker is not installed on the dev machine.** Verified without Docker:
production frontend build + backend serving the SPA (deep links OK) + DB-path override
all work. Test the image on any Docker machine (or let Render build it in Phase 10).
## Publish
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# macOS/Linux equivalent of start.ps1: backend (FastAPI, :8000) and frontend
# dev server (Vite, :5173). Ctrl-C stops both.
set -euo pipefail
cd "$(dirname "$0")"
if [ ! -d backend/.venv ]; then
echo "First-time setup: creating backend/.venv and installing dependencies..."
python3 -m venv backend/.venv
backend/.venv/bin/pip install -r backend/requirements.txt
fi
if [ ! -d frontend/node_modules ]; then
echo "First-time setup: npm install..."
(cd frontend && npm install)
fi
(cd backend && .venv/bin/uvicorn app.main:app --port 8000 --reload) &
BACKEND_PID=$!
trap 'kill "$BACKEND_PID" 2>/dev/null' EXIT
echo "Backend: http://localhost:8000 (API docs: http://localhost:8000/docs)"
echo "Frontend: http://localhost:5173"
cd frontend && npm run dev