ragbox-core 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ragbox_core-1.0.0/LICENSE +21 -0
- ragbox_core-1.0.0/PKG-INFO +121 -0
- ragbox_core-1.0.0/README.md +73 -0
- ragbox_core-1.0.0/pyproject.toml +56 -0
- ragbox_core-1.0.0/ragbox/__init__.py +175 -0
- ragbox_core-1.0.0/ragbox/cli.py +106 -0
- ragbox_core-1.0.0/ragbox/config/__init__.py +3 -0
- ragbox_core-1.0.0/ragbox/config/defaults.py +28 -0
- ragbox_core-1.0.0/ragbox/core/__init__.py +18 -0
- ragbox_core-1.0.0/ragbox/core/agentic_orchestrator.py +178 -0
- ragbox_core-1.0.0/ragbox/core/chunking_engine.py +169 -0
- ragbox_core-1.0.0/ragbox/core/document_processor.py +206 -0
- ragbox_core-1.0.0/ragbox/core/knowledge_graph.py +339 -0
- ragbox_core-1.0.0/ragbox/core/reranker.py +73 -0
- ragbox_core-1.0.0/ragbox/core/retrieval_fusion.py +92 -0
- ragbox_core-1.0.0/ragbox/core/self_healing.py +334 -0
- ragbox_core-1.0.0/ragbox/models/__init__.py +3 -0
- ragbox_core-1.0.0/ragbox/models/chunks.py +35 -0
- ragbox_core-1.0.0/ragbox/models/documents.py +51 -0
- ragbox_core-1.0.0/ragbox/models/graph.py +41 -0
- ragbox_core-1.0.0/ragbox/models/queries.py +39 -0
- ragbox_core-1.0.0/ragbox/utils/__init__.py +1 -0
- ragbox_core-1.0.0/ragbox/utils/cost_tracker.py +217 -0
- ragbox_core-1.0.0/ragbox/utils/embeddings.py +180 -0
- ragbox_core-1.0.0/ragbox/utils/llm_clients.py +271 -0
- ragbox_core-1.0.0/ragbox/utils/vector_stores.py +273 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RAGBox Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ragbox-core
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: RAG-in-a-Box: Zero-Configuration Self-Building Agentic RAG System
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Staff+ Engineer
|
|
7
|
+
Author-email: staff@ragbox.ai
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: aiofiles (>=23.0,<24.0)
|
|
15
|
+
Requires-Dist: anthropic
|
|
16
|
+
Requires-Dist: camelot-py
|
|
17
|
+
Requires-Dist: chromadb (>=0.4,<0.5)
|
|
18
|
+
Requires-Dist: groq
|
|
19
|
+
Requires-Dist: igraph
|
|
20
|
+
Requires-Dist: leidenalg
|
|
21
|
+
Requires-Dist: llama-cpp-python
|
|
22
|
+
Requires-Dist: loguru (>=0.7,<0.8)
|
|
23
|
+
Requires-Dist: neo4j (>=5.0,<6.0)
|
|
24
|
+
Requires-Dist: networkx (>=3.0,<4.0)
|
|
25
|
+
Requires-Dist: numpy (>=1.24,<2.0)
|
|
26
|
+
Requires-Dist: openai
|
|
27
|
+
Requires-Dist: paddleocr
|
|
28
|
+
Requires-Dist: pdfplumber
|
|
29
|
+
Requires-Dist: pydantic (>=2.0,<3.0)
|
|
30
|
+
Requires-Dist: pypdf
|
|
31
|
+
Requires-Dist: python-dotenv
|
|
32
|
+
Requires-Dist: python-louvain
|
|
33
|
+
Requires-Dist: python-magic
|
|
34
|
+
Requires-Dist: python-pptx
|
|
35
|
+
Requires-Dist: rank-bm25
|
|
36
|
+
Requires-Dist: rich (>=13.0,<14.0)
|
|
37
|
+
Requires-Dist: scikit-learn (>=1.3,<2.0)
|
|
38
|
+
Requires-Dist: scipy (>=1.11,<2.0)
|
|
39
|
+
Requires-Dist: sentence-transformers
|
|
40
|
+
Requires-Dist: tenacity
|
|
41
|
+
Requires-Dist: tiktoken
|
|
42
|
+
Requires-Dist: tree-sitter
|
|
43
|
+
Requires-Dist: tree-sitter-python
|
|
44
|
+
Requires-Dist: typer (>=0.9,<0.10)
|
|
45
|
+
Requires-Dist: watchdog (>=3.0,<4.0)
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# RAGBox
|
|
49
|
+
|
|
50
|
+
**RAG-in-a-Box: Zero-Configuration Self-Building Agentic RAG System**
|
|
51
|
+
|
|
52
|
+
RAGBox is a production-ready, auto-configuring, async-first RAG engine that combines Vector Search, Agentic Orchestration, and Graph Retrieval natively.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install ragbox
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> **Note on Dependencies:** Advanced document processing features like OCR and complex PDF parsing require system-level dependencies. Depending on your OS, you may need to install standard C++ build tools or Tesseract for `paddleocr` and `pdfplumber` to function optimally.
|
|
61
|
+
|
|
62
|
+
## Quick Start (3-Line API)
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from ragbox import RAGBox
|
|
66
|
+
|
|
67
|
+
# Automatically ingests, builds graphs, configures vector db, and chunks
|
|
68
|
+
rag = RAGBox("./company-docs")
|
|
69
|
+
|
|
70
|
+
# Intelligent routing via query classification
|
|
71
|
+
answer = rag.query("What's our vacation policy?")
|
|
72
|
+
print(answer)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## CLI Interface
|
|
76
|
+
|
|
77
|
+
RAGBox provides a dead-simple CLI for running locally without writing code:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Point to your documents. RAGBox will self-build the index and graph.
|
|
81
|
+
ragbox init ./company-docs
|
|
82
|
+
|
|
83
|
+
# Query the active index
|
|
84
|
+
ragbox query "What's our vacation policy?" -d ./company-docs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Architecture
|
|
88
|
+
|
|
89
|
+
```mermaid
|
|
90
|
+
graph TD
|
|
91
|
+
A[Local Documents] --> B{Document Processor Auto-Router}
|
|
92
|
+
B --> C[AST / OCR / PDF Parsing]
|
|
93
|
+
C --> D[Chunking Engine]
|
|
94
|
+
D --> E[(Vector Store)]
|
|
95
|
+
C --> F[(Knowledge Graph)]
|
|
96
|
+
|
|
97
|
+
Q[User Query] --> G[Agentic Orchestrator]
|
|
98
|
+
G --> H[Retrieval Fusion Engine]
|
|
99
|
+
E --> H
|
|
100
|
+
F --> H
|
|
101
|
+
H --> G
|
|
102
|
+
G --> I[Final Answer]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Risk Surface Analysis
|
|
106
|
+
|
|
107
|
+
* **Temporal Edges (T=0 vs T=Scale):** At T=0, `ragbox init` is blocking to guarantee index availability. At T=scale, the background daemon handles delta updates (via watchdog) to prevent index staleness and thundering herds.
|
|
108
|
+
* **Adversarial Edges:** Subject to standard prompt injection if queries are exposed raw to external users. The Orchestrator currently assumes trusted inputs.
|
|
109
|
+
* **Resource Edges:** High concurrency read/write spikes memory due to dual maintenance of the local Vector DB and the Knowledge Graph.
|
|
110
|
+
|
|
111
|
+
## Features
|
|
112
|
+
|
|
113
|
+
* **Self-Healing Infrastructure:** Watchdog auto-detects changes and updates vector stores & knowledge graphs incrementally, preventing index staleness or storms.
|
|
114
|
+
* **Auto-Document Intelligence:** Automatically detects PDF, Text, Images, and Code to use AST, OCR (`paddleocr`), or structural layouts (`pdfplumber`).
|
|
115
|
+
* **Cost Estimator:** See the expected USD cost of indexing *before* it runs.
|
|
116
|
+
* **Auto-Knowledge-Graph (GraphRAG):** Extracts entities and communities automatically using the Leiden algorithm for structured reasoning.
|
|
117
|
+
* **Retrieval Fusion & Reranking:** Merges Dense Vectors and Graph Search using Reciprocal Rank Fusion, then reranks the massive candidate pool using a highly accurate `ms-marco` Cross-Encoder.
|
|
118
|
+
* **Late Chunking:** Contextual sequence embeddings! Vectors are calculated over the full document bounds before being pooled into chunks, preserving global semantic context within local tokens.
|
|
119
|
+
* **Agentic Orchestrator & Intelligent Routing:** Automatically routes incoming queries into 6 distinct pipelines: Vector, Keyword, Graph, Multi-Query, Time-Based, and Agentic.
|
|
120
|
+
* **Multi-Query Expansion:** Broad intent queries are dynamically expanded into multiple variations by the LLM, retrieving and fusing results across all variations for unparalleled recall.
|
|
121
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# RAGBox
|
|
2
|
+
|
|
3
|
+
**RAG-in-a-Box: Zero-Configuration Self-Building Agentic RAG System**
|
|
4
|
+
|
|
5
|
+
RAGBox is a production-ready, auto-configuring, async-first RAG engine that combines Vector Search, Agentic Orchestration, and Graph Retrieval natively.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install ragbox
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> **Note on Dependencies:** Advanced document processing features like OCR and complex PDF parsing require system-level dependencies. Depending on your OS, you may need to install standard C++ build tools or Tesseract for `paddleocr` and `pdfplumber` to function optimally.
|
|
14
|
+
|
|
15
|
+
## Quick Start (3-Line API)
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from ragbox import RAGBox
|
|
19
|
+
|
|
20
|
+
# Automatically ingests, builds graphs, configures vector db, and chunks
|
|
21
|
+
rag = RAGBox("./company-docs")
|
|
22
|
+
|
|
23
|
+
# Intelligent routing via query classification
|
|
24
|
+
answer = rag.query("What's our vacation policy?")
|
|
25
|
+
print(answer)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## CLI Interface
|
|
29
|
+
|
|
30
|
+
RAGBox provides a dead-simple CLI for running locally without writing code:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Point to your documents. RAGBox will self-build the index and graph.
|
|
34
|
+
ragbox init ./company-docs
|
|
35
|
+
|
|
36
|
+
# Query the active index
|
|
37
|
+
ragbox query "What's our vacation policy?" -d ./company-docs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Architecture
|
|
41
|
+
|
|
42
|
+
```mermaid
|
|
43
|
+
graph TD
|
|
44
|
+
A[Local Documents] --> B{Document Processor Auto-Router}
|
|
45
|
+
B --> C[AST / OCR / PDF Parsing]
|
|
46
|
+
C --> D[Chunking Engine]
|
|
47
|
+
D --> E[(Vector Store)]
|
|
48
|
+
C --> F[(Knowledge Graph)]
|
|
49
|
+
|
|
50
|
+
Q[User Query] --> G[Agentic Orchestrator]
|
|
51
|
+
G --> H[Retrieval Fusion Engine]
|
|
52
|
+
E --> H
|
|
53
|
+
F --> H
|
|
54
|
+
H --> G
|
|
55
|
+
G --> I[Final Answer]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Risk Surface Analysis
|
|
59
|
+
|
|
60
|
+
* **Temporal Edges (T=0 vs T=Scale):** At T=0, `ragbox init` is blocking to guarantee index availability. At T=scale, the background daemon handles delta updates (via watchdog) to prevent index staleness and thundering herds.
|
|
61
|
+
* **Adversarial Edges:** Subject to standard prompt injection if queries are exposed raw to external users. The Orchestrator currently assumes trusted inputs.
|
|
62
|
+
* **Resource Edges:** High concurrency read/write spikes memory due to dual maintenance of the local Vector DB and the Knowledge Graph.
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
* **Self-Healing Infrastructure:** Watchdog auto-detects changes and updates vector stores & knowledge graphs incrementally, preventing index staleness or storms.
|
|
67
|
+
* **Auto-Document Intelligence:** Automatically detects PDF, Text, Images, and Code to use AST, OCR (`paddleocr`), or structural layouts (`pdfplumber`).
|
|
68
|
+
* **Cost Estimator:** See the expected USD cost of indexing *before* it runs.
|
|
69
|
+
* **Auto-Knowledge-Graph (GraphRAG):** Extracts entities and communities automatically using the Leiden algorithm for structured reasoning.
|
|
70
|
+
* **Retrieval Fusion & Reranking:** Merges Dense Vectors and Graph Search using Reciprocal Rank Fusion, then reranks the massive candidate pool using a highly accurate `ms-marco` Cross-Encoder.
|
|
71
|
+
* **Late Chunking:** Contextual sequence embeddings! Vectors are calculated over the full document bounds before being pooled into chunks, preserving global semantic context within local tokens.
|
|
72
|
+
* **Agentic Orchestrator & Intelligent Routing:** Automatically routes incoming queries into 6 distinct pipelines: Vector, Keyword, Graph, Multi-Query, Time-Based, and Agentic.
|
|
73
|
+
* **Multi-Query Expansion:** Broad intent queries are dynamically expanded into multiple variations by the LLM, retrieving and fusing results across all variations for unparalleled recall.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "ragbox-core"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "RAG-in-a-Box: Zero-Configuration Self-Building Agentic RAG System"
|
|
5
|
+
authors = ["Staff+ Engineer <staff@ragbox.ai>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
packages = [{include = "ragbox"}]
|
|
8
|
+
exclude = ["tests/", "docs/", ".env", "*.db", "chroma_db/", "knowledge_graph/", "logs/"]
|
|
9
|
+
[tool.poetry.scripts]
|
|
10
|
+
ragbox = "ragbox.cli:app"
|
|
11
|
+
|
|
12
|
+
[tool.poetry.dependencies]
|
|
13
|
+
python = "^3.11"
|
|
14
|
+
pydantic = "^2.0"
|
|
15
|
+
aiofiles = "^23.0"
|
|
16
|
+
watchdog = "^3.0"
|
|
17
|
+
chromadb = "^0.4"
|
|
18
|
+
neo4j = "^5.0"
|
|
19
|
+
networkx = "^3.0"
|
|
20
|
+
scikit-learn = "^1.3"
|
|
21
|
+
pypdf = "*"
|
|
22
|
+
pdfplumber = "*"
|
|
23
|
+
camelot-py = "*"
|
|
24
|
+
tree-sitter = "*"
|
|
25
|
+
tree-sitter-python = "*"
|
|
26
|
+
paddleocr = "*"
|
|
27
|
+
sentence-transformers = "*"
|
|
28
|
+
rank-bm25 = "*"
|
|
29
|
+
numpy = "^1.24"
|
|
30
|
+
scipy = "^1.11"
|
|
31
|
+
loguru = "^0.7"
|
|
32
|
+
typer = "^0.9"
|
|
33
|
+
rich = "^13.0"
|
|
34
|
+
llama-cpp-python = "*"
|
|
35
|
+
openai = "*"
|
|
36
|
+
anthropic = "*"
|
|
37
|
+
groq = "*"
|
|
38
|
+
python-dotenv = "*"
|
|
39
|
+
python-pptx = "*"
|
|
40
|
+
tenacity = "*"
|
|
41
|
+
tiktoken = "*"
|
|
42
|
+
python-magic = "*"
|
|
43
|
+
leidenalg = "*"
|
|
44
|
+
python-louvain = "*"
|
|
45
|
+
igraph = "*"
|
|
46
|
+
|
|
47
|
+
[tool.poetry.group.dev.dependencies]
|
|
48
|
+
pytest = "^7.4.0"
|
|
49
|
+
pytest-asyncio = "^0.21.1"
|
|
50
|
+
mypy = "^1.5.0"
|
|
51
|
+
black = "^23.7.0"
|
|
52
|
+
ruff = "^0.0.285"
|
|
53
|
+
|
|
54
|
+
[build-system]
|
|
55
|
+
requires = ["poetry-core"]
|
|
56
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RAGBox: Zero-Configuration Self-Building Agentic RAG System.
|
|
3
|
+
|
|
4
|
+
Provides the public RAGBox class for one-line integrations.
|
|
5
|
+
"""
|
|
6
|
+
import asyncio
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from loguru import logger
|
|
11
|
+
|
|
12
|
+
from ragbox.config.defaults import Settings
|
|
13
|
+
from ragbox.core.agentic_orchestrator import AgenticOrchestrator
|
|
14
|
+
from ragbox.core.chunking_engine import ChunkingEngine
|
|
15
|
+
from ragbox.core.document_processor import DocumentProcessorRouter
|
|
16
|
+
from ragbox.core.knowledge_graph import OptimizedKnowledgeGraph
|
|
17
|
+
from ragbox.core.retrieval_fusion import RetrievalFusionEngine
|
|
18
|
+
from ragbox.core.self_healing import SelfHealer
|
|
19
|
+
from ragbox.models.queries import Answer
|
|
20
|
+
from ragbox.utils.embeddings import EmbeddingAutoDetector
|
|
21
|
+
from ragbox.utils.llm_clients import LLMAutoDetector
|
|
22
|
+
from ragbox.utils.vector_stores import VectorStoreAutoDetector
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RAGBox:
|
|
26
|
+
"""
|
|
27
|
+
RAG-in-a-Box: Zero-Configuration Self-Building Agentic RAG System.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, document_dir: str | Path, config: Optional[Settings] = None) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Initialize a complete RAG system pointing to a directory.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
document_dir: Path to the directory containing documents.
|
|
36
|
+
config: Optional configuration overrides.
|
|
37
|
+
"""
|
|
38
|
+
self.document_dir = Path(document_dir)
|
|
39
|
+
self.config = config or Settings()
|
|
40
|
+
|
|
41
|
+
# Initialize Core Layers Auto-magically
|
|
42
|
+
self.llm_client = LLMAutoDetector.detect(self.config)
|
|
43
|
+
self.embedding_provider = EmbeddingAutoDetector.detect(self.config)
|
|
44
|
+
self.vector_store = VectorStoreAutoDetector.detect(self.config, self.embedding_provider)
|
|
45
|
+
|
|
46
|
+
self.document_processor = DocumentProcessorRouter()
|
|
47
|
+
self.chunking_engine = ChunkingEngine(self.llm_client, self.embedding_provider)
|
|
48
|
+
self.knowledge_graph = OptimizedKnowledgeGraph(llm_client=self.llm_client)
|
|
49
|
+
|
|
50
|
+
self.retriever = RetrievalFusionEngine(
|
|
51
|
+
vector_store=self.vector_store,
|
|
52
|
+
knowledge_graph=self.knowledge_graph,
|
|
53
|
+
embedding_provider=self.embedding_provider,
|
|
54
|
+
llm_client=self.llm_client
|
|
55
|
+
)
|
|
56
|
+
self.orchestrator = AgenticOrchestrator(
|
|
57
|
+
retriever=self.retriever,
|
|
58
|
+
llm_client=self.llm_client,
|
|
59
|
+
document_processor=self.document_processor,
|
|
60
|
+
knowledge_graph=self.knowledge_graph
|
|
61
|
+
)
|
|
62
|
+
self.self_healer = SelfHealer(
|
|
63
|
+
document_dir=self.document_dir,
|
|
64
|
+
document_processor=self.document_processor,
|
|
65
|
+
chunking_engine=self.chunking_engine,
|
|
66
|
+
vector_store=self.vector_store,
|
|
67
|
+
knowledge_graph=self.knowledge_graph
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Start initial build and self-healing daemon
|
|
71
|
+
logger.info(f"Initializing RAGBox for {self.document_dir}")
|
|
72
|
+
self._ensure_built()
|
|
73
|
+
|
|
74
|
+
def _ensure_built(self) -> None:
|
|
75
|
+
"""Synchronously trigger the build process to guarantee readiness."""
|
|
76
|
+
try:
|
|
77
|
+
loop = asyncio.get_running_loop()
|
|
78
|
+
except RuntimeError:
|
|
79
|
+
loop = asyncio.new_event_loop()
|
|
80
|
+
asyncio.set_event_loop(loop)
|
|
81
|
+
|
|
82
|
+
if loop.is_running():
|
|
83
|
+
asyncio.create_task(self.self_healer.initial_build())
|
|
84
|
+
else:
|
|
85
|
+
loop.run_until_complete(self.self_healer.initial_build())
|
|
86
|
+
|
|
87
|
+
# Start watchdog
|
|
88
|
+
self.self_healer.start_watchdog()
|
|
89
|
+
|
|
90
|
+
def query(self, question: str) -> str:
|
|
91
|
+
"""
|
|
92
|
+
Query the RAGBox system synchronously.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
question: The user's query.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
The direct answer string.
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
loop = asyncio.get_running_loop()
|
|
102
|
+
if loop.is_running():
|
|
103
|
+
raise RuntimeError("Cannot call synchronous `query` inside an active event loop. Use `aquery`.")
|
|
104
|
+
except RuntimeError:
|
|
105
|
+
loop = asyncio.new_event_loop()
|
|
106
|
+
asyncio.set_event_loop(loop)
|
|
107
|
+
|
|
108
|
+
answer: Answer = loop.run_until_complete(self.orchestrator.execute(question))
|
|
109
|
+
return answer.content
|
|
110
|
+
|
|
111
|
+
async def aquery(self, question: str) -> str:
|
|
112
|
+
"""
|
|
113
|
+
Async evaluation of a query.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
question: The user's query.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
The direct answer string.
|
|
120
|
+
"""
|
|
121
|
+
answer: Answer = await self.orchestrator.execute(question)
|
|
122
|
+
return answer.content
|
|
123
|
+
|
|
124
|
+
def estimate_cost(self, query: Optional[str] = None) -> str:
|
|
125
|
+
"""
|
|
126
|
+
Estimate the cost of a query or indexing the corpus upfront.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
query: The query to run. If None, estimates the cost of indexing the entire corpus.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
A string detailing the estimated cost.
|
|
133
|
+
"""
|
|
134
|
+
from ragbox.utils.cost_tracker import CostEstimator
|
|
135
|
+
|
|
136
|
+
# We assume the default model for estimating cost
|
|
137
|
+
estimator = CostEstimator(self.llm_client.model_name if hasattr(self.llm_client, "model_name") else "gpt-4o")
|
|
138
|
+
|
|
139
|
+
if query is None:
|
|
140
|
+
# Estimate cost of indexing the corpus based on file size
|
|
141
|
+
total_bytes = 0
|
|
142
|
+
for ext in self.document_processor.processors.keys():
|
|
143
|
+
for p in self.document_dir.rglob(f"*{ext}"):
|
|
144
|
+
if p.is_file():
|
|
145
|
+
total_bytes += p.stat().st_size
|
|
146
|
+
|
|
147
|
+
# Wild guess: 1 byte ~ 0.25 tokens
|
|
148
|
+
estimated_tokens = int(total_bytes * 0.25)
|
|
149
|
+
# Embedding cost
|
|
150
|
+
embed_cost = (estimated_tokens / 1_000_000) * 0.13 # large embedding assumption
|
|
151
|
+
return f"Corpus Indexing Estimate: ~{estimated_tokens} tokens. Embedding Cost: ${embed_cost:.4f}"
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
# Simulate retrieval and estimation for query
|
|
155
|
+
try:
|
|
156
|
+
loop = asyncio.get_running_loop()
|
|
157
|
+
if loop.is_running():
|
|
158
|
+
raise RuntimeError("Cannot call synchronous `estimate_cost` inside loop.")
|
|
159
|
+
except RuntimeError:
|
|
160
|
+
loop = asyncio.new_event_loop()
|
|
161
|
+
asyncio.set_event_loop(loop)
|
|
162
|
+
|
|
163
|
+
# Retrieve mock sources
|
|
164
|
+
sources = loop.run_until_complete(self.retriever.retrieve(query))
|
|
165
|
+
context_text = "\n".join([s.text for s in sources])
|
|
166
|
+
|
|
167
|
+
estimate = estimator.estimate_generation(
|
|
168
|
+
prompt=f"{context_text}\n{query}",
|
|
169
|
+
approx_output_tokens=500
|
|
170
|
+
)
|
|
171
|
+
return estimate.__str__()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
__all__ = ["RAGBox"]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
import asyncio
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.markdown import Markdown
|
|
7
|
+
|
|
8
|
+
from ragbox import RAGBox
|
|
9
|
+
from ragbox.config.defaults import Settings
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(
|
|
12
|
+
name="ragbox",
|
|
13
|
+
help="RAGBox: Zero-Configuration Self-Building Agentic RAG System",
|
|
14
|
+
add_completion=False,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
@app.command()
|
|
20
|
+
def init(
|
|
21
|
+
document_dir: Path = typer.Argument(
|
|
22
|
+
...,
|
|
23
|
+
exists=True,
|
|
24
|
+
file_okay=False,
|
|
25
|
+
dir_okay=True,
|
|
26
|
+
help="Directory containing local documents to index.",
|
|
27
|
+
),
|
|
28
|
+
config_file: Path = typer.Option(
|
|
29
|
+
None,
|
|
30
|
+
"--config",
|
|
31
|
+
"-c",
|
|
32
|
+
help="Path to an optional JSON/YAML configuration file.",
|
|
33
|
+
)
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Initialize a RAGBox instance in the specified directory.
|
|
37
|
+
|
|
38
|
+
This command blocks until the initial index and knowledge graph are built.
|
|
39
|
+
Afterward, it starts the background daemon to watch for changes.
|
|
40
|
+
"""
|
|
41
|
+
console.print(Panel(f"Initializing RAGBox at [cyan]{document_dir}[/cyan]", border_style="green"))
|
|
42
|
+
|
|
43
|
+
# In a real implementation this might parse config_file into Settings
|
|
44
|
+
settings = Settings()
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
# Pre-flight cost estimation
|
|
48
|
+
rg_pre = RAGBox(document_dir, config=settings)
|
|
49
|
+
cost_estimate = rg_pre.estimate_cost(query=None)
|
|
50
|
+
console.print(Panel(f"[bold yellow]{cost_estimate}[/bold yellow]", title="Cost Estimate"))
|
|
51
|
+
|
|
52
|
+
# RAGBox __init__ calls _ensure_built which builds synchronously implicitly via asyncio
|
|
53
|
+
with console.status("[bold green]Building Vector Store and Knowledge Graph...", spinner="dots"):
|
|
54
|
+
rg = rg_pre # It's already built by the init above
|
|
55
|
+
console.print("[bold green]✓ Indexing complete.[/bold green] RAGBox is ready for queries.")
|
|
56
|
+
console.print("The self-healing daemon is now active in the background for this session.")
|
|
57
|
+
|
|
58
|
+
# Keep process alive to allow watchdog to run, or exit if init is purely
|
|
59
|
+
# meant to pre-compute. Because RAGBox design spins up daemon threads,
|
|
60
|
+
# we'll keep it alive here if we want continuous syncing.
|
|
61
|
+
console.print("[yellow]Press Ctrl+C to stop the daemon.[/yellow]")
|
|
62
|
+
try:
|
|
63
|
+
while True:
|
|
64
|
+
# Wait forever
|
|
65
|
+
asyncio.run(asyncio.sleep(3600))
|
|
66
|
+
except KeyboardInterrupt:
|
|
67
|
+
console.print("Daemon stopped.")
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
console.print(f"[bold red]Error initializing RAGBox: {e}[/bold red]")
|
|
71
|
+
raise typer.Exit(code=1)
|
|
72
|
+
|
|
73
|
+
@app.command()
|
|
74
|
+
def query(
|
|
75
|
+
question: str = typer.Argument(..., help="The question to ask the RAG system."),
|
|
76
|
+
document_dir: Path = typer.Option(
|
|
77
|
+
".",
|
|
78
|
+
"--dir",
|
|
79
|
+
"-d",
|
|
80
|
+
help="Directory where RAGBox is initialized.",
|
|
81
|
+
exists=True,
|
|
82
|
+
dir_okay=True,
|
|
83
|
+
)
|
|
84
|
+
):
|
|
85
|
+
"""
|
|
86
|
+
Query an existing RAGBox instance.
|
|
87
|
+
"""
|
|
88
|
+
console.print(f"[bold blue]Querying RAGBox in {document_dir}...[/bold blue]\n")
|
|
89
|
+
try:
|
|
90
|
+
rg = RAGBox(document_dir)
|
|
91
|
+
|
|
92
|
+
# Estimation
|
|
93
|
+
cost_estimate = rg.estimate_cost(query=question)
|
|
94
|
+
console.print(f"[yellow]Estimation:[/yellow] {cost_estimate}")
|
|
95
|
+
|
|
96
|
+
with console.status("[bold green]Agentic Orchestrator thinking...", spinner="dots"):
|
|
97
|
+
answer = rg.query(question)
|
|
98
|
+
|
|
99
|
+
console.print(Panel(Markdown(answer), title="Answer", border_style="blue"))
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
console.print(f"[bold red]Error querying RAGBox: {e}[/bold red]")
|
|
103
|
+
raise typer.Exit(code=1)
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
app()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Zero-Configuration Settings via Pydantic using dotenv.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
class Settings(BaseSettings):
|
|
9
|
+
"""
|
|
10
|
+
RAGBox Configuration.
|
|
11
|
+
Prioritizes Env Vars, falls back to .env if present, otherwise defaults.
|
|
12
|
+
"""
|
|
13
|
+
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8', extra='ignore')
|
|
14
|
+
|
|
15
|
+
# API Keys
|
|
16
|
+
openai_api_key: Optional[str] = Field(default=None, description="OpenAI API Key")
|
|
17
|
+
anthropic_api_key: Optional[str] = Field(default=None, description="Anthropic API Key")
|
|
18
|
+
groq_api_key: Optional[str] = Field(default=None, description="Groq API Key")
|
|
19
|
+
pinecone_api_key: Optional[str] = Field(default=None, description="Pinecone API Key")
|
|
20
|
+
|
|
21
|
+
# Local paths
|
|
22
|
+
local_model_path: str = Field(default="models/llama-3.1-8b-instruct.gguf", description="Path for local LLM")
|
|
23
|
+
chroma_db_dir: str = Field(default="./chroma_db", description="Path for local vector DB")
|
|
24
|
+
|
|
25
|
+
# Behaviors
|
|
26
|
+
log_level: str = "INFO"
|
|
27
|
+
max_agent_steps: int = 5
|
|
28
|
+
graph_community_level: int = 1
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core RAGBox mechanisms.
|
|
3
|
+
"""
|
|
4
|
+
from .agentic_orchestrator import AgenticOrchestrator
|
|
5
|
+
from .chunking_engine import ChunkingEngine
|
|
6
|
+
from .document_processor import DocumentProcessorRouter
|
|
7
|
+
from .knowledge_graph import OptimizedKnowledgeGraph
|
|
8
|
+
from .retrieval_fusion import RetrievalFusionEngine
|
|
9
|
+
from .self_healing import SelfHealer
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"AgenticOrchestrator",
|
|
13
|
+
"ChunkingEngine",
|
|
14
|
+
"DocumentProcessorRouter",
|
|
15
|
+
"OptimizedKnowledgeGraph",
|
|
16
|
+
"RetrievalFusionEngine",
|
|
17
|
+
"SelfHealer",
|
|
18
|
+
]
|