Spaces:
Build error
Build error
Upload 25 files
Browse files- .dockerignore +63 -0
- .env.example +171 -0
- .gitattributes +1 -0
- .gitignore +136 -0
- .python-version +1 -0
- CLAUDE.md +3 -0
- CONFIGURATION.md +108 -0
- CONTRIBUTING.md +52 -0
- Dockerfile +95 -0
- Dockerfile.single +99 -0
- LICENSE +17 -0
- MIGRATION.md +397 -0
- Makefile +201 -0
- PWA_IMPLEMENTATION.md +292 -0
- README.md +452 -10
- batch_fix_services.py +77 -0
- docker-compose.dev.yml +26 -0
- docker-compose.full.yml +25 -0
- docker-compose.single.yml +20 -0
- logo.png +3 -0
- mypy.ini +36 -0
- pyproject.toml +98 -0
- run_api.py +31 -0
- supervisord.conf +40 -0
- supervisord.single.conf +52 -0
- uv.lock +0 -0
.dockerignore
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
notebooks/
|
| 2 |
+
data/
|
| 3 |
+
.uploads/
|
| 4 |
+
.venv/
|
| 5 |
+
.env
|
| 6 |
+
sqlite-db/
|
| 7 |
+
temp/
|
| 8 |
+
google-credentials.json
|
| 9 |
+
docker-compose*
|
| 10 |
+
.docker_data/
|
| 11 |
+
docs/
|
| 12 |
+
surreal_data/
|
| 13 |
+
surreal-data/
|
| 14 |
+
notebook_data/
|
| 15 |
+
temp/
|
| 16 |
+
*.env
|
| 17 |
+
.git/
|
| 18 |
+
.github/
|
| 19 |
+
|
| 20 |
+
# Frontend build artifacts and dependencies
|
| 21 |
+
frontend/node_modules/
|
| 22 |
+
frontend/.next/
|
| 23 |
+
frontend/.env.local
|
| 24 |
+
|
| 25 |
+
# Cache directories (recursive patterns)
|
| 26 |
+
**/__pycache__/
|
| 27 |
+
**/.mypy_cache/
|
| 28 |
+
**/.ruff_cache/
|
| 29 |
+
**/.pytest_cache/
|
| 30 |
+
**/*.pyc
|
| 31 |
+
**/*.pyo
|
| 32 |
+
**/*.pyd
|
| 33 |
+
.coverage
|
| 34 |
+
.coverage.*
|
| 35 |
+
htmlcov/
|
| 36 |
+
.tox/
|
| 37 |
+
.nox/
|
| 38 |
+
.cache/
|
| 39 |
+
nosetests.xml
|
| 40 |
+
coverage.xml
|
| 41 |
+
*.cover
|
| 42 |
+
*.py,cover
|
| 43 |
+
.hypothesis/
|
| 44 |
+
|
| 45 |
+
# IDE and editor files
|
| 46 |
+
.vscode/
|
| 47 |
+
.idea/
|
| 48 |
+
*.swp
|
| 49 |
+
*.swo
|
| 50 |
+
*~
|
| 51 |
+
|
| 52 |
+
# OS files
|
| 53 |
+
.DS_Store
|
| 54 |
+
.DS_Store?
|
| 55 |
+
._*
|
| 56 |
+
.Spotlight-V100
|
| 57 |
+
.Trashes
|
| 58 |
+
ehthumbs.db
|
| 59 |
+
Thumbs.db
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
.quarentena/
|
| 63 |
+
surreal_single_data/
|
.env.example
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# API CONFIGURATION
|
| 3 |
+
# URL where the API can be accessed by the browser
|
| 4 |
+
# This setting allows the frontend to connect to the API at runtime (no rebuild needed!)
|
| 5 |
+
#
|
| 6 |
+
# IMPORTANT: Do NOT include /api at the end - it will be added automatically!
|
| 7 |
+
#
|
| 8 |
+
# Common scenarios:
|
| 9 |
+
# - Docker on localhost: http://localhost:5055 (default, works for most cases)
|
| 10 |
+
# - Docker on LAN/remote server: http://192.168.1.100:5055 or http://your-server-ip:5055
|
| 11 |
+
# - Behind reverse proxy with custom domain: https://your-domain.com
|
| 12 |
+
# - Behind reverse proxy with subdomain: https://api.your-domain.com
|
| 13 |
+
#
|
| 14 |
+
# Examples for reverse proxy users:
|
| 15 |
+
# - API_URL=https://notebook.example.com (frontend will call https://notebook.example.com/api/*)
|
| 16 |
+
# - API_URL=https://api.example.com (frontend will call https://api.example.com/api/*)
|
| 17 |
+
#
|
| 18 |
+
# Note: If not set, the system will auto-detect based on the incoming request.
|
| 19 |
+
# Only set this if you need to override the auto-detection (e.g., reverse proxy scenarios).
|
| 20 |
+
API_URL=http://localhost:5055
|
| 21 |
+
|
| 22 |
+
# INTERNAL API URL (Server-Side)
|
| 23 |
+
# URL where Next.js server-side should proxy API requests (via rewrites)
|
| 24 |
+
# This is DIFFERENT from API_URL which is used by the browser client
|
| 25 |
+
#
|
| 26 |
+
# INTERNAL_API_URL is used by Next.js rewrites to forward /api/* requests to the FastAPI backend
|
| 27 |
+
# API_URL is used by the browser to know where to make API calls
|
| 28 |
+
#
|
| 29 |
+
# Default: http://localhost:5055 (single-container deployment - both services on same host)
|
| 30 |
+
# Override for multi-container: INTERNAL_API_URL=http://api-service:5055
|
| 31 |
+
#
|
| 32 |
+
# Common scenarios:
|
| 33 |
+
# - Single container (default): Don't set - defaults to http://localhost:5055
|
| 34 |
+
# - Multi-container Docker Compose: INTERNAL_API_URL=http://api:5055 (use service name)
|
| 35 |
+
# - Kubernetes/advanced networking: INTERNAL_API_URL=http://api-service.namespace.svc.cluster.local:5055
|
| 36 |
+
#
|
| 37 |
+
# Why two variables?
|
| 38 |
+
# - API_URL: External/public URL that browsers use (can be https://your-domain.com)
|
| 39 |
+
# - INTERNAL_API_URL: Internal container networking URL (usually http://localhost:5055 or service name)
|
| 40 |
+
#
|
| 41 |
+
# INTERNAL_API_URL=http://localhost:5055
|
| 42 |
+
|
| 43 |
+
# API CLIENT TIMEOUT (in seconds)
|
| 44 |
+
# Controls how long the frontend/Streamlit UI waits for API responses
|
| 45 |
+
# Increase this if you're using slow AI providers or hardware (Ollama on CPU, remote LM Studio, etc.)
|
| 46 |
+
# Default: 300 seconds (5 minutes) - sufficient for most transformation/insight operations
|
| 47 |
+
#
|
| 48 |
+
# Common scenarios:
|
| 49 |
+
# - Fast cloud APIs (OpenAI, Anthropic): 300 seconds is more than enough
|
| 50 |
+
# - Local Ollama on GPU: 300 seconds should work fine
|
| 51 |
+
# - Local Ollama on CPU: Consider 600 seconds (10 minutes) or more
|
| 52 |
+
# - Remote LM Studio over slow network: Consider 900 seconds (15 minutes)
|
| 53 |
+
# - Very large documents: May need 900+ seconds
|
| 54 |
+
#
|
| 55 |
+
# API_CLIENT_TIMEOUT=300
|
| 56 |
+
|
| 57 |
+
# ESPERANTO LLM TIMEOUT (in seconds)
|
| 58 |
+
# Controls the timeout for AI model API calls at the Esperanto library level
|
| 59 |
+
# This is separate from API_CLIENT_TIMEOUT and applies to the actual LLM provider requests
|
| 60 |
+
# Only increase this if you're experiencing timeouts during model inference itself
|
| 61 |
+
# Default: 60 seconds (built into Esperanto)
|
| 62 |
+
#
|
| 63 |
+
# Important: This should generally be LOWER than API_CLIENT_TIMEOUT to allow proper error handling
|
| 64 |
+
#
|
| 65 |
+
# Common scenarios:
|
| 66 |
+
# - Fast cloud APIs (OpenAI, Anthropic, Groq): 60 seconds is sufficient
|
| 67 |
+
# - Local Ollama with small models: 120-180 seconds may help
|
| 68 |
+
# - Local Ollama with large models on CPU: 300+ seconds
|
| 69 |
+
# - Remote or self-hosted LLMs: 180-300 seconds depending on hardware
|
| 70 |
+
#
|
| 71 |
+
# Note: If transformations complete but you see timeout errors, increase API_CLIENT_TIMEOUT first.
|
| 72 |
+
# Only increase ESPERANTO_LLM_TIMEOUT if the model itself is timing out during inference.
|
| 73 |
+
#
|
| 74 |
+
# ESPERANTO_LLM_TIMEOUT=60
|
| 75 |
+
|
| 76 |
+
# SECURITY
|
| 77 |
+
# Set this to protect your Open Notebook instance with a password (for public hosting)
|
| 78 |
+
# OPEN_NOTEBOOK_PASSWORD=
|
| 79 |
+
|
| 80 |
+
# OPENAI
|
| 81 |
+
# OPENAI_API_KEY=
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
# ANTHROPIC
|
| 85 |
+
# ANTHROPIC_API_KEY=
|
| 86 |
+
|
| 87 |
+
# GEMINI
|
| 88 |
+
# this is the best model for long context and podcast generation
|
| 89 |
+
# GOOGLE_API_KEY=
|
| 90 |
+
# GEMINI_API_BASE_URL= # Optional: Override default endpoint (for Vertex AI, proxies, etc.)
|
| 91 |
+
|
| 92 |
+
# VERTEXAI
|
| 93 |
+
# VERTEX_PROJECT=my-google-cloud-project-name
|
| 94 |
+
# GOOGLE_APPLICATION_CREDENTIALS=./google-credentials.json
|
| 95 |
+
# VERTEX_LOCATION=us-east5
|
| 96 |
+
|
| 97 |
+
# MISTRAL
|
| 98 |
+
# MISTRAL_API_KEY=
|
| 99 |
+
|
| 100 |
+
# DEEPSEEK
|
| 101 |
+
# DEEPSEEK_API_KEY=
|
| 102 |
+
|
| 103 |
+
# OLLAMA
|
| 104 |
+
# OLLAMA_API_BASE="http://10.20.30.20:11434"
|
| 105 |
+
|
| 106 |
+
# OPEN ROUTER
|
| 107 |
+
# OPENROUTER_BASE_URL="https://openrouter.ai/api/v1"
|
| 108 |
+
# OPENROUTER_API_KEY=
|
| 109 |
+
|
| 110 |
+
# GROQ
|
| 111 |
+
# GROQ_API_KEY=
|
| 112 |
+
|
| 113 |
+
# XAI
|
| 114 |
+
# XAI_API_KEY=
|
| 115 |
+
|
| 116 |
+
# ELEVENLABS
|
| 117 |
+
# Used only by the podcast feature
|
| 118 |
+
# ELEVENLABS_API_KEY=
|
| 119 |
+
|
| 120 |
+
# TTS BATCH SIZE
|
| 121 |
+
# Controls concurrent TTS requests for podcast generation (default: 5)
|
| 122 |
+
# Lower values reduce provider load but increase generation time
|
| 123 |
+
# Recommended: OpenAI=5, ElevenLabs=2, Google=4, Custom=1
|
| 124 |
+
# TTS_BATCH_SIZE=2
|
| 125 |
+
|
| 126 |
+
# VOYAGE AI
|
| 127 |
+
# VOYAGE_API_KEY=
|
| 128 |
+
|
| 129 |
+
# OPENAI COMPATIBLE ENDPOINTS
|
| 130 |
+
# Generic configuration (applies to all modalities: language, embedding, STT, TTS)
|
| 131 |
+
# OPENAI_COMPATIBLE_BASE_URL=http://localhost:1234/v1
|
| 132 |
+
# OPENAI_COMPATIBLE_API_KEY=
|
| 133 |
+
|
| 134 |
+
# Mode-specific configuration (overrides generic if set)
|
| 135 |
+
# Use these when you want different endpoints for different capabilities
|
| 136 |
+
# OPENAI_COMPATIBLE_BASE_URL_LLM=http://localhost:1234/v1
|
| 137 |
+
# OPENAI_COMPATIBLE_API_KEY_LLM=
|
| 138 |
+
# OPENAI_COMPATIBLE_BASE_URL_EMBEDDING=http://localhost:8080/v1
|
| 139 |
+
# OPENAI_COMPATIBLE_API_KEY_EMBEDDING=
|
| 140 |
+
# OPENAI_COMPATIBLE_BASE_URL_STT=http://localhost:9000/v1
|
| 141 |
+
# OPENAI_COMPATIBLE_API_KEY_STT=
|
| 142 |
+
# OPENAI_COMPATIBLE_BASE_URL_TTS=http://localhost:9000/v1
|
| 143 |
+
# OPENAI_COMPATIBLE_API_KEY_TTS=
|
| 144 |
+
|
| 145 |
+
# AZURE OPENAI
|
| 146 |
+
# AZURE_OPENAI_API_KEY=
|
| 147 |
+
# AZURE_OPENAI_ENDPOINT=
|
| 148 |
+
# AZURE_OPENAI_API_VERSION="2024-12-01-preview"
|
| 149 |
+
# AZURE_OPENAI_DEPLOYMENT_NAME=
|
| 150 |
+
|
| 151 |
+
# USE THIS IF YOU WANT TO DEBUG THE APP ON LANGSMITH
|
| 152 |
+
# LANGCHAIN_TRACING_V2=true
|
| 153 |
+
# LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
|
| 154 |
+
# LANGCHAIN_API_KEY=
|
| 155 |
+
# LANGCHAIN_PROJECT="Open Notebook"
|
| 156 |
+
|
| 157 |
+
# CONNECTION DETAILS FOR YOUR SURREAL DB
|
| 158 |
+
# New format (preferred) - WebSocket URL
|
| 159 |
+
SURREAL_URL="ws://surrealdb/rpc:8000"
|
| 160 |
+
SURREAL_USER="root"
|
| 161 |
+
SURREAL_PASSWORD="root"
|
| 162 |
+
SURREAL_NAMESPACE="open_notebook"
|
| 163 |
+
SURREAL_DATABASE="staging"
|
| 164 |
+
|
| 165 |
+
# OPEN_NOTEBOOK_PASSWORD=
|
| 166 |
+
|
| 167 |
+
# FIRECRAWL - Get a key at https://firecrawl.dev/
|
| 168 |
+
FIRECRAWL_API_KEY=
|
| 169 |
+
|
| 170 |
+
# JINA - Get a key at https://jina.ai/
|
| 171 |
+
JINA_API_KEY=
|
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
logo.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
prompts/patterns/user/
|
| 3 |
+
/notebooks/
|
| 4 |
+
data/
|
| 5 |
+
.uploads/
|
| 6 |
+
sqlite-db/
|
| 7 |
+
surreal-data/
|
| 8 |
+
docker.env
|
| 9 |
+
!setup_guide/docker.env
|
| 10 |
+
notebook_data/
|
| 11 |
+
# Python-specific
|
| 12 |
+
*.py[cod]
|
| 13 |
+
__pycache__/
|
| 14 |
+
*.so
|
| 15 |
+
todo.md
|
| 16 |
+
temp/
|
| 17 |
+
google-credentials.json
|
| 18 |
+
# Distribution / packaging
|
| 19 |
+
.Python
|
| 20 |
+
build/
|
| 21 |
+
develop-eggs/
|
| 22 |
+
dist/
|
| 23 |
+
downloads/
|
| 24 |
+
eggs/
|
| 25 |
+
.eggs/
|
| 26 |
+
/lib/
|
| 27 |
+
/lib64/
|
| 28 |
+
parts/
|
| 29 |
+
sdist/
|
| 30 |
+
var/
|
| 31 |
+
wheels/
|
| 32 |
+
share/python-wheels/
|
| 33 |
+
*.egg-info/
|
| 34 |
+
.installed.cfg
|
| 35 |
+
*.egg
|
| 36 |
+
|
| 37 |
+
# PyInstaller
|
| 38 |
+
*.manifest
|
| 39 |
+
*.spec
|
| 40 |
+
|
| 41 |
+
# Installer logs
|
| 42 |
+
pip-log.txt
|
| 43 |
+
pip-delete-this-directory.txt
|
| 44 |
+
|
| 45 |
+
# Unit test / coverage reports
|
| 46 |
+
htmlcov/
|
| 47 |
+
.tox/
|
| 48 |
+
.nox/
|
| 49 |
+
.coverage
|
| 50 |
+
.coverage.*
|
| 51 |
+
.cache
|
| 52 |
+
nosetests.xml
|
| 53 |
+
coverage.xml
|
| 54 |
+
*.cover
|
| 55 |
+
*.py,cover
|
| 56 |
+
.hypothesis/
|
| 57 |
+
.pytest_cache/
|
| 58 |
+
|
| 59 |
+
# Jupyter Notebook
|
| 60 |
+
.ipynb_checkpoints
|
| 61 |
+
|
| 62 |
+
# IPython
|
| 63 |
+
profile_default/
|
| 64 |
+
ipython_config.py
|
| 65 |
+
|
| 66 |
+
# Environments
|
| 67 |
+
.env
|
| 68 |
+
.venv
|
| 69 |
+
env/
|
| 70 |
+
venv/
|
| 71 |
+
ENV/
|
| 72 |
+
env.bak/
|
| 73 |
+
venv.bak/
|
| 74 |
+
|
| 75 |
+
# PyCharm
|
| 76 |
+
.idea/
|
| 77 |
+
|
| 78 |
+
# VS Code
|
| 79 |
+
.vscode/
|
| 80 |
+
|
| 81 |
+
# Spyder project settings
|
| 82 |
+
.spyderproject
|
| 83 |
+
.spyproject
|
| 84 |
+
|
| 85 |
+
# Rope project settings
|
| 86 |
+
.ropeproject
|
| 87 |
+
|
| 88 |
+
# mkdocs documentation
|
| 89 |
+
/site
|
| 90 |
+
|
| 91 |
+
# mypy
|
| 92 |
+
.mypy_cache/
|
| 93 |
+
.dmypy.json
|
| 94 |
+
dmypy.json
|
| 95 |
+
|
| 96 |
+
# Pyre type checker
|
| 97 |
+
.pyre/
|
| 98 |
+
|
| 99 |
+
# pytype static type analyzer
|
| 100 |
+
.pytype/
|
| 101 |
+
|
| 102 |
+
# Cython debug symbols
|
| 103 |
+
cython_debug/
|
| 104 |
+
|
| 105 |
+
# macOS
|
| 106 |
+
.DS_Store
|
| 107 |
+
|
| 108 |
+
# Windows
|
| 109 |
+
Thumbs.db
|
| 110 |
+
ehthumbs.db
|
| 111 |
+
desktop.ini
|
| 112 |
+
|
| 113 |
+
# Linux
|
| 114 |
+
*~
|
| 115 |
+
|
| 116 |
+
# Log files
|
| 117 |
+
*.log
|
| 118 |
+
|
| 119 |
+
# Database files
|
| 120 |
+
*.db
|
| 121 |
+
*.sqlite3
|
| 122 |
+
|
| 123 |
+
.quarentena
|
| 124 |
+
|
| 125 |
+
claude-logs/
|
| 126 |
+
.claude/sessions
|
| 127 |
+
**/claude-logs
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
docs/custom_gpt
|
| 131 |
+
doc_exports/
|
| 132 |
+
|
| 133 |
+
specs/
|
| 134 |
+
.claude
|
| 135 |
+
|
| 136 |
+
.playwright-mcp/
|
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.12
|
CLAUDE.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
We have a good amount of documentation on this project on the ./docs folder. Please read through them when necessary, and always review the docs/index.md file before starting a new feature so you know at least which docs are available.
|
| 3 |
+
|
CONFIGURATION.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Configuration Guide
|
| 2 |
+
|
| 3 |
+
## API Connection Configuration
|
| 4 |
+
|
| 5 |
+
Starting from version 1.0.0-alpha, Open Notebook uses a simplified API connection system that automatically configures itself based on your deployment environment.
|
| 6 |
+
|
| 7 |
+
### How It Works
|
| 8 |
+
|
| 9 |
+
The frontend automatically discovers the API location at runtime by analyzing the incoming HTTP request. This eliminates the need for complex network configurations and works for both Docker deployment modes:
|
| 10 |
+
- Multi-container (docker-compose with separate SurrealDB)
|
| 11 |
+
- Single-container (all services in one container)
|
| 12 |
+
|
| 13 |
+
**Auto-detection logic:**
|
| 14 |
+
1. If `API_URL` environment variable is set → use it (explicit override)
|
| 15 |
+
2. Otherwise, detect from the HTTP request:
|
| 16 |
+
- Uses the same hostname you're accessing the frontend from
|
| 17 |
+
- Automatically changes port to 5055 (API port)
|
| 18 |
+
- Respects `X-Forwarded-Proto` header for reverse proxy setups
|
| 19 |
+
3. Falls back to `http://localhost:5055` if detection fails
|
| 20 |
+
|
| 21 |
+
**Examples:**
|
| 22 |
+
- Access frontend at `http://localhost:8502` → API at `http://localhost:5055` ✅
|
| 23 |
+
- Access frontend at `http://10.20.30.20:8502` → API at `http://10.20.30.20:5055` ✅
|
| 24 |
+
- Access frontend at `http://my-server:8502` → API at `http://my-server:5055` ✅
|
| 25 |
+
|
| 26 |
+
**No configuration needed** for most deployments!
|
| 27 |
+
|
| 28 |
+
### Custom Configuration
|
| 29 |
+
|
| 30 |
+
If you need to change the API URL (e.g., running on a different host, port, or domain), you can configure it using the `API_URL` environment variable.
|
| 31 |
+
|
| 32 |
+
#### Option 1: Using docker-compose (Recommended)
|
| 33 |
+
|
| 34 |
+
Edit your `docker.env` file:
|
| 35 |
+
|
| 36 |
+
```env
|
| 37 |
+
API_URL=http://your-server-ip:5055
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
Or add it to your `docker-compose.yml`:
|
| 41 |
+
|
| 42 |
+
```yaml
|
| 43 |
+
services:
|
| 44 |
+
open_notebook:
|
| 45 |
+
image: lfnovo/open_notebook:v1-latest
|
| 46 |
+
ports:
|
| 47 |
+
- "8502:8502"
|
| 48 |
+
- "5055:5055" # API port must be exposed
|
| 49 |
+
environment:
|
| 50 |
+
- API_URL=http://your-server-ip:5055
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
#### Option 2: Using docker run
|
| 54 |
+
|
| 55 |
+
```bash
|
| 56 |
+
docker run -e API_URL=http://your-server-ip:5055 \
|
| 57 |
+
-p 8502:8502 \
|
| 58 |
+
-p 5055:5055 \
|
| 59 |
+
lfnovo/open_notebook:v1-latest-single
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
### Important Notes
|
| 63 |
+
|
| 64 |
+
1. **Port 5055 must be exposed**: The browser needs direct access to the API, so port 5055 must be mapped in your Docker configuration.
|
| 65 |
+
|
| 66 |
+
2. **Use the externally accessible URL**: The `API_URL` should be the URL that a browser can reach, not internal Docker networking addresses.
|
| 67 |
+
|
| 68 |
+
3. **Protocol matters**: Use `http://` for local deployments, `https://` if you've set up SSL.
|
| 69 |
+
|
| 70 |
+
### Examples
|
| 71 |
+
|
| 72 |
+
#### Running on a different host
|
| 73 |
+
```env
|
| 74 |
+
API_URL=http://192.168.1.100:5055
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
#### Running on a custom domain with SSL
|
| 78 |
+
```env
|
| 79 |
+
API_URL=https://notebook.example.com/api
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
#### Running on a custom port
|
| 83 |
+
```env
|
| 84 |
+
API_URL=http://localhost:3055
|
| 85 |
+
```
|
| 86 |
+
(Remember to update the port mapping in docker-compose accordingly)
|
| 87 |
+
|
| 88 |
+
### Troubleshooting
|
| 89 |
+
|
| 90 |
+
**"Unable to connect to server" error on login:**
|
| 91 |
+
1. Verify port 5055 is exposed in your Docker configuration
|
| 92 |
+
2. Check that `API_URL` matches the URL your browser can access
|
| 93 |
+
3. Try accessing `http://localhost:5055/health` directly in your browser
|
| 94 |
+
4. If that fails, the API isn't running or port isn't exposed
|
| 95 |
+
|
| 96 |
+
**API works but frontend doesn't connect:**
|
| 97 |
+
1. Check browser console for CORS errors
|
| 98 |
+
2. Verify `API_URL` is set correctly
|
| 99 |
+
3. Make sure you're using the same protocol (http/https) throughout
|
| 100 |
+
|
| 101 |
+
### Migration from Previous Versions
|
| 102 |
+
|
| 103 |
+
If you were previously exposing port 5055 manually or had custom configurations, you may need to:
|
| 104 |
+
1. Update your `docker.env` or environment variables to include `API_URL`
|
| 105 |
+
2. Ensure port 5055 is exposed in your docker-compose.yml (it's now required)
|
| 106 |
+
3. Remove any custom Next.js configuration or environment variables you may have added
|
| 107 |
+
|
| 108 |
+
The default configuration will work for most users without any changes.
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to Open Notebook
|
| 2 |
+
|
| 3 |
+
First off, thank you for considering contributing to Open Notebook! What makes open source great is the fact that we can work together and accomplish things we would never do on our own. All suggestions are welcome.
|
| 4 |
+
|
| 5 |
+
## Code of Conduct
|
| 6 |
+
|
| 7 |
+
By participating in this project, you are expected to uphold our Code of Conduct (to be created separately).
|
| 8 |
+
|
| 9 |
+
## How Can I Contribute?
|
| 10 |
+
|
| 11 |
+
### Reporting Bugs
|
| 12 |
+
|
| 13 |
+
- Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/yourusername/open-notebook/issues).
|
| 14 |
+
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/yourusername/open-notebook/issues/new). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
|
| 15 |
+
|
| 16 |
+
### Suggesting Enhancements
|
| 17 |
+
|
| 18 |
+
- Open a new issue with a clear title and detailed description of the suggested enhancement.
|
| 19 |
+
- Provide any relevant examples or mockups if applicable.
|
| 20 |
+
|
| 21 |
+
### Pull Requests
|
| 22 |
+
|
| 23 |
+
1. Fork the repo and create your branch from `main`.
|
| 24 |
+
2. If you've added code that should be tested, add tests.
|
| 25 |
+
3. Ensure the test suite passes.
|
| 26 |
+
4. Make sure your code lints.
|
| 27 |
+
5. Issue that pull request!
|
| 28 |
+
|
| 29 |
+
## Styleguides
|
| 30 |
+
|
| 31 |
+
### Git Commit Messages
|
| 32 |
+
|
| 33 |
+
- Use the present tense ("Add feature" not "Added feature")
|
| 34 |
+
- Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
|
| 35 |
+
- Limit the first line to 72 characters or less
|
| 36 |
+
- Reference issues and pull requests liberally after the first line
|
| 37 |
+
|
| 38 |
+
### Python Styleguide
|
| 39 |
+
|
| 40 |
+
- Follow PEP 8 guidelines
|
| 41 |
+
- Use type hints where possible
|
| 42 |
+
- Write docstrings for all functions, classes, and modules
|
| 43 |
+
|
| 44 |
+
### Documentation Styleguide
|
| 45 |
+
|
| 46 |
+
- Use Markdown for documentation files
|
| 47 |
+
- Reference functions and classes appropriately
|
| 48 |
+
|
| 49 |
+
## Additional Notes
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
Thank you for contributing to Open Notebook!
|
Dockerfile
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Build stage
|
| 2 |
+
FROM python:3.12-slim-bookworm AS builder
|
| 3 |
+
|
| 4 |
+
# Install uv using the official method
|
| 5 |
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
| 6 |
+
|
| 7 |
+
# Install system dependencies required for building certain Python packages
|
| 8 |
+
# Add Node.js 20.x LTS for building frontend
|
| 9 |
+
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
| 10 |
+
gcc g++ git make \
|
| 11 |
+
curl \
|
| 12 |
+
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 13 |
+
&& apt-get install -y nodejs \
|
| 14 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
+
|
| 16 |
+
# Set build optimization environment variables
|
| 17 |
+
ENV MAKEFLAGS="-j$(nproc)"
|
| 18 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 19 |
+
ENV PYTHONUNBUFFERED=1
|
| 20 |
+
ENV UV_COMPILE_BYTECODE=1
|
| 21 |
+
ENV UV_LINK_MODE=copy
|
| 22 |
+
|
| 23 |
+
# Set the working directory in the container to /app
|
| 24 |
+
WORKDIR /app
|
| 25 |
+
|
| 26 |
+
# Copy dependency files and minimal package structure first for better layer caching
|
| 27 |
+
COPY pyproject.toml uv.lock ./
|
| 28 |
+
COPY open_notebook/__init__.py ./open_notebook/__init__.py
|
| 29 |
+
|
| 30 |
+
# Install dependencies with optimizations (this layer will be cached unless dependencies change)
|
| 31 |
+
RUN uv sync --frozen --no-dev
|
| 32 |
+
|
| 33 |
+
# Copy the rest of the application code
|
| 34 |
+
COPY . /app
|
| 35 |
+
|
| 36 |
+
# Install frontend dependencies and build
|
| 37 |
+
WORKDIR /app/frontend
|
| 38 |
+
RUN npm ci
|
| 39 |
+
RUN npm run build
|
| 40 |
+
|
| 41 |
+
# Return to app root
|
| 42 |
+
WORKDIR /app
|
| 43 |
+
|
| 44 |
+
# Runtime stage
|
| 45 |
+
FROM python:3.12-slim-bookworm AS runtime
|
| 46 |
+
|
| 47 |
+
# Install only runtime system dependencies (no build tools)
|
| 48 |
+
# Add Node.js 20.x LTS for running frontend
|
| 49 |
+
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
| 50 |
+
ffmpeg \
|
| 51 |
+
supervisor \
|
| 52 |
+
curl \
|
| 53 |
+
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 54 |
+
&& apt-get install -y nodejs \
|
| 55 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 56 |
+
|
| 57 |
+
# Install uv using the official method
|
| 58 |
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
| 59 |
+
|
| 60 |
+
# Set the working directory in the container to /app
|
| 61 |
+
WORKDIR /app
|
| 62 |
+
|
| 63 |
+
# Copy the virtual environment from builder stage
|
| 64 |
+
COPY --from=builder /app/.venv /app/.venv
|
| 65 |
+
|
| 66 |
+
# Copy the application code
|
| 67 |
+
COPY --from=builder /app /app
|
| 68 |
+
|
| 69 |
+
# Copy built frontend from builder stage
|
| 70 |
+
COPY --from=builder /app/frontend/.next/standalone /app/frontend/
|
| 71 |
+
COPY --from=builder /app/frontend/.next/static /app/frontend/.next/static
|
| 72 |
+
COPY --from=builder /app/frontend/public /app/frontend/public
|
| 73 |
+
|
| 74 |
+
# Expose ports for Frontend and API
|
| 75 |
+
EXPOSE 8502 5055
|
| 76 |
+
|
| 77 |
+
RUN mkdir -p /app/data
|
| 78 |
+
|
| 79 |
+
# Copy supervisord configuration
|
| 80 |
+
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
| 81 |
+
|
| 82 |
+
# Create log directories
|
| 83 |
+
RUN mkdir -p /var/log/supervisor
|
| 84 |
+
|
| 85 |
+
# Runtime API URL Configuration
|
| 86 |
+
# The API_URL environment variable can be set at container runtime to configure
|
| 87 |
+
# where the frontend should connect to the API. This allows the same Docker image
|
| 88 |
+
# to work in different deployment scenarios without rebuilding.
|
| 89 |
+
#
|
| 90 |
+
# If not set, the system will auto-detect based on incoming requests.
|
| 91 |
+
# Set API_URL when using reverse proxies or custom domains.
|
| 92 |
+
#
|
| 93 |
+
# Example: docker run -e API_URL=https://your-domain.com/api ...
|
| 94 |
+
|
| 95 |
+
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
Dockerfile.single
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Build stage
|
| 2 |
+
FROM python:3.12-slim-bookworm AS builder
|
| 3 |
+
|
| 4 |
+
# Install uv using the official method
|
| 5 |
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
| 6 |
+
|
| 7 |
+
# Install system dependencies required for building certain Python packages
|
| 8 |
+
# Add Node.js 20.x LTS for building frontend
|
| 9 |
+
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
| 10 |
+
gcc g++ git make \
|
| 11 |
+
curl \
|
| 12 |
+
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 13 |
+
&& apt-get install -y nodejs \
|
| 14 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 15 |
+
|
| 16 |
+
# Set build optimization environment variables
|
| 17 |
+
ENV MAKEFLAGS="-j$(nproc)"
|
| 18 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 19 |
+
ENV PYTHONUNBUFFERED=1
|
| 20 |
+
ENV UV_COMPILE_BYTECODE=1
|
| 21 |
+
ENV UV_LINK_MODE=copy
|
| 22 |
+
|
| 23 |
+
# Set the working directory in the container to /app
|
| 24 |
+
WORKDIR /app
|
| 25 |
+
|
| 26 |
+
# Copy dependency files and minimal package structure first for better layer caching
|
| 27 |
+
COPY pyproject.toml uv.lock ./
|
| 28 |
+
COPY open_notebook/__init__.py ./open_notebook/__init__.py
|
| 29 |
+
|
| 30 |
+
# Install dependencies with optimizations (this layer will be cached unless dependencies change)
|
| 31 |
+
RUN uv sync --frozen --no-dev
|
| 32 |
+
|
| 33 |
+
# Copy the rest of the application code
|
| 34 |
+
COPY . /app
|
| 35 |
+
|
| 36 |
+
# Install frontend dependencies and build
|
| 37 |
+
WORKDIR /app/frontend
|
| 38 |
+
RUN npm ci
|
| 39 |
+
RUN npm run build
|
| 40 |
+
|
| 41 |
+
# Return to app root
|
| 42 |
+
WORKDIR /app
|
| 43 |
+
|
| 44 |
+
# Runtime stage
|
| 45 |
+
FROM python:3.12-slim-bookworm AS runtime
|
| 46 |
+
|
| 47 |
+
# Install runtime system dependencies including curl for SurrealDB installation
|
| 48 |
+
# Add Node.js 20.x LTS for running frontend
|
| 49 |
+
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
|
| 50 |
+
ffmpeg \
|
| 51 |
+
supervisor \
|
| 52 |
+
curl \
|
| 53 |
+
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
| 54 |
+
&& apt-get install -y nodejs \
|
| 55 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 56 |
+
|
| 57 |
+
# Install SurrealDB
|
| 58 |
+
RUN curl --proto '=https' --tlsv1.2 -sSf https://install.surrealdb.com | sh
|
| 59 |
+
|
| 60 |
+
# Install uv using the official method
|
| 61 |
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
| 62 |
+
|
| 63 |
+
# Set the working directory in the container to /app
|
| 64 |
+
WORKDIR /app
|
| 65 |
+
|
| 66 |
+
# Copy the virtual environment from builder stage
|
| 67 |
+
COPY --from=builder /app/.venv /app/.venv
|
| 68 |
+
|
| 69 |
+
# Copy the application code
|
| 70 |
+
COPY --from=builder /app /app
|
| 71 |
+
|
| 72 |
+
# Copy built frontend from builder stage
|
| 73 |
+
COPY --from=builder /app/frontend/.next/standalone /app/frontend/
|
| 74 |
+
COPY --from=builder /app/frontend/.next/static /app/frontend/.next/static
|
| 75 |
+
COPY --from=builder /app/frontend/public /app/frontend/public
|
| 76 |
+
|
| 77 |
+
# Create directories for data persistence
|
| 78 |
+
RUN mkdir -p /app/data /mydata
|
| 79 |
+
|
| 80 |
+
# Expose ports for Frontend and API
|
| 81 |
+
EXPOSE 8502 5055
|
| 82 |
+
|
| 83 |
+
# Copy single-container supervisord configuration
|
| 84 |
+
COPY supervisord.single.conf /etc/supervisor/conf.d/supervisord.conf
|
| 85 |
+
|
| 86 |
+
# Create log directories
|
| 87 |
+
RUN mkdir -p /var/log/supervisor
|
| 88 |
+
|
| 89 |
+
# Runtime API URL Configuration
|
| 90 |
+
# The API_URL environment variable can be set at container runtime to configure
|
| 91 |
+
# where the frontend should connect to the API. This allows the same Docker image
|
| 92 |
+
# to work in different deployment scenarios without rebuilding.
|
| 93 |
+
#
|
| 94 |
+
# If not set, the system will auto-detect based on incoming requests.
|
| 95 |
+
# Set API_URL when using reverse proxies or custom domains.
|
| 96 |
+
#
|
| 97 |
+
# Example: docker run -e API_URL=https://your-domain.com/api ...
|
| 98 |
+
|
| 99 |
+
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
Copyright (c) 2024 Luis Novo
|
| 3 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 4 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 5 |
+
in the Software without restriction, including without limitation the rights
|
| 6 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 7 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 8 |
+
furnished to do so, subject to the following conditions:
|
| 9 |
+
The above copyright notice and this permission notice shall be included in all
|
| 10 |
+
copies or substantial portions of the Software.
|
| 11 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 12 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 13 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 14 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 15 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 16 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 17 |
+
SOFTWARE.
|
MIGRATION.md
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Migration Guide: Streamlit to React/Next.js Frontend
|
| 2 |
+
|
| 3 |
+
**Version**: 1.0.0
|
| 4 |
+
**Last Updated**: October 2025
|
| 5 |
+
|
| 6 |
+
This guide helps existing Open Notebook users migrate from the legacy Streamlit frontend to the new React/Next.js frontend.
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## ⚠️ Breaking Changes in v1.0
|
| 11 |
+
|
| 12 |
+
Open Notebook v1.0 introduces breaking changes that require manual migration. Please read this section carefully before upgrading.
|
| 13 |
+
|
| 14 |
+
### Docker Tag Changes
|
| 15 |
+
|
| 16 |
+
**The "latest" tag is now frozen** at the last Streamlit version. Starting with v1.0, we use versioned tags to prevent unexpected breaking changes:
|
| 17 |
+
|
| 18 |
+
- **`latest`** and **`latest-single`** → FROZEN at Streamlit version (will not update)
|
| 19 |
+
- **`v1-latest`** and **`v1-latest-single`** → NEW tags for v1.x releases (recommended)
|
| 20 |
+
- **`X.Y.Z`** and **`X.Y.Z-single`** → Specific version tags (unchanged)
|
| 21 |
+
|
| 22 |
+
**Why this change?**
|
| 23 |
+
The v1.0 release brings significant architectural changes (Streamlit → React/Next.js frontend). Freezing the "latest" tag prevents existing deployments from breaking unexpectedly, while the new "v1-latest" tag allows users to explicitly opt into the v1 architecture.
|
| 24 |
+
|
| 25 |
+
### Quick Migration for Docker Users
|
| 26 |
+
|
| 27 |
+
If you're currently using `latest` or `latest-single`, you need to:
|
| 28 |
+
|
| 29 |
+
1. **Update your docker-compose.yml or docker run command**:
|
| 30 |
+
```yaml
|
| 31 |
+
# Before:
|
| 32 |
+
image: lfnovo/open_notebook:latest-single
|
| 33 |
+
|
| 34 |
+
# After (recommended):
|
| 35 |
+
image: lfnovo/open_notebook:v1-latest-single
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
2. **Expose port 5055** for the API (required in v1):
|
| 39 |
+
```yaml
|
| 40 |
+
ports:
|
| 41 |
+
- "8502:8502" # Frontend
|
| 42 |
+
- "5055:5055" # API (NEW - required)
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
3. **Verify API connectivity** after upgrade:
|
| 46 |
+
```bash
|
| 47 |
+
curl http://localhost:5055/api/config
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
### API Connectivity (Port 5055)
|
| 51 |
+
|
| 52 |
+
**Important:** v1.0 requires port 5055 to be exposed to your host machine so the frontend can communicate with the API.
|
| 53 |
+
|
| 54 |
+
**Auto-Detection:** The Next.js frontend automatically detects the API URL:
|
| 55 |
+
- If you access the frontend at `http://localhost:8502`, it uses `http://localhost:5055`
|
| 56 |
+
- If you access the frontend at `http://192.168.1.100:8502`, it uses `http://192.168.1.100:5055`
|
| 57 |
+
- If you access the frontend at `http://my-server:8502`, it uses `http://my-server:5055`
|
| 58 |
+
|
| 59 |
+
**Manual Override:** If auto-detection doesn't work (e.g., reverse proxy, complex networking), set the `API_URL` environment variable:
|
| 60 |
+
|
| 61 |
+
```bash
|
| 62 |
+
# Docker run example
|
| 63 |
+
docker run -d \
|
| 64 |
+
--name open-notebook \
|
| 65 |
+
-p 8502:8502 -p 5055:5055 \
|
| 66 |
+
-e API_URL=http://my-custom-api:5055 \
|
| 67 |
+
-v ./notebook_data:/app/data \
|
| 68 |
+
-v ./surreal_data:/mydata \
|
| 69 |
+
lfnovo/open_notebook:v1-latest-single
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
```yaml
|
| 73 |
+
# docker-compose.yml example
|
| 74 |
+
services:
|
| 75 |
+
open_notebook:
|
| 76 |
+
image: lfnovo/open_notebook:v1-latest-single
|
| 77 |
+
ports:
|
| 78 |
+
- "8502:8502"
|
| 79 |
+
- "5055:5055"
|
| 80 |
+
environment:
|
| 81 |
+
- API_URL=http://my-custom-api:5055
|
| 82 |
+
volumes:
|
| 83 |
+
- ./notebook_data:/app/data
|
| 84 |
+
- ./surreal_data:/mydata
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### Health Check
|
| 88 |
+
|
| 89 |
+
Verify your API is accessible with:
|
| 90 |
+
|
| 91 |
+
```bash
|
| 92 |
+
# Local deployment
|
| 93 |
+
curl http://localhost:5055/api/config
|
| 94 |
+
|
| 95 |
+
# Remote deployment
|
| 96 |
+
curl http://your-server-ip:5055/api/config
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
Expected response:
|
| 100 |
+
```json
|
| 101 |
+
{
|
| 102 |
+
"version": "1.0.0",
|
| 103 |
+
"latestVersion": "1.0.0",
|
| 104 |
+
"hasUpdate": false,
|
| 105 |
+
"dbStatus": "online"
|
| 106 |
+
}
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
Note: The API URL is now auto-detected by the frontend from the hostname you're accessing, so `/api/config` no longer returns `apiUrl`.
|
| 110 |
+
|
| 111 |
+
### Troubleshooting
|
| 112 |
+
|
| 113 |
+
**Problem:** Frontend shows "Cannot connect to API" error
|
| 114 |
+
- **Check:** Is port 5055 exposed? Run `docker ps` and verify port mapping
|
| 115 |
+
- **Check:** Can you reach the API? Run `curl http://localhost:5055/api/config`
|
| 116 |
+
- **Solution:** If using custom networking, set `API_URL` environment variable
|
| 117 |
+
|
| 118 |
+
**Problem:** Auto-detection uses wrong hostname
|
| 119 |
+
- **Example:** Frontend at `http://internal-hostname:8502` but API should use `http://public-hostname:5055`
|
| 120 |
+
- **Solution:** Set `API_URL=http://public-hostname:5055` environment variable
|
| 121 |
+
|
| 122 |
+
**Problem:** Still running the old Streamlit version after `docker pull`
|
| 123 |
+
- **Check:** Are you using the "latest" tag? It's frozen at Streamlit version
|
| 124 |
+
- **Solution:** Update to `v1-latest` or `v1-latest-single` tag
|
| 125 |
+
|
| 126 |
+
---
|
| 127 |
+
|
| 128 |
+
## What Changed
|
| 129 |
+
|
| 130 |
+
Open Notebook has migrated from a Streamlit-based frontend to a modern React/Next.js application. This brings significant improvements in performance, user experience, and maintainability.
|
| 131 |
+
|
| 132 |
+
### Key Changes
|
| 133 |
+
|
| 134 |
+
| Aspect | Before (Streamlit) | After (React/Next.js) |
|
| 135 |
+
|--------|-------------------|----------------------|
|
| 136 |
+
| **Frontend Framework** | Streamlit | Next.js 15 + React 18 |
|
| 137 |
+
| **UI Components** | Streamlit widgets | shadcn/ui + Radix UI |
|
| 138 |
+
| **Frontend Port** | 8502 | 8502 (unchanged) |
|
| 139 |
+
| **API Port** | 5055 | 5055 (unchanged) |
|
| 140 |
+
| **Navigation** | Sidebar with emoji icons | Clean sidebar navigation |
|
| 141 |
+
| **Performance** | Server-side rendering | Client-side React with API calls |
|
| 142 |
+
| **Customization** | Limited | Highly customizable |
|
| 143 |
+
|
| 144 |
+
### What Stayed the Same
|
| 145 |
+
|
| 146 |
+
- **Core functionality**: All features remain available
|
| 147 |
+
- **API backend**: FastAPI backend unchanged
|
| 148 |
+
- **Database**: SurrealDB unchanged
|
| 149 |
+
- **Data format**: No data migration needed
|
| 150 |
+
- **Configuration**: Same environment variables
|
| 151 |
+
- **Docker deployment**: Same ports and setup
|
| 152 |
+
|
| 153 |
+
## Migration Paths
|
| 154 |
+
|
| 155 |
+
### Path 1: Docker Users (Recommended)
|
| 156 |
+
|
| 157 |
+
If you're running Open Notebook via Docker, migration is automatic:
|
| 158 |
+
|
| 159 |
+
1. **Stop the current version**:
|
| 160 |
+
```bash
|
| 161 |
+
docker-compose down
|
| 162 |
+
```
|
| 163 |
+
|
| 164 |
+
2. **Update to the latest image**:
|
| 165 |
+
```bash
|
| 166 |
+
# Update docker-compose.yml to use v1-latest
|
| 167 |
+
# Change from:
|
| 168 |
+
image: lfnovo/open_notebook:latest-single
|
| 169 |
+
# To:
|
| 170 |
+
image: lfnovo/open_notebook:v1-latest-single
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
3. **Start the new version**:
|
| 174 |
+
```bash
|
| 175 |
+
docker-compose pull
|
| 176 |
+
docker-compose up -d
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
4. **Access the new frontend**:
|
| 180 |
+
- Frontend: http://localhost:8502 (new React UI)
|
| 181 |
+
- API Docs: http://localhost:5055/docs
|
| 182 |
+
|
| 183 |
+
**Your data is automatically preserved!** All notebooks, sources, and notes carry over seamlessly.
|
| 184 |
+
|
| 185 |
+
### Path 2: Source Code Users
|
| 186 |
+
|
| 187 |
+
If you're running from source code:
|
| 188 |
+
|
| 189 |
+
1. **Pull the latest code**:
|
| 190 |
+
```bash
|
| 191 |
+
git pull origin main
|
| 192 |
+
```
|
| 193 |
+
|
| 194 |
+
2. **Install frontend dependencies**:
|
| 195 |
+
```bash
|
| 196 |
+
cd frontend
|
| 197 |
+
npm install
|
| 198 |
+
cd ..
|
| 199 |
+
```
|
| 200 |
+
|
| 201 |
+
3. **Update Python dependencies**:
|
| 202 |
+
```bash
|
| 203 |
+
uv sync
|
| 204 |
+
```
|
| 205 |
+
|
| 206 |
+
4. **Start services** (3 terminals):
|
| 207 |
+
```bash
|
| 208 |
+
# Terminal 1: Database
|
| 209 |
+
make database
|
| 210 |
+
|
| 211 |
+
# Terminal 2: API
|
| 212 |
+
uv run python api/main.py
|
| 213 |
+
|
| 214 |
+
# Terminal 3: Frontend (NEW)
|
| 215 |
+
cd frontend && npm run dev
|
| 216 |
+
```
|
| 217 |
+
|
| 218 |
+
5. **Access the application**:
|
| 219 |
+
- Frontend: http://localhost:8502
|
| 220 |
+
- API: http://localhost:5055
|
| 221 |
+
|
| 222 |
+
## Breaking Changes
|
| 223 |
+
|
| 224 |
+
### Removed Features
|
| 225 |
+
|
| 226 |
+
The following Streamlit-specific features are no longer available:
|
| 227 |
+
|
| 228 |
+
- **Streamlit cache**: Replaced with React Query caching
|
| 229 |
+
- **Streamlit session state**: Replaced with React state management
|
| 230 |
+
- **Direct file access via Streamlit**: Use API endpoints instead
|
| 231 |
+
|
| 232 |
+
### Changed Navigation
|
| 233 |
+
|
| 234 |
+
Navigation paths have been simplified:
|
| 235 |
+
|
| 236 |
+
| Old Path | New Path |
|
| 237 |
+
|----------|----------|
|
| 238 |
+
| Settings → Models | Models |
|
| 239 |
+
| Settings → Advanced | Advanced |
|
| 240 |
+
| Other paths | (Same but cleaner navigation) |
|
| 241 |
+
|
| 242 |
+
### API Changes
|
| 243 |
+
|
| 244 |
+
**No breaking API changes!** The REST API remains fully backward compatible.
|
| 245 |
+
|
| 246 |
+
## New Features in React Version
|
| 247 |
+
|
| 248 |
+
The React frontend brings several improvements:
|
| 249 |
+
|
| 250 |
+
### Performance
|
| 251 |
+
- **Faster page loads**: Client-side rendering with React
|
| 252 |
+
- **Better caching**: React Query for intelligent data caching
|
| 253 |
+
- **Optimized builds**: Next.js automatic code splitting
|
| 254 |
+
|
| 255 |
+
### User Experience
|
| 256 |
+
- **Modern UI**: Clean, professional interface with shadcn/ui
|
| 257 |
+
- **Responsive design**: Better mobile and tablet support
|
| 258 |
+
- **Keyboard shortcuts**: Improved keyboard navigation
|
| 259 |
+
- **Real-time updates**: Better WebSocket support
|
| 260 |
+
|
| 261 |
+
### Developer Experience
|
| 262 |
+
- **TypeScript**: Full type safety
|
| 263 |
+
- **Component library**: Reusable UI components
|
| 264 |
+
- **Hot reload**: Instant updates during development
|
| 265 |
+
- **Testing**: Better test infrastructure
|
| 266 |
+
|
| 267 |
+
## Troubleshooting
|
| 268 |
+
|
| 269 |
+
### Issue: Can't access the frontend
|
| 270 |
+
|
| 271 |
+
**Solution**:
|
| 272 |
+
```bash
|
| 273 |
+
# Check if services are running
|
| 274 |
+
docker-compose ps
|
| 275 |
+
|
| 276 |
+
# Check logs
|
| 277 |
+
docker-compose logs open_notebook
|
| 278 |
+
|
| 279 |
+
# Restart services
|
| 280 |
+
docker-compose restart
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
### Issue: API errors in new frontend
|
| 284 |
+
|
| 285 |
+
**Solution**:
|
| 286 |
+
The new frontend requires the API to be running. Ensure:
|
| 287 |
+
```bash
|
| 288 |
+
# API should be accessible at
|
| 289 |
+
curl http://localhost:5055/health
|
| 290 |
+
|
| 291 |
+
# If not, check API logs
|
| 292 |
+
docker-compose logs open_notebook | grep api
|
| 293 |
+
```
|
| 294 |
+
|
| 295 |
+
### Issue: Missing data after migration
|
| 296 |
+
|
| 297 |
+
**Solution**:
|
| 298 |
+
Data is preserved automatically. If you don't see your data:
|
| 299 |
+
|
| 300 |
+
1. Check database volume is mounted correctly:
|
| 301 |
+
```bash
|
| 302 |
+
docker-compose down
|
| 303 |
+
# Verify volumes in docker-compose.yml:
|
| 304 |
+
# - ./surreal_data:/mydata (for multi-container)
|
| 305 |
+
# - ./surreal_single_data:/mydata (for single-container)
|
| 306 |
+
docker-compose up -d
|
| 307 |
+
```
|
| 308 |
+
|
| 309 |
+
2. Check SurrealDB is running:
|
| 310 |
+
```bash
|
| 311 |
+
docker-compose logs surrealdb
|
| 312 |
+
```
|
| 313 |
+
|
| 314 |
+
### Issue: Port conflicts
|
| 315 |
+
|
| 316 |
+
**Solution**:
|
| 317 |
+
If ports 8502 or 5055 are already in use:
|
| 318 |
+
|
| 319 |
+
```bash
|
| 320 |
+
# Find what's using the port
|
| 321 |
+
lsof -i :8502
|
| 322 |
+
lsof -i :5055
|
| 323 |
+
|
| 324 |
+
# Stop conflicting service or change Open Notebook ports
|
| 325 |
+
# Edit docker-compose.yml:
|
| 326 |
+
ports:
|
| 327 |
+
- "8503:8502" # Change external port
|
| 328 |
+
- "5056:5055" # Change external port
|
| 329 |
+
```
|
| 330 |
+
|
| 331 |
+
## Rollback Instructions
|
| 332 |
+
|
| 333 |
+
If you need to roll back to the Streamlit version:
|
| 334 |
+
|
| 335 |
+
### Docker Users
|
| 336 |
+
|
| 337 |
+
```bash
|
| 338 |
+
# Stop current version
|
| 339 |
+
docker-compose down
|
| 340 |
+
|
| 341 |
+
# Edit docker-compose.yml to use old image
|
| 342 |
+
# Change to: lfnovo/open_notebook:streamlit-latest
|
| 343 |
+
|
| 344 |
+
# Start old version
|
| 345 |
+
docker-compose up -d
|
| 346 |
+
```
|
| 347 |
+
|
| 348 |
+
### Source Code Users
|
| 349 |
+
|
| 350 |
+
```bash
|
| 351 |
+
# Checkout the last Streamlit version tag
|
| 352 |
+
git checkout tags/streamlit-final
|
| 353 |
+
|
| 354 |
+
# Install dependencies
|
| 355 |
+
uv sync
|
| 356 |
+
|
| 357 |
+
# Start Streamlit
|
| 358 |
+
uv run streamlit run app_home.py
|
| 359 |
+
```
|
| 360 |
+
|
| 361 |
+
## Getting Help
|
| 362 |
+
|
| 363 |
+
If you encounter issues during migration:
|
| 364 |
+
|
| 365 |
+
- **Discord**: Join our [Discord community](https://discord.gg/37XJPXfz2w) for real-time help
|
| 366 |
+
- **GitHub Issues**: Report bugs at [github.com/lfnovo/open-notebook/issues](https://github.com/lfnovo/open-notebook/issues)
|
| 367 |
+
- **Documentation**: Check [full documentation](https://github.com/lfnovo/open-notebook/tree/main/docs)
|
| 368 |
+
|
| 369 |
+
## FAQs
|
| 370 |
+
|
| 371 |
+
### Will my notebooks and data be lost?
|
| 372 |
+
No! All data is preserved. The database and API backend are unchanged.
|
| 373 |
+
|
| 374 |
+
### Do I need to update my API integrations?
|
| 375 |
+
No! The REST API remains fully backward compatible.
|
| 376 |
+
|
| 377 |
+
### Can I use both frontends simultaneously?
|
| 378 |
+
Technically yes, but not recommended. Choose one for consistency.
|
| 379 |
+
|
| 380 |
+
### What about my custom Streamlit pages?
|
| 381 |
+
Custom Streamlit pages won't work with the React frontend. Consider:
|
| 382 |
+
- Using the REST API to build custom integrations
|
| 383 |
+
- Contributing React components to the project
|
| 384 |
+
- Requesting features in GitHub issues
|
| 385 |
+
|
| 386 |
+
### Is the Streamlit version still supported?
|
| 387 |
+
The Streamlit version is no longer actively developed. We recommend migrating to the React version for the best experience and latest features.
|
| 388 |
+
|
| 389 |
+
## Timeline
|
| 390 |
+
|
| 391 |
+
- **Legacy (Pre-v1.0)**: Streamlit frontend
|
| 392 |
+
- **Current (v1.0+)**: React/Next.js frontend
|
| 393 |
+
- **Future**: Continued React development with new features
|
| 394 |
+
|
| 395 |
+
---
|
| 396 |
+
|
| 397 |
+
**Ready to migrate?** Follow the migration path for your deployment method above. The process is straightforward and your data is safe!
|
Makefile
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: run frontend check ruff database lint api start-all stop-all status clean-cache worker worker-start worker-stop worker-restart
|
| 2 |
+
.PHONY: docker-buildx-prepare docker-buildx-clean docker-buildx-reset
|
| 3 |
+
.PHONY: docker-push docker-push-latest docker-release tag export-docs
|
| 4 |
+
|
| 5 |
+
# Get version from pyproject.toml
|
| 6 |
+
VERSION := $(shell grep -m1 version pyproject.toml | cut -d'"' -f2)
|
| 7 |
+
|
| 8 |
+
# Image names for both registries
|
| 9 |
+
DOCKERHUB_IMAGE := lfnovo/open_notebook
|
| 10 |
+
GHCR_IMAGE := ghcr.io/lfnovo/open-notebook
|
| 11 |
+
|
| 12 |
+
# Build platforms
|
| 13 |
+
PLATFORMS := linux/amd64,linux/arm64
|
| 14 |
+
|
| 15 |
+
database:
|
| 16 |
+
docker compose up -d surrealdb
|
| 17 |
+
|
| 18 |
+
run:
|
| 19 |
+
@echo "⚠️ Warning: Starting frontend only. For full functionality, use 'make start-all'"
|
| 20 |
+
cd frontend && npm run dev
|
| 21 |
+
|
| 22 |
+
frontend:
|
| 23 |
+
cd frontend && npm run dev
|
| 24 |
+
|
| 25 |
+
lint:
|
| 26 |
+
uv run python -m mypy .
|
| 27 |
+
|
| 28 |
+
ruff:
|
| 29 |
+
ruff check . --fix
|
| 30 |
+
|
| 31 |
+
# === Docker Build Setup ===
|
| 32 |
+
docker-buildx-prepare:
|
| 33 |
+
@docker buildx inspect multi-platform-builder >/dev/null 2>&1 || \
|
| 34 |
+
docker buildx create --use --name multi-platform-builder --driver docker-container
|
| 35 |
+
@docker buildx use multi-platform-builder
|
| 36 |
+
|
| 37 |
+
docker-buildx-clean:
|
| 38 |
+
@echo "🧹 Cleaning up buildx builders..."
|
| 39 |
+
@docker buildx rm multi-platform-builder 2>/dev/null || true
|
| 40 |
+
@docker ps -a | grep buildx_buildkit | awk '{print $$1}' | xargs -r docker rm -f 2>/dev/null || true
|
| 41 |
+
@echo "✅ Buildx cleanup complete!"
|
| 42 |
+
|
| 43 |
+
docker-buildx-reset: docker-buildx-clean docker-buildx-prepare
|
| 44 |
+
@echo "✅ Buildx reset complete!"
|
| 45 |
+
|
| 46 |
+
# === Docker Build Targets ===
|
| 47 |
+
|
| 48 |
+
# Build and push version tags ONLY (no latest) for both regular and single images
|
| 49 |
+
docker-push: docker-buildx-prepare
|
| 50 |
+
@echo "📤 Building and pushing version $(VERSION) to both registries..."
|
| 51 |
+
@echo "🔨 Building regular image..."
|
| 52 |
+
docker buildx build --pull \
|
| 53 |
+
--platform $(PLATFORMS) \
|
| 54 |
+
--progress=plain \
|
| 55 |
+
-t $(DOCKERHUB_IMAGE):$(VERSION) \
|
| 56 |
+
-t $(GHCR_IMAGE):$(VERSION) \
|
| 57 |
+
--push \
|
| 58 |
+
.
|
| 59 |
+
@echo "🔨 Building single-container image..."
|
| 60 |
+
docker buildx build --pull \
|
| 61 |
+
--platform $(PLATFORMS) \
|
| 62 |
+
--progress=plain \
|
| 63 |
+
-f Dockerfile.single \
|
| 64 |
+
-t $(DOCKERHUB_IMAGE):$(VERSION)-single \
|
| 65 |
+
-t $(GHCR_IMAGE):$(VERSION)-single \
|
| 66 |
+
--push \
|
| 67 |
+
.
|
| 68 |
+
@echo "✅ Pushed version $(VERSION) to both registries (latest NOT updated)"
|
| 69 |
+
@echo " 📦 Docker Hub:"
|
| 70 |
+
@echo " - $(DOCKERHUB_IMAGE):$(VERSION)"
|
| 71 |
+
@echo " - $(DOCKERHUB_IMAGE):$(VERSION)-single"
|
| 72 |
+
@echo " 📦 GHCR:"
|
| 73 |
+
@echo " - $(GHCR_IMAGE):$(VERSION)"
|
| 74 |
+
@echo " - $(GHCR_IMAGE):$(VERSION)-single"
|
| 75 |
+
|
| 76 |
+
# Update v1-latest tags to current version (both regular and single images)
|
| 77 |
+
docker-push-latest: docker-buildx-prepare
|
| 78 |
+
@echo "📤 Updating v1-latest tags to version $(VERSION)..."
|
| 79 |
+
@echo "🔨 Building regular image with latest tag..."
|
| 80 |
+
docker buildx build --pull \
|
| 81 |
+
--platform $(PLATFORMS) \
|
| 82 |
+
--progress=plain \
|
| 83 |
+
-t $(DOCKERHUB_IMAGE):$(VERSION) \
|
| 84 |
+
-t $(DOCKERHUB_IMAGE):v1-latest \
|
| 85 |
+
-t $(GHCR_IMAGE):$(VERSION) \
|
| 86 |
+
-t $(GHCR_IMAGE):v1-latest \
|
| 87 |
+
--push \
|
| 88 |
+
.
|
| 89 |
+
@echo "🔨 Building single-container image with latest tag..."
|
| 90 |
+
docker buildx build --pull \
|
| 91 |
+
--platform $(PLATFORMS) \
|
| 92 |
+
--progress=plain \
|
| 93 |
+
-f Dockerfile.single \
|
| 94 |
+
-t $(DOCKERHUB_IMAGE):$(VERSION)-single \
|
| 95 |
+
-t $(DOCKERHUB_IMAGE):v1-latest-single \
|
| 96 |
+
-t $(GHCR_IMAGE):$(VERSION)-single \
|
| 97 |
+
-t $(GHCR_IMAGE):v1-latest-single \
|
| 98 |
+
--push \
|
| 99 |
+
.
|
| 100 |
+
@echo "✅ Updated v1-latest to version $(VERSION)"
|
| 101 |
+
@echo " 📦 Docker Hub:"
|
| 102 |
+
@echo " - $(DOCKERHUB_IMAGE):$(VERSION) → v1-latest"
|
| 103 |
+
@echo " - $(DOCKERHUB_IMAGE):$(VERSION)-single → v1-latest-single"
|
| 104 |
+
@echo " 📦 GHCR:"
|
| 105 |
+
@echo " - $(GHCR_IMAGE):$(VERSION) → v1-latest"
|
| 106 |
+
@echo " - $(GHCR_IMAGE):$(VERSION)-single → v1-latest-single"
|
| 107 |
+
|
| 108 |
+
# Full release: push version AND update latest tags
|
| 109 |
+
docker-release: docker-push-latest
|
| 110 |
+
@echo "✅ Full release complete for version $(VERSION)"
|
| 111 |
+
|
| 112 |
+
tag:
|
| 113 |
+
@version=$$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/'); \
|
| 114 |
+
echo "Creating tag v$$version"; \
|
| 115 |
+
git tag "v$$version"; \
|
| 116 |
+
git push origin "v$$version"
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
dev:
|
| 120 |
+
docker compose -f docker-compose.dev.yml up --build
|
| 121 |
+
|
| 122 |
+
full:
|
| 123 |
+
docker compose -f docker-compose.full.yml up --build
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
api:
|
| 127 |
+
uv run run_api.py
|
| 128 |
+
|
| 129 |
+
# === Worker Management ===
|
| 130 |
+
.PHONY: worker worker-start worker-stop worker-restart
|
| 131 |
+
|
| 132 |
+
worker: worker-start
|
| 133 |
+
|
| 134 |
+
worker-start:
|
| 135 |
+
@echo "Starting surreal-commands worker..."
|
| 136 |
+
uv run --env-file .env surreal-commands-worker --import-modules commands
|
| 137 |
+
|
| 138 |
+
worker-stop:
|
| 139 |
+
@echo "Stopping surreal-commands worker..."
|
| 140 |
+
pkill -f "surreal-commands-worker" || true
|
| 141 |
+
|
| 142 |
+
worker-restart: worker-stop
|
| 143 |
+
@sleep 2
|
| 144 |
+
@$(MAKE) worker-start
|
| 145 |
+
|
| 146 |
+
# === Service Management ===
|
| 147 |
+
start-all:
|
| 148 |
+
@echo "🚀 Starting Open Notebook (Database + API + Worker + Frontend)..."
|
| 149 |
+
@echo "📊 Starting SurrealDB..."
|
| 150 |
+
@docker compose up -d surrealdb
|
| 151 |
+
@sleep 3
|
| 152 |
+
@echo "🔧 Starting API backend..."
|
| 153 |
+
@uv run run_api.py &
|
| 154 |
+
@sleep 3
|
| 155 |
+
@echo "⚙️ Starting background worker..."
|
| 156 |
+
@uv run --env-file .env surreal-commands-worker --import-modules commands &
|
| 157 |
+
@sleep 2
|
| 158 |
+
@echo "🌐 Starting Next.js frontend..."
|
| 159 |
+
@echo "✅ All services started!"
|
| 160 |
+
@echo "📱 Frontend: http://localhost:3000"
|
| 161 |
+
@echo "🔗 API: http://localhost:5055"
|
| 162 |
+
@echo "📚 API Docs: http://localhost:5055/docs"
|
| 163 |
+
cd frontend && npm run dev
|
| 164 |
+
|
| 165 |
+
stop-all:
|
| 166 |
+
@echo "🛑 Stopping all Open Notebook services..."
|
| 167 |
+
@pkill -f "next dev" || true
|
| 168 |
+
@pkill -f "surreal-commands-worker" || true
|
| 169 |
+
@pkill -f "run_api.py" || true
|
| 170 |
+
@pkill -f "uvicorn api.main:app" || true
|
| 171 |
+
@docker compose down
|
| 172 |
+
@echo "✅ All services stopped!"
|
| 173 |
+
|
| 174 |
+
status:
|
| 175 |
+
@echo "📊 Open Notebook Service Status:"
|
| 176 |
+
@echo "Database (SurrealDB):"
|
| 177 |
+
@docker compose ps surrealdb 2>/dev/null || echo " ❌ Not running"
|
| 178 |
+
@echo "API Backend:"
|
| 179 |
+
@pgrep -f "run_api.py\|uvicorn api.main:app" >/dev/null && echo " ✅ Running" || echo " ❌ Not running"
|
| 180 |
+
@echo "Background Worker:"
|
| 181 |
+
@pgrep -f "surreal-commands-worker" >/dev/null && echo " ✅ Running" || echo " ❌ Not running"
|
| 182 |
+
@echo "Next.js Frontend:"
|
| 183 |
+
@pgrep -f "next dev" >/dev/null && echo " ✅ Running" || echo " ❌ Not running"
|
| 184 |
+
|
| 185 |
+
# === Documentation Export ===
|
| 186 |
+
export-docs:
|
| 187 |
+
@echo "📚 Exporting documentation..."
|
| 188 |
+
@uv run python scripts/export_docs.py
|
| 189 |
+
@echo "✅ Documentation export complete!"
|
| 190 |
+
|
| 191 |
+
# === Cleanup ===
|
| 192 |
+
clean-cache:
|
| 193 |
+
@echo "🧹 Cleaning cache directories..."
|
| 194 |
+
@find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
|
| 195 |
+
@find . -name ".mypy_cache" -type d -exec rm -rf {} + 2>/dev/null || true
|
| 196 |
+
@find . -name ".ruff_cache" -type d -exec rm -rf {} + 2>/dev/null || true
|
| 197 |
+
@find . -name ".pytest_cache" -type d -exec rm -rf {} + 2>/dev/null || true
|
| 198 |
+
@find . -name "*.pyc" -type f -delete 2>/dev/null || true
|
| 199 |
+
@find . -name "*.pyo" -type f -delete 2>/dev/null || true
|
| 200 |
+
@find . -name "*.pyd" -type f -delete 2>/dev/null || true
|
| 201 |
+
@echo "✅ Cache directories cleaned!"
|
PWA_IMPLEMENTATION.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PWA Implementation Guide for Open Notebook
|
| 2 |
+
|
| 3 |
+
## What Was Implemented
|
| 4 |
+
|
| 5 |
+
Open Notebook has been successfully converted into a Progressive Web App (PWA) with the following features:
|
| 6 |
+
|
| 7 |
+
### Features Added
|
| 8 |
+
|
| 9 |
+
1. **Installable App**
|
| 10 |
+
- Users can install Open Notebook to their home screen on mobile and desktop
|
| 11 |
+
- Works on iOS, Android, Windows, Mac, and Linux
|
| 12 |
+
- App appears in app launchers just like native apps
|
| 13 |
+
|
| 14 |
+
2. **Offline Support**
|
| 15 |
+
- Service worker caching for faster load times
|
| 16 |
+
- Graceful offline fallback page
|
| 17 |
+
- API caching with Network-First strategy (5-minute cache)
|
| 18 |
+
|
| 19 |
+
3. **Smart Caching**
|
| 20 |
+
- Static assets (JS, CSS, images) cached for 24 hours
|
| 21 |
+
- Google Fonts cached for optimal performance
|
| 22 |
+
- Next.js image optimization cached
|
| 23 |
+
|
| 24 |
+
4. **Install Prompt**
|
| 25 |
+
- Smart install prompt appears after 30 seconds
|
| 26 |
+
- Dismissible with 7-day cooldown
|
| 27 |
+
- Auto-detects if already installed
|
| 28 |
+
|
| 29 |
+
5. **Mobile Optimized**
|
| 30 |
+
- Apple Touch Icon support
|
| 31 |
+
- Proper viewport and theme-color meta tags
|
| 32 |
+
- App shortcuts for quick actions
|
| 33 |
+
|
| 34 |
+
## Files Modified/Created
|
| 35 |
+
|
| 36 |
+
### Modified Files
|
| 37 |
+
- `frontend/next.config.ts` - PWA configuration with caching strategies
|
| 38 |
+
- `frontend/src/app/layout.tsx` - Added PWA meta tags and install prompt
|
| 39 |
+
- `frontend/package.json` - Added next-pwa dependency
|
| 40 |
+
|
| 41 |
+
### New Files
|
| 42 |
+
- `frontend/public/manifest.json` - Web app manifest with app metadata
|
| 43 |
+
- `frontend/public/offline.html` - Offline fallback page
|
| 44 |
+
- `frontend/src/components/common/InstallPWA.tsx` - Install prompt component
|
| 45 |
+
- `frontend/generate-icons.js` - Icon generation script
|
| 46 |
+
- `frontend/public/icon-*.png` - PWA icons (9 sizes)
|
| 47 |
+
- `frontend/public/apple-touch-icon.png` - iOS home screen icon
|
| 48 |
+
|
| 49 |
+
## How to Test
|
| 50 |
+
|
| 51 |
+
### 1. Build and Start the App
|
| 52 |
+
|
| 53 |
+
```bash
|
| 54 |
+
cd /home/john/opennotebook/frontend
|
| 55 |
+
npm run build
|
| 56 |
+
npm start
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
Or with Docker:
|
| 60 |
+
```bash
|
| 61 |
+
cd /home/john/opennotebook
|
| 62 |
+
docker compose up --build
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
### 2. Test on Desktop (Chrome/Edge)
|
| 66 |
+
|
| 67 |
+
1. Open Chrome/Edge browser
|
| 68 |
+
2. Navigate to your Open Notebook URL (e.g., `http://localhost:8502`)
|
| 69 |
+
3. Look for the install icon in the address bar (⊕ or ⬇️)
|
| 70 |
+
4. Click it and select "Install"
|
| 71 |
+
5. The app will open in its own window
|
| 72 |
+
|
| 73 |
+
**Alternative:**
|
| 74 |
+
- Open DevTools (F12)
|
| 75 |
+
- Go to "Application" tab
|
| 76 |
+
- Click "Manifest" to verify manifest is loaded
|
| 77 |
+
- Check "Service Workers" to see if worker is active
|
| 78 |
+
- Use "Lighthouse" tab to run PWA audit
|
| 79 |
+
|
| 80 |
+
### 3. Test on Android
|
| 81 |
+
|
| 82 |
+
1. Open Chrome browser on Android
|
| 83 |
+
2. Navigate to your Open Notebook URL
|
| 84 |
+
3. Wait 30 seconds for the install prompt to appear
|
| 85 |
+
4. Or tap the menu (⋮) and select "Install app" or "Add to Home Screen"
|
| 86 |
+
5. Tap "Install"
|
| 87 |
+
6. Find the app icon on your home screen
|
| 88 |
+
|
| 89 |
+
**Testing Tips:**
|
| 90 |
+
- Use Chrome's Device Mode in DevTools to simulate mobile
|
| 91 |
+
- Remote debug using `chrome://inspect` on desktop
|
| 92 |
+
- Check console for any PWA-related errors
|
| 93 |
+
|
| 94 |
+
### 4. Test on iOS (Safari)
|
| 95 |
+
|
| 96 |
+
1. Open Safari on iOS
|
| 97 |
+
2. Navigate to your Open Notebook URL
|
| 98 |
+
3. Tap the Share button (square with arrow)
|
| 99 |
+
4. Scroll down and tap "Add to Home Screen"
|
| 100 |
+
5. Customize name if desired and tap "Add"
|
| 101 |
+
6. Find the app icon on your home screen
|
| 102 |
+
|
| 103 |
+
**Note:** iOS has limited PWA support:
|
| 104 |
+
- No automatic install prompt
|
| 105 |
+
- No background sync
|
| 106 |
+
- Limited push notification support
|
| 107 |
+
|
| 108 |
+
### 5. Test Offline Functionality
|
| 109 |
+
|
| 110 |
+
**Desktop:**
|
| 111 |
+
1. Open DevTools (F12)
|
| 112 |
+
2. Go to "Network" tab
|
| 113 |
+
3. Check "Offline" checkbox
|
| 114 |
+
4. Refresh the page
|
| 115 |
+
5. You should see the offline fallback page
|
| 116 |
+
|
| 117 |
+
**Mobile:**
|
| 118 |
+
1. Enable Airplane mode
|
| 119 |
+
2. Open the installed app
|
| 120 |
+
3. You should see cached content or offline page
|
| 121 |
+
|
| 122 |
+
### 6. Test PWA Features with Lighthouse
|
| 123 |
+
|
| 124 |
+
1. Open Chrome DevTools (F12)
|
| 125 |
+
2. Go to "Lighthouse" tab
|
| 126 |
+
3. Select "Progressive Web App" category
|
| 127 |
+
4. Click "Analyze page load"
|
| 128 |
+
5. Review the PWA score (should be 90+)
|
| 129 |
+
|
| 130 |
+
## PWA Configuration Details
|
| 131 |
+
|
| 132 |
+
### Caching Strategies
|
| 133 |
+
|
| 134 |
+
| Resource Type | Strategy | Cache Duration | Notes |
|
| 135 |
+
|--------------|----------|----------------|-------|
|
| 136 |
+
| API Calls | NetworkFirst | 5 minutes | Falls back to cache if network is slow (10s timeout) |
|
| 137 |
+
| Static JS/CSS | StaleWhileRevalidate | 24 hours | Always serves from cache, updates in background |
|
| 138 |
+
| Images | StaleWhileRevalidate | 24 hours | Cached for fast loading |
|
| 139 |
+
| Google Fonts | CacheFirst (webfonts) / StaleWhileRevalidate (CSS) | 365 days / 7 days | Optimal font loading |
|
| 140 |
+
|
| 141 |
+
### Manifest Features
|
| 142 |
+
|
| 143 |
+
- **Display Mode:** Standalone (looks like a native app)
|
| 144 |
+
- **Orientation:** Portrait-primary (mobile optimized)
|
| 145 |
+
- **Theme Color:** #000000 (customizable in manifest.json)
|
| 146 |
+
- **Background Color:** #ffffff (customizable in manifest.json)
|
| 147 |
+
- **App Shortcuts:** Quick access to New Notebook and Search
|
| 148 |
+
|
| 149 |
+
## Customization
|
| 150 |
+
|
| 151 |
+
### Change Theme Colors
|
| 152 |
+
|
| 153 |
+
Edit `frontend/public/manifest.json`:
|
| 154 |
+
```json
|
| 155 |
+
{
|
| 156 |
+
"theme_color": "#667eea",
|
| 157 |
+
"background_color": "#ffffff"
|
| 158 |
+
}
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
Also update in `frontend/src/app/layout.tsx`:
|
| 162 |
+
```tsx
|
| 163 |
+
<meta name="theme-color" content="#667eea" />
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
### Adjust Install Prompt Timing
|
| 167 |
+
|
| 168 |
+
Edit `frontend/src/components/common/InstallPWA.tsx`:
|
| 169 |
+
```tsx
|
| 170 |
+
// Change from 30 seconds (30000ms) to desired delay
|
| 171 |
+
setTimeout(() => {
|
| 172 |
+
setShowInstallPrompt(true);
|
| 173 |
+
}, 30000); // Change this value
|
| 174 |
+
```
|
| 175 |
+
|
| 176 |
+
### Modify Caching Behavior
|
| 177 |
+
|
| 178 |
+
Edit `frontend/next.config.ts` in the `runtimeCaching` array:
|
| 179 |
+
- Change `handler` types: `NetworkFirst`, `CacheFirst`, `StaleWhileRevalidate`
|
| 180 |
+
- Adjust `maxAgeSeconds` for cache duration
|
| 181 |
+
- Modify `maxEntries` for cache size limits
|
| 182 |
+
|
| 183 |
+
### Disable PWA in Development
|
| 184 |
+
|
| 185 |
+
PWA is automatically disabled in development mode. To enable it, edit `next.config.ts`:
|
| 186 |
+
```tsx
|
| 187 |
+
disable: false, // Change from process.env.NODE_ENV === "development"
|
| 188 |
+
```
|
| 189 |
+
|
| 190 |
+
## Troubleshooting
|
| 191 |
+
|
| 192 |
+
### Install Button Not Showing
|
| 193 |
+
|
| 194 |
+
1. Check if already installed (look for standalone display mode)
|
| 195 |
+
2. PWA criteria not met - run Lighthouse audit
|
| 196 |
+
3. HTTPS required (except localhost)
|
| 197 |
+
4. Service worker may not be registered - check DevTools > Application > Service Workers
|
| 198 |
+
|
| 199 |
+
### Service Worker Not Updating
|
| 200 |
+
|
| 201 |
+
1. In DevTools > Application > Service Workers
|
| 202 |
+
2. Check "Update on reload"
|
| 203 |
+
3. Click "Unregister" and reload page
|
| 204 |
+
4. Or use "Skip waiting" button
|
| 205 |
+
|
| 206 |
+
### Icons Not Loading
|
| 207 |
+
|
| 208 |
+
1. Verify icons exist: `ls frontend/public/icon-*.png`
|
| 209 |
+
2. Regenerate if needed: `node frontend/generate-icons.js`
|
| 210 |
+
3. Check manifest.json paths match icon filenames
|
| 211 |
+
4. Clear cache and reinstall app
|
| 212 |
+
|
| 213 |
+
### Manifest Not Found
|
| 214 |
+
|
| 215 |
+
1. Check that manifest.json exists in `frontend/public/`
|
| 216 |
+
2. Verify build output includes public files
|
| 217 |
+
3. Check browser console for 404 errors
|
| 218 |
+
4. Ensure `manifest: "/manifest.json"` in layout.tsx
|
| 219 |
+
|
| 220 |
+
### App Not Working Offline
|
| 221 |
+
|
| 222 |
+
1. Service worker must be active (check DevTools)
|
| 223 |
+
2. Visit pages while online first to cache them
|
| 224 |
+
3. API calls require cached responses or fallbacks
|
| 225 |
+
4. Check offline.html is in public directory
|
| 226 |
+
|
| 227 |
+
## Production Deployment
|
| 228 |
+
|
| 229 |
+
### Important Considerations
|
| 230 |
+
|
| 231 |
+
1. **HTTPS Required**
|
| 232 |
+
- PWAs require HTTPS (except localhost)
|
| 233 |
+
- Ensure your production server has valid SSL certificate
|
| 234 |
+
|
| 235 |
+
2. **Cache Updates**
|
| 236 |
+
- Service worker updates automatically on new deployments
|
| 237 |
+
- Users get updates when they close and reopen the app
|
| 238 |
+
|
| 239 |
+
3. **Environment Variables**
|
| 240 |
+
- `NODE_ENV=production` enables PWA features
|
| 241 |
+
- `API_URL` must be set correctly for your deployment
|
| 242 |
+
|
| 243 |
+
4. **Docker Deployment**
|
| 244 |
+
- PWA files are included in the standalone build
|
| 245 |
+
- Icons and manifest are served from the public directory
|
| 246 |
+
- No additional configuration needed
|
| 247 |
+
|
| 248 |
+
## Next Steps
|
| 249 |
+
|
| 250 |
+
### Optional Enhancements
|
| 251 |
+
|
| 252 |
+
1. **Push Notifications**
|
| 253 |
+
- Add web push notification support
|
| 254 |
+
- Requires backend integration for push subscriptions
|
| 255 |
+
|
| 256 |
+
2. **Background Sync**
|
| 257 |
+
- Queue API requests when offline
|
| 258 |
+
- Sync when connection is restored
|
| 259 |
+
|
| 260 |
+
3. **Share Target API**
|
| 261 |
+
- Allow sharing content to Open Notebook from other apps
|
| 262 |
+
- Add to manifest.json
|
| 263 |
+
|
| 264 |
+
4. **App Shortcuts**
|
| 265 |
+
- Already configured in manifest
|
| 266 |
+
- Can add more shortcuts for quick actions
|
| 267 |
+
|
| 268 |
+
5. **Screenshots**
|
| 269 |
+
- Add app screenshots to manifest
|
| 270 |
+
- Improves install prompt on some platforms
|
| 271 |
+
|
| 272 |
+
## Resources
|
| 273 |
+
|
| 274 |
+
- [PWA Documentation](https://web.dev/progressive-web-apps/)
|
| 275 |
+
- [next-pwa GitHub](https://github.com/shadowwalker/next-pwa)
|
| 276 |
+
- [Workbox Documentation](https://developers.google.com/web/tools/workbox)
|
| 277 |
+
- [Manifest Generator](https://www.simicart.com/manifest-generator.html/)
|
| 278 |
+
- [PWA Testing Tools](https://www.pwabuilder.com/)
|
| 279 |
+
|
| 280 |
+
## Support
|
| 281 |
+
|
| 282 |
+
For issues specific to Open Notebook PWA:
|
| 283 |
+
- Check browser console for errors
|
| 284 |
+
- Run Lighthouse audit for PWA compliance
|
| 285 |
+
- Verify service worker is active
|
| 286 |
+
- Test on different devices and browsers
|
| 287 |
+
|
| 288 |
+
---
|
| 289 |
+
|
| 290 |
+
**Implementation Date:** October 28, 2025
|
| 291 |
+
**Implemented By:** Claude Code Assistant
|
| 292 |
+
**Status:** ✅ Complete and Ready for Testing
|
README.md
CHANGED
|
@@ -1,13 +1,455 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<a id="readme-top"></a>
|
| 2 |
+
|
| 3 |
+
<!-- [![Contributors][contributors-shield]][contributors-url] -->
|
| 4 |
+
[![Forks][forks-shield]][forks-url]
|
| 5 |
+
[![Stargazers][stars-shield]][stars-url]
|
| 6 |
+
[![Issues][issues-shield]][issues-url]
|
| 7 |
+
[![MIT License][license-shield]][license-url]
|
| 8 |
+
<!-- [![LinkedIn][linkedin-shield]][linkedin-url] -->
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
<!-- PROJECT LOGO -->
|
| 12 |
+
<br />
|
| 13 |
+
<div align="center">
|
| 14 |
+
<a href="https://github.com/lfnovo/open-notebook">
|
| 15 |
+
<img src="docs/assets/hero.svg" alt="Logo">
|
| 16 |
+
</a>
|
| 17 |
+
|
| 18 |
+
<h3 align="center">Open Notebook</h3>
|
| 19 |
+
|
| 20 |
+
<p align="center">
|
| 21 |
+
An open source, privacy-focused alternative to Google's Notebook LM!
|
| 22 |
+
<br /><strong>Join our <a href="https://discord.gg/37XJPXfz2w">Discord server</a> for help, to share workflow ideas, and suggest features!</strong>
|
| 23 |
+
<br />
|
| 24 |
+
<a href="https://www.open-notebook.ai"><strong>Checkout our website »</strong></a>
|
| 25 |
+
<br />
|
| 26 |
+
<br />
|
| 27 |
+
<a href="docs/getting-started/index.md">📚 Get Started</a>
|
| 28 |
+
·
|
| 29 |
+
<a href="docs/user-guide/index.md">📖 User Guide</a>
|
| 30 |
+
·
|
| 31 |
+
<a href="docs/features/index.md">✨ Features</a>
|
| 32 |
+
·
|
| 33 |
+
<a href="docs/deployment/index.md">🚀 Deploy</a>
|
| 34 |
+
</p>
|
| 35 |
+
</div>
|
| 36 |
+
|
| 37 |
+
<div align="center">
|
| 38 |
+
<!-- Keep these links. Translations will automatically update with the README. -->
|
| 39 |
+
<a href="https://zdoc.app/de/lfnovo/open-notebook">Deutsch</a> |
|
| 40 |
+
<a href="https://zdoc.app/es/lfnovo/open-notebook">Español</a> |
|
| 41 |
+
<a href="https://zdoc.app/fr/lfnovo/open-notebook">français</a> |
|
| 42 |
+
<a href="https://zdoc.app/ja/lfnovo/open-notebook">日本語</a> |
|
| 43 |
+
<a href="https://zdoc.app/ko/lfnovo/open-notebook">한국어</a> |
|
| 44 |
+
<a href="https://zdoc.app/pt/lfnovo/open-notebook">Português</a> |
|
| 45 |
+
<a href="https://zdoc.app/ru/lfnovo/open-notebook">Русский</a> |
|
| 46 |
+
<a href="https://zdoc.app/zh/lfnovo/open-notebook">中文</a>
|
| 47 |
+
</div>
|
| 48 |
+
|
| 49 |
+
## A private, multi-model, 100% local, full-featured alternative to Notebook LM
|
| 50 |
+
|
| 51 |
+

|
| 52 |
+
|
| 53 |
+
In a world dominated by Artificial Intelligence, having the ability to think 🧠 and acquire new knowledge 💡, is a skill that should not be a privilege for a few, nor restricted to a single provider.
|
| 54 |
+
|
| 55 |
+
**Open Notebook empowers you to:**
|
| 56 |
+
- 🔒 **Control your data** - Keep your research private and secure
|
| 57 |
+
- 🤖 **Choose your AI models** - Support for 16+ providers including OpenAI, Anthropic, Ollama, LM Studio, and more
|
| 58 |
+
- 📚 **Organize multi-modal content** - PDFs, videos, audio, web pages, and more
|
| 59 |
+
- 🎙️ **Generate professional podcasts** - Advanced multi-speaker podcast generation
|
| 60 |
+
- 🔍 **Search intelligently** - Full-text and vector search across all your content
|
| 61 |
+
- 💬 **Chat with context** - AI conversations powered by your research
|
| 62 |
+
|
| 63 |
+
Learn more about our project at [https://www.open-notebook.ai](https://www.open-notebook.ai)
|
| 64 |
+
|
| 65 |
---
|
| 66 |
+
|
| 67 |
+
## ⚠️ IMPORTANT: v1.0 Breaking Changes
|
| 68 |
+
|
| 69 |
+
**If you're upgrading from a previous version**, please note:
|
| 70 |
+
|
| 71 |
+
- 🏷️ **Docker tags have changed**: The `latest` tag is now **frozen** at the last Streamlit version
|
| 72 |
+
- 🆕 **Use `v1-latest` tag** for the new React/Next.js version (recommended)
|
| 73 |
+
- 🔌 **Port 5055 required**: You must expose port 5055 for the API to work
|
| 74 |
+
- 📖 **Read the migration guide**: See [MIGRATION.md](MIGRATION.md) for detailed upgrade instructions
|
| 75 |
+
|
| 76 |
+
**New users**: You can ignore this notice and proceed with the Quick Start below using the `v1-latest-single` tag.
|
| 77 |
+
|
| 78 |
---
|
| 79 |
|
| 80 |
+
## 🆚 Open Notebook vs Google Notebook LM
|
| 81 |
+
|
| 82 |
+
| Feature | Open Notebook | Google Notebook LM | Advantage |
|
| 83 |
+
|---------|---------------|--------------------|-----------|
|
| 84 |
+
| **Privacy & Control** | Self-hosted, your data | Google cloud only | Complete data sovereignty |
|
| 85 |
+
| **AI Provider Choice** | 16+ providers (OpenAI, Anthropic, Ollama, LM Studio, etc.) | Google models only | Flexibility and cost optimization |
|
| 86 |
+
| **Podcast Speakers** | 1-4 speakers with custom profiles | 2 speakers only | Extreme flexibility |
|
| 87 |
+
| **Context Control** | 3 granular levels | All-or-nothing | Privacy and performance tuning |
|
| 88 |
+
| **Content Transformations** | Custom and built-in | Limited options | Unlimited processing power |
|
| 89 |
+
| **API Access** | Full REST API | No API | Complete automation |
|
| 90 |
+
| **Deployment** | Docker, cloud, or local | Google hosted only | Deploy anywhere |
|
| 91 |
+
| **Citations** | Comprehensive with sources | Basic references | Research integrity |
|
| 92 |
+
| **Customization** | Open source, fully customizable | Closed system | Unlimited extensibility |
|
| 93 |
+
| **Cost** | Pay only for AI usage | Monthly subscription + usage | Transparent and controllable |
|
| 94 |
+
|
| 95 |
+
**Why Choose Open Notebook?**
|
| 96 |
+
- 🔒 **Privacy First**: Your sensitive research stays completely private
|
| 97 |
+
- 💰 **Cost Control**: Choose cheaper AI providers or run locally with Ollama
|
| 98 |
+
- 🎙️ **Better Podcasts**: Full script control and multi-speaker flexibility vs limited 2-speaker deep-dive format
|
| 99 |
+
- 🔧 **Unlimited Customization**: Modify, extend, and integrate as needed
|
| 100 |
+
- 🌐 **No Vendor Lock-in**: Switch providers, deploy anywhere, own your data
|
| 101 |
+
|
| 102 |
+
### Built With
|
| 103 |
+
|
| 104 |
+
[![Python][Python]][Python-url] [![Next.js][Next.js]][Next-url] [![React][React]][React-url] [![SurrealDB][SurrealDB]][SurrealDB-url] [![LangChain][LangChain]][LangChain-url]
|
| 105 |
+
|
| 106 |
+
## 🚀 Quick Start
|
| 107 |
+
|
| 108 |
+
**Docker Images Available:**
|
| 109 |
+
- **Docker Hub**: `lfnovo/open_notebook:v1-latest-single`
|
| 110 |
+
- **GitHub Container Registry**: `ghcr.io/lfnovo/open-notebook:v1-latest-single`
|
| 111 |
+
|
| 112 |
+
Both registries contain identical images - choose whichever you prefer!
|
| 113 |
+
|
| 114 |
+
### Choose Your Setup:
|
| 115 |
+
|
| 116 |
+
<table>
|
| 117 |
+
<tr>
|
| 118 |
+
<td width="50%">
|
| 119 |
+
|
| 120 |
+
#### 🏠 **Local Machine Setup**
|
| 121 |
+
Perfect if Docker runs on the **same computer** where you'll access Open Notebook.
|
| 122 |
+
|
| 123 |
+
```bash
|
| 124 |
+
mkdir open-notebook && cd open-notebook
|
| 125 |
+
|
| 126 |
+
docker run -d \
|
| 127 |
+
--name open-notebook \
|
| 128 |
+
-p 8502:8502 -p 5055:5055 \
|
| 129 |
+
-v ./notebook_data:/app/data \
|
| 130 |
+
-v ./surreal_data:/mydata \
|
| 131 |
+
-e OPENAI_API_KEY=your_key_here \
|
| 132 |
+
-e SURREAL_URL="ws://localhost:8000/rpc" \
|
| 133 |
+
-e SURREAL_USER="root" \
|
| 134 |
+
-e SURREAL_PASSWORD="root" \
|
| 135 |
+
-e SURREAL_NAMESPACE="open_notebook" \
|
| 136 |
+
-e SURREAL_DATABASE="production" \
|
| 137 |
+
lfnovo/open_notebook:v1-latest-single
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
**Access at:** http://localhost:8502
|
| 141 |
+
|
| 142 |
+
</td>
|
| 143 |
+
<td width="50%">
|
| 144 |
+
|
| 145 |
+
#### 🌐 **Remote Server Setup**
|
| 146 |
+
Use this for servers, Raspberry Pi, NAS, Proxmox, or any remote machine.
|
| 147 |
+
|
| 148 |
+
```bash
|
| 149 |
+
mkdir open-notebook && cd open-notebook
|
| 150 |
+
|
| 151 |
+
docker run -d \
|
| 152 |
+
--name open-notebook \
|
| 153 |
+
-p 8502:8502 -p 5055:5055 \
|
| 154 |
+
-v ./notebook_data:/app/data \
|
| 155 |
+
-v ./surreal_data:/mydata \
|
| 156 |
+
-e OPENAI_API_KEY=your_key_here \
|
| 157 |
+
-e API_URL=http://YOUR_SERVER_IP:5055 \
|
| 158 |
+
-e SURREAL_URL="ws://localhost:8000/rpc" \
|
| 159 |
+
-e SURREAL_USER="root" \
|
| 160 |
+
-e SURREAL_PASSWORD="root" \
|
| 161 |
+
-e SURREAL_NAMESPACE="open_notebook" \
|
| 162 |
+
-e SURREAL_DATABASE="production" \
|
| 163 |
+
lfnovo/open_notebook:v1-latest-single
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
**Replace `YOUR_SERVER_IP`** with your server's IP (e.g., `192.168.1.100`) or domain
|
| 167 |
+
|
| 168 |
+
**Access at:** http://YOUR_SERVER_IP:8502
|
| 169 |
+
|
| 170 |
+
</td>
|
| 171 |
+
</tr>
|
| 172 |
+
</table>
|
| 173 |
+
|
| 174 |
+
> **⚠️ Critical Setup Notes:**
|
| 175 |
+
>
|
| 176 |
+
> **Both ports are required:**
|
| 177 |
+
> - **Port 8502**: Web interface (what you see in your browser)
|
| 178 |
+
> - **Port 5055**: API backend (required for the app to function)
|
| 179 |
+
>
|
| 180 |
+
> **API_URL must match how YOU access the server:**
|
| 181 |
+
> - ✅ Access via `http://192.168.1.100:8502` → set `API_URL=http://192.168.1.100:5055`
|
| 182 |
+
> - ✅ Access via `http://myserver.local:8502` → set `API_URL=http://myserver.local:5055`
|
| 183 |
+
> - ❌ Don't use `localhost` for remote servers - it won't work from other devices!
|
| 184 |
+
|
| 185 |
+
### Using Docker Compose (Recommended for Easy Management)
|
| 186 |
+
|
| 187 |
+
Create a `docker-compose.yml` file:
|
| 188 |
+
|
| 189 |
+
```yaml
|
| 190 |
+
services:
|
| 191 |
+
open_notebook:
|
| 192 |
+
image: lfnovo/open_notebook:v1-latest-single
|
| 193 |
+
# Or use: ghcr.io/lfnovo/open-notebook:v1-latest-single
|
| 194 |
+
ports:
|
| 195 |
+
- "8502:8502" # Web UI
|
| 196 |
+
- "5055:5055" # API (required!)
|
| 197 |
+
environment:
|
| 198 |
+
- OPENAI_API_KEY=your_key_here
|
| 199 |
+
# For remote access, uncomment and set your server IP/domain:
|
| 200 |
+
# - API_URL=http://192.168.1.100:5055
|
| 201 |
+
# Database connection (required for single-container)
|
| 202 |
+
- SURREAL_URL=ws://localhost:8000/rpc
|
| 203 |
+
- SURREAL_USER=root
|
| 204 |
+
- SURREAL_PASSWORD=root
|
| 205 |
+
- SURREAL_NAMESPACE=open_notebook
|
| 206 |
+
- SURREAL_DATABASE=production
|
| 207 |
+
volumes:
|
| 208 |
+
- ./notebook_data:/app/data
|
| 209 |
+
- ./surreal_data:/mydata
|
| 210 |
+
restart: always
|
| 211 |
+
```
|
| 212 |
+
|
| 213 |
+
Start with: `docker compose up -d`
|
| 214 |
+
|
| 215 |
+
**What gets created:**
|
| 216 |
+
```
|
| 217 |
+
open-notebook/
|
| 218 |
+
├── docker-compose.yml # Your configuration
|
| 219 |
+
├── notebook_data/ # Your notebooks and research content
|
| 220 |
+
└── surreal_data/ # Database files
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
### 🆘 Quick Troubleshooting
|
| 224 |
+
|
| 225 |
+
| Problem | Solution |
|
| 226 |
+
|---------|----------|
|
| 227 |
+
| **"Unable to connect to server"** | Set `API_URL` environment variable to match how you access the server (see remote setup above) |
|
| 228 |
+
| **Blank page or errors** | Ensure BOTH ports (8502 and 5055) are exposed in your docker command |
|
| 229 |
+
| **Works on server but not from other computers** | Don't use `localhost` in `API_URL` - use your server's actual IP address |
|
| 230 |
+
| **"404" or "config endpoint" errors** | Don't add `/api` to `API_URL` - use just `http://your-ip:5055` |
|
| 231 |
+
| **Still having issues?** | Check our [5-minute troubleshooting guide](docs/troubleshooting/quick-fixes.md) or [join Discord](https://discord.gg/37XJPXfz2w) |
|
| 232 |
+
|
| 233 |
+
### How Open Notebook Works
|
| 234 |
+
|
| 235 |
+
```
|
| 236 |
+
┌─────────────────────────────────────────────────────────┐
|
| 237 |
+
│ Your Browser │
|
| 238 |
+
│ Access: http://your-server-ip:8502 │
|
| 239 |
+
└────────────────┬────────────────────────────────────────┘
|
| 240 |
+
│
|
| 241 |
+
▼
|
| 242 |
+
┌───────────────┐
|
| 243 |
+
│ Port 8502 │ ← Next.js Frontend (what you see)
|
| 244 |
+
│ Frontend │ Also proxies API requests internally!
|
| 245 |
+
└───────┬───────┘
|
| 246 |
+
│ proxies /api/* requests ↓
|
| 247 |
+
▼
|
| 248 |
+
┌───────────────┐
|
| 249 |
+
│ Port 5055 │ ← FastAPI Backend (handles requests)
|
| 250 |
+
│ API │
|
| 251 |
+
└───────┬───────┘
|
| 252 |
+
│
|
| 253 |
+
▼
|
| 254 |
+
┌───────────────┐
|
| 255 |
+
│ SurrealDB │ ← Database (internal, auto-configured)
|
| 256 |
+
│ (Port 8000) │
|
| 257 |
+
└───────────────┘
|
| 258 |
+
```
|
| 259 |
+
|
| 260 |
+
**Key Points:**
|
| 261 |
+
- **v1.1+**: Next.js automatically proxies `/api/*` requests to the backend, simplifying reverse proxy setup
|
| 262 |
+
- Your browser loads the frontend from port 8502
|
| 263 |
+
- The frontend needs to know where to find the API - when accessing remotely, set: `API_URL=http://your-server-ip:5055`
|
| 264 |
+
- **Behind reverse proxy?** You only need to proxy to port 8502 now! See [Reverse Proxy Guide](docs/deployment/reverse-proxy.md)
|
| 265 |
+
|
| 266 |
+
## Star History
|
| 267 |
+
|
| 268 |
+
[](https://www.star-history.com/#lfnovo/open-notebook&type=date&legend=top-left)
|
| 269 |
+
|
| 270 |
+
### 🛠️ Full Installation
|
| 271 |
+
For development or customization:
|
| 272 |
+
```bash
|
| 273 |
+
git clone https://github.com/lfnovo/open-notebook
|
| 274 |
+
cd open-notebook
|
| 275 |
+
make start-all
|
| 276 |
+
```
|
| 277 |
+
|
| 278 |
+
### 📖 Need Help?
|
| 279 |
+
- **🤖 AI Installation Assistant**: We have a [CustomGPT built to help you install Open Notebook](https://chatgpt.com/g/g-68776e2765b48191bd1bae3f30212631-open-notebook-installation-assistant) - it will guide you through each step!
|
| 280 |
+
- **New to Open Notebook?** Start with our [Getting Started Guide](docs/getting-started/index.md)
|
| 281 |
+
- **Need installation help?** Check our [Installation Guide](docs/getting-started/installation.md)
|
| 282 |
+
- **Want to see it in action?** Try our [Quick Start Tutorial](docs/getting-started/quick-start.md)
|
| 283 |
+
|
| 284 |
+
## Provider Support Matrix
|
| 285 |
+
|
| 286 |
+
Thanks to the [Esperanto](https://github.com/lfnovo/esperanto) library, we support this providers out of the box!
|
| 287 |
+
|
| 288 |
+
| Provider | LLM Support | Embedding Support | Speech-to-Text | Text-to-Speech |
|
| 289 |
+
|--------------|-------------|------------------|----------------|----------------|
|
| 290 |
+
| OpenAI | ✅ | ✅ | ✅ | ✅ |
|
| 291 |
+
| Anthropic | ✅ | ❌ | ❌ | ❌ |
|
| 292 |
+
| Groq | ✅ | ❌ | ✅ | ❌ |
|
| 293 |
+
| Google (GenAI) | ✅ | ✅ | ❌ | ✅ |
|
| 294 |
+
| Vertex AI | ✅ | ✅ | ❌ | ✅ |
|
| 295 |
+
| Ollama | ✅ | ✅ | ❌ | ❌ |
|
| 296 |
+
| Perplexity | ✅ | ❌ | ❌ | ❌ |
|
| 297 |
+
| ElevenLabs | ❌ | ❌ | ✅ | ✅ |
|
| 298 |
+
| Azure OpenAI | ✅ | ✅ | ❌ | ❌ |
|
| 299 |
+
| Mistral | ✅ | ✅ | ❌ | ❌ |
|
| 300 |
+
| DeepSeek | ✅ | ❌ | ❌ | ❌ |
|
| 301 |
+
| Voyage | ❌ | ✅ | ❌ | ❌ |
|
| 302 |
+
| xAI | ✅ | ❌ | ❌ | ❌ |
|
| 303 |
+
| OpenRouter | ✅ | ❌ | ❌ | ❌ |
|
| 304 |
+
| OpenAI Compatible* | ✅ | ❌ | ❌ | ❌ |
|
| 305 |
+
|
| 306 |
+
*Supports LM Studio and any OpenAI-compatible endpoint
|
| 307 |
+
|
| 308 |
+
## ✨ Key Features
|
| 309 |
+
|
| 310 |
+
### Core Capabilities
|
| 311 |
+
- **🔒 Privacy-First**: Your data stays under your control - no cloud dependencies
|
| 312 |
+
- **🎯 Multi-Notebook Organization**: Manage multiple research projects seamlessly
|
| 313 |
+
- **📚 Universal Content Support**: PDFs, videos, audio, web pages, Office docs, and more
|
| 314 |
+
- **🤖 Multi-Model AI Support**: 16+ providers including OpenAI, Anthropic, Ollama, Google, LM Studio, and more
|
| 315 |
+
- **🎙️ Professional Podcast Generation**: Advanced multi-speaker podcasts with Episode Profiles
|
| 316 |
+
- **🔍 Intelligent Search**: Full-text and vector search across all your content
|
| 317 |
+
- **💬 Context-Aware Chat**: AI conversations powered by your research materials
|
| 318 |
+
- **📝 AI-Assisted Notes**: Generate insights or write notes manually
|
| 319 |
+
|
| 320 |
+
### Advanced Features
|
| 321 |
+
- **⚡ Reasoning Model Support**: Full support for thinking models like DeepSeek-R1 and Qwen3
|
| 322 |
+
- **🔧 Content Transformations**: Powerful customizable actions to summarize and extract insights
|
| 323 |
+
- **🌐 Comprehensive REST API**: Full programmatic access for custom integrations [](http://localhost:5055/docs)
|
| 324 |
+
- **🔐 Optional Password Protection**: Secure public deployments with authentication
|
| 325 |
+
- **📊 Fine-Grained Context Control**: Choose exactly what to share with AI models
|
| 326 |
+
- **📎 Citations**: Get answers with proper source citations
|
| 327 |
+
|
| 328 |
+
### Three-Column Interface
|
| 329 |
+
1. **Sources**: Manage all your research materials
|
| 330 |
+
2. **Notes**: Create manual or AI-generated notes
|
| 331 |
+
3. **Chat**: Converse with AI using your content as context
|
| 332 |
+
|
| 333 |
+
[](https://www.youtube.com/watch?v=D-760MlGwaI)
|
| 334 |
+
|
| 335 |
+
## 📚 Documentation
|
| 336 |
+
|
| 337 |
+
### Getting Started
|
| 338 |
+
- **[📖 Introduction](docs/getting-started/introduction.md)** - Learn what Open Notebook offers
|
| 339 |
+
- **[⚡ Quick Start](docs/getting-started/quick-start.md)** - Get up and running in 5 minutes
|
| 340 |
+
- **[🔧 Installation](docs/getting-started/installation.md)** - Comprehensive setup guide
|
| 341 |
+
- **[🎯 Your First Notebook](docs/getting-started/first-notebook.md)** - Step-by-step tutorial
|
| 342 |
+
|
| 343 |
+
### User Guide
|
| 344 |
+
- **[📱 Interface Overview](docs/user-guide/interface-overview.md)** - Understanding the layout
|
| 345 |
+
- **[📚 Notebooks](docs/user-guide/notebooks.md)** - Organizing your research
|
| 346 |
+
- **[📄 Sources](docs/user-guide/sources.md)** - Managing content types
|
| 347 |
+
- **[📝 Notes](docs/user-guide/notes.md)** - Creating and managing notes
|
| 348 |
+
- **[💬 Chat](docs/user-guide/chat.md)** - AI conversations
|
| 349 |
+
- **[🔍 Search](docs/user-guide/search.md)** - Finding information
|
| 350 |
+
|
| 351 |
+
### Advanced Topics
|
| 352 |
+
- **[🎙️ Podcast Generation](docs/features/podcasts.md)** - Create professional podcasts
|
| 353 |
+
- **[🔧 Content Transformations](docs/features/transformations.md)** - Customize content processing
|
| 354 |
+
- **[🤖 AI Models](docs/features/ai-models.md)** - AI model configuration
|
| 355 |
+
- **[🔧 REST API Reference](docs/development/api-reference.md)** - Complete API documentation
|
| 356 |
+
- **[🔐 Security](docs/deployment/security.md)** - Password protection and privacy
|
| 357 |
+
- **[🚀 Deployment](docs/deployment/index.md)** - Complete deployment guides for all scenarios
|
| 358 |
+
|
| 359 |
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
| 360 |
+
|
| 361 |
+
## 🗺️ Roadmap
|
| 362 |
+
|
| 363 |
+
### Upcoming Features
|
| 364 |
+
- **Live Front-End Updates**: Real-time UI updates for smoother experience
|
| 365 |
+
- **Async Processing**: Faster UI through asynchronous content processing
|
| 366 |
+
- **Cross-Notebook Sources**: Reuse research materials across projects
|
| 367 |
+
- **Bookmark Integration**: Connect with your favorite bookmarking apps
|
| 368 |
+
|
| 369 |
+
### Recently Completed ✅
|
| 370 |
+
- **Next.js Frontend**: Modern React-based frontend with improved performance
|
| 371 |
+
- **Comprehensive REST API**: Full programmatic access to all functionality
|
| 372 |
+
- **Multi-Model Support**: 16+ AI providers including OpenAI, Anthropic, Ollama, LM Studio
|
| 373 |
+
- **Advanced Podcast Generator**: Professional multi-speaker podcasts with Episode Profiles
|
| 374 |
+
- **Content Transformations**: Powerful customizable actions for content processing
|
| 375 |
+
- **Enhanced Citations**: Improved layout and finer control for source citations
|
| 376 |
+
- **Multiple Chat Sessions**: Manage different conversations within notebooks
|
| 377 |
+
|
| 378 |
+
See the [open issues](https://github.com/lfnovo/open-notebook/issues) for a full list of proposed features and known issues.
|
| 379 |
+
|
| 380 |
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
## 🤝 Community & Contributing
|
| 384 |
+
|
| 385 |
+
### Join the Community
|
| 386 |
+
- 💬 **[Discord Server](https://discord.gg/37XJPXfz2w)** - Get help, share ideas, and connect with other users
|
| 387 |
+
- 🐛 **[GitHub Issues](https://github.com/lfnovo/open-notebook/issues)** - Report bugs and request features
|
| 388 |
+
- ⭐ **Star this repo** - Show your support and help others discover Open Notebook
|
| 389 |
+
|
| 390 |
+
### Contributing
|
| 391 |
+
We welcome contributions! We're especially looking for help with:
|
| 392 |
+
- **Frontend Development**: Help improve our modern Next.js/React UI
|
| 393 |
+
- **Testing & Bug Fixes**: Make Open Notebook more robust
|
| 394 |
+
- **Feature Development**: Build the coolest research tool together
|
| 395 |
+
- **Documentation**: Improve guides and tutorials
|
| 396 |
+
|
| 397 |
+
**Current Tech Stack**: Python, FastAPI, Next.js, React, SurrealDB
|
| 398 |
+
**Future Roadmap**: Real-time updates, enhanced async processing
|
| 399 |
+
|
| 400 |
+
See our [Contributing Guide](CONTRIBUTING.md) for detailed information on how to get started.
|
| 401 |
+
|
| 402 |
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
| 403 |
+
|
| 404 |
+
|
| 405 |
+
## 📄 License
|
| 406 |
+
|
| 407 |
+
Open Notebook is MIT licensed. See the [LICENSE](LICENSE) file for details.
|
| 408 |
+
|
| 409 |
+
## 📞 Contact
|
| 410 |
+
|
| 411 |
+
**Luis Novo** - [@lfnovo](https://twitter.com/lfnovo)
|
| 412 |
+
|
| 413 |
+
**Community Support**:
|
| 414 |
+
- 💬 [Discord Server](https://discord.gg/37XJPXfz2w) - Get help, share ideas, and connect with users
|
| 415 |
+
- 🐛 [GitHub Issues](https://github.com/lfnovo/open-notebook/issues) - Report bugs and request features
|
| 416 |
+
- 🌐 [Website](https://www.open-notebook.ai) - Learn more about the project
|
| 417 |
+
|
| 418 |
+
## 🙏 Acknowledgments
|
| 419 |
+
|
| 420 |
+
Open Notebook is built on the shoulders of amazing open-source projects:
|
| 421 |
+
|
| 422 |
+
* **[Podcast Creator](https://github.com/lfnovo/podcast-creator)** - Advanced podcast generation capabilities
|
| 423 |
+
* **[Surreal Commands](https://github.com/lfnovo/surreal-commands)** - Background job processing
|
| 424 |
+
* **[Content Core](https://github.com/lfnovo/content-core)** - Content processing and management
|
| 425 |
+
* **[Esperanto](https://github.com/lfnovo/esperanto)** - Multi-provider AI model abstraction
|
| 426 |
+
* **[Docling](https://github.com/docling-project/docling)** - Document processing and parsing
|
| 427 |
+
|
| 428 |
+
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
| 429 |
+
|
| 430 |
+
|
| 431 |
+
<!-- MARKDOWN LINKS & IMAGES -->
|
| 432 |
+
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
| 433 |
+
[contributors-shield]: https://img.shields.io/github/contributors/lfnovo/open-notebook.svg?style=for-the-badge
|
| 434 |
+
[contributors-url]: https://github.com/lfnovo/open-notebook/graphs/contributors
|
| 435 |
+
[forks-shield]: https://img.shields.io/github/forks/lfnovo/open-notebook.svg?style=for-the-badge
|
| 436 |
+
[forks-url]: https://github.com/lfnovo/open-notebook/network/members
|
| 437 |
+
[stars-shield]: https://img.shields.io/github/stars/lfnovo/open-notebook.svg?style=for-the-badge
|
| 438 |
+
[stars-url]: https://github.com/lfnovo/open-notebook/stargazers
|
| 439 |
+
[issues-shield]: https://img.shields.io/github/issues/lfnovo/open-notebook.svg?style=for-the-badge
|
| 440 |
+
[issues-url]: https://github.com/lfnovo/open-notebook/issues
|
| 441 |
+
[license-shield]: https://img.shields.io/github/license/lfnovo/open-notebook.svg?style=for-the-badge
|
| 442 |
+
[license-url]: https://github.com/lfnovo/open-notebook/blob/master/LICENSE.txt
|
| 443 |
+
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
|
| 444 |
+
[linkedin-url]: https://linkedin.com/in/lfnovo
|
| 445 |
+
[product-screenshot]: images/screenshot.png
|
| 446 |
+
[Next.js]: https://img.shields.io/badge/Next.js-000000?style=for-the-badge&logo=next.js&logoColor=white
|
| 447 |
+
[Next-url]: https://nextjs.org/
|
| 448 |
+
[React]: https://img.shields.io/badge/React-61DAFB?style=for-the-badge&logo=react&logoColor=black
|
| 449 |
+
[React-url]: https://reactjs.org/
|
| 450 |
+
[Python]: https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white
|
| 451 |
+
[Python-url]: https://www.python.org/
|
| 452 |
+
[LangChain]: https://img.shields.io/badge/LangChain-3A3A3A?style=for-the-badge&logo=chainlink&logoColor=white
|
| 453 |
+
[LangChain-url]: https://www.langchain.com/
|
| 454 |
+
[SurrealDB]: https://img.shields.io/badge/SurrealDB-FF5E00?style=for-the-badge&logo=databricks&logoColor=white
|
| 455 |
+
[SurrealDB-url]: https://surrealdb.com/
|
batch_fix_services.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Batch fix service files for mypy errors."""
|
| 3 |
+
import re
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
SERVICE_FILES = [
|
| 7 |
+
'api/notes_service.py',
|
| 8 |
+
'api/insights_service.py',
|
| 9 |
+
'api/episode_profiles_service.py',
|
| 10 |
+
'api/settings_service.py',
|
| 11 |
+
'api/sources_service.py',
|
| 12 |
+
'api/podcast_service.py',
|
| 13 |
+
'api/command_service.py',
|
| 14 |
+
]
|
| 15 |
+
|
| 16 |
+
BASE_DIR = Path('/Users/luisnovo/dev/projetos/open-notebook/open-notebook')
|
| 17 |
+
|
| 18 |
+
for service_file in SERVICE_FILES:
|
| 19 |
+
file_path = BASE_DIR / service_file
|
| 20 |
+
if not file_path.exists():
|
| 21 |
+
print(f"Skipping {service_file} - file not found")
|
| 22 |
+
continue
|
| 23 |
+
|
| 24 |
+
content = file_path.read_text()
|
| 25 |
+
original_content = content
|
| 26 |
+
|
| 27 |
+
# Pattern to find: var_name = api_client.method(args)
|
| 28 |
+
# Followed by: var_name["key"] or var_name.get("key")
|
| 29 |
+
lines = content.split('\n')
|
| 30 |
+
new_lines = []
|
| 31 |
+
i = 0
|
| 32 |
+
|
| 33 |
+
while i < len(lines):
|
| 34 |
+
line = lines[i]
|
| 35 |
+
|
| 36 |
+
# Check if this line has an api_client call assignment
|
| 37 |
+
match = re.match(r'(\s*)(\w+)\s*=\s*api_client\.(\w+)\((.*)\)\s*$', line)
|
| 38 |
+
if match and 'response = api_client' not in line:
|
| 39 |
+
indent = match.group(1)
|
| 40 |
+
var_name = match.group(2)
|
| 41 |
+
method_name = match.group(3)
|
| 42 |
+
args = match.group(4)
|
| 43 |
+
|
| 44 |
+
# Look ahead to see if this variable is used with dict access
|
| 45 |
+
has_dict_access = False
|
| 46 |
+
for j in range(i+1, min(i+15, len(lines))):
|
| 47 |
+
next_line = lines[j]
|
| 48 |
+
if f'{var_name}["' in next_line or f"{var_name}['" in next_line or f'{var_name}.get(' in next_line:
|
| 49 |
+
has_dict_access = True
|
| 50 |
+
break
|
| 51 |
+
# Stop looking if we hit a blank line, new function, or new assignment
|
| 52 |
+
if (not next_line.strip() or
|
| 53 |
+
next_line.strip().startswith('def ') or
|
| 54 |
+
next_line.strip().startswith('class ') or
|
| 55 |
+
(re.match(r'\s*\w+\s*=', next_line) and var_name not in next_line)):
|
| 56 |
+
break
|
| 57 |
+
|
| 58 |
+
if has_dict_access:
|
| 59 |
+
# Replace with response and isinstance check
|
| 60 |
+
new_lines.append(f'{indent}response = api_client.{method_name}({args})')
|
| 61 |
+
new_lines.append(f'{indent}{var_name} = response if isinstance(response, dict) else response[0]')
|
| 62 |
+
i += 1
|
| 63 |
+
continue
|
| 64 |
+
|
| 65 |
+
new_lines.append(line)
|
| 66 |
+
i += 1
|
| 67 |
+
|
| 68 |
+
new_content = '\n'.join(new_lines)
|
| 69 |
+
|
| 70 |
+
# Check if content changed
|
| 71 |
+
if new_content != original_content:
|
| 72 |
+
file_path.write_text(new_content)
|
| 73 |
+
print(f"✓ Fixed {service_file}")
|
| 74 |
+
else:
|
| 75 |
+
print(f"- No changes needed for {service_file}")
|
| 76 |
+
|
| 77 |
+
print("\nDone!")
|
docker-compose.dev.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
surrealdb:
|
| 3 |
+
image: surrealdb/surrealdb:v2
|
| 4 |
+
volumes:
|
| 5 |
+
- ./surreal_data:/mydata
|
| 6 |
+
environment:
|
| 7 |
+
- SURREAL_EXPERIMENTAL_GRAPHQL=true
|
| 8 |
+
command: start --log info --user root --pass root rocksdb:/mydata/mydatabase.db
|
| 9 |
+
pull_policy: always
|
| 10 |
+
user: root
|
| 11 |
+
restart: always
|
| 12 |
+
open_notebook:
|
| 13 |
+
build:
|
| 14 |
+
context: .
|
| 15 |
+
dockerfile: Dockerfile
|
| 16 |
+
ports:
|
| 17 |
+
- "8502:8502"
|
| 18 |
+
- "5055:5055"
|
| 19 |
+
env_file:
|
| 20 |
+
- ./docker.env
|
| 21 |
+
depends_on:
|
| 22 |
+
- surrealdb
|
| 23 |
+
volumes:
|
| 24 |
+
- ./notebook_data:/app/data
|
| 25 |
+
restart: always
|
| 26 |
+
|
docker-compose.full.yml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
surrealdb:
|
| 3 |
+
image: surrealdb/surrealdb:v2
|
| 4 |
+
volumes:
|
| 5 |
+
- ./surreal_data:/mydata
|
| 6 |
+
environment:
|
| 7 |
+
- SURREAL_EXPERIMENTAL_GRAPHQL=true
|
| 8 |
+
ports:
|
| 9 |
+
- "8000:8000"
|
| 10 |
+
command: start --log info --user root --pass root rocksdb:/mydata/mydatabase.db
|
| 11 |
+
pull_policy: always
|
| 12 |
+
user: root
|
| 13 |
+
restart: always
|
| 14 |
+
open_notebook:
|
| 15 |
+
image: lfnovo/open_notebook:v1-latest
|
| 16 |
+
ports:
|
| 17 |
+
- "8502:8502"
|
| 18 |
+
- "5055:5055"
|
| 19 |
+
env_file:
|
| 20 |
+
- ./docker.env
|
| 21 |
+
depends_on:
|
| 22 |
+
- surrealdb
|
| 23 |
+
volumes:
|
| 24 |
+
- ./notebook_data:/app/data
|
| 25 |
+
restart: always
|
docker-compose.single.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
open_notebook_single:
|
| 3 |
+
# image: lfnovo/open_notebook:v1-latest-single
|
| 4 |
+
build:
|
| 5 |
+
context: .
|
| 6 |
+
dockerfile: Dockerfile.single
|
| 7 |
+
ports:
|
| 8 |
+
- "8502:8502" # Next.js Frontend
|
| 9 |
+
- "5055:5055" # REST API
|
| 10 |
+
env_file:
|
| 11 |
+
- ./docker.env
|
| 12 |
+
volumes:
|
| 13 |
+
- ./notebook_data:/app/data # Application data
|
| 14 |
+
- ./surreal_single_data:/mydata # SurrealDB data
|
| 15 |
+
restart: always
|
| 16 |
+
# Single container includes all services: SurrealDB, API, Worker, and Next.js Frontend
|
| 17 |
+
# Access:
|
| 18 |
+
# - Next.js UI: http://localhost:8502
|
| 19 |
+
# - REST API: http://localhost:5055
|
| 20 |
+
# - API Documentation: http://localhost:5055/docs
|
logo.png
ADDED
|
Git LFS Details
|
mypy.ini
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[mypy]
|
| 2 |
+
# Only check for syntax errors, not type errors
|
| 3 |
+
# This allows the codebase to gradually add type hints
|
| 4 |
+
warn_return_any = False
|
| 5 |
+
warn_unused_configs = True
|
| 6 |
+
ignore_missing_imports = True
|
| 7 |
+
no_implicit_optional = False
|
| 8 |
+
check_untyped_defs = False
|
| 9 |
+
check_untyped_defs = True
|
| 10 |
+
explicit_package_bases = True
|
| 11 |
+
mypy_path = .
|
| 12 |
+
|
| 13 |
+
# Disable type checking for files with many errors
|
| 14 |
+
[mypy-api.client]
|
| 15 |
+
ignore_errors = True
|
| 16 |
+
|
| 17 |
+
[mypy-api.podcast_api_service]
|
| 18 |
+
ignore_errors = True
|
| 19 |
+
|
| 20 |
+
[mypy-api.auth]
|
| 21 |
+
ignore_errors = True
|
| 22 |
+
|
| 23 |
+
[mypy-api.routers.models]
|
| 24 |
+
ignore_errors = True
|
| 25 |
+
|
| 26 |
+
[mypy-open_notebook.domain.base]
|
| 27 |
+
ignore_errors = True
|
| 28 |
+
|
| 29 |
+
[mypy-open_notebook.domain.notebook]
|
| 30 |
+
ignore_errors = True
|
| 31 |
+
|
| 32 |
+
[mypy-open_notebook.graphs.transformation]
|
| 33 |
+
ignore_errors = True
|
| 34 |
+
|
| 35 |
+
[mypy-open_notebook.graphs.ask]
|
| 36 |
+
ignore_errors = True
|
pyproject.toml
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "open-notebook"
|
| 3 |
+
version = "1.1.1"
|
| 4 |
+
description = "An open source implementation of a research assistant, inspired by Google Notebook LM"
|
| 5 |
+
authors = [
|
| 6 |
+
{name = "Luis Novo", email = "lfnovo@gmail.com"}
|
| 7 |
+
]
|
| 8 |
+
readme = "README.md"
|
| 9 |
+
classifiers = [
|
| 10 |
+
"License :: OSI Approved :: MIT License",
|
| 11 |
+
"Programming Language :: Python :: 3",
|
| 12 |
+
"Programming Language :: Python :: 3.11",
|
| 13 |
+
]
|
| 14 |
+
requires-python = ">=3.11,<3.13"
|
| 15 |
+
dependencies = [
|
| 16 |
+
"fastapi>=0.104.0",
|
| 17 |
+
"uvicorn>=0.24.0",
|
| 18 |
+
"pydantic>=2.9.2",
|
| 19 |
+
"loguru>=0.7.2",
|
| 20 |
+
"langchain>=0.3.3",
|
| 21 |
+
"langgraph>=0.2.38",
|
| 22 |
+
"tiktoken>=0.8.0",
|
| 23 |
+
"langgraph-checkpoint-sqlite>=2.0.0",
|
| 24 |
+
"langchain-community>=0.3.3",
|
| 25 |
+
"langchain-openai>=0.2.3",
|
| 26 |
+
"langchain-anthropic>=0.2.3",
|
| 27 |
+
"langchain-ollama>=0.2.0",
|
| 28 |
+
"langchain-google-genai>=2.1.10",
|
| 29 |
+
"langchain-groq>=0.2.1",
|
| 30 |
+
"langchain_mistralai>=0.2.1",
|
| 31 |
+
"langchain_deepseek>=0.1.3",
|
| 32 |
+
"tomli>=2.0.2",
|
| 33 |
+
"groq>=0.12.0",
|
| 34 |
+
"python-dotenv>=1.0.1",
|
| 35 |
+
"httpx[socks]>=0.27.0",
|
| 36 |
+
"content-core>=1.0.2",
|
| 37 |
+
"ai-prompter>=0.3",
|
| 38 |
+
"esperanto>=2.4.1",
|
| 39 |
+
"langchain-google-vertexai>=2.0.28",
|
| 40 |
+
"surrealdb>=1.0.4",
|
| 41 |
+
"surreal-commands>=1.0.13",
|
| 42 |
+
"podcast-creator>=0.7.0",
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
[tool.setuptools]
|
| 46 |
+
package-dir = {"open_notebook" = "open_notebook"}
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
[project.optional-dependencies]
|
| 50 |
+
dev = [
|
| 51 |
+
"ipykernel>=6.29.5",
|
| 52 |
+
"ruff>=0.5.5",
|
| 53 |
+
"mypy>=1.11.1",
|
| 54 |
+
"types-requests>=2.32.0.20241016",
|
| 55 |
+
"ipywidgets>=8.1.5",
|
| 56 |
+
"pre-commit>=4.0.1",
|
| 57 |
+
"pytest>=8.0.0",
|
| 58 |
+
]
|
| 59 |
+
|
| 60 |
+
[build-system]
|
| 61 |
+
requires = ["setuptools>=61.0"]
|
| 62 |
+
build-backend = "setuptools.build_meta"
|
| 63 |
+
|
| 64 |
+
[dependency-groups]
|
| 65 |
+
dev = [
|
| 66 |
+
"pre-commit>=4.1.0",
|
| 67 |
+
"pytest-asyncio>=1.2.0",
|
| 68 |
+
"types-requests>=2.32.4.20250913",
|
| 69 |
+
]
|
| 70 |
+
|
| 71 |
+
[tool.isort]
|
| 72 |
+
profile = "black"
|
| 73 |
+
line_length = 88
|
| 74 |
+
|
| 75 |
+
[tool.ruff]
|
| 76 |
+
line-length = 88
|
| 77 |
+
|
| 78 |
+
[tool.ruff.lint]
|
| 79 |
+
select = ["E", "F", "I"]
|
| 80 |
+
ignore = [
|
| 81 |
+
"E501", # line too long
|
| 82 |
+
"E402", # module level import not at top of file (Streamlit requires this pattern)
|
| 83 |
+
"E722", # do not use bare except (legacy code pattern)
|
| 84 |
+
"F401", # imported but unused (may be used in type hints or re-exports)
|
| 85 |
+
"F541", # f-string without placeholders
|
| 86 |
+
"F841", # local variable assigned but never used
|
| 87 |
+
]
|
| 88 |
+
|
| 89 |
+
[tool.ruff.lint.per-file-ignores]
|
| 90 |
+
# Streamlit files need nest_asyncio.apply() before imports
|
| 91 |
+
"app_home.py" = ["E402"]
|
| 92 |
+
"pages/**/*.py" = ["E402"]
|
| 93 |
+
|
| 94 |
+
[tool.mypy]
|
| 95 |
+
# Exclude Streamlit UI pages from type checking
|
| 96 |
+
[[tool.mypy.overrides]]
|
| 97 |
+
module = "pages.*"
|
| 98 |
+
ignore_errors = true
|
run_api.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Startup script for Open Notebook API server.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import sys
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
import uvicorn
|
| 11 |
+
|
| 12 |
+
# Add the current directory to Python path so imports work
|
| 13 |
+
current_dir = Path(__file__).parent
|
| 14 |
+
sys.path.insert(0, str(current_dir))
|
| 15 |
+
|
| 16 |
+
if __name__ == "__main__":
|
| 17 |
+
# Default configuration
|
| 18 |
+
host = os.getenv("API_HOST", "127.0.0.1")
|
| 19 |
+
port = int(os.getenv("API_PORT", "5055"))
|
| 20 |
+
reload = os.getenv("API_RELOAD", "true").lower() == "true"
|
| 21 |
+
|
| 22 |
+
print(f"Starting Open Notebook API server on {host}:{port}")
|
| 23 |
+
print(f"Reload mode: {reload}")
|
| 24 |
+
|
| 25 |
+
uvicorn.run(
|
| 26 |
+
"api.main:app",
|
| 27 |
+
host=host,
|
| 28 |
+
port=port,
|
| 29 |
+
reload=reload,
|
| 30 |
+
reload_dirs=[str(current_dir)] if reload else None,
|
| 31 |
+
)
|
supervisord.conf
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[supervisord]
|
| 2 |
+
nodaemon=true
|
| 3 |
+
logfile=/dev/stdout
|
| 4 |
+
logfile_maxbytes=0
|
| 5 |
+
pidfile=/tmp/supervisord.pid
|
| 6 |
+
|
| 7 |
+
[program:api]
|
| 8 |
+
command=uv run uvicorn api.main:app --host 0.0.0.0 --port 5055
|
| 9 |
+
stdout_logfile=/dev/stdout
|
| 10 |
+
stdout_logfile_maxbytes=0
|
| 11 |
+
stderr_logfile=/dev/stderr
|
| 12 |
+
stderr_logfile_maxbytes=0
|
| 13 |
+
autorestart=true
|
| 14 |
+
priority=10
|
| 15 |
+
autostart=true
|
| 16 |
+
|
| 17 |
+
[program:worker]
|
| 18 |
+
command=uv run surreal-commands-worker --import-modules commands
|
| 19 |
+
stdout_logfile=/dev/stdout
|
| 20 |
+
stdout_logfile_maxbytes=0
|
| 21 |
+
stderr_logfile=/dev/stderr
|
| 22 |
+
stderr_logfile_maxbytes=0
|
| 23 |
+
autorestart=true
|
| 24 |
+
priority=20
|
| 25 |
+
autostart=true
|
| 26 |
+
startsecs=3
|
| 27 |
+
|
| 28 |
+
[program:frontend]
|
| 29 |
+
command=bash -c "sleep 5 && npm run start"
|
| 30 |
+
directory=/app/frontend
|
| 31 |
+
environment=NODE_ENV="production",PORT="8502"
|
| 32 |
+
passenv=API_URL,NEXT_PUBLIC_API_URL,INTERNAL_API_URL
|
| 33 |
+
stdout_logfile=/dev/stdout
|
| 34 |
+
stdout_logfile_maxbytes=0
|
| 35 |
+
stderr_logfile=/dev/stderr
|
| 36 |
+
stderr_logfile_maxbytes=0
|
| 37 |
+
autorestart=true
|
| 38 |
+
priority=30
|
| 39 |
+
autostart=true
|
| 40 |
+
startsecs=5
|
supervisord.single.conf
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[supervisord]
|
| 2 |
+
nodaemon=true
|
| 3 |
+
logfile=/dev/stdout
|
| 4 |
+
logfile_maxbytes=0
|
| 5 |
+
pidfile=/tmp/supervisord.pid
|
| 6 |
+
|
| 7 |
+
[program:surrealdb]
|
| 8 |
+
command=surreal start --log trace --user root --pass root rocksdb:/mydata/mydatabase.db
|
| 9 |
+
stdout_logfile=/dev/stdout
|
| 10 |
+
stdout_logfile_maxbytes=0
|
| 11 |
+
stderr_logfile=/dev/stderr
|
| 12 |
+
stderr_logfile_maxbytes=0
|
| 13 |
+
autorestart=true
|
| 14 |
+
priority=5
|
| 15 |
+
autostart=true
|
| 16 |
+
startsecs=5
|
| 17 |
+
|
| 18 |
+
[program:api]
|
| 19 |
+
command=uv run uvicorn api.main:app --host 0.0.0.0 --port 5055
|
| 20 |
+
stdout_logfile=/dev/stdout
|
| 21 |
+
stdout_logfile_maxbytes=0
|
| 22 |
+
stderr_logfile=/dev/stderr
|
| 23 |
+
stderr_logfile_maxbytes=0
|
| 24 |
+
autorestart=true
|
| 25 |
+
priority=10
|
| 26 |
+
autostart=true
|
| 27 |
+
startsecs=3
|
| 28 |
+
|
| 29 |
+
[program:worker]
|
| 30 |
+
command=uv run surreal-commands-worker --import-modules commands
|
| 31 |
+
stdout_logfile=/dev/stdout
|
| 32 |
+
stdout_logfile_maxbytes=0
|
| 33 |
+
stderr_logfile=/dev/stderr
|
| 34 |
+
stderr_logfile_maxbytes=0
|
| 35 |
+
autorestart=true
|
| 36 |
+
priority=20
|
| 37 |
+
autostart=true
|
| 38 |
+
startsecs=3
|
| 39 |
+
|
| 40 |
+
[program:frontend]
|
| 41 |
+
command=bash -c "sleep 5 && npm run start"
|
| 42 |
+
directory=/app/frontend
|
| 43 |
+
environment=NODE_ENV="production",PORT="8502"
|
| 44 |
+
passenv=API_URL,NEXT_PUBLIC_API_URL,INTERNAL_API_URL
|
| 45 |
+
stdout_logfile=/dev/stdout
|
| 46 |
+
stdout_logfile_maxbytes=0
|
| 47 |
+
stderr_logfile=/dev/stderr
|
| 48 |
+
stderr_logfile_maxbytes=0
|
| 49 |
+
autorestart=true
|
| 50 |
+
priority=30
|
| 51 |
+
autostart=true
|
| 52 |
+
startsecs=5
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|