Gemini Integration:
- Added Google Gemini 2.0 Flash as alternative to OpenAI GPT-4
- Per-notebook model selection (choose when creating)
- Model type stored in notebooks.model_type column
- Complete support for chat, synthesis, and podcasts
LLM Factory:
- Created llm_factory.py module
- get_llm_by_type('openai' | 'gemini')
- get_structured_llm() for pydantic outputs
- Model display names and emojis
- Cost information
Model Selection UI:
- Dropdown in notebook creation form
- Options: OpenAI GPT-4 or Gemini 2.0 Flash
- Shows cost comparison
- Model badge in notebook detail header
- Displays: "🤖 Using OpenAI GPT-4" or "✨ Using Gemini 2.0 Flash"
Integration Points:
- pipeline_manager.py: Query engine uses selected model
- notebook_synthesis.py: Synthesis uses selected model
- background_tasks.py: Podcasts use selected model
- pages/3_Notebook_Chat.py: Chat uses selected model
- All functions pass model_type parameter
Cost Savings:
- Gemini 2.0 Flash: FREE tier available
- OpenAI GPT-4: ~$0.03/1K tokens
- Users can choose based on budget/quality needs
Dependencies Added:
- llama-index-llms-gemini>=0.3.0
- google-generativeai>=0.8.0
Note: Requires GOOGLE_API_KEY in .env (optional)
- If not set, Gemini notebooks will error
- OpenAI notebooks continue to work
Database:
- Added model_type VARCHAR(50) DEFAULT 'openai'
- Indexed for performance
- Existing notebooks default to 'openai'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Chat System Complete:
- Fixed function name conflict (chat → query_chat)
- Private chats show "🤝 Share" button (action to take)
- Shared chats show "🔒 Make Private" button (action to take)
- Button text now shows the ACTION not the current state
- New Chat button works perfectly
- Chat sessions listed in sidebar
- Multiple chats per notebook per user
- Rename chat functionality
- Delete chat functionality
- Share/unshare toggle
- Privacy by default
Features Working:
✅ Create new chat (fresh context)
✅ Switch between chat sessions
✅ Rename any chat
✅ Share chat with collaborators
✅ Unshare (make private again)
✅ Delete chat sessions
✅ View shared chats from others
✅ Chat history persistence
✅ Private by default
✅ Per-notebook pipeline isolation
Bug Fixes:
- Renamed chat() function to avoid shadowing by loop variable
- Fixed shared chat actions menu (⋮ now visible)
- Added extensive debug logging
- Better error handling in pipeline queries
- Fixed button text logic (show action, not state)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Security Fix:
- Fixed critical data leakage where all users shared one pipeline
- Each notebook now gets dedicated LlamaCloud pipeline
- Complete data isolation between notebooks
- Users can ONLY query their own notebook's documents
Pipeline Management:
- Created pipeline_manager.py module
- create_notebook_pipeline() creates dedicated pipeline
- add_document_to_pipeline() adds to specific pipeline
- query_notebook_pipeline() queries only that pipeline
- get_notebook_query_engine() returns isolated query engine
Database Changes:
- Added pipeline_id column to notebooks table
- Indexed for performance
- Stored when notebook created
Notebook Creation:
- create_notebook() now creates LlamaCloud pipeline
- Pipeline named: "notebook_{id}_{name}"
- pipeline_id stored in notebook record
- Async pipeline creation
Document Processing:
- execute_document_processing_task() uses notebook.pipeline_id
- Documents added to NOTEBOOK's pipeline (not shared!)
- Complete isolation per notebook
- Validates pipeline exists before processing
Chat Updates:
- Removed MCP client (was using shared pipeline!)
- Now uses pipeline_manager.query_notebook_pipeline()
- Queries ONLY the notebook's dedicated pipeline
- Shows warning if notebook has no pipeline
- Caption: "Chatting across X documents in this notebook only"
Bug Fixes:
- Fixed Admin Dashboard import (BackgroundTask from background_tasks)
- Yellow button CSS using correct selector (baseButton-primary)
- Delete buttons stay red using :has(div:contains()) selector
Data Isolation Verification:
- Each notebook = separate LlamaCloud pipeline
- Each pipeline = isolated index
- Chat queries single pipeline only
- No cross-notebook data leakage
Migration Note:
- Old notebooks without pipeline_id will show warning
- Need to create new notebooks to get pipeline isolation
- Could add migration script to create pipelines for existing notebooks
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Button Color Fix:
- Changed CSS selector to target data-testid="baseButton-primary"
- Primary buttons now yellow (#FFC407) with black text
- Hover state: darker yellow (#E6B006)
- Delete/Remove buttons stay red for safety
- Better font-weight (600) for buttons
Critical Issue Documented:
- Created CRITICAL_ISSUE.md documenting data leakage
- ALL users share ONE LlamaCloud pipeline
- Chat queries return documents from ALL notebooks (not just user's)
- SEVERE privacy/security issue
- Must be fixed before production use
Issue Details:
- utils.py uses single PIPELINE_ID from .env
- All documents added to same index
- query_index() searches entire shared index
- No user/notebook isolation in queries
Recommended Fix:
- Per-notebook pipelines (best for NotebookLM model)
- Store pipeline_id in notebooks table
- Create pipeline when notebook created
- Query only that notebook's pipeline
- Complete data isolation
Background Queue Status:
- Document processing IS using background queue ✓
- Some tasks failing with "Event loop is closed"
- Need to investigate async/threading issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Logo Implementation:
- Logo now appears on ALL pages automatically
- Moved logo display to apply_custom_styles() function
- 300px width, positioned at top with margin adjustments
- Uses SBLM.jpg from src/notebookllama/
Login Page Improvements:
- Sidebar completely hidden when not logged in
- Cleaner login experience
- No navigation shown to unauthenticated users
- Title updated to "Sandbox-NotebookLM - Login"
Admin Dashboard:
- Replaced Observability Dashboard with Admin Dashboard
- Shows platform usage statistics:
* Total users, notebooks, documents, chat messages
* Estimated costs (documents, chats, podcasts)
* Recent activity (users, notebooks, documents)
* Background task monitoring
* User analytics (most active users)
* System health (failed/pending tasks)
Admin Access Control:
- Only user ID 1 or users with "admin" in email can access
- Admin link only shows in sidebar for admins
- Protected with access check
Cost Tracking:
- Document processing: ~$0.60 each
- Chat messages: ~$0.01 each
- Podcasts: ~$0.50 each
- Total cost estimate displayed
Analytics Features:
- Top 5 most active users by notebook count
- Recent users/notebooks/documents lists
- Background task status with color coding
- System health indicators
- Real-time statistics
Files:
- Created pages/5_Admin_Dashboard.py
- Removed pages/5_Observability_Dashboard.py (backed up)
- Updated styles.py with show_logo() function
- Updated App.py navigation to show Admin conditionally
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
UI Updates:
- Changed login page title to "Sandbox-NotebookLM - Login"
- Hidden deploy button in top right (toolbar hidden)
- Added Sandbox-NotebookLM logo to top left header
- Logo is SVG with concentric circles icon
- Logo shows "Sandbox" and "NotebookLM" text
- Montserrat font in logo matches app
CSS Changes:
- [data-testid="stToolbar"] display:none (hides deploy)
- [data-testid="stHeader"] background-image with logo SVG
- Logo positioned 10px from left, centered vertically
- 160px logo size
- Header padding adjusted for logo space
Visual Improvements:
- Cleaner header without deploy button
- Professional branding with logo
- Consistent typography throughout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Permission System Upgrade:
- Added SHARE permission level to database enum
- Three permission tiers now:
* READ: View and chat only
* WRITE: View, chat, add documents, generate podcasts
* SHARE (Write+Share): All of WRITE + can share with others
- Only owners can grant SHARE permission
- Users with SHARE can add more collaborators
Voice Selection for Podcasts:
- Added 8 popular ElevenLabs voices to choose from
- Speaker 1 (Analytical): Brian, Adam, Charlie, Daniel
- Speaker 2 (Explanatory): Sarah, Bella, Charlotte, Emily
- Voice IDs stored in task parameters
- Passed through to audio generation
- Default: Brian + Sarah (original voices)
Voice Options:
- Brian (Default Male) - nPczCjzI2devNBz1zQrb
- Sarah (Default Female) - Xb7hH8MSUJpSbSDYk0k2
- Adam (Deep Male) - pNInz6obpgDQGcFmaJgB
- Bella (Friendly Female) - EXAVITQu4vr4xnSDxMaL
- Charlie (Casual Male) - IKne3meq5aSn9XLyUdCD
- Charlotte (Professional Female) - XB0fDUnXU5powFXDhCwa
- Daniel (British Male) - onwK4e9ZLuTAKqWW03F9
- Emily (Warm Female) - LcfcDJNUP1GQjkzn1xUU
UI Updates:
- Voice selection dropdowns in podcast generation
- Helpful descriptions for each speaker role
- Permission level shown as "Write + Share" in UI
- Help text explains each permission tier
- Share button visible for users with SHARE permission
Technical:
- Updated audio.py to accept voice parameters
- Updated background_tasks.py to pass voices
- Database enum extended
- Permission checks updated throughout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Background Document Processing:
- Documents now process in background queue (like podcasts!)
- Upload 10+ PDFs and navigate away immediately
- Each document processes independently (~1 minute each)
- Status tracking for all documents
- Can view processing progress in notebook detail
- Automatic refresh option to check status
Processing Status Display:
- Shows "⏳ X documents currently processing"
- Expandable status list with filename and state
- Icons: ⏳ pending, 🔄 in progress, ✓ completed
- Refresh button to check latest status
- Processing happens in parallel threads
Navigation Fix:
- Fixed CSS to hide Streamlit's auto-generated page list (bottom-left)
- Kept custom navigation at top of sidebar
- Better selector: section[data-testid="stSidebarNav"]
- Custom nav remains visible and functional
Technical:
- Extended background_tasks.py to handle document processing
- Created execute_document_processing_task function
- start_document_processing_background creates tasks
- get_notebook_processing_tasks retrieves status
- Task routing based on task_type
- Proper temp file cleanup in background
User Experience:
- Can upload 20 documents and leave immediately
- No more waiting 20+ minutes on one page
- Processing continues in background
- Come back anytime to check progress
- Much better for large batch uploads
Button Updates:
- "Upload & Process" → "Upload & Process in Background"
- Clear messaging about background processing
- Task IDs shown for tracking
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Rebranding:
- Changed app name from NotebookLlaMa to Sandbox-NotebookLM
- Updated all page titles
- Updated dashboard title and welcome message
UI Improvements:
- Reduced sidebar username size (was too large)
- Changed "Welcome, username!" to just "username" with emoji
- Email shown as caption below username
- Removed redundant bottom-left navigation menu (hidden via CSS)
- Sidebar navigation headers reduced to 14px
- Logout button now full-width for better UX
Typography Refinements:
- Sidebar headers: 16px → 14px
- Navigation items cleaner
- Better visual hierarchy
- More professional appearance
CSS Changes:
- Added [data-testid="stSidebarNav"] display:none to hide duplicate nav
- Reduced sidebar h1/h2/h3 to 14px
- Better spacing in sidebar
- Consistent font weights
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>