ragdoc 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.
Files changed (68) hide show
  1. ragdoc-0.1.0/LICENSE +21 -0
  2. ragdoc-0.1.0/PKG-INFO +191 -0
  3. ragdoc-0.1.0/README.md +163 -0
  4. ragdoc-0.1.0/pyproject.toml +42 -0
  5. ragdoc-0.1.0/setup.cfg +4 -0
  6. ragdoc-0.1.0/src/ragdoc/__init__.py +33 -0
  7. ragdoc-0.1.0/src/ragdoc/artifacts.py +256 -0
  8. ragdoc-0.1.0/src/ragdoc/attribution/__init__.py +40 -0
  9. ragdoc-0.1.0/src/ragdoc/attribution/checks.py +420 -0
  10. ragdoc-0.1.0/src/ragdoc/attribution/engine.py +269 -0
  11. ragdoc-0.1.0/src/ragdoc/attribution/verdict.py +338 -0
  12. ragdoc-0.1.0/src/ragdoc/batch/__init__.py +245 -0
  13. ragdoc-0.1.0/src/ragdoc/chunker/__init__.py +248 -0
  14. ragdoc-0.1.0/src/ragdoc/cli.py +397 -0
  15. ragdoc-0.1.0/src/ragdoc/compare/__init__.py +140 -0
  16. ragdoc-0.1.0/src/ragdoc/config.py +54 -0
  17. ragdoc-0.1.0/src/ragdoc/indexer/__init__.py +130 -0
  18. ragdoc-0.1.0/src/ragdoc/indexer/local_embeddings.py +199 -0
  19. ragdoc-0.1.0/src/ragdoc/loader/__init__.py +95 -0
  20. ragdoc-0.1.0/src/ragdoc/loader/pdfplumber_loader.py +70 -0
  21. ragdoc-0.1.0/src/ragdoc/loader/pymupdf_loader.py +84 -0
  22. ragdoc-0.1.0/src/ragdoc/loader/pypdf_loader.py +66 -0
  23. ragdoc-0.1.0/src/ragdoc/loader/registry.py +73 -0
  24. ragdoc-0.1.0/src/ragdoc/report/__init__.py +186 -0
  25. ragdoc-0.1.0/src/ragdoc/report/_table.py +45 -0
  26. ragdoc-0.1.0/src/ragdoc/report/batch.py +170 -0
  27. ragdoc-0.1.0/src/ragdoc/report/compare.py +111 -0
  28. ragdoc-0.1.0/src/ragdoc/report/retrieved.py +101 -0
  29. ragdoc-0.1.0/src/ragdoc/report/sweep.py +155 -0
  30. ragdoc-0.1.0/src/ragdoc/report/symbols.py +76 -0
  31. ragdoc-0.1.0/src/ragdoc/retriever/__init__.py +145 -0
  32. ragdoc-0.1.0/src/ragdoc/sweep/__init__.py +151 -0
  33. ragdoc-0.1.0/src/ragdoc.egg-info/PKG-INFO +191 -0
  34. ragdoc-0.1.0/src/ragdoc.egg-info/SOURCES.txt +66 -0
  35. ragdoc-0.1.0/src/ragdoc.egg-info/dependency_links.txt +1 -0
  36. ragdoc-0.1.0/src/ragdoc.egg-info/entry_points.txt +2 -0
  37. ragdoc-0.1.0/src/ragdoc.egg-info/requires.txt +5 -0
  38. ragdoc-0.1.0/src/ragdoc.egg-info/top_level.txt +1 -0
  39. ragdoc-0.1.0/tests/test_ascii_rendering.py +134 -0
  40. ragdoc-0.1.0/tests/test_attribution_fixtures.py +91 -0
  41. ragdoc-0.1.0/tests/test_batch.py +319 -0
  42. ragdoc-0.1.0/tests/test_batch_input.py +35 -0
  43. ragdoc-0.1.0/tests/test_batch_runner.py +84 -0
  44. ragdoc-0.1.0/tests/test_checks.py +203 -0
  45. ragdoc-0.1.0/tests/test_cli_batch.py +101 -0
  46. ragdoc-0.1.0/tests/test_cli_input.py +237 -0
  47. ragdoc-0.1.0/tests/test_cli_loader.py +162 -0
  48. ragdoc-0.1.0/tests/test_cli_show_retrieved.py +103 -0
  49. ragdoc-0.1.0/tests/test_cli_sweep.py +158 -0
  50. ragdoc-0.1.0/tests/test_cli_verbose.py +74 -0
  51. ragdoc-0.1.0/tests/test_compare.py +268 -0
  52. ragdoc-0.1.0/tests/test_config.py +59 -0
  53. ragdoc-0.1.0/tests/test_empty_pages.py +47 -0
  54. ragdoc-0.1.0/tests/test_indexer_errors.py +74 -0
  55. ragdoc-0.1.0/tests/test_indexer_quiet.py +130 -0
  56. ragdoc-0.1.0/tests/test_loader_errors.py +117 -0
  57. ragdoc-0.1.0/tests/test_loader_registry.py +57 -0
  58. ragdoc-0.1.0/tests/test_loaders.py +65 -0
  59. ragdoc-0.1.0/tests/test_pdfplumber_loader.py +47 -0
  60. ragdoc-0.1.0/tests/test_pypdf_loader.py +50 -0
  61. ragdoc-0.1.0/tests/test_report.py +157 -0
  62. ragdoc-0.1.0/tests/test_report_batch.py +97 -0
  63. ragdoc-0.1.0/tests/test_report_compare.py +130 -0
  64. ragdoc-0.1.0/tests/test_report_retrieved.py +85 -0
  65. ragdoc-0.1.0/tests/test_report_sweep.py +133 -0
  66. ragdoc-0.1.0/tests/test_sweep.py +101 -0
  67. ragdoc-0.1.0/tests/test_symbols.py +76 -0
  68. ragdoc-0.1.0/tests/test_table.py +46 -0
