ragkit-dev 0.1.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.
- ragkit_dev-0.1.0/CHANGELOG.md +86 -0
- ragkit_dev-0.1.0/LICENSE +21 -0
- ragkit_dev-0.1.0/PKG-INFO +448 -0
- ragkit_dev-0.1.0/README.md +394 -0
- ragkit_dev-0.1.0/hatch_build.py +17 -0
- ragkit_dev-0.1.0/pyproject.toml +118 -0
- ragkit_dev-0.1.0/src/rag_kit/__init__.py +44 -0
- ragkit_dev-0.1.0/src/rag_kit/__main__.py +5 -0
- ragkit_dev-0.1.0/src/rag_kit/api.py +155 -0
- ragkit_dev-0.1.0/src/rag_kit/cli.py +484 -0
- ragkit_dev-0.1.0/src/rag_kit/env.py +84 -0
- ragkit_dev-0.1.0/src/rag_kit/errors.py +37 -0
- ragkit_dev-0.1.0/src/rag_kit/log.py +42 -0
- ragkit_dev-0.1.0/src/rag_kit/pdf_font_repair.py +132 -0
- ragkit_dev-0.1.0/src/rag_kit/pipeline.py +169 -0
- ragkit_dev-0.1.0/src/rag_kit/py.typed +0 -0
- ragkit_dev-0.1.0/src/rag_kit/settings.py +247 -0
- ragkit_dev-0.1.0/src/rag_kit/step01_load_pdf.py +38 -0
- ragkit_dev-0.1.0/src/rag_kit/step02_extract_text.py +138 -0
- ragkit_dev-0.1.0/src/rag_kit/step03_clean_text.py +76 -0
- ragkit_dev-0.1.0/src/rag_kit/step04_chunking.py +36 -0
- ragkit_dev-0.1.0/src/rag_kit/step05_embedding.py +77 -0
- ragkit_dev-0.1.0/src/rag_kit/step06_vector_store.py +251 -0
- ragkit_dev-0.1.0/src/rag_kit/step08_query_embedding.py +17 -0
- ragkit_dev-0.1.0/src/rag_kit/step09_retrieve.py +34 -0
- ragkit_dev-0.1.0/src/rag_kit/step10_generate.py +84 -0
- ragkit_dev-0.1.0/src/rag_kit/step11_answer.py +60 -0
- ragkit_dev-0.1.0/src/rag_kit/ui/__init__.py +1 -0
- ragkit_dev-0.1.0/src/rag_kit/ui/app.py +153 -0
- ragkit_dev-0.1.0/tests/__init__.py +0 -0
- ragkit_dev-0.1.0/tests/conftest.py +96 -0
- ragkit_dev-0.1.0/tests/fixtures/empty_env.txt +1 -0
- ragkit_dev-0.1.0/tests/integration/__init__.py +0 -0
- ragkit_dev-0.1.0/tests/integration/test_real_pipeline.py +106 -0
- ragkit_dev-0.1.0/tests/test_answer.py +116 -0
- ragkit_dev-0.1.0/tests/test_api.py +188 -0
- ragkit_dev-0.1.0/tests/test_cli.py +357 -0
- ragkit_dev-0.1.0/tests/test_env.py +175 -0
- ragkit_dev-0.1.0/tests/test_font_repair.py +75 -0
- ragkit_dev-0.1.0/tests/test_imports.py +85 -0
- ragkit_dev-0.1.0/tests/test_logging.py +92 -0
- ragkit_dev-0.1.0/tests/test_network_guard.py +38 -0
- ragkit_dev-0.1.0/tests/test_project_template.py +75 -0
- ragkit_dev-0.1.0/tests/test_release_gate.py +907 -0
- ragkit_dev-0.1.0/tests/test_release_scripts.py +163 -0
- ragkit_dev-0.1.0/tests/test_release_workflow.py +308 -0
- ragkit_dev-0.1.0/tests/test_settings.py +213 -0
- ragkit_dev-0.1.0/tests/test_text_processing.py +157 -0
- ragkit_dev-0.1.0/tests/test_vector_store.py +100 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0rc1 (release candidate)
|
|
4
|
+
|
|
5
|
+
Release candidate for 0.1.0, used to rehearse the release on TestPyPI. It
|
|
6
|
+
contains everything listed under 0.1.0 below; the generator's npm version is
|
|
7
|
+
`0.1.0-rc.1`. Rehearsals never publish to PyPI or npm.
|
|
8
|
+
|
|
9
|
+
## 0.1.0 (2026-11-10)
|
|
10
|
+
|
|
11
|
+
First packaged release: the toolkit is now the installable Python package
|
|
12
|
+
`ragkit-dev` on PyPI (import name `rag_kit`) with a `rag-kit` command. The
|
|
13
|
+
distribution is not called `rag-kit`: PyPI's name-similarity check would reject
|
|
14
|
+
`rag-kit` as too close to the existing, unrelated `ragkit` project.
|
|
15
|
+
|
|
16
|
+
### Migrating from the script-based checkout
|
|
17
|
+
|
|
18
|
+
Install the checkout as a package first (`pip install -e ".[local,gemini]"`,
|
|
19
|
+
plus `api`, `ui` or `dev` as needed; see the README).
|
|
20
|
+
|
|
21
|
+
| Before | Now |
|
|
22
|
+
| ------ | --- |
|
|
23
|
+
| `pip install -r requirements.txt` | `pip install -e ".[local,gemini]"` |
|
|
24
|
+
| `pip install -r requirements-api.txt` / `-ui.txt` / `-dev.txt` | extras `api`, `ui`, `dev` |
|
|
25
|
+
| `python cli.py <command> …` | `rag-kit <command> …` or `python -m rag_kit <command> …` |
|
|
26
|
+
| `python ingest.py FILE` | `rag-kit ingest FILE` |
|
|
27
|
+
| `python ingest.py --pdf FILE` | `rag-kit ingest FILE` (`--pdf` was removed) |
|
|
28
|
+
| `python ask.py "question"` | `rag-kit ask "question"` |
|
|
29
|
+
| `uvicorn main:app` | `rag-kit serve`, or `uvicorn rag_kit.api:app` |
|
|
30
|
+
| `streamlit run streamlit_app.py` | `rag-kit ui` |
|
|
31
|
+
| `python scripts/smoke_bge_m3.py` | `rag-kit check --deep` |
|
|
32
|
+
| `from rag.pipeline import Pipeline` | `from rag_kit import Pipeline` (or `rag_kit.pipeline`) |
|
|
33
|
+
| `from rag.<module> import …` | `from rag_kit.<module> import …` (same module names) |
|
|
34
|
+
| `import config; config.TOP_K` | `from rag_kit import Settings; Settings.load().top_k` |
|
|
35
|
+
| `main.create_app(...)` | `rag_kit.api.create_app(...)` |
|
|
36
|
+
| logger `rag` | logger `rag_kit` |
|
|
37
|
+
| `rag.step07_user_question` | removed (unused; the CLI and API take the question) |
|
|
38
|
+
|
|
39
|
+
### Changed behaviour
|
|
40
|
+
|
|
41
|
+
- **Project folder.** Commands work on the project given by `--project DIR`,
|
|
42
|
+
else `RAG_PROJECT_DIR`, else the nearest folder at or above the current
|
|
43
|
+
directory that contains `rag-kit.toml`. Without one they stop with an error.
|
|
44
|
+
Previously paths were tied to the folder `cli.py` lived in, so commands
|
|
45
|
+
worked from anywhere; now run them inside the project or pass `--project`.
|
|
46
|
+
This repository contains a `rag-kit.toml`, so its `.env` and `qdrant_data/`
|
|
47
|
+
keep working.
|
|
48
|
+
- **Environment export.** Importing `config` used to copy every `.env` key,
|
|
49
|
+
including `GOOGLE_API_KEY`, into `os.environ`. Now only the `rag-kit`
|
|
50
|
+
command, the default API app and the UI export, and only an allow-list
|
|
51
|
+
(Hugging Face / PyTorch runtime variables, proxies, CA bundles, plus names
|
|
52
|
+
in `RAG_EXPORT_ENV`). rag-kit's own settings are never exported. See
|
|
53
|
+
"Variables for other libraries" in the README.
|
|
54
|
+
- **`rag-kit serve` / `ui`** always pass the project to the server process in
|
|
55
|
+
`RAG_PROJECT_DIR`; `--collection` still applies to that process only.
|
|
56
|
+
- **`rag-kit check`** reads dependencies from the installed package's extras
|
|
57
|
+
and names the extra to install (`pip install "ragkit-dev[api]"`). It also
|
|
58
|
+
prints the project folder and the names of exported variables, and explains
|
|
59
|
+
how to create `.env` from `.env.example` when it is missing.
|
|
60
|
+
- **UI uploads** go to the project's `uploads/` folder.
|
|
61
|
+
- **API** returns 503 when no project can be found.
|
|
62
|
+
|
|
63
|
+
### Unchanged
|
|
64
|
+
|
|
65
|
+
Collection defaults (`pdf_rag`, `BAAI/bge-m3`), the chunk ID namespace and
|
|
66
|
+
metadata keys, the `[S1]` source markers, the `/health`, `/query` and
|
|
67
|
+
`documents --json` schemas, and the 4000-character question limit. Existing
|
|
68
|
+
Qdrant collections need no migration.
|
|
69
|
+
|
|
70
|
+
### Project generator
|
|
71
|
+
|
|
72
|
+
- New npm package `rag-kit-dev` (in `generator/`, version-locked to rag-kit):
|
|
73
|
+
`npx rag-kit-dev my-rag` creates a project with `rag-kit.toml`,
|
|
74
|
+
`.env.example`, `.gitignore`, `requirements.txt`, `data/`, `example.py` and
|
|
75
|
+
a README, and installs rag-kit into `.venv` with uv or pip. It never creates
|
|
76
|
+
`.env`, asks for API keys, downloads the embedding model, overwrites files or
|
|
77
|
+
deletes anything.
|
|
78
|
+
|
|
79
|
+
### Earlier fixes in this release
|
|
80
|
+
|
|
81
|
+
- Header/footer removal no longer deletes matching words from body text.
|
|
82
|
+
- The Gemini SDK is imported only when an answer is generated.
|
|
83
|
+
- Settings are an injectable, side-effect-free `Settings` object.
|
|
84
|
+
- Library code logs instead of printing; `--json` keeps stdout pure.
|
|
85
|
+
- API application factory (`create_app`) with a race-free pipeline and a
|
|
86
|
+
4000-character question limit.
|
ragkit_dev-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Riyad
|
|
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,448 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ragkit-dev
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A reusable, developer-focused RAG toolkit for document ingestion, retrieval, and source-grounded answers.
|
|
5
|
+
Project-URL: Repository, https://github.com/shamiulriyad/rag-learning
|
|
6
|
+
Project-URL: Issues, https://github.com/shamiulriyad/rag-learning/issues
|
|
7
|
+
Author: Riyad
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: embeddings,langchain,pdf,qdrant,rag,retrieval-augmented-generation
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: <3.13,>=3.11
|
|
21
|
+
Requires-Dist: langchain-core<2,>=1.6.9
|
|
22
|
+
Requires-Dist: langchain-qdrant<2,>=1.1
|
|
23
|
+
Requires-Dist: langchain-text-splitters<2,>=1.1
|
|
24
|
+
Requires-Dist: packaging>=24
|
|
25
|
+
Requires-Dist: pymupdf<3,>=1.28
|
|
26
|
+
Requires-Dist: python-dotenv<2,>=1.2
|
|
27
|
+
Requires-Dist: qdrant-client<2,>=1.19
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: fastapi<1,>=0.143; extra == 'all'
|
|
30
|
+
Requires-Dist: langchain-google-genai<5,>=4.4; extra == 'all'
|
|
31
|
+
Requires-Dist: langchain-huggingface<2,>=1.2; extra == 'all'
|
|
32
|
+
Requires-Dist: sentence-transformers<7,>=6.1; extra == 'all'
|
|
33
|
+
Requires-Dist: streamlit<2,>=1.65; extra == 'all'
|
|
34
|
+
Requires-Dist: uvicorn[standard]<1,>=0.54; extra == 'all'
|
|
35
|
+
Provides-Extra: api
|
|
36
|
+
Requires-Dist: fastapi<1,>=0.143; extra == 'api'
|
|
37
|
+
Requires-Dist: uvicorn[standard]<1,>=0.54; extra == 'api'
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: fastapi<1,>=0.143; extra == 'dev'
|
|
40
|
+
Requires-Dist: httpx<1,>=0.28; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest-socket<1,>=0.8.1; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest<10,>=9.1; extra == 'dev'
|
|
43
|
+
Requires-Dist: pyyaml<7,>=6.0.2; extra == 'dev'
|
|
44
|
+
Requires-Dist: ruff<1,>=0.17; extra == 'dev'
|
|
45
|
+
Requires-Dist: uvicorn[standard]<1,>=0.54; extra == 'dev'
|
|
46
|
+
Provides-Extra: gemini
|
|
47
|
+
Requires-Dist: langchain-google-genai<5,>=4.4; extra == 'gemini'
|
|
48
|
+
Provides-Extra: local
|
|
49
|
+
Requires-Dist: langchain-huggingface<2,>=1.2; extra == 'local'
|
|
50
|
+
Requires-Dist: sentence-transformers<7,>=6.1; extra == 'local'
|
|
51
|
+
Provides-Extra: ui
|
|
52
|
+
Requires-Dist: streamlit<2,>=1.65; extra == 'ui'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# rag-kit
|
|
56
|
+
|
|
57
|
+
A reusable, developer-focused RAG toolkit for document ingestion, retrieval,
|
|
58
|
+
and source-grounded answers. Index PDF, text and Markdown files into Qdrant,
|
|
59
|
+
then ask questions and get answers that cite the chunks (and PDF page numbers)
|
|
60
|
+
they came from.
|
|
61
|
+
|
|
62
|
+
Every pipeline step is its own module under [`src/rag_kit/`](https://github.com/shamiulriyad/rag-learning/tree/main/src/rag_kit), so
|
|
63
|
+
you can read, test and swap each one. Use it from the `rag-kit` command, from
|
|
64
|
+
Python, through an optional FastAPI service, or through an optional Streamlit
|
|
65
|
+
test UI.
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
> **Names:** the Python package is `ragkit-dev` (you `import rag_kit` and run
|
|
70
|
+
> `rag-kit`); the project generator is the npm package `rag-kit-dev`. Version
|
|
71
|
+
> 0.1.0. Upgrading from the script-based version? See
|
|
72
|
+
> [CHANGELOG.md](https://github.com/shamiulriyad/rag-learning/blob/main/CHANGELOG.md) for the old-to-new command table.
|
|
73
|
+
|
|
74
|
+
## Start a new project
|
|
75
|
+
|
|
76
|
+
`rag-kit-dev`, the npm package in [`generator/`](https://github.com/shamiulriyad/rag-learning/tree/main/generator),
|
|
77
|
+
creates a project folder (settings template, `data/`, an example) and a `.venv`
|
|
78
|
+
with rag-kit installed. It explains the local-vs-Gemini embedding choice before
|
|
79
|
+
installing anything and never creates `.env` or asks for an API key.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx rag-kit-dev my-rag
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
To try an unreleased build instead (testing only), build the wheel in a
|
|
86
|
+
checkout and point the generator at it. The `--package-spec` path is relative
|
|
87
|
+
to the folder you run the command in:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv build --out-dir dist
|
|
91
|
+
node generator/bin/rag-kit-dev.js my-rag --embeddings gemini --package-spec dist/ragkit_dev-0.1.0-py3-none-any.whl
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## What it does
|
|
95
|
+
|
|
96
|
+
| Step | Module | Notes |
|
|
97
|
+
| ---- | ------ | ----- |
|
|
98
|
+
| 1 Load | `step01_load_pdf.py` | `.pdf`, `.txt`, `.md`; validates before any work |
|
|
99
|
+
| 2 Extract | `step02_extract_text.py` | one Document per PDF page; optional font repair |
|
|
100
|
+
| 3 Clean | `step03_clean_text.py` | unwrap lines, join hyphenation, drop headers/footers |
|
|
101
|
+
| 4 Chunk | `step04_chunking.py` | recursive splitter, overlap, `chunk_id` per document |
|
|
102
|
+
| 5 Embed | `step05_embedding.py` | local Hugging Face model (default `BAAI/bge-m3`) or Gemini |
|
|
103
|
+
| 6 Store | `step06_vector_store.py` | Qdrant, embedded on disk or a server |
|
|
104
|
+
| 8–9 Retrieve | `step08`, `step09` | cosine search, optional minimum score |
|
|
105
|
+
| 10 Generate | `step10_generate.py` | Gemini, context-only, tags claims `[S1]`, `[S2]`… |
|
|
106
|
+
| 11 Answer | `step11_answer.py` | answer plus the sources behind each marker |
|
|
107
|
+
|
|
108
|
+
Step 7 (the question) comes from the CLI, the API or the UI.
|
|
109
|
+
[`pipeline.py`](https://github.com/shamiulriyad/rag-learning/blob/main/src/rag_kit/pipeline.py) wires the steps together; the CLI,
|
|
110
|
+
API and UI all use it. See [docs/pipeline.md](https://github.com/shamiulriyad/rag-learning/blob/main/docs/pipeline.md) for per-step
|
|
111
|
+
notes.
|
|
112
|
+
|
|
113
|
+
## Prerequisites
|
|
114
|
+
|
|
115
|
+
- **Python 3.11 or 3.12** (the package refuses other versions for now).
|
|
116
|
+
- A **Gemini API key** for answer generation
|
|
117
|
+
([get one](https://aistudio.google.com/app/apikey)). Ingestion and retrieval
|
|
118
|
+
with the default local embeddings need no key.
|
|
119
|
+
- For local embeddings: disk space for PyTorch and the model. `BAAI/bge-m3` is
|
|
120
|
+
about 2.2 GB and is downloaded to the Hugging Face cache on first use.
|
|
121
|
+
- Optional: Docker, if you prefer a Qdrant server to the embedded store.
|
|
122
|
+
|
|
123
|
+
## Install
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
py -3.11 -m venv .venv # macOS/Linux: python3.11 -m venv .venv
|
|
127
|
+
.venv\Scripts\activate # macOS/Linux: source .venv/bin/activate
|
|
128
|
+
python -m pip install -U pip
|
|
129
|
+
pip install "ragkit-dev[local,gemini]" # local embeddings + Gemini answers
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The package is named `ragkit-dev`; `pip install ragkit` installs a different,
|
|
133
|
+
unrelated project. `pip install ragkit-dev` alone gives the core (enough for
|
|
134
|
+
`rag-kit check`); add extras in brackets, e.g. `pip install "ragkit-dev[gemini,api]"`.
|
|
135
|
+
|
|
136
|
+
**From a checkout (development):** to work on the code or test unreleased
|
|
137
|
+
changes, install the repository in editable mode instead. Wherever this README
|
|
138
|
+
says `pip install "ragkit-dev[...]"`, use `pip install -e ".[...]"` from the
|
|
139
|
+
checkout:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/shamiulriyad/rag-learning.git
|
|
143
|
+
cd rag-learning
|
|
144
|
+
pip install -e ".[local,gemini]"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Choose extras for what you need:
|
|
148
|
+
|
|
149
|
+
| Extra | Adds | Needed for |
|
|
150
|
+
| ----- | ---- | ---------- |
|
|
151
|
+
| *(none)* | LangChain core, Qdrant, PyMuPDF | ingestion/retrieval plumbing, `rag-kit check` |
|
|
152
|
+
| `local` | sentence-transformers (pulls in PyTorch) | `EMBEDDING_PROVIDER=huggingface` (default) |
|
|
153
|
+
| `gemini` | langchain-google-genai | answers, and `EMBEDDING_PROVIDER=google` |
|
|
154
|
+
| `api` | FastAPI, uvicorn | `rag-kit serve` |
|
|
155
|
+
| `ui` | Streamlit | `rag-kit ui` |
|
|
156
|
+
| `dev` | pytest, httpx, ruff (+ `api`) | running the tests |
|
|
157
|
+
| `all` | `local`, `gemini`, `api`, `ui` | everything |
|
|
158
|
+
|
|
159
|
+
**Linux and CPU-only PyTorch (recommended):** on Linux, PyTorch from PyPI
|
|
160
|
+
pulls in CUDA libraries (several GB). For CPU-only local embeddings, install
|
|
161
|
+
the CPU build from PyTorch's own index **first**, in the same virtual
|
|
162
|
+
environment, then rag-kit:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
166
|
+
pip install "ragkit-dev[local,gemini]" # keeps the CPU torch that is installed
|
|
167
|
+
|
|
168
|
+
# with uv instead of pip:
|
|
169
|
+
uv pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
170
|
+
uv pip install "ragkit-dev[local,gemini]"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
From a checkout, the second command is `pip install -e ".[local,gemini]"`
|
|
174
|
+
(`uv pip install -e ".[local,gemini]"`).
|
|
175
|
+
|
|
176
|
+
This works on x86_64 and aarch64 Linux with Python 3.11 and 3.12. Later
|
|
177
|
+
`pip install -U "ragkit-dev[local]"` keeps the CPU build as long as it satisfies
|
|
178
|
+
the requirement; upgrading torch itself (`pip install -U torch`) without the
|
|
179
|
+
`--index-url` above would switch to the CUDA build. If a CUDA build is already
|
|
180
|
+
installed, start from a fresh virtual environment: reinstalling torch over it
|
|
181
|
+
leaves the `nvidia-*` packages behind. With an NVIDIA GPU you want to use,
|
|
182
|
+
skip the first command.
|
|
183
|
+
|
|
184
|
+
On Windows and macOS, PyTorch from PyPI does not pull in CUDA libraries, so no
|
|
185
|
+
extra step is needed.
|
|
186
|
+
|
|
187
|
+
## Set up a project
|
|
188
|
+
|
|
189
|
+
A project is a folder with a `rag-kit.toml` marker file. It holds your `.env`,
|
|
190
|
+
your documents and the embedded Qdrant store; nothing is ever written inside
|
|
191
|
+
the installed package. This repository is itself a project.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
mkdir my-rag && cd my-rag
|
|
195
|
+
# create the marker (its contents are reserved; an empty file is fine)
|
|
196
|
+
echo "# rag-kit project" > rag-kit.toml
|
|
197
|
+
# copy .env.example from this repository to my-rag/.env, then set GOOGLE_API_KEY
|
|
198
|
+
rag-kit check # settings, dependencies, vector store
|
|
199
|
+
rag-kit check --deep # also loads the embedding model, compares dimensions
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Commands find the project like this:
|
|
203
|
+
|
|
204
|
+
1. `--project DIR` (any command; no marker needed),
|
|
205
|
+
2. else the `RAG_PROJECT_DIR` environment variable,
|
|
206
|
+
3. else the nearest folder at or above the current directory that contains
|
|
207
|
+
`rag-kit.toml`.
|
|
208
|
+
|
|
209
|
+
If none applies, the command stops with an error instead of creating a store
|
|
210
|
+
somewhere unexpected. Relative paths in `.env` (`QDRANT_PATH`, `PDF_PATH`) are
|
|
211
|
+
resolved from the project folder, so commands behave the same from any
|
|
212
|
+
subfolder.
|
|
213
|
+
|
|
214
|
+
## Configure
|
|
215
|
+
|
|
216
|
+
Settings come from the project's `.env` (or the file named by `RAG_ENV_FILE`).
|
|
217
|
+
Environment variables win over `.env`, and command-line flags such as
|
|
218
|
+
`--collection`, `-k` and `--min-score` win over both.
|
|
219
|
+
|
|
220
|
+
| Variable | Default | Purpose |
|
|
221
|
+
| -------- | ------- | ------- |
|
|
222
|
+
| `GOOGLE_API_KEY` | – | Gemini key (generation; embeddings if provider is `google`) |
|
|
223
|
+
| `LLM_MODEL` | `gemini-2.5-flash` | Gemini model for answers |
|
|
224
|
+
| `TEMPERATURE` | `0.2` | LLM temperature |
|
|
225
|
+
| `EMBEDDING_PROVIDER` | `huggingface` | `huggingface` (local) or `google` |
|
|
226
|
+
| `EMBEDDING_MODEL` | `BAAI/bge-m3` | 1024-dim; `models/gemini-embedding-001` for `google` |
|
|
227
|
+
| `EMBEDDING_DIM` | auto | set only to skip auto-detection |
|
|
228
|
+
| `QDRANT_PATH` | – | embedded store folder, e.g. `qdrant_data` (wins over URL) |
|
|
229
|
+
| `QDRANT_URL` / `QDRANT_API_KEY` | `http://localhost:6333` | Qdrant server |
|
|
230
|
+
| `COLLECTION_NAME` | `pdf_rag` | collection to read and write |
|
|
231
|
+
| `PDF_PATH` | `data/sample.pdf` | file for `ingest` with no arguments |
|
|
232
|
+
| `PDF_FONT_REPAIR` | `false` | repair scrambled-glyph PDFs (see below) |
|
|
233
|
+
| `CHUNK_SIZE` / `CHUNK_OVERLAP` | `1000` / `150` | chunking |
|
|
234
|
+
| `TOP_K` | `4` | chunks per question |
|
|
235
|
+
| `MIN_SCORE` | – | drop chunks below this cosine score |
|
|
236
|
+
| `EMBED_BATCH_SIZE` / `EMBED_SLEEP` | `90` / `0` (`60` for google) | ingestion batching |
|
|
237
|
+
| `RAG_PROJECT_DIR` | – | project folder (environment only) |
|
|
238
|
+
| `RAG_ENV_FILE` | `<project>/.env` | use another settings file (environment only) |
|
|
239
|
+
| `RAG_EXPORT_ENV` | – | extra `.env` names to export, comma-separated (see below) |
|
|
240
|
+
|
|
241
|
+
Without `QDRANT_PATH`, rag-kit connects to a Qdrant server at `QDRANT_URL`.
|
|
242
|
+
A collection is tied to the embedding model that built it. If the model's
|
|
243
|
+
dimension does not match the collection, every command stops with an error
|
|
244
|
+
instead of writing incompatible vectors.
|
|
245
|
+
|
|
246
|
+
### Variables for other libraries (`HF_HOME`, proxies)
|
|
247
|
+
|
|
248
|
+
Some libraries read only the process environment: Hugging Face reads `HF_HOME`
|
|
249
|
+
when it is first imported, and HTTP clients read proxy variables. So that
|
|
250
|
+
these can live in `.env` too, the `rag-kit` command, `rag-kit serve` (the
|
|
251
|
+
default `rag_kit.api:app`) and `rag-kit ui` copy an **allow-list** of `.env`
|
|
252
|
+
keys into the environment at startup:
|
|
253
|
+
|
|
254
|
+
- `HF_*`, `HUGGINGFACE_*`, `TRANSFORMERS_*`, `SENTENCE_TRANSFORMERS_*`, `TORCH_*`,
|
|
255
|
+
`TOKENIZERS_PARALLELISM`, `CUDA_VISIBLE_DEVICES`, `OMP_NUM_THREADS`
|
|
256
|
+
- `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, `ALL_PROXY` (either case),
|
|
257
|
+
`REQUESTS_CA_BUNDLE`, `SSL_CERT_FILE`, `SSL_CERT_DIR`, `CURL_CA_BUNDLE`
|
|
258
|
+
- any names you list in `RAG_EXPORT_ENV=NAME1,NAME2`
|
|
259
|
+
|
|
260
|
+
rag-kit's own settings, including `GOOGLE_API_KEY` and `QDRANT_API_KEY`, and
|
|
261
|
+
any `RAG_*` variable are **never** exported, even if listed. Variables already
|
|
262
|
+
set in the environment win, empty values are skipped, and only names are ever
|
|
263
|
+
printed (`rag-kit check` lists them). `HF_TOKEN` is a secret but is exported,
|
|
264
|
+
because Hugging Face reads it only from the environment.
|
|
265
|
+
|
|
266
|
+
Importing `rag_kit`, building a `Pipeline` or calling `Settings.load()` never
|
|
267
|
+
changes the environment. In your own program, call
|
|
268
|
+
`rag_kit.env.export_env_file(settings)` before the first local embedding is
|
|
269
|
+
created if you want the same behaviour.
|
|
270
|
+
|
|
271
|
+
## Ingest documents
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
rag-kit ingest data/book.pdf notes.md # several files at once
|
|
275
|
+
rag-kit ingest # PDF_PATH from .env
|
|
276
|
+
rag-kit ingest report.pdf --collection experiments
|
|
277
|
+
rag-kit ingest scanned-font.pdf --font-repair on
|
|
278
|
+
rag-kit ingest --project ~/my-rag report.pdf
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
- **Re-ingesting replaces.** Chunks get IDs derived from file name, content
|
|
282
|
+
hash and position. Ingesting a file again overwrites its chunks and removes
|
|
283
|
+
any older ones with the same file name, so nothing is duplicated. Two
|
|
284
|
+
different files with the same name in one collection count as one document.
|
|
285
|
+
- **Delete one document:** `rag-kit delete report.pdf` (asks first; `-y` to skip).
|
|
286
|
+
- **List documents:** `rag-kit documents`, or `--json` for
|
|
287
|
+
`{"collection": str, "total_chunks": int, "documents": [{"file": str, "chunks": int}]}`
|
|
288
|
+
(stable schema; files sorted by name).
|
|
289
|
+
- **Start over:** `rag-kit ingest file.pdf --recreate` drops the whole
|
|
290
|
+
collection first. Needed after changing the embedding model.
|
|
291
|
+
- **File names starting with `-`** look like options to the CLI. Write
|
|
292
|
+
`./-name.pdf`, or put `--` before the files:
|
|
293
|
+
`rag-kit ingest --font-repair on -- -Free-English-Grammar.pdf`.
|
|
294
|
+
|
|
295
|
+
## Ask questions
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
rag-kit ask "What is a countable noun?"
|
|
299
|
+
rag-kit ask # interactive, 'exit' to quit
|
|
300
|
+
rag-kit ask "..." --show-chunks # also print each chunk in full
|
|
301
|
+
rag-kit ask "..." --json # machine-readable
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The answer is printed with its `[S1]`… markers followed by the sources, each
|
|
305
|
+
with file, page (PDFs only) and similarity score. If nothing is retrieved (or
|
|
306
|
+
nothing passes `--min-score`), the LLM is not called and the status is
|
|
307
|
+
`no_results`.
|
|
308
|
+
|
|
309
|
+
## Inspect retrieval
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
rag-kit search "What is a countable noun?" -k 8 # no LLM call
|
|
313
|
+
rag-kit search "..." --full # whole chunk text
|
|
314
|
+
rag-kit search "..." --json # scores + metadata
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Each hit shows score, file, page, `chunk_id` and `doc_id`. With `--json`, step
|
|
318
|
+
progress goes to stderr and stdout holds only the JSON.
|
|
319
|
+
|
|
320
|
+
## Optional FastAPI service
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
pip install "ragkit-dev[api]" # from a checkout: pip install -e ".[api]"
|
|
324
|
+
rag-kit serve --port 8000 # or: uvicorn rag_kit.api:app --port 8000
|
|
325
|
+
rag-kit serve --collection experiments
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`--collection` (also on `ui`) applies to that server process only; without it
|
|
329
|
+
the server uses `COLLECTION_NAME`. The command prints which collection it uses,
|
|
330
|
+
passes the project to the server in `RAG_PROJECT_DIR`, and never modifies
|
|
331
|
+
`.env`. When you start uvicorn yourself, run it inside the project or set
|
|
332
|
+
`RAG_PROJECT_DIR`.
|
|
333
|
+
|
|
334
|
+
- `GET /health` → `{"status": "ok", "ready": true}`
|
|
335
|
+
- `POST /query` with `{"question": "...", "top_k": 4}` →
|
|
336
|
+
`{"answer": "...", "status": "answered" | "no_results", "sources": [{"page", "source", "score", "marker", "chunk_id", "text"}]}`
|
|
337
|
+
|
|
338
|
+
`answer` has the markers stripped; `marker` on each source maps them back.
|
|
339
|
+
Pipeline failures (including a missing project) return 503 with the reason.
|
|
340
|
+
Questions longer than 4000 characters are rejected with 422.
|
|
341
|
+
|
|
342
|
+
The service has no authentication and binds to `127.0.0.1` by default; do not
|
|
343
|
+
expose it publicly. To embed it elsewhere, build your own instance with
|
|
344
|
+
`rag_kit.api.create_app(settings=..., pipeline=...)`.
|
|
345
|
+
|
|
346
|
+
## Optional Streamlit test UI
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
pip install "ragkit-dev[ui]" # from a checkout: pip install -e ".[ui]"
|
|
350
|
+
rag-kit ui # http://localhost:8501
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Upload and ingest documents, ask questions or run retrieval only, and inspect
|
|
354
|
+
scores, pages, chunk text and metadata. Uploads are saved under the project's
|
|
355
|
+
`uploads/` folder (git-ignored here). It is a testing tool, not a production
|
|
356
|
+
front end.
|
|
357
|
+
|
|
358
|
+
## Use from Python
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
from rag_kit import Pipeline, Settings
|
|
362
|
+
|
|
363
|
+
settings = Settings.load("path/to/project") # reads path/to/project/.env
|
|
364
|
+
pipeline = Pipeline(settings=settings)
|
|
365
|
+
pipeline.ingest("data/book.pdf")
|
|
366
|
+
result = pipeline.ask("What is a noun?")
|
|
367
|
+
print(result.status, result.answer_without_markers)
|
|
368
|
+
for source in result.sources:
|
|
369
|
+
print(source["marker"], source["file"], source["page"], source["score"])
|
|
370
|
+
pipeline.close()
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
`Settings.load()` without a folder finds the project the same way the CLI
|
|
374
|
+
does. Override values with `settings.replace(top_k=8)`. `Settings.load` does
|
|
375
|
+
not change `os.environ`, and API keys are left out of its `repr`.
|
|
376
|
+
|
|
377
|
+
The pipeline reports progress through the `rag_kit` logger and prints nothing
|
|
378
|
+
on its own; call `rag_kit.log.show_progress()` (as the CLI does) or configure
|
|
379
|
+
`logging` yourself to see it.
|
|
380
|
+
|
|
381
|
+
## Supported inputs and providers
|
|
382
|
+
|
|
383
|
+
- **Files:** `.pdf` (text layer required), `.txt` and `.md` (UTF-8).
|
|
384
|
+
- **Embeddings:** any sentence-transformers model through Hugging Face, or
|
|
385
|
+
Gemini embeddings.
|
|
386
|
+
- **LLM:** Gemini via `langchain-google-genai`.
|
|
387
|
+
- **Vector store:** Qdrant, embedded (`QDRANT_PATH`) or server (`QDRANT_URL`).
|
|
388
|
+
|
|
389
|
+
### PDF font repair
|
|
390
|
+
|
|
391
|
+
Some PDFs embed subset fonts without a `ToUnicode` map, and every extractor
|
|
392
|
+
returns scrambled glyphs (`& ? ! & &`).
|
|
393
|
+
[`pdf_font_repair.py`](https://github.com/shamiulriyad/rag-learning/blob/main/src/rag_kit/pdf_font_repair.py) reverses that
|
|
394
|
+
substitution for the `-Free-English-Grammar.pdf` kept in this repository (it
|
|
395
|
+
is not part of any package). It is off by default; enable it with
|
|
396
|
+
`PDF_FONT_REPAIR=true` or `--font-repair on`. Its maps are specific to that
|
|
397
|
+
PDF; for other broken PDFs, use OCR instead.
|
|
398
|
+
|
|
399
|
+
## Tests
|
|
400
|
+
|
|
401
|
+
The tests live in the repository, so run them from a checkout:
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
pip install -e ".[dev,gemini]"
|
|
405
|
+
python -m pytest # unit tests: no network, no model download, no API calls
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
The unit tests never read your `.env` or touch your Qdrant store. Integration
|
|
409
|
+
tests are opt-in. They run `rag-kit` against this checkout's real `.env` and
|
|
410
|
+
need the `local` extra:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# PowerShell: $env:RAG_RUN_INTEGRATION = "1"
|
|
414
|
+
RAG_RUN_INTEGRATION=1 python -m pytest -m integration
|
|
415
|
+
RAG_RUN_INTEGRATION=1 RAG_RUN_GEMINI=1 python -m pytest -m "integration or gemini" # uses Gemini quota
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
They read `COLLECTION_NAME` without changing it, and ingest only into a
|
|
419
|
+
uniquely named collection inside a temporary Qdrant folder. Stop `serve` and
|
|
420
|
+
`ui` first.
|
|
421
|
+
|
|
422
|
+
## Troubleshooting
|
|
423
|
+
|
|
424
|
+
| Message | Fix |
|
|
425
|
+
| ------- | --- |
|
|
426
|
+
| `No rag-kit project found` | Run inside a folder with `rag-kit.toml`, pass `--project DIR`, or set `RAG_PROJECT_DIR`. |
|
|
427
|
+
| `[warn] .env not created yet` (from `rag-kit check`) | Copy the template: `cp .env.example .env` (PowerShell: `Copy-Item .env.example .env`), then set `GOOGLE_API_KEY`. Without `.env`, rag-kit looks for a Qdrant server instead of a local store. |
|
|
428
|
+
| `No local Qdrant store at …` | Ingest something first, or point `QDRANT_PATH` at the existing store. |
|
|
429
|
+
| `… is in use by another process` | Embedded Qdrant allows one process. Stop `serve`/`ui`/other commands, or use a Qdrant server. |
|
|
430
|
+
| `Collection 'x' holds N-dimensional vectors, but … produces M` | The embedding model changed. Restore `EMBEDDING_MODEL`, use another `COLLECTION_NAME`, or `--recreate`. |
|
|
431
|
+
| `GOOGLE_API_KEY is not set` | Put the key in the project's `.env`. |
|
|
432
|
+
| `… is not installed. Run: pip install "ragkit-dev[…]"` | Install the extra named in the message. |
|
|
433
|
+
| `… could not answer … 429` | Gemini rate limit or quota. Wait, or raise `EMBED_SLEEP` when using Gemini embeddings. |
|
|
434
|
+
| `… page(s) look corrupted` | Scrambled text: try `--font-repair on`; scanned PDF: run OCR (e.g. `ocrmypdf`). |
|
|
435
|
+
| `Unsupported file type` | Convert to PDF, `.txt` or `.md`. |
|
|
436
|
+
|
|
437
|
+
## Known limitations
|
|
438
|
+
|
|
439
|
+
- Embedded Qdrant is single-process: run one of CLI / API / UI at a time.
|
|
440
|
+
- No OCR: scanned PDFs need to be OCR'd first.
|
|
441
|
+
- Documents are identified by file name within a collection.
|
|
442
|
+
- Only Gemini is wired up for generation.
|
|
443
|
+
- Chunks indexed before the metadata migration lack `doc_id` and `file_type`;
|
|
444
|
+
re-ingest the file to add them.
|
|
445
|
+
|
|
446
|
+
## License
|
|
447
|
+
|
|
448
|
+
[MIT](https://github.com/shamiulriyad/rag-learning/blob/main/LICENSE)
|