A powerful desktop RAG (Retrieval-Augmented Generation) application built with Electron, React, and FastAPI. Chat with AI models (Ollama/OpenAI) with document-based context and long-term memory.
- Multiple LLM Support: Works with Ollama (local) or OpenAI models
- Streaming Responses: Real-time token streaming with Server-Sent Events (SSE)
- Conversation History: SQLite-backed persistent chat storage
- Chat Management: Create, rename, delete, and search through conversations
- Automatic Title Generation: AI-generated chat titles based on conversation content
- Multi-Format Support: PDF, TXT, MD, JSON, PY, DOCX
- OCR Fallback: Automatic OCR for scanned PDFs using Tesseract
- Smart Chunking: Semantic text splitting with configurable chunk size/overlap
- Vector Storage: ChromaDB for efficient similarity search
- Real-Time Progress: SSE-based upload progress with stage updates
- Search Modes: Normal (LLM only), Embeddings Only (RAG), or All (hybrid)
- Long-Term Memory: Mem0 integration for cross-session context retention
- Automatic Deduplication: Prevents redundant memory storage
- Semantic Search: Retrieve relevant memories based on current query
- User-Scoped: Memories isolated per user
- Platform-Specific Storage: Uses AppData on Windows, ~/Library on macOS, ~/.config on Linux
- SQLite Database: Users, Chats, Messages, Documents, UserSettings
- ChromaDB Collections: Per-chat vector stores for document embeddings
- Mem0 Storage: Long-term memory in dedicated ChromaDB collection
- Per-User Settings: Model selection, temperature, max_tokens, top_p, top_k, system prompt
- Dark/Light Theme: Persistent theme with system integration
- Backend Auto-Start: Electron spawns backend subprocess on launch
- Health Monitoring: Real-time connection status indicator
- Automatic Cleanup: Temporary files deleted after processing
- Size Validation: Configurable upload limits (default: 100MB)
- Error Recovery: Graceful fallbacks for missing dependencies
- Single Instance Lock: Prevents multiple app instances
graph TB
A[Electron Main Process] -->|Spawns| B[backend.exe]
A -->|Loads| C[React/Vite UI]
C -->|HTTP/SSE| D[FastAPI Backend]
D -->|LLM/Embeddings| E[Ollama/OpenAI]
D -->|Vector Store| F[ChromaDB]
D -->|Persistence| G[SQLite]
D -->|Memory| H[Mem0]
D -->|PDF Processing| I[OCR/PyPDF2]
Tech Stack:
- Frontend: Electron 26, TypeScript, React 19, Vite, TailwindCSS 4
- Backend: FastAPI, ChromaDB, SQLite (SQLModel), Mem0, LangChain
- LLM Providers: Ollama (local), OpenAI (cloud)
- Build Tools: PyInstaller (backend), electron-builder (packaging)
- Node.js 18+ (for Electron/React)
- Python 3.10+ (for FastAPI backend)
- Ollama (optional, for local LLM) - Download
- Poppler (for PDF processing with OCR) - Download
- Tesseract OCR (for scanned PDFs) - Download
git clone https://github.com/yourusername/ElectronAIChat.git
cd ElectronAIChatcd backend
pip install -r requirements.txt
# Copy and configure environment variables
cp .env.example .env
# Edit .env to set:
# - LLM_PROVIDER (ollama or openai)
# - OLLAMA_HOST (if using Ollama)
# - OPENAI_API_KEY (if using OpenAI)
# - POPPLER_PATH (path to Poppler bin directory)cd electron
npm installTerminal 1: Start Backend
cd backend
python main.py # FastAPI runs on http://127.0.0.1:8000Terminal 2: Start Electron + React Dev Server
cd electron
npm run start # Vite on http://localhost:5173, Electron watchesKey Points:
- Dev mode expects backend running separately
- Hot reload enabled for both frontend and backend
- Electron loads
http://localhost:5173when not packaged - Backend logs to console and
logs/directory
Backend (.env in backend/):
LLM_PROVIDER=ollama # "ollama" or "openai"
OLLAMA_HOST=http://localhost:11434
OLLAMA_EMBED_MODEL=nomic-embed-text
OLLAMA_LLM_MODEL=llama2
OPENAI_API_KEY=sk-... # Required if LLM_PROVIDER=openai
OPENAI_EMBED_MODEL=text-embedding-3-small
OPENAI_LLM_MODEL=gpt-3.5-turbo
USE_APP_DATA_DIR=false # Override packaged detection
POPPLER_PATH=C:\path\to\poppler\bin # For PDF OCRcd backend
pyinstaller backend.spec # Creates dist/backend.execd electron
npm run prepackage # Copies backend.exe to electron/dist/
npm run package # Creates installer in electron/dist/Output:
- Windows:
electron/dist/ElectronAIChat Setup X.X.X.exe(NSIS installer) - Includes both Electron app and backend.exe
- Installer allows custom installation directory
prePackage.jschecks forbackend.exe, builds if missing- Copies
backend.exetoelectron/dist/ electron-builderpackages app with backend as extraResource- Backend runs as subprocess in production
When packaged, application data is stored in platform-specific directories:
- Windows:
%APPDATA%\ElectronAIChat - macOS:
~/Library/Application Support/ElectronAIChat - Linux:
~/.config/ElectronAIChat
Contents:
chat_history.db- SQLite database (users, chats, messages, documents, settings)chroma_db/{chatId}/- Per-chat vector stores for RAGchroma_db/mem0/- Long-term memory storageuploads/- Temporary upload directory (cleaned after processing)logs/- Backend application logs
Documents are processed in stages:
- Upload: Validate size and type
- Extract: PyPDF2 for text, OCR fallback for scanned PDFs, JSON parsing
- Chunk: Semantic splitting with
RecursiveCharacterTextSplitter(500 chars, 50 overlap) - Embed: Generate embeddings with Ollama or OpenAI
- Store: Save to ChromaDB with metadata (chatId, userId, filename)
- Query: Retrieve top-k similar chunks during chat for context injection
Search Modes:
- Normal: LLM without RAG context
- Embeddings Only: RAG-only responses (requires documents)
- All: Hybrid approach with both LLM knowledge and document context
Powered by Mem0 for long-term context retention:
- Automatically stores user/assistant messages after chat
- Extracts facts and prevents duplication
- Retrieves relevant memories based on current query
- Injected into system prompt for context-aware responses
Expected Behavior:
- Empty results mean Mem0 found no NEW facts to store (deduplication working)
- Falls back to
MemoryStub(naive in-memory store) ifmem0aiunavailable
Server-Sent Events (SSE) for real-time token streaming:
// Frontend creates message before stream starts
const aiMessage = { id: messageId, role: 'assistant', content: '' };
// Progressive updates as tokens arrive
chunk.token && updateMessage(aiMessage.id, content += chunk.token);
// Final event signals completion with sources
chunk.done && attachSources(aiMessage.id, chunk.sources);Backend emits:
yield f"data: {json.dumps({'token': token, 'done': False})}\n\n"
# ... more tokens ...
yield f"data: {json.dumps({'token': '', 'done': True, 'sources': [...]})}\n\n"GET /- API overview and system infoGET /api/health- Health check for all componentsPOST /api/chat/stream- Streaming chat completions (SSE)
GET /api/chats/{user_id}- List user's chatsPOST /api/chats/create- Create new chatGET /api/chats/detail/{chat_id}- Get chat with messagesPUT /api/chats/{chat_id}- Update chat (title, search_mode)DELETE /api/chats/{chat_id}- Delete chat
POST /documents/upload- Upload document (non-streaming)POST /documents/upload/stream- Upload with progress (SSE)
POST /api/users/create- Create userGET /api/users/{username}- Get user by usernameGET /api/users/{user_id}/settings- Get user settingsPUT /api/users/{user_id}/settings- Update user settings
POST /api/admin/reset- Delete all application data (DANGEROUS)GET /api/admin/data-locations- Get storage pathsGET /api/admin/has-data- Check if data exists
# 1. Run backend directly to see errors
cd backend
python main.py
# 2. Check database (delete if schema changed)
rm chat_history.db # Or delete in AppData
# 3. Verify dependencies
pip install -r requirements.txt# Delete and rebuild collection
rm -rf "%APPDATA%\ElectronAIChat\chroma_db\{chatId}"
# Re-upload documents to recreate# 1. Install Tesseract OCR
# Download from: https://github.com/tesseract-ocr/tesseract
# 2. Install Poppler
# Download from: https://github.com/oschwaldp/poppler-windows/releases
# 3. Set POPPLER_PATH in .env
POPPLER_PATH=C:\path\to\poppler-xx\bin# Windows: Kill all backend processes
taskkill /IM backend.exe /T /F
# Ensure Electron's before-quit hook is working
# Check main.ts: app.on('before-quit', ...) calls stopBackend()- Backend Startup: First launch slower (30s timeout) due to database init and model loading
- OCR Dependency: Hardcoded Poppler path in
backend/app/config.py(override viaPOPPLER_PATHenv var) - CORS: Backend allows all origins in development (
allow_origins=["*"]) - No Migration System: Database schema changes require manual deletion of
chat_history.db - Single User Focus: Multi-user support exists but UI designed for single-user desktop use
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CONTRIBUTING.md for detailed guidelines.
ElectronAIChat is free, open, and hackable. Run it, fork it, and share it — no strings attached — except one: don't sell it as-a-service without permission.
See LICENSE for full terms.
- LangChain - Embeddings and RAG framework
- ChromaDB - Vector database
- Mem0 - Memory management system
- FastAPI - Backend framework
- Electron - Desktop app framework
- Ollama - Local LLM runtime
For questions or issues:
- Open an issue on GitHub
- Check the troubleshooting section
- Review backend logs in
logs/directory
Built with ❤️ for local-first AI applications