jmisak commited on
Commit
6f25064
·
verified ·
1 Parent(s): 99640e0

Upload 25 files

Browse files
.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
- title: OpenNotebook
3
- emoji: 📚
4
- colorFrom: red
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
- short_description: 'Notebook LM '
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ ![New Notebook](docs/assets/asset_list.png)
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
+ [![Star History Chart](https://api.star-history.com/svg?repos=lfnovo/open-notebook&type=date&legend=top-left)](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 [![API Docs](https://img.shields.io/badge/API-Documentation-blue?style=flat-square)](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
+ [![Check out our podcast sample](https://img.youtube.com/vi/D-760MlGwaI/0.jpg)](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

  • SHA256: 05939a3fd9754da64ed098be04acb9775deba89b9965961616d7877cc0ee17c7
  • Pointer size: 132 Bytes
  • Size of remote file: 1.05 MB
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