raglib-py 0.1.3__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.
- raglib_py-0.1.3/.gitignore +38 -0
- raglib_py-0.1.3/LICENSE +21 -0
- raglib_py-0.1.3/PKG-INFO +161 -0
- raglib_py-0.1.3/README.md +52 -0
- raglib_py-0.1.3/pyproject.toml +99 -0
- raglib_py-0.1.3/raglib/__init__.py +17 -0
- raglib_py-0.1.3/raglib/components/__init__.py +41 -0
- raglib_py-0.1.3/raglib/components/context_reducer.py +65 -0
- raglib_py-0.1.3/raglib/components/decision.py +63 -0
- raglib_py-0.1.3/raglib/components/deduplicator.py +58 -0
- raglib_py-0.1.3/raglib/components/evaluator.py +57 -0
- raglib_py-0.1.3/raglib/components/generator.py +91 -0
- raglib_py-0.1.3/raglib/components/hybrid_retriever.py +99 -0
- raglib_py-0.1.3/raglib/components/memory.py +58 -0
- raglib_py-0.1.3/raglib/components/multi_hop_retriever.py +40 -0
- raglib_py-0.1.3/raglib/components/multi_query_retriever.py +63 -0
- raglib_py-0.1.3/raglib/components/planner.py +44 -0
- raglib_py-0.1.3/raglib/components/query_expander.py +52 -0
- raglib_py-0.1.3/raglib/components/query_rewriter.py +38 -0
- raglib_py-0.1.3/raglib/components/refiner.py +37 -0
- raglib_py-0.1.3/raglib/components/reflection.py +48 -0
- raglib_py-0.1.3/raglib/components/reranker.py +54 -0
- raglib_py-0.1.3/raglib/components/retriever.py +342 -0
- raglib_py-0.1.3/raglib/components/router_retriever.py +70 -0
- raglib_py-0.1.3/raglib/components/web_retriever.py +36 -0
- raglib_py-0.1.3/raglib/config.py +39 -0
- raglib_py-0.1.3/raglib/constants.py +33 -0
- raglib_py-0.1.3/raglib/core/__init__.py +5 -0
- raglib_py-0.1.3/raglib/core/base.py +211 -0
- raglib_py-0.1.3/raglib/embedding/__init__.py +25 -0
- raglib_py-0.1.3/raglib/embedding/base_embedding.py +26 -0
- raglib_py-0.1.3/raglib/embedding/embedding_factory.py +52 -0
- raglib_py-0.1.3/raglib/embedding/google_embedding.py +53 -0
- raglib_py-0.1.3/raglib/embedding/huggingface_embedding.py +56 -0
- raglib_py-0.1.3/raglib/embedding/mock_embedding.py +51 -0
- raglib_py-0.1.3/raglib/embedding/ollama_embedding.py +59 -0
- raglib_py-0.1.3/raglib/embedding/openai_embedding.py +55 -0
- raglib_py-0.1.3/raglib/facade.py +459 -0
- raglib_py-0.1.3/raglib/llm/__init__.py +6 -0
- raglib_py-0.1.3/raglib/llm/base_client.py +21 -0
- raglib_py-0.1.3/raglib/llm/constants.py +32 -0
- raglib_py-0.1.3/raglib/llm/langchain_adapter.py +193 -0
- raglib_py-0.1.3/raglib/llm/mock_client.py +116 -0
- raglib_py-0.1.3/raglib/llm/provider_detector.py +162 -0
- raglib_py-0.1.3/raglib/loaders/__init__.py +26 -0
- raglib_py-0.1.3/raglib/loaders/chunk_splitter.py +129 -0
- raglib_py-0.1.3/raglib/loaders/document_loader.py +129 -0
- raglib_py-0.1.3/raglib/loaders/exceptions.py +11 -0
- raglib_py-0.1.3/raglib/loaders/pdf_loader.py +114 -0
- raglib_py-0.1.3/raglib/loaders/plain_text_loader.py +34 -0
- raglib_py-0.1.3/raglib/loaders/powerpoint_loader.py +49 -0
- raglib_py-0.1.3/raglib/loaders/pptx_loader.py +52 -0
- raglib_py-0.1.3/raglib/loaders/text_loader.py +39 -0
- raglib_py-0.1.3/raglib/loaders/web_loader.py +48 -0
- raglib_py-0.1.3/raglib/loaders/webpage_loader.py +84 -0
- raglib_py-0.1.3/raglib/loaders/word_loader.py +50 -0
- raglib_py-0.1.3/raglib/main.py +271 -0
- raglib_py-0.1.3/raglib/preprocessing/__init__.py +5 -0
- raglib_py-0.1.3/raglib/preprocessing/chunk_splitter.py +104 -0
- raglib_py-0.1.3/raglib/providers/__init__.py +31 -0
- raglib_py-0.1.3/raglib/providers/base_provider.py +73 -0
- raglib_py-0.1.3/raglib/providers/bing_provider.py +83 -0
- raglib_py-0.1.3/raglib/providers/brave_provider.py +91 -0
- raglib_py-0.1.3/raglib/providers/duckduckgo_provider.py +83 -0
- raglib_py-0.1.3/raglib/providers/exa_provider.py +88 -0
- raglib_py-0.1.3/raglib/providers/google_cse_provider.py +88 -0
- raglib_py-0.1.3/raglib/providers/searxng_provider.py +93 -0
- raglib_py-0.1.3/raglib/providers/serpapi_provider.py +84 -0
- raglib_py-0.1.3/raglib/providers/tavily_provider.py +93 -0
- raglib_py-0.1.3/raglib/rag_types/__init__.py +29 -0
- raglib_py-0.1.3/raglib/rag_types/advanced_rag.py +65 -0
- raglib_py-0.1.3/raglib/rag_types/agentic_rag.py +67 -0
- raglib_py-0.1.3/raglib/rag_types/corrective_rag.py +72 -0
- raglib_py-0.1.3/raglib/rag_types/hybrid_rag.py +54 -0
- raglib_py-0.1.3/raglib/rag_types/memory_rag.py +57 -0
- raglib_py-0.1.3/raglib/rag_types/multi_hop_rag.py +65 -0
- raglib_py-0.1.3/raglib/rag_types/multi_query_rag.py +63 -0
- raglib_py-0.1.3/raglib/rag_types/naive_rag.py +46 -0
- raglib_py-0.1.3/raglib/rag_types/routing_rag.py +47 -0
- raglib_py-0.1.3/raglib/rag_types/self_rag.py +85 -0
- raglib_py-0.1.3/raglib/rag_types/tool_augmented_rag.py +65 -0
- raglib_py-0.1.3/raglib/rag_types/web_rag.py +54 -0
- raglib_py-0.1.3/raglib/schemas.py +50 -0
- raglib_py-0.1.3/raglib/session/__init__.py +11 -0
- raglib_py-0.1.3/raglib/session/interactive.py +121 -0
- raglib_py-0.1.3/raglib/vectorstores/__init__.py +21 -0
- raglib_py-0.1.3/raglib/vectorstores/base_store.py +44 -0
- raglib_py-0.1.3/raglib/vectorstores/chroma_store.py +106 -0
- raglib_py-0.1.3/raglib/vectorstores/factory.py +130 -0
- raglib_py-0.1.3/raglib/vectorstores/in_memory_store.py +64 -0
- raglib_py-0.1.3/raglib/vision/__init__.py +23 -0
- raglib_py-0.1.3/raglib/vision/anthropic_vision.py +82 -0
- raglib_py-0.1.3/raglib/vision/base_vision.py +16 -0
- raglib_py-0.1.3/raglib/vision/google_vision.py +75 -0
- raglib_py-0.1.3/raglib/vision/mock_vision.py +19 -0
- raglib_py-0.1.3/raglib/vision/openai_vision.py +76 -0
- raglib_py-0.1.3/raglib/vision/vision_factory.py +43 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
*.so
|
|
7
|
+
|
|
8
|
+
# Build artifacts
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.egg
|
|
13
|
+
|
|
14
|
+
# Test and tooling caches
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
.coverage.*
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Local runtime/state files
|
|
23
|
+
.raglib_chroma/
|
|
24
|
+
*.sqlite3
|
|
25
|
+
*.db
|
|
26
|
+
|
|
27
|
+
# Editors/OS
|
|
28
|
+
.vscode/
|
|
29
|
+
.idea/
|
|
30
|
+
Thumbs.db
|
|
31
|
+
Desktop.ini
|
|
32
|
+
|
|
33
|
+
# Secrets/env files
|
|
34
|
+
.env
|
|
35
|
+
.env.*
|
|
36
|
+
*.pem
|
|
37
|
+
*.key
|
|
38
|
+
*.token
|
raglib_py-0.1.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 raglib maintainers
|
|
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.
|
raglib_py-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: raglib-py
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A modular, production-grade Retrieval-Augmented Generation library
|
|
5
|
+
Project-URL: Homepage, https://github.com/himanshau/raglib
|
|
6
|
+
Project-URL: Repository, https://github.com/himanshau/raglib
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/himanshau/raglib/issues
|
|
8
|
+
Author: raglib maintainers
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 raglib maintainers
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: ai,llm,nlp,rag,retrieval,vector-search
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
42
|
+
Requires-Python: >=3.9
|
|
43
|
+
Requires-Dist: duckduckgo-search>=3.9
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: chromadb>=0.5.0; extra == 'all'
|
|
46
|
+
Requires-Dist: langchain-anthropic>=0.1.0; extra == 'all'
|
|
47
|
+
Requires-Dist: langchain-core>=0.2.0; extra == 'all'
|
|
48
|
+
Requires-Dist: langchain-google-genai>=1.0.0; extra == 'all'
|
|
49
|
+
Requires-Dist: langchain-groq>=0.1.0; extra == 'all'
|
|
50
|
+
Requires-Dist: langchain-huggingface>=0.0.3; extra == 'all'
|
|
51
|
+
Requires-Dist: langchain-ollama>=0.1.0; extra == 'all'
|
|
52
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == 'all'
|
|
53
|
+
Requires-Dist: pillow>=10.0.0; extra == 'all'
|
|
54
|
+
Requires-Dist: pymupdf>=1.23.0; extra == 'all'
|
|
55
|
+
Requires-Dist: pytesseract>=0.3.10; extra == 'all'
|
|
56
|
+
Requires-Dist: python-docx>=1.0.0; extra == 'all'
|
|
57
|
+
Requires-Dist: python-pptx>=0.6.21; extra == 'all'
|
|
58
|
+
Requires-Dist: sentence-transformers>=2.6.0; extra == 'all'
|
|
59
|
+
Provides-Extra: all-llm
|
|
60
|
+
Requires-Dist: langchain-anthropic>=0.1.0; extra == 'all-llm'
|
|
61
|
+
Requires-Dist: langchain-core>=0.2.0; extra == 'all-llm'
|
|
62
|
+
Requires-Dist: langchain-google-genai>=1.0.0; extra == 'all-llm'
|
|
63
|
+
Requires-Dist: langchain-groq>=0.1.0; extra == 'all-llm'
|
|
64
|
+
Requires-Dist: langchain-ollama>=0.1.0; extra == 'all-llm'
|
|
65
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == 'all-llm'
|
|
66
|
+
Provides-Extra: anthropic
|
|
67
|
+
Requires-Dist: langchain-anthropic>=0.1.0; extra == 'anthropic'
|
|
68
|
+
Provides-Extra: chroma
|
|
69
|
+
Requires-Dist: chromadb>=0.5.0; extra == 'chroma'
|
|
70
|
+
Provides-Extra: dev
|
|
71
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
72
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
73
|
+
Requires-Dist: pytest-mock>=3.11.0; extra == 'dev'
|
|
74
|
+
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
75
|
+
Requires-Dist: twine>=4.0.0; extra == 'dev'
|
|
76
|
+
Provides-Extra: docx
|
|
77
|
+
Requires-Dist: python-docx>=1.0.0; extra == 'docx'
|
|
78
|
+
Provides-Extra: faiss
|
|
79
|
+
Requires-Dist: faiss-cpu>=1.7.0; extra == 'faiss'
|
|
80
|
+
Provides-Extra: free-embed
|
|
81
|
+
Requires-Dist: langchain-huggingface>=0.0.3; extra == 'free-embed'
|
|
82
|
+
Requires-Dist: sentence-transformers>=2.6.0; extra == 'free-embed'
|
|
83
|
+
Provides-Extra: google
|
|
84
|
+
Requires-Dist: langchain-google-genai>=1.0.0; extra == 'google'
|
|
85
|
+
Provides-Extra: groq
|
|
86
|
+
Requires-Dist: langchain-groq>=0.1.0; extra == 'groq'
|
|
87
|
+
Provides-Extra: langchain
|
|
88
|
+
Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
|
|
89
|
+
Provides-Extra: ocr
|
|
90
|
+
Requires-Dist: pillow>=10.0.0; extra == 'ocr'
|
|
91
|
+
Requires-Dist: pytesseract>=0.3.10; extra == 'ocr'
|
|
92
|
+
Provides-Extra: ollama
|
|
93
|
+
Requires-Dist: langchain-ollama>=0.1.0; extra == 'ollama'
|
|
94
|
+
Provides-Extra: openai
|
|
95
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == 'openai'
|
|
96
|
+
Provides-Extra: pdf
|
|
97
|
+
Requires-Dist: pymupdf>=1.23.0; extra == 'pdf'
|
|
98
|
+
Provides-Extra: pptx
|
|
99
|
+
Requires-Dist: python-pptx>=0.6.21; extra == 'pptx'
|
|
100
|
+
Provides-Extra: serpapi
|
|
101
|
+
Requires-Dist: google-search-results>=2.4.0; extra == 'serpapi'
|
|
102
|
+
Provides-Extra: tavily
|
|
103
|
+
Requires-Dist: tavily-python>=0.2.0; extra == 'tavily'
|
|
104
|
+
Provides-Extra: vision
|
|
105
|
+
Requires-Dist: langchain-anthropic>=0.1.0; extra == 'vision'
|
|
106
|
+
Requires-Dist: langchain-google-genai>=1.0.0; extra == 'vision'
|
|
107
|
+
Requires-Dist: langchain-openai>=0.1.0; extra == 'vision'
|
|
108
|
+
Description-Content-Type: text/markdown
|
|
109
|
+
|
|
110
|
+
# raglib
|
|
111
|
+
|
|
112
|
+
raglib is a modular, production-grade Python library for Retrieval-Augmented Generation (RAG).
|
|
113
|
+
|
|
114
|
+
## Installation
|
|
115
|
+
|
|
116
|
+
Install from PyPI:
|
|
117
|
+
|
|
118
|
+
pip install raglib-py
|
|
119
|
+
|
|
120
|
+
Install with optional extras:
|
|
121
|
+
|
|
122
|
+
pip install raglib-py[tavily,serpapi,faiss]
|
|
123
|
+
|
|
124
|
+
## Quick import check
|
|
125
|
+
|
|
126
|
+
python -c "from raglib.rag_types.naive_rag import NaiveRAG; print('Import successful')"
|
|
127
|
+
|
|
128
|
+
## One-line API quickstart
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from raglib import RAG
|
|
132
|
+
|
|
133
|
+
rag = RAG("my_documents/")
|
|
134
|
+
result = rag.query("What is this report about?")
|
|
135
|
+
|
|
136
|
+
print(result.answer)
|
|
137
|
+
print(result.sources)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
You can also add more sources later:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
rag.add("new_data.docx")
|
|
144
|
+
rag.add("https://example.com/article")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Features
|
|
148
|
+
|
|
149
|
+
- Modular retrieval components (vector, web, hybrid, routing, multi-query, multi-hop)
|
|
150
|
+
- RAG strategy orchestrators (naive, advanced, corrective, self, agentic, and more)
|
|
151
|
+
- Mock LLM client for offline testing
|
|
152
|
+
- Provider abstraction with fallback chaining
|
|
153
|
+
- Full test suite with unit, integration, e2e, and edge coverage
|
|
154
|
+
|
|
155
|
+
## Detailed usage guide
|
|
156
|
+
|
|
157
|
+
See docs/USAGE.md for a full Python usage guide with quickstart, component wiring, and advanced orchestrator examples.
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# raglib
|
|
2
|
+
|
|
3
|
+
raglib is a modular, production-grade Python library for Retrieval-Augmented Generation (RAG).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install from PyPI:
|
|
8
|
+
|
|
9
|
+
pip install raglib-py
|
|
10
|
+
|
|
11
|
+
Install with optional extras:
|
|
12
|
+
|
|
13
|
+
pip install raglib-py[tavily,serpapi,faiss]
|
|
14
|
+
|
|
15
|
+
## Quick import check
|
|
16
|
+
|
|
17
|
+
python -c "from raglib.rag_types.naive_rag import NaiveRAG; print('Import successful')"
|
|
18
|
+
|
|
19
|
+
## One-line API quickstart
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from raglib import RAG
|
|
23
|
+
|
|
24
|
+
rag = RAG("my_documents/")
|
|
25
|
+
result = rag.query("What is this report about?")
|
|
26
|
+
|
|
27
|
+
print(result.answer)
|
|
28
|
+
print(result.sources)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
You can also add more sources later:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
rag.add("new_data.docx")
|
|
35
|
+
rag.add("https://example.com/article")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Modular retrieval components (vector, web, hybrid, routing, multi-query, multi-hop)
|
|
41
|
+
- RAG strategy orchestrators (naive, advanced, corrective, self, agentic, and more)
|
|
42
|
+
- Mock LLM client for offline testing
|
|
43
|
+
- Provider abstraction with fallback chaining
|
|
44
|
+
- Full test suite with unit, integration, e2e, and edge coverage
|
|
45
|
+
|
|
46
|
+
## Detailed usage guide
|
|
47
|
+
|
|
48
|
+
See docs/USAGE.md for a full Python usage guide with quickstart, component wiring, and advanced orchestrator examples.
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "raglib-py"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "A modular, production-grade Retrieval-Augmented Generation library"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "raglib maintainers" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.9"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"duckduckgo-search>=3.9"
|
|
17
|
+
]
|
|
18
|
+
keywords = ["rag", "llm", "retrieval", "ai", "nlp", "vector-search"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/himanshau/raglib"
|
|
34
|
+
Repository = "https://github.com/himanshau/raglib"
|
|
35
|
+
"Bug Tracker" = "https://github.com/himanshau/raglib/issues"
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
tavily = ["tavily-python>=0.2.0"]
|
|
39
|
+
serpapi = ["google-search-results>=2.4.0"]
|
|
40
|
+
faiss = ["faiss-cpu>=1.7.0"]
|
|
41
|
+
chroma = ["chromadb>=0.5.0"]
|
|
42
|
+
openai = ["langchain-openai>=0.1.0"]
|
|
43
|
+
anthropic = ["langchain-anthropic>=0.1.0"]
|
|
44
|
+
groq = ["langchain-groq>=0.1.0"]
|
|
45
|
+
google = ["langchain-google-genai>=1.0.0"]
|
|
46
|
+
ollama = ["langchain-ollama>=0.1.0"]
|
|
47
|
+
langchain = ["langchain-core>=0.2.0"]
|
|
48
|
+
pdf = ["PyMuPDF>=1.23.0"]
|
|
49
|
+
docx = ["python-docx>=1.0.0"]
|
|
50
|
+
pptx = ["python-pptx>=0.6.21"]
|
|
51
|
+
free-embed = ["langchain-huggingface>=0.0.3", "sentence-transformers>=2.6.0"]
|
|
52
|
+
ocr = ["pytesseract>=0.3.10", "Pillow>=10.0.0"]
|
|
53
|
+
vision = [
|
|
54
|
+
"langchain-openai>=0.1.0",
|
|
55
|
+
"langchain-anthropic>=0.1.0",
|
|
56
|
+
"langchain-google-genai>=1.0.0",
|
|
57
|
+
]
|
|
58
|
+
all-llm = [
|
|
59
|
+
"langchain-core>=0.2.0",
|
|
60
|
+
"langchain-openai>=0.1.0",
|
|
61
|
+
"langchain-anthropic>=0.1.0",
|
|
62
|
+
"langchain-groq>=0.1.0",
|
|
63
|
+
"langchain-google-genai>=1.0.0",
|
|
64
|
+
"langchain-ollama>=0.1.0",
|
|
65
|
+
]
|
|
66
|
+
all = [
|
|
67
|
+
"chromadb>=0.5.0",
|
|
68
|
+
"langchain-core>=0.2.0",
|
|
69
|
+
"langchain-openai>=0.1.0",
|
|
70
|
+
"langchain-anthropic>=0.1.0",
|
|
71
|
+
"langchain-groq>=0.1.0",
|
|
72
|
+
"langchain-google-genai>=1.0.0",
|
|
73
|
+
"langchain-ollama>=0.1.0",
|
|
74
|
+
"langchain-huggingface>=0.0.3",
|
|
75
|
+
"sentence-transformers>=2.6.0",
|
|
76
|
+
"PyMuPDF>=1.23.0",
|
|
77
|
+
"python-docx>=1.0.0",
|
|
78
|
+
"python-pptx>=0.6.21",
|
|
79
|
+
"pytesseract>=0.3.10",
|
|
80
|
+
"Pillow>=10.0.0",
|
|
81
|
+
]
|
|
82
|
+
dev = [
|
|
83
|
+
"pytest>=7.4.0",
|
|
84
|
+
"pytest-cov>=4.1.0",
|
|
85
|
+
"pytest-mock>=3.11.0",
|
|
86
|
+
"build>=1.0.0",
|
|
87
|
+
"twine>=4.0.0",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[tool.hatch.build.targets.wheel]
|
|
91
|
+
packages = ["raglib"]
|
|
92
|
+
|
|
93
|
+
[tool.hatch.build.targets.sdist]
|
|
94
|
+
include = [
|
|
95
|
+
"raglib/**/*.py",
|
|
96
|
+
"README.md",
|
|
97
|
+
"LICENSE",
|
|
98
|
+
"pyproject.toml",
|
|
99
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Public package exports for raglib."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from raglib.facade import RAG
|
|
6
|
+
from raglib.llm.mock_client import MockLLMClient
|
|
7
|
+
from raglib.schemas import Document, GenerationResult, QueryResult
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"RAG",
|
|
11
|
+
"Document",
|
|
12
|
+
"QueryResult",
|
|
13
|
+
"GenerationResult",
|
|
14
|
+
"MockLLMClient",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.3"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Component exports for raglib retrieval and generation building blocks."""
|
|
2
|
+
|
|
3
|
+
from raglib.components.context_reducer import ContextReducer
|
|
4
|
+
from raglib.components.decision import DecisionEngine
|
|
5
|
+
from raglib.components.deduplicator import Deduplicator
|
|
6
|
+
from raglib.components.evaluator import Evaluator
|
|
7
|
+
from raglib.components.generator import Generator
|
|
8
|
+
from raglib.components.hybrid_retriever import HybridRetriever
|
|
9
|
+
from raglib.components.memory import MemoryModule
|
|
10
|
+
from raglib.components.multi_hop_retriever import MultiHopRetriever
|
|
11
|
+
from raglib.components.multi_query_retriever import MultiQueryRetriever
|
|
12
|
+
from raglib.components.planner import Planner
|
|
13
|
+
from raglib.components.query_expander import QueryExpander
|
|
14
|
+
from raglib.components.query_rewriter import QueryRewriter
|
|
15
|
+
from raglib.components.refiner import Refiner
|
|
16
|
+
from raglib.components.reflection import ReflectionModule
|
|
17
|
+
from raglib.components.reranker import Reranker
|
|
18
|
+
from raglib.components.retriever import Retriever
|
|
19
|
+
from raglib.components.router_retriever import RouterRetriever
|
|
20
|
+
from raglib.components.web_retriever import WebRetriever
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Retriever",
|
|
24
|
+
"WebRetriever",
|
|
25
|
+
"HybridRetriever",
|
|
26
|
+
"MultiQueryRetriever",
|
|
27
|
+
"RouterRetriever",
|
|
28
|
+
"MultiHopRetriever",
|
|
29
|
+
"Reranker",
|
|
30
|
+
"Evaluator",
|
|
31
|
+
"Refiner",
|
|
32
|
+
"QueryRewriter",
|
|
33
|
+
"QueryExpander",
|
|
34
|
+
"Deduplicator",
|
|
35
|
+
"ContextReducer",
|
|
36
|
+
"MemoryModule",
|
|
37
|
+
"Planner",
|
|
38
|
+
"ReflectionModule",
|
|
39
|
+
"DecisionEngine",
|
|
40
|
+
"Generator",
|
|
41
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Context reduction utilities for prompt token budgeting."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
from raglib.schemas import Document
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ContextReducer:
|
|
15
|
+
"""Trims retrieved context to fit a target token budget."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, max_context_tokens: int = 3000):
|
|
18
|
+
"""Initialize context token budget."""
|
|
19
|
+
|
|
20
|
+
self.max_context_tokens = max_context_tokens
|
|
21
|
+
|
|
22
|
+
def reduce(self, documents: List[Document], max_tokens: Optional[int] = None) -> List[Document]:
|
|
23
|
+
"""Reduce documents until the token budget is satisfied."""
|
|
24
|
+
|
|
25
|
+
budget = max_tokens if max_tokens is not None else self.max_context_tokens
|
|
26
|
+
reduced: List[Document] = []
|
|
27
|
+
used_tokens = 0
|
|
28
|
+
|
|
29
|
+
for doc in documents:
|
|
30
|
+
doc_tokens = self._estimate_tokens(doc.content)
|
|
31
|
+
if used_tokens + doc_tokens <= budget:
|
|
32
|
+
reduced.append(doc)
|
|
33
|
+
used_tokens += doc_tokens
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
remaining = budget - used_tokens
|
|
37
|
+
if remaining <= 0:
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
trimmed_content = self._truncate_to_tokens(doc.content, remaining)
|
|
41
|
+
if trimmed_content.strip():
|
|
42
|
+
reduced.append(
|
|
43
|
+
replace(
|
|
44
|
+
doc,
|
|
45
|
+
content=trimmed_content,
|
|
46
|
+
metadata={**doc.metadata, "trimmed": True},
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
used_tokens = budget
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
logger.info("ContextReducer used %d/%d tokens", used_tokens, budget)
|
|
53
|
+
return reduced
|
|
54
|
+
|
|
55
|
+
def _estimate_tokens(self, text: str) -> int:
|
|
56
|
+
"""Estimate token count from whitespace-separated words."""
|
|
57
|
+
|
|
58
|
+
return max(1, int(len(text.split()) * 1.2))
|
|
59
|
+
|
|
60
|
+
def _truncate_to_tokens(self, text: str, max_tokens: int) -> str:
|
|
61
|
+
"""Truncate text to an approximate token count."""
|
|
62
|
+
|
|
63
|
+
words = text.split()
|
|
64
|
+
max_words = max(1, int(max_tokens / 1.2))
|
|
65
|
+
return " ".join(words[:max_words])
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Decision engine for retrieval gating and mode selection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from raglib.llm.base_client import BaseLLMClient
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
RETRIEVAL_VECTOR: str = "vector"
|
|
13
|
+
RETRIEVAL_WEB: str = "web"
|
|
14
|
+
RETRIEVAL_HYBRID: str = "hybrid"
|
|
15
|
+
RETRIEVAL_NONE: str = "none"
|
|
16
|
+
ALLOWED_RETRIEVAL_TYPES = {
|
|
17
|
+
RETRIEVAL_VECTOR,
|
|
18
|
+
RETRIEVAL_WEB,
|
|
19
|
+
RETRIEVAL_HYBRID,
|
|
20
|
+
RETRIEVAL_NONE,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DecisionEngine:
|
|
25
|
+
"""Decides whether retrieval is needed and what retrieval mode to use."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, llm_client: Optional[BaseLLMClient] = None):
|
|
28
|
+
"""Initialize decision policy with an optional LLM client."""
|
|
29
|
+
|
|
30
|
+
self.llm_client = llm_client
|
|
31
|
+
|
|
32
|
+
def should_retrieve(self, query: str) -> bool:
|
|
33
|
+
"""Return whether retrieval should run for this query."""
|
|
34
|
+
|
|
35
|
+
route = self.retrieval_type(query)
|
|
36
|
+
decision = route != RETRIEVAL_NONE
|
|
37
|
+
logger.info("DecisionEngine should_retrieve=%s route=%s", decision, route)
|
|
38
|
+
return decision
|
|
39
|
+
|
|
40
|
+
def retrieval_type(self, query: str) -> str:
|
|
41
|
+
"""Return one of: vector, web, hybrid, none."""
|
|
42
|
+
|
|
43
|
+
if self.llm_client is not None:
|
|
44
|
+
prompt = (
|
|
45
|
+
"Decide retrieval_type for this query. Allowed: vector, web, hybrid, none.\n"
|
|
46
|
+
f"Query: {query}\n"
|
|
47
|
+
"Return one token only."
|
|
48
|
+
)
|
|
49
|
+
response = self.llm_client.complete(prompt=prompt).strip().lower()
|
|
50
|
+
if response in ALLOWED_RETRIEVAL_TYPES:
|
|
51
|
+
logger.info("DecisionEngine selected via LLM: %s", response)
|
|
52
|
+
return response
|
|
53
|
+
|
|
54
|
+
lower = query.lower().strip()
|
|
55
|
+
if not lower:
|
|
56
|
+
return RETRIEVAL_NONE
|
|
57
|
+
if any(token in lower for token in ("hello", "thanks", "hi", "good morning")):
|
|
58
|
+
return RETRIEVAL_NONE
|
|
59
|
+
if any(token in lower for token in ("latest", "today", "news", "current", "web")):
|
|
60
|
+
return RETRIEVAL_WEB
|
|
61
|
+
if any(token in lower for token in ("compare", "versus", "vs", "trend")):
|
|
62
|
+
return RETRIEVAL_HYBRID
|
|
63
|
+
return RETRIEVAL_VECTOR
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Near-duplicate removal for retrieved document sets."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
from typing import List, Set
|
|
8
|
+
|
|
9
|
+
from raglib.schemas import Document
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Deduplicator:
|
|
15
|
+
"""Removes semantically similar duplicate document chunks."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, similarity_threshold: float = 0.85):
|
|
18
|
+
"""Initialize deduplication threshold."""
|
|
19
|
+
|
|
20
|
+
self.similarity_threshold = similarity_threshold
|
|
21
|
+
|
|
22
|
+
def deduplicate(self, documents: List[Document]) -> List[Document]:
|
|
23
|
+
"""Return documents after near-duplicate filtering."""
|
|
24
|
+
|
|
25
|
+
unique_docs: List[Document] = []
|
|
26
|
+
signatures: List[Set[str]] = []
|
|
27
|
+
|
|
28
|
+
for doc in documents:
|
|
29
|
+
signature = self._signature(doc.content)
|
|
30
|
+
if not signatures:
|
|
31
|
+
unique_docs.append(doc)
|
|
32
|
+
signatures.append(signature)
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
is_duplicate = any(
|
|
36
|
+
self._jaccard(signature, existing) >= self.similarity_threshold
|
|
37
|
+
for existing in signatures
|
|
38
|
+
)
|
|
39
|
+
if not is_duplicate:
|
|
40
|
+
unique_docs.append(doc)
|
|
41
|
+
signatures.append(signature)
|
|
42
|
+
|
|
43
|
+
logger.info("Deduplicator kept %d/%d documents", len(unique_docs), len(documents))
|
|
44
|
+
return unique_docs
|
|
45
|
+
|
|
46
|
+
def _signature(self, text: str) -> Set[str]:
|
|
47
|
+
"""Build a token-set signature for similarity checks."""
|
|
48
|
+
|
|
49
|
+
return set(re.findall(r"[a-zA-Z0-9]+", text.lower()))
|
|
50
|
+
|
|
51
|
+
def _jaccard(self, a: Set[str], b: Set[str]) -> float:
|
|
52
|
+
"""Compute Jaccard similarity between token signatures."""
|
|
53
|
+
|
|
54
|
+
if not a and not b:
|
|
55
|
+
return 1.0
|
|
56
|
+
if not a or not b:
|
|
57
|
+
return 0.0
|
|
58
|
+
return len(a & b) / len(a | b)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Retrieval quality evaluator used for corrective feedback loops."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
from dataclasses import replace
|
|
8
|
+
from typing import List, Set
|
|
9
|
+
|
|
10
|
+
from raglib.schemas import Document
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Evaluator:
|
|
16
|
+
"""Scores relevance and filters low-quality retrieval results."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, relevance_threshold: float = 0.3):
|
|
19
|
+
"""Initialize evaluator with a minimum relevance threshold."""
|
|
20
|
+
|
|
21
|
+
self.relevance_threshold = relevance_threshold
|
|
22
|
+
|
|
23
|
+
def evaluate(self, query: str, documents: List[Document]) -> List[Document]:
|
|
24
|
+
"""Filter documents by relevance score threshold."""
|
|
25
|
+
|
|
26
|
+
passed: List[Document] = []
|
|
27
|
+
for doc in documents:
|
|
28
|
+
score = self.score_document(query, doc)
|
|
29
|
+
if score >= self.relevance_threshold:
|
|
30
|
+
passed.append(replace(doc, score=score))
|
|
31
|
+
|
|
32
|
+
logger.info(
|
|
33
|
+
"Evaluator kept %d/%d documents with threshold %.2f",
|
|
34
|
+
len(passed),
|
|
35
|
+
len(documents),
|
|
36
|
+
self.relevance_threshold,
|
|
37
|
+
)
|
|
38
|
+
return passed
|
|
39
|
+
|
|
40
|
+
def score_document(self, query: str, doc: Document) -> float:
|
|
41
|
+
"""Compute a relevance score for a single document."""
|
|
42
|
+
|
|
43
|
+
query_terms = self._tokenize(query)
|
|
44
|
+
doc_terms = self._tokenize(doc.content)
|
|
45
|
+
if not query_terms or not doc_terms:
|
|
46
|
+
return 0.0
|
|
47
|
+
|
|
48
|
+
overlap = len(query_terms & doc_terms) / len(query_terms)
|
|
49
|
+
density = len(query_terms & doc_terms) / max(len(doc_terms), 1)
|
|
50
|
+
phrase_bonus = 0.2 if query.lower() in doc.content.lower() else 0.0
|
|
51
|
+
score = min(1.0, overlap * 0.7 + density * 0.3 + phrase_bonus)
|
|
52
|
+
return score
|
|
53
|
+
|
|
54
|
+
def _tokenize(self, text: str) -> Set[str]:
|
|
55
|
+
"""Tokenize text into a normalized set of terms."""
|
|
56
|
+
|
|
57
|
+
return set(re.findall(r"[a-zA-Z0-9]+", text.lower()))
|