Interactive scene exploration application built with React (Vite) frontend and FastAPI backend. Generate and explore interconnected scenes using AI-powered image generation and analysis.
- Scene Generation: AI-powered scene creation with image generation, visual/sound/smell keywords, and vibe detection
- Route Building: Create and manage routes through multiple scenes
- Ghost Scenes: Automatic pre-generation of next scenes for seamless exploration
- User Authentication: JWT-based authentication with user isolation
- Real-time Updates: Polling and optimistic UI updates for smooth user experience
- Docker and Docker Compose
- OpenAI API key (for scene generation)
- Copy the example environment file:
cp example.env .env- Edit
.envand set yourOPENAI_API_KEY:
OPENAI_API_KEY=your-api-key-here- Start the application:
docker compose up --build- Access the application:
- Frontend:
http://localhost:5173 - Backend API:
http://localhost:8000 - API Documentation:
http://localhost:8000/docs - Uploaded files:
http://localhost:8000/uploads/<name>
On first startup, an admin user is automatically created. The default credentials are admin/admin, but you should change these in production by setting ADMIN_USERNAME and ADMIN_PASSWORD environment variables.
All API endpoints (except /api/health and /api/auth/login) require authentication via Bearer token.
POST /api/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "admin"
}Response:
{
"access_token": "eyJ...",
"token_type": "bearer"
}Include the token in the Authorization header:
Authorization: Bearer <token>
- Users can only see and modify their own scenes and routes
- Admin user is automatically created on first startup
- Set
ADMIN_USERNAMEandADMIN_PASSWORDenvironment variables to customize admin credentials
OPENAI_API_KEY: Your OpenAI API key (required for scene generation)JWT_SECRET_KEY: Secret key for JWT token signing (MUST be changed in production)
ADMIN_USERNAME: Admin username (default:admin)ADMIN_PASSWORD: Admin password (default:admin)MONGO_URI: MongoDB connection URI (default:mongodb://mongodb:27017)MONGO_DB: MongoDB database name (default:scene_explorer)UPLOAD_DIR: Directory for uploaded files (default:uploads)CELERY_BROKER_URL: Redis URL for Celery (default:redis://redis:6379/0)LLM_PROVIDER:stuboropenai(default:stub)OPENAI_BASE_URL: OpenAI API base URL (default:https://api.openai.com/v1)OPENAI_MODEL: OpenAI model name (default:gpt-4o-mini)OPENAI_IMAGE_MODEL: OpenAI image model (default:dall-e-3)OPENAI_VISION_MODEL: OpenAI vision model (default:gpt-4o-mini)
python3 -c "import secrets; print(secrets.token_urlsafe(32))"Run tests locally:
python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt
cd backend
pytest -v- Upload:
POST /api/uploads(multipart form field:file) - Serve:
GET /uploads/<name> - Stored on disk in:
./data/uploads/(bind-mounted into the backend container)
- Create:
POST /api/scenes - List:
GET /api/scenes - Delete:
DELETE /api/scenes/<scene_id>- Stored in MongoDB (see
docker-compose.yml)
- Stored in MongoDB (see
Create payload:
{
"name": "string | null",
"initial_prompt": "string | null",
"image_url": "https://example.com/image.png",
"visual": "string",
"sound": "string",
"smell": "string",
"vibe": "string | null"
}MongoDB (local):
- URI:
mongodb://localhost:27017 - DB:
scene_explorer - Data directory:
./data/mongodb/
Backend includes a small LLM wrapper (backend/app/llm.py) with a single method:
process(user_prompt, system_prompt=None) -> str
Configuration (env vars):
LLM_PROVIDER:stub(default) oropenaiOPENAI_API_KEY: required ifLLM_PROVIDER=openaiOPENAI_BASE_URL: defaults tohttps://api.openai.com/v1OPENAI_MODEL: defaults togpt-4o-miniOPENAI_IMAGE_MODEL: defaults todall-e-3OPENAI_VISION_MODEL: defaults togpt-4o-mini
To run with OpenAI locally:
cp example.env .env
# edit .env and set OPENAI_API_KEY
docker compose up --buildAPI:
POST /api/llm/processwith JSON{ "user_prompt": "...", "system_prompt": "..." }
Backend includes SceneGenerator (backend/app/scene_generation.py) which:
- Takes an
initial_prompt - Generates an image first (OpenAI images) from the initial prompt and saves it to
./data/uploads/ - Uses the generated image to derive
visual,sound,smell, optionalvibe(comma-separated keywords / short phrases, max 5) - Persists the created scene in MongoDB with
image_url=/uploads/<name>.png
API:
POST /api/scenes/generatewith JSON{ "initial_prompt": "..." }
- Create:
POST /api/routeswith JSON{ "name": "string | null", "direction": "string | null", "scene_ids": ["<scene_id>", "..."] } - Update:
PUT /api/routes/<route_id>with JSON{ "name": "string | null", "direction": "string | null", "scene_ids": ["<scene_id>", "..."] } - List:
GET /api/routes(returns routes with embeddedscenes) - Get:
GET /api/routes/<route_id>(returns a single route with embeddedscenes) - Delete:
DELETE /api/routes/<route_id> - Proceed:
POST /api/routes/<route_id>/proceed(generates and appends a new scene to the route)
Routes automatically generate "ghost scenes" - the next scene is pre-generated in the background for faster user experience.
- Check ghost status:
GET /api/routes/<route_id>/ghost - Claim ghost:
POST /api/routes/<route_id>/claim-ghost(adds the pre-generated scene to the route)
When you proceed past the last scene in a route, if a ghost scene is ready, it's automatically claimed. Otherwise, a new scene is generated synchronously.
The repository includes migration scripts for data updates:
Migrates existing scenes and routes to belong to the admin user. Run this if you have existing data from before user authentication was added.
cd backend
python3 migrate_add_users.pySets the is_ghost flag consistently across all scenes. Run this to ensure ghost scenes are properly marked.
cd backend
python3 migrate_is_ghost.pyBoth scripts use environment variables MONGO_URI and MONGO_DB (defaults: mongodb://localhost:27017 and scene_explorer).
From frontend/:
npm install
npx playwright install
npm run test:e2eNotes:
- Tests assume the stack is already running (
docker compose up --build) and will seed data via the backend API. - Tests log in with
admin/admincredentials.
Before deploying to production:
- Change JWT Secret: Set
JWT_SECRET_KEYto a strong random secret (use the command above to generate one) - Change Admin Credentials: Set
ADMIN_USERNAMEandADMIN_PASSWORDto secure values - Review CORS Settings: Currently no CORS middleware is configured - add appropriate CORS settings for your frontend domain
- Use Environment Variables: Never commit
.envfiles - use your deployment platform's secret management - Database Security: Ensure MongoDB is not exposed publicly without authentication
- HTTPS: Always use HTTPS in production
# JWT Secret
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# Admin Password (use a password manager or generate securely)- Frontend: React with Redux Toolkit for state management, React Router for navigation
- Backend: FastAPI with MongoDB for data persistence
- Background Jobs: Celery with Redis for asynchronous scene generation
- Authentication: JWT tokens with bcrypt password hashing
- Image Generation: OpenAI DALL-E for scene images
- Scene Analysis: OpenAI Vision API for extracting keywords and vibe
GET /api/health- Health checkPOST /api/auth/login- User login
GET /api/scenes- List user's scenesPOST /api/scenes- Create a scenePOST /api/scenes/generate- Generate a new scene from promptDELETE /api/scenes/<scene_id>- Delete a sceneGET /api/routes- List user's routesPOST /api/routes- Create a routeGET /api/routes/<route_id>- Get a routePUT /api/routes/<route_id>- Update a routeDELETE /api/routes/<route_id>- Delete a routePOST /api/routes/<route_id>/proceed- Proceed route (generate next scene)GET /api/routes/<route_id>/ghost- Get ghost scene statusPOST /api/routes/<route_id>/claim-ghost- Claim pre-generated ghost scenePOST /api/uploads- Upload a filePOST /api/llm/process- Process text with LLM
- Python: Follow PEP 8, use type hints
- JavaScript: Use single quotes, follow existing patterns
- Tests: Write tests before implementation (TDD approach)
- Documentation: Avoid comments unless necessary (code should be self-documenting)
# Backend tests
cd backend
pytest -v
# Frontend E2E tests
cd frontend
npm run test:e2eSee LICENSE file for details.