ragdoc-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmed Imran
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.
ragdoc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,191 @@
1
+ Metadata-Version: 2.4
2
+ Name: ragdoc
3
+ Version: 0.1.0
4
+ Summary: Headless diagnostic for PDF RAG pipelines: attributes a lost answer to the pipeline stage that lost it.
5
+ Author: Ahmed Imran
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://ahmedimran.dev
8
+ Project-URL: Source, https://github.com/Sheikh-Ahmed-Imran/rag-doc
9
+ Project-URL: Issues, https://github.com/Sheikh-Ahmed-Imran/rag-doc/issues
10
+ Keywords: rag,pdf,retrieval-augmented-generation,embeddings,llm,diagnostics,attribution
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Text Processing :: General
19
+ Requires-Python: <3.13,>=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: PyMuPDF>=1.24
23
+ Requires-Dist: pdfplumber>=0.10
24
+ Requires-Dist: pypdf>=6.21.2
25
+ Requires-Dist: sentence-transformers>=2.2
26
+ Requires-Dist: numpy>=1.24
27
+ Dynamic: license-file
28
+
29
+ # ragdoc
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/ragdoc.svg)](https://pypi.org/project/ragdoc/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/ragdoc.svg)](https://pypi.org/project/ragdoc/)
33
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
34
+
35
+ **Find out which stage of your PDF RAG pipeline lost the answer.**
36
+
37
+ When a retrieval-augmented pipeline fails to answer a question you *know* the
38
+ document contains, the hard part is rarely the fix — it is working out **where** it
39
+ broke. A bad chunk size and a bad retriever look identical from the outside: in both
40
+ cases the answer just doesn't come back. `ragdoc` ends that guesswork. Give it a PDF,
41
+ a question, and the answer you know is in the document, and it tells you the single
42
+ stage that lost it — **extraction**, **chunking**, or **retrieval** — with the
43
+ evidence behind the verdict.
44
+
45
+ It is a headless, offline, deterministic CLI. No API keys, no LLM calls, no telemetry.
46
+
47
+ ## Project status
48
+
49
+ ragdoc is in **beta** (`0.x`). Its attribution engine and CLI are covered by an
50
+ extensive automated test suite — unit tests plus integration tests against fixture
51
+ PDFs that exercise each stage and every failure mode. What is still maturing is
52
+ *breadth*: validation across a wide range of real-world PDFs is ongoing, so on unusual
53
+ layouts or heavily structured documents a verdict may warrant a careful read. Treat the
54
+ output as strong, evidence-backed signal rather than an oracle, and expect the occasional
55
+ rough edge before `1.0`. Reports of PDFs it gets wrong are especially welcome.
56
+
57
+ ## How it works
58
+
59
+ `ragdoc` runs your document through the forward pipeline once, then runs a chain of
60
+ backward checks that each consume one stage's output:
61
+
62
+ ```
63
+ load → chunk → index → retrieve (the forward pipeline)
64
+ │ │ │ │
65
+ locate → survive ───────→ rank (the backward checks)
66
+ ```
67
+
68
+ - **locate** — is the expected answer actually in the extracted text? If not, the
69
+ loader lost it → **extraction**.
70
+ - **survive** — does the answer survive chunking intact inside one chunk, with the
71
+ section context it needs to be findable? If a boundary cut it, or its heading was
72
+ never embedded → **chunking**.
73
+ - **rank** — does the chunk holding the answer rank within `top_k`? If it ranks too
74
+ low → **retrieval**.
75
+
76
+ The chain stops at the first failing stage; every later stage is reported as *not
77
+ reached*, never as a false pass. The answer is supplied by you — nothing is inferred
78
+ from the model's own scores — so the verdict is grounded, not another guess.
79
+
80
+ ## Install
81
+
82
+ ```bash
83
+ pip install ragdoc
84
+ ```
85
+
86
+ Requires Python 3.12. The first run downloads a small local embedding model
87
+ (`all-MiniLM-L6-v2`); every run after that is fully offline.
88
+
89
+ ## Quick start
90
+
91
+ ```bash
92
+ ragdoc diagnose paper.pdf "What was the sample size?" "384 participants"
93
+ ```
94
+
95
+ ```text
96
+ extraction ✓
97
+ chunking ✗ section heading not embedded in chunk text
98
+ retrieval ✗ target chunk ranked 23 of 400; precision@5 = 0.00 (max 0.20); RR = 0.04
99
+ generation — not reached
100
+
101
+ VERDICT: chunking — the answer's chunk sits under a heading that is not embedded
102
+ FIX: prepend section path to chunk text before embedding
103
+
104
+ Run configuration:
105
+ loader: pymupdf
106
+ chunk size: 500
107
+ overlap: 50
108
+ embedding model: all-MiniLM-L6-v2
109
+ top_k: 5
110
+ prepend_section_context: False
111
+ ```
112
+
113
+ The answer can also be read from a file (handy for long or multi-line answers):
114
+
115
+ ```bash
116
+ ragdoc diagnose paper.pdf "What was the sample size?" --answer-file answer.txt
117
+ ```
118
+
119
+ Add `--verbose` for the full evidence behind each check, `--show-retrieved` to see the
120
+ retrieved chunks with the target marked, or `--ascii` for terminals that can't render
121
+ Unicode.
122
+
123
+ ## Commands
124
+
125
+ ### `diagnose` — one question, one verdict
126
+ ```bash
127
+ ragdoc diagnose paper.pdf "What was the sample size?" "384 participants"
128
+ ```
129
+
130
+ ### `compare` — how different loaders extract the same answer
131
+ Silent extraction failures are often a loader problem. `compare` runs every PDF loader
132
+ against the same answer so you can see which one actually preserves it.
133
+ ```bash
134
+ ragdoc compare paper.pdf "384 participants"
135
+ ```
136
+
137
+ ### `batch` — a failure distribution across a question set
138
+ One verdict tells you about one question; a *distribution* tells you where a pipeline
139
+ systematically breaks. Point `batch` at a JSON question set and it reports how the
140
+ failures split across the stages.
141
+ ```bash
142
+ ragdoc batch paper.pdf questions.json --json results.json
143
+ ```
144
+
145
+ The question set is a JSON array:
146
+ ```json
147
+ [
148
+ { "question": "What was the sample size?", "expected_answer": "384 participants" },
149
+ { "question": "Which model performed best?", "expected_answer": "the gradient-boosted ensemble" }
150
+ ]
151
+ ```
152
+
153
+ ### `sweep` — find the best configuration
154
+ Chunk size is a balance: too small splits answers apart (chunking failures), too big
155
+ dilutes them (retrieval failures). `sweep` runs the whole question set across a grid of
156
+ configurations and names the one that survives the most answers.
157
+ ```bash
158
+ ragdoc sweep paper.pdf questions.json --chunk-size 500,800,1200 --overlap 0,50
159
+ ```
160
+
161
+ It prints a table — one row per configuration, with the varied knobs, the no-failure
162
+ count, and the retrieval metrics — and highlights the winner. Use `--objective` to rank
163
+ by `no-failure` (default), `hit-rate`, or `mrr`.
164
+
165
+ ## Configuration
166
+
167
+ Every knob has a sensible default and can be overridden on `diagnose` and `batch` (and
168
+ swept as a comma-separated list on `sweep`):
169
+
170
+ | Flag | Meaning | Default |
171
+ |---|---|---|
172
+ | `--chunk-size` | characters per chunk | `500` |
173
+ | `--overlap` | characters shared between adjacent chunks | `50` |
174
+ | `--top-k` | retrieval cutoff the ranking is judged against | `10` |
175
+ | `--embedding-model` | sentence-transformers model name | `all-MiniLM-L6-v2` |
176
+ | `--prepend-section-context` / `--no-prepend-section-context` | prepend the section path to chunk text before embedding | off |
177
+ | `--loader` | PDF extraction backend (`pymupdf`, `pdfplumber`, `pypdf`) | `pymupdf` |
178
+
179
+ ## Known limitations
180
+
181
+ - **The answer must appear in the document text.** Matching is verbatim or normalized
182
+ (whitespace, case, and Unicode compatibility forms such as ligatures are forgiven) —
183
+ it does **not** handle paraphrase or reworded answers.
184
+ - **Scanned / image-only pages are not read.** Pages with no extractable text are
185
+ flagged in an advisory, but `ragdoc` does no OCR.
186
+ - **The generation stage is not evaluated** — it is always reported as *not reached*.
187
+ `ragdoc` diagnoses retrieval-and-earlier, where the failures it targets live.
188
+
189
+ ## License
190
+
191
+ [MIT](LICENSE) © 2026 Ahmed Imran
ragdoc-0.1.0/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # ragdoc
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/ragdoc.svg)](https://pypi.org/project/ragdoc/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/ragdoc.svg)](https://pypi.org/project/ragdoc/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ **Find out which stage of your PDF RAG pipeline lost the answer.**
8
+
9
+ When a retrieval-augmented pipeline fails to answer a question you *know* the
10
+ document contains, the hard part is rarely the fix — it is working out **where** it
11
+ broke. A bad chunk size and a bad retriever look identical from the outside: in both
12
+ cases the answer just doesn't come back. `ragdoc` ends that guesswork. Give it a PDF,
13
+ a question, and the answer you know is in the document, and it tells you the single
14
+ stage that lost it — **extraction**, **chunking**, or **retrieval** — with the
15
+ evidence behind the verdict.
16
+
17
+ It is a headless, offline, deterministic CLI. No API keys, no LLM calls, no telemetry.
18
+
19
+ ## Project status
20
+
21
+ ragdoc is in **beta** (`0.x`). Its attribution engine and CLI are covered by an
22
+ extensive automated test suite — unit tests plus integration tests against fixture
23
+ PDFs that exercise each stage and every failure mode. What is still maturing is
24
+ *breadth*: validation across a wide range of real-world PDFs is ongoing, so on unusual
25
+ layouts or heavily structured documents a verdict may warrant a careful read. Treat the
26
+ output as strong, evidence-backed signal rather than an oracle, and expect the occasional
27
+ rough edge before `1.0`. Reports of PDFs it gets wrong are especially welcome.
28
+
29
+ ## How it works
30
+
31
+ `ragdoc` runs your document through the forward pipeline once, then runs a chain of
32
+ backward checks that each consume one stage's output:
33
+
34
+ ```
35
+ load → chunk → index → retrieve (the forward pipeline)
36
+ │ │ │ │
37
+ locate → survive ───────→ rank (the backward checks)
38
+ ```
39
+
40
+ - **locate** — is the expected answer actually in the extracted text? If not, the
41
+ loader lost it → **extraction**.
42
+ - **survive** — does the answer survive chunking intact inside one chunk, with the
43
+ section context it needs to be findable? If a boundary cut it, or its heading was
44
+ never embedded → **chunking**.
45
+ - **rank** — does the chunk holding the answer rank within `top_k`? If it ranks too
46
+ low → **retrieval**.
47
+
48
+ The chain stops at the first failing stage; every later stage is reported as *not
49
+ reached*, never as a false pass. The answer is supplied by you — nothing is inferred
50
+ from the model's own scores — so the verdict is grounded, not another guess.
51
+
52
+ ## Install
53
+
54
+ ```bash
55
+ pip install ragdoc
56
+ ```
57
+
58
+ Requires Python 3.12. The first run downloads a small local embedding model
59
+ (`all-MiniLM-L6-v2`); every run after that is fully offline.
60
+
61
+ ## Quick start
62
+
63
+ ```bash
64
+ ragdoc diagnose paper.pdf "What was the sample size?" "384 participants"
65
+ ```
66
+
67
+ ```text
68
+ extraction ✓
69
+ chunking ✗ section heading not embedded in chunk text
70
+ retrieval ✗ target chunk ranked 23 of 400; precision@5 = 0.00 (max 0.20); RR = 0.04
71
+ generation — not reached
72
+
73
+ VERDICT: chunking — the answer's chunk sits under a heading that is not embedded
74
+ FIX: prepend section path to chunk text before embedding
75
+
76
+ Run configuration:
77
+ loader: pymupdf
78
+ chunk size: 500
79
+ overlap: 50
80
+ embedding model: all-MiniLM-L6-v2
81
+ top_k: 5
82
+ prepend_section_context: False
83
+ ```
84
+
85
+ The answer can also be read from a file (handy for long or multi-line answers):
86
+
87
+ ```bash
88
+ ragdoc diagnose paper.pdf "What was the sample size?" --answer-file answer.txt
89
+ ```
90
+
91
+ Add `--verbose` for the full evidence behind each check, `--show-retrieved` to see the
92
+ retrieved chunks with the target marked, or `--ascii` for terminals that can't render
93
+ Unicode.
94
+
95
+ ## Commands
96
+
97
+ ### `diagnose` — one question, one verdict
98
+ ```bash
99
+ ragdoc diagnose paper.pdf "What was the sample size?" "384 participants"
100
+ ```
101
+
102
+ ### `compare` — how different loaders extract the same answer
103
+ Silent extraction failures are often a loader problem. `compare` runs every PDF loader
104
+ against the same answer so you can see which one actually preserves it.
105
+ ```bash
106
+ ragdoc compare paper.pdf "384 participants"
107
+ ```
108
+
109
+ ### `batch` — a failure distribution across a question set
110
+ One verdict tells you about one question; a *distribution* tells you where a pipeline
111
+ systematically breaks. Point `batch` at a JSON question set and it reports how the
112
+ failures split across the stages.
113
+ ```bash
114
+ ragdoc batch paper.pdf questions.json --json results.json
115
+ ```
116
+
117
+ The question set is a JSON array:
118
+ ```json
119
+ [
120
+ { "question": "What was the sample size?", "expected_answer": "384 participants" },
121
+ { "question": "Which model performed best?", "expected_answer": "the gradient-boosted ensemble" }
122
+ ]
123
+ ```
124
+
125
+ ### `sweep` — find the best configuration
126
+ Chunk size is a balance: too small splits answers apart (chunking failures), too big
127
+ dilutes them (retrieval failures). `sweep` runs the whole question set across a grid of
128
+ configurations and names the one that survives the most answers.
129
+ ```bash
130
+ ragdoc sweep paper.pdf questions.json --chunk-size 500,800,1200 --overlap 0,50
131
+ ```
132
+
133
+ It prints a table — one row per configuration, with the varied knobs, the no-failure
134
+ count, and the retrieval metrics — and highlights the winner. Use `--objective` to rank
135
+ by `no-failure` (default), `hit-rate`, or `mrr`.
136
+
137
+ ## Configuration
138
+
139
+ Every knob has a sensible default and can be overridden on `diagnose` and `batch` (and
140
+ swept as a comma-separated list on `sweep`):
141
+
142
+ | Flag | Meaning | Default |
143
+ |---|---|---|
144
+ | `--chunk-size` | characters per chunk | `500` |
145
+ | `--overlap` | characters shared between adjacent chunks | `50` |
146
+ | `--top-k` | retrieval cutoff the ranking is judged against | `10` |
147
+ | `--embedding-model` | sentence-transformers model name | `all-MiniLM-L6-v2` |
148
+ | `--prepend-section-context` / `--no-prepend-section-context` | prepend the section path to chunk text before embedding | off |
149
+ | `--loader` | PDF extraction backend (`pymupdf`, `pdfplumber`, `pypdf`) | `pymupdf` |
150
+
151
+ ## Known limitations
152
+
153
+ - **The answer must appear in the document text.** Matching is verbatim or normalized
154
+ (whitespace, case, and Unicode compatibility forms such as ligatures are forgiven) —
155
+ it does **not** handle paraphrase or reworded answers.
156
+ - **Scanned / image-only pages are not read.** Pages with no extractable text are
157
+ flagged in an advisory, but `ragdoc` does no OCR.
158
+ - **The generation stage is not evaluated** — it is always reported as *not reached*.
159
+ `ragdoc` diagnoses retrieval-and-earlier, where the failures it targets live.
160
+
161
+ ## License
162
+
163
+ [MIT](LICENSE) © 2026 Ahmed Imran
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ragdoc"
7
+ version = "0.1.0"
8
+ description = "Headless diagnostic for PDF RAG pipelines: attributes a lost answer to the pipeline stage that lost it."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "Ahmed Imran" }]
13
+ # Pinned to 3.12: the embedding stack (sentence-transformers / torch) does not
14
+ # reliably install on 3.14.
15
+ requires-python = ">=3.12,<3.13"
16
+ # PyMuPDF / pdfplumber / pypdf extract the PDF. sentence-transformers runs the
17
+ # embedding model locally, downloading it only on first use (offline thereafter);
18
+ # numpy backs the retriever's brute-force cosine scoring. The embedding stack is
19
+ # imported lazily, so the heavy import stays confined to the indexer.
20
+ dependencies = ["PyMuPDF>=1.24", "pdfplumber>=0.10", "pypdf>=6.21.2", "sentence-transformers>=2.2", "numpy>=1.24"]
21
+ keywords = ["rag", "pdf", "retrieval-augmented-generation", "embeddings", "llm", "diagnostics", "attribution"]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Environment :: Console",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
30
+ "Topic :: Text Processing :: General",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://ahmedimran.dev"
35
+ Source = "https://github.com/Sheikh-Ahmed-Imran/rag-doc"
36
+ Issues = "https://github.com/Sheikh-Ahmed-Imran/rag-doc/issues"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [project.scripts]
42
+ ragdoc = "ragdoc.cli:main"
ragdoc-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,33 @@
1
+ """ragdoc — headless attribution engine for PDF RAG pipelines.
2
+
3
+ This top level re-exports the run configuration and the artifact/result types
4
+ that form the shared vocabulary of the pipeline and the attribution engine, so
5
+ callers can ``from ragdoc import RunConfig, ExtractedDoc, Chunk, Ranking,
6
+ CheckResult`` without reaching into submodules.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from ragdoc.artifacts import (
12
+ CharSpan,
13
+ Chunk,
14
+ CheckResult,
15
+ CheckStatus,
16
+ ExtractedDoc,
17
+ PageSpan,
18
+ Ranking,
19
+ RankedChunk,
20
+ )
21
+ from ragdoc.config import RunConfig
22
+
23
+ __all__ = [
24
+ "RunConfig",
25
+ "CharSpan",
26
+ "PageSpan",
27
+ "ExtractedDoc",
28
+ "Chunk",
29
+ "RankedChunk",
30
+ "Ranking",
31
+ "CheckStatus",
32
+ "CheckResult",
33
+ ]