{"id":50253679,"url":"https://github.com/zaxbysauce/trainingapp","last_synced_at":"2026-05-27T03:14:50.580Z","repository":{"id":343853156,"uuid":"1168799869","full_name":"zaxbysauce/trainingapp","owner":"zaxbysauce","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-17T20:44:52.000Z","size":2585,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-17T20:45:59.379Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Roff","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zaxbysauce.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/security_hardening_guide.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-27T20:12:24.000Z","updated_at":"2026-05-17T20:44:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zaxbysauce/trainingapp","commit_stats":null,"previous_names":["zaxbysauce/trainingapp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zaxbysauce/trainingapp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaxbysauce%2Ftrainingapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaxbysauce%2Ftrainingapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaxbysauce%2Ftrainingapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaxbysauce%2Ftrainingapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zaxbysauce","download_url":"https://codeload.github.com/zaxbysauce/trainingapp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zaxbysauce%2Ftrainingapp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33548868,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-27T03:14:49.623Z","updated_at":"2026-05-27T03:14:50.569Z","avatar_url":"https://github.com/zaxbysauce.png","language":"Roff","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Document Q\u0026A Assistant\n\nA fully offline RAG-based document question answering system optimized for Windows PCs. Features semantic search, hybrid retrieval, and CPU-based LLM inference with GGUF models.\n\n## 🚀 Features\n\n### Core Capabilities\n- **Offline-First Design**: No internet required after initial setup\n- **Multi-format Support**: PDF, DOCX, PPTX, TXT, MD documents\n- **Hybrid Retrieval**: BM25 + Vector search with Reciprocal Rank Fusion (RRF)\n- **Window Expansion**: Automatically fetches adjacent context chunks\n- **Smart Chunking**: Paragraph and sentence boundary aware\n- **Cross-Encoder Reranking**: Optional MS MARCO MiniLM for precise ranking\n\n### LLM Backend (GGUF-Only)\nThe application uses GGUF models via llama-cpp-python for fully offline inference:\n\n- **Default Model**: Gemma 4 E2B (Q5_K_M GGUF, ~3.1GB) — bundled\n- Set via: `RAG_GGUF_PATH` environment variable or `--gguf-path` CLI option\n- No GPU required\n- No network access required\n- ~5-10 tokens/second on standard CPU\n\n### Hardware Requirements\n#### Minimum (Intel 11th Gen i5, 16GB RAM)\n- Windows 11 (64-bit)\n- Intel Core i5 11th generation or newer (or equivalent AMD Ryzen 5000+)\n- Intel integrated graphics (present on all 11th gen+ Intel CPUs) — no discrete GPU required\n- 16GB RAM\n- ~4GB free storage for model + app\n- **Performance**: ~5-7 tokens/second\n\n#### Recommended (Intel 12th Gen i7, 32GB RAM)\n- Intel Core i7 12th generation or newer (or equivalent AMD Ryzen 7000+)\n- Intel Iris Xe integrated graphics or discrete GPU\n- 32GB RAM\n- SSD for vector database\n- **Performance**: ~10-15 tokens/second\n\n#### High-Performance (Intel 13th Gen i9, 64GB RAM)\n- High-end CPU (Intel Core i9 or AMD Ryzen 9)\n- 64GB RAM\n- **Performance**: ~15-20 tokens/second (CPU-only with GGUF)\n\n## 🆕 New Features (Version 2.0.0)\n\n### Layout and Responsive Behavior (Phase 3)\n- **Dynamic Text Wrapping**: Chat messages automatically wrap based on window width — text reflows as you resize the window\n- **Empty State Guide**: Friendly placeholder shown when no documents are loaded, with sample questions and quick-start button\n- **Operation Cancellation**: Cancel long-running operations (ingestion, querying, engine init) via Cancel button or Escape key\n\n### Interactive Source Pills (Phase 4)\n\n### Settings Tooltips (Phase 4)\n- **CTkTooltip Class**: Non-blocking hover tooltips with 500ms delay for all settings fields\n- **Contextual Help**: Each RAG configuration field has descriptive hint text explaining its purpose\n- **Dark Theme Tooltips**: Tooltips use dark background (#3a3a4e) with white text for consistent visibility\n\n### Settings (Phase 6)\n- **Real-time UI Updates**: Font size slider now applies to all widgets immediately when saved\n- **Debug Mode**: Toggle debug-level logging for troubleshooting\n- **Log File Persistence**: Customizable log file path with automatic persistence\n- **Auto-Reconfiguration**: RAG settings (chunk size, n_results, etc.) trigger engine reinitialization when changed\n\n### Performance \u0026 Thread Safety (Phase 5)\n- **Thread-Safe RAG Engine**: Full serialization via `asyncio.to_thread()` wrapping for blocking endpoints\n- **ChromaDB Locking**: `RLock` for vector store operations preventing concurrent access corruption\n- **BM25 Index Threadsafety**: Incremental add operations protected by RLock for safe concurrent document ingestion\n- **Lazy LLM Initialization**: On-demand LLM loading reduces memory footprint for CLI/API modes\n- **Cancellation Propagation**: `cancellation_event` passed through query processing for responsive long-operation termination\n- **Memory Budget Checks**: Pre-ingestion memory validation prevents OOM errors on large document sets\n- **QueryTransformer Singleton**: Shared transformer instance across requests with thread-safe initialization\n- **Cross-Encoder threadsafety**: `__new__` pattern ensures single instance with RLock for concurrent reranking\n- **Neighborhood Expansion**: Increased k from 3 to 5 chunks for better context coverage in streaming mode\n- **Embedding Batch Normalization**: Consistent batch sizes for predictable memory usage during ingestion\n\n### Chat Improvements (Phase 7)\n- **Thinking Indicator**: Animated \"Thinking...\" with dots while LLM generates responses\n- **Smart Regeneration**: \"Regenerate\" button replaces the last assistant message instead of creating duplicates\n- **Feedback System**: Working thumbs up/down buttons that persist to database\n- **Conversation Context Menu**: Right-click options to delete or rename conversations\n- **Time Display**: Relative timestamps in sidebar (e.g., \"2 min ago\", \"Yesterday\")\n\n### Keyboard Shortcuts \u0026 UX (Phase 2)\n- **Enter Key Submission**: Press Enter to submit questions (no need to click \"Ask\" button)\n- **Escape Key**: Clears input field or cancels active operations\n- **Ctrl+Enter**: Alternative shortcut for submitting questions\n- **Ctrl+L**: Quick clear chat shortcut\n- **Ctrl+,**: Open settings dialog shortcut\n- **Inline Typing Indicator**: \"Thinking...\" indicator appears in chat area while processing (replaces status bar overwrite)\n- **Clear Chat Confirmation**: Clear button requires a second click within 3 seconds to prevent accidental deletion\n- **Settings Switch Labels**: CTkSwitch widgets now display descriptive text labels (\"Enable Hybrid Search\", \"Enable Reranking\")\n\n## 📦 Installation\n\n### Method 1: Standard Python Installation\n\n#### Prerequisites\n- Windows 10 or later\n- Python 3.10+\n- pip package manager\n\n#### Installation Steps\n\n1. **Clone or download the repository**\n   ```powershell\n   cd doc_qa_app\n   ```\n\n2. **Install dependencies**\n   ```powershell\n   pip install -r requirements.txt\n   ```\n\n3. **Download required models**\n\n   **GGUF Model (Required for LLM inference)**\n   ```powershell\n   # Default model: Gemma 4 E2B (Q5_K_M) is bundled\n   # To use a custom model, download any GGUF format model\n   # From Hugging Face: https://huggingface.co/models?search=gguf\n   ```\n\n   **Embedding Model (Required for search)**\n   ```powershell\n   # BAAI/bge-small-en-v1.5 is automatically downloaded on first use\n   # Can be manually downloaded if needed for offline installation\n   ```\n\n4. **Run the application**\n\n   **GUI Mode** (default):\n   ```powershell\n   python main.py\n   ```\n\n   **CLI Mode**:\n   ```powershell\n   python main.py --cli\n   ```\n\n   **API Server**:\n   ```powershell\n   python main.py --api --port 8080\n   ```\n\n### Method 2: Offline Bundle Installation (Recommended for Enterprises)\n\n1. **Download the offline installer bundle**\n   - Includes Python embeddable, wheels, and model files\n\n2. **Extract the bundle**\n   - Unzip to a directory on your machine\n\n3. **Install**\n   - Run the provided installer or execute `main.py`\n\n4. **No internet required** after installation\n\n### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `RAG_DB_PATH` | Vector database location | `./doc_qa_db` |\n| `RAG_GGUF_PATH` | Path to GGUF model file | - |\n| `RAG_CHUNK_SIZE` | Document chunk size (words) | `512` |\n| `RAG_N_RESULTS` | Context chunks to retrieve | `3` |\n| `RAG_MAX_TOKENS` | Max response tokens | `1024` |\n| `RAG_TEMPERATURE` | LLM temperature | `0.3` |\n| `API_PORT` | API server port | `8080` |\n\n## 🔐 API Authentication (Production Required)\n\n⚠️ **Warning**: Authentication is **disabled by default** for development convenience. **MUST be enabled** for any production or shared environment.\n\n### Enabling Authentication\n\nSet both environment variables to enable authentication:\n\n| Variable | Description | Example |\n|----------|-------------|---------|\n| `ENABLE_AUTH` | Enable authentication (any value enables) | `true` |\n| `API_KEY` | Secret API key for authentication | `your-secure-api-key` |\n\n#### Linux/macOS\n```bash\nexport ENABLE_AUTH=true\nexport API_KEY=\"your-secure-api-key\"\npython main.py --api --port 8080\n```\n\n#### Windows PowerShell\n```powershell\n$env:ENABLE_AUTH=$true\n$env:API_KEY=\"your-secure-api-key\"\npython main.py --api --port 8080\n```\n\n### Using Authentication\n\nAll API requests require authentication headers:\n\n- **API Key**: `X-API-Key: \u003cyour-api-key\u003e`\n- **JWT Bearer Token**: `Authorization: Bearer \u003cjwt-token\u003e`\n\n### Python Example\n\n```python\nimport requests\nimport os\n\n# Configure authentication\nos.environ[\"ENABLE_AUTH\"] = \"true\"\nos.environ[\"API_KEY\"] = \"your-secure-api-key\"\n\n# Make authenticated request\nheaders = {\n    \"X-API-Key\": os.environ[\"API_KEY\"]\n}\n\nresponse = requests.post(\"http://localhost:8080/ask\", json={\n    \"question\": \"What are the main findings?\",\n    \"n_results\": 3\n}, headers=headers)\n\nprint(response.json())\n```\n\n### Security Notes\n\n- Always use HTTPS in production\n- Rotate API keys regularly\n- Store API keys in environment variables, never in code\n- See [USAGE.md](USAGE.md) for complete authentication documentation\n\n**Backend Selection:**\nThe application uses GGUF models only via llama-cpp-python.\nIf `RAG_GGUF_PATH` is set, that model is used. Otherwise, defaults to bundled Gemma 4.\n\n## 📖 Usage\n\n### Ingest Documents\n\n**GUI Mode**:\n1. Click \"Ingest\" button\n2. Select document folder (folder-based ingestion)\n3. Wait for processing to complete\n\n*Note: GUI supports folder-based batch ingestion. For single-file upload, use API or CLI mode.*\n\n**CLI Mode**:\n```powershell\n# Ingest all documents in a directory\npython main.py --ingest \"C:\\Documents\\reports\"\n\n# Ingest a single file\npython main.py --ingest \"C:\\Documents\\report.pdf\"\n```\n\n**API Mode**:\n```python\nimport requests\n\n# Ingest entire directory\nresponse = requests.post(\"http://localhost:8080/ingest\", json={\n    \"directory\": \"C:/Documents/reports\"\n})\nprint(response.json())\n\n# Upload and ingest single file\nwith open(\"C:/Documents/report.pdf\", \"rb\") as f:\n    response = requests.post(\n        \"http://localhost:8080/ingest/file\",\n        files={\"file\": (\"report.pdf\", f, \"application/pdf\")}\n    )\nprint(response.json())\n```\n\n### Ask Questions\n\n**GUI Mode**:\n1. Type your question in the input field\n2. Press Enter or click \"Ask\"\n3. View the answer with source citations\n\n**CLI Mode**:\n```powershell\n# Single question\npython main.py --query \"What are the main findings?\"\n\n# Interactive mode\npython main.py --cli\n```\n\n**API Mode**:\n```python\nimport requests\n\nresponse = requests.post(\"http://localhost:8080/ask\", json={\n    \"question\": \"What are the main findings?\",\n    \"n_results\": 3\n})\nprint(response.json())\n```\n\n### Advanced Features\n\n#### Hybrid Search (Default: Enabled)\nCombines BM25 keyword search with vector semantic search using RRF fusion:\n- BM25: Fast keyword matching\n- Vector: Semantic understanding\n- RRF Fusion: Combines both for optimal results\n\n#### Window Expansion\nAutomatically fetches adjacent chunks around retrieved results:\n- Configurable window size (default: 1 chunk)\n- Ensures context continuity\n- Improves answer quality for multi-part questions\n\n#### Cross-Encoder Reranking\nMS MARCO TinyBERT reranker (enabled by default):\n- Ranks retrieved chunks by relevance after initial retrieval\n- Higher accuracy than pure hybrid search\n- Lightweight (~85MB) — optimized for minimum-spec hardware\n- Can be disabled via Settings dialog\n\n#### Step-back Query Transform\nKeyword-based query expansion (disabled by default):\n- Extracts key terms from questions to improve retrieval\n- Note: The LLM-based step-back transformation is not wired (latency cost too high for minimum-spec hardware)\n\n## ⚙️ Configuration\n\n### GUI Settings Dialog\n\n**LLM Settings**:\n- GGUF Model Path: Path to `.gguf` model file\n\n**RAG Settings**:\n- Chunk Size: Number of words per chunk\n- Results to Retrieve: Number of chunks for context\n- Max Tokens: Maximum response length\n- Temperature: Response creativity (0.0-1.0)\n\n**Advanced Settings**:\n- Hybrid Search: Enable/disable BM25+Vector search\n- Window Expansion: Number of adjacent chunks to fetch\n- Cross-Encoder Reranking: Enable/disable reranking\n\n### Command-Line Options\n\n```powershell\npython main.py [OPTIONS]\n\nOptions:\n  --api                         Run API server\n  --cli                         Run in interactive CLI mode\n  --ingest PATH                 Ingest documents from directory\n  --query QUESTION              Ask a question\n  --db-path PATH                Path to vector database (default: ./doc_qa_db)\n  --model-path PATH             Path to GGUF model file (legacy alias for --gguf-path)\n  --gguf-path PATH              GGUF model path\n  --port PORT                   API server port (default: 8080)\n  --chunk-size SIZE             Chunk size in words (default: 512)\n  --chunk-overlap N             Chunk overlap in words (default: 50)\n```\n\n## 🏗️ Architecture\n\n### Overview\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│                     Document Q\u0026A App                         │\n├─────────────────────────────────────────────────────────────┤\n│                                                               │\n│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐  │\n│  │ Document     │    │ Vector Store │    │ LLM Interface│  │\n│  │ Processor    │───▶│ (ChromaDB+   │    │ (GGUF-only)  │  │\n│  │              │    │  BM25+RRF)   │◀───│             │  │\n│  └──────────────┘    └──────────────┘    └──────────────┘  │\n│         │                   │                    │          │\n│         └───────────────────┴────────────────────┘          │\n│                           │                                 │\n│                    ┌──────▼──────┐                          │\n│                    │ RAG Engine  │                          │\n│                    │ (Query      │                          │\n│                    │  Processing)│                          │\n│                    └──────┬──────┘                          │\n│                           │                                 │\n│                    ┌──────▼──────┐                          │\n│                    │ GUI / API   │                          │\n│                    └─────────────┘                          │\n│                                                               │\n└─────────────────────────────────────────────────────────────┘\n```\n\n### Components\n\n**Document Processor**\n- Extracts text from PDF, DOCX, PPTX, TXT, MD\n- Semantic chunking with paragraph/sentence boundaries\n- Chunk overlap for context continuity\n\n**Vector Store**\n- ChromaDB for semantic vector storage\n- BM25Index for keyword-based search\n- Reciprocal Rank Fusion (RRF) for hybrid results\n- Window expansion for context fetching\n\n**LLM Interface**\n- GGUF via llama-cpp-python (CPU-only, fully offline)\n\n**RAG Engine**\n- Query processing and routing\n- Hybrid search orchestration\n- Context assembly and answer generation\n- Source citation tracking\n\n## 🔧 Troubleshooting\n\n### \"No LLM backend available\"\n\n**Solution 1: GGUF Model Not Found**\n```powershell\n# Check if model file exists (default bundled model)\ndir gemma-4-E2B-it-Q5_K-M.gguf\n\n# If not, download from:\n# https://huggingface.co/google/gemma-4-2b-it-gguf\n```\n\n**Solution 2: Wrong Model Path**\n- Check Settings dialog for correct path\n- Use \"Browse\" button to select model file\n\n### \"chromadb not installed\"\n\n```powershell\npip install chromadb --break-system-packages\n```\n\n### \"sentence-transformers not installed\"\n\n```powershell\npip install sentence-transformers\n```\n\n### \"llama-cpp-python not installed\"\n\n```powershell\n# CPU-only build (recommended)\npip install llama-cpp-python\n\n# With CUDA support (if you have NVIDIA GPU)\npip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cu121\n```\n\n### Slow First Run\n\n- Embedding model (~80MB) downloads on first use\n- Subsequent runs use cached model\n- BM25 index is built on first ingestion\n\n### Memory Errors with Large Documents\n\n**Solution 1: Reduce chunk size**\n```powershell\npython main.py --chunk-size 128\n```\n\n**Solution 2: Increase chunk overlap**\n```powershell\npython main.py --chunk-size 256 --chunk-overlap 100\n```\n\n**Solution 3: Reduce number of results**\n```powershell\n$env:RAG_N_RESULTS=2\n```\n\n### Hybrid Search Not Working\n\n**Check BM25 is enabled**:\n```python\n# In API, check config\nfrom rag_engine import create_engine_from_env\nengine = create_engine_from_env()\nprint(engine.config.hybrid_search)  # Should be True\n```\n\n**Verify both backends loaded**:\n```python\n# Check vector store stats\nstats = engine.vector_store.get_stats()\nprint(f\"Embedding model: {stats['embedding_model']}\")\nprint(f\"BM25 index: {'Ready' if engine.vector_store.bm25_index else 'Not built'}\")\n```\n\n## 📚 API Reference\n\n### Endpoints\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/` | GET | Health check |\n| `/stats` | GET | Engine statistics |\n| `/ask` | POST | Ask a question |\n| `/search` | POST | Search documents |\n| `/ingest` | POST | Ingest directory |\n| `/ingest/file` | POST | Upload and ingest file |\n| `/documents` | GET | List documents |\n| `/documents` | DELETE | Clear all documents |\n\n### Example: Ask a Question\n\n```python\nimport requests\nimport json\n\n# Configure the engine\nos.environ[\"RAG_GGUF_PATH\"] = \"path/to/gemma-4-E2B-it-Q5_K-M.gguf\"\n\n# Start API server in another terminal\n# python main.py --api --port 8080\n\n# Ask a question\nresponse = requests.post(\"http://localhost:8080/ask\", json={\n    \"question\": \"What are the main findings?\",\n    \"n_results\": 3\n})\n\nresult = response.json()\nprint(f\"Answer: {result['answer']}\")\nprint(f\"Sources: {result['sources']}\")\nprint(f\"Inference time: {result['inference_time']:.2f}s\")\n```\n\n## 📦 Building Standalone Executable\n\n### Prerequisites\n\n```powershell\npip install pyinstaller\n```\n\n### Build\n\n```powershell\npython build.py\n```\n\nThe executable will be created in `dist/DocumentQA.exe`.\n\n### Including Models (Offline Bundle)\n\nTo create an offline installer:\n\n```powershell\n# Prepare installer files\npython scripts/build_installer.py\n\n# Manually download:\n# 1. GGUF model to build_installer/models/\n# 2. Embedding model to build_installer/embeddings/\n# 3. Python embeddable to python_embeddable/\n\n# Run Inno Setup\niscc build_installer/setup.iss\n```\n\nThis creates an offline installer with all dependencies and models included.\n\n## 📋 Project Structure\n\n```\ndoc_qa_app/\n├── main.py                 # Main entry point\n├── app_gui.py              # GUI application (customtkinter)\n├── api_server.py           # FastAPI REST server\n├── rag_engine.py           # RAG orchestration\n├── document_processor.py   # Document extraction \u0026 semantic chunking\n├── vector_store.py         # Vector search (ChromaDB + BM25 + RRF)\n├── llm_interface.py        # LLM interface (GGUF-only)\n├── reranking.py            # Cross-encoder reranking\n├── query_transformer.py    # Query transformation\n├── utils.py                # Utility functions (RRF fusion)\n├── requirements.txt        # Python dependencies\n├── build.py                # PyInstaller build script\n├── scripts/\n│   └── build_installer.py  # Inno Setup preparation\n└── README.md               # This file\n```\n\n## 🛡️ Security \u0026 Privacy\n\n- **Offline-Only**: No data leaves your machine\n- **No Cloud Services**: All processing is local\n- **Model Bundling**: Models are stored locally\n- **Portable**: Can be run from USB drive\n\n## 📄 License\n\nMIT License - See LICENSE file for details.\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests if applicable\n5. Submit a pull request\n\n## 🙏 Acknowledgments\n\n- [ChromaDB](https://www.trychroma.com/) - Vector database\n- [Sentence Transformers](https://www.sbert.net/) - Embedding models\n- [llama-cpp-python](https://github.com/abetlen/llama-cpp-python) - GGUF inference\n- [PyMuPDF](https://pymupdf.readthedocs.io/) - PDF processing\n- [CustomTkinter](https://customtkinter.tomschimansky.com/) - Modern GUI toolkit\n\n---\n**Version**: 2.2.0\n**Last Updated**: 2026-05-17\n**Hardware**: CPU-only optimized for Intel 11th gen i5 and above (16GB RAM minimum)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaxbysauce%2Ftrainingapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzaxbysauce%2Ftrainingapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzaxbysauce%2Ftrainingapp/lists"}