verbatim-core 0.1.9__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 (29) hide show
  1. verbatim_core-0.1.9/.gitignore +218 -0
  2. verbatim_core-0.1.9/PKG-INFO +84 -0
  3. verbatim_core-0.1.9/README.md +64 -0
  4. verbatim_core-0.1.9/pyproject.toml +40 -0
  5. verbatim_core-0.1.9/verbatim_core/__init__.py +24 -0
  6. verbatim_core-0.1.9/verbatim_core/cli.py +71 -0
  7. verbatim_core-0.1.9/verbatim_core/enhance.py +76 -0
  8. verbatim_core-0.1.9/verbatim_core/extractor_models/dataset.py +258 -0
  9. verbatim_core-0.1.9/verbatim_core/extractor_models/model.py +151 -0
  10. verbatim_core-0.1.9/verbatim_core/extractor_models/preprocess_ragbench.py +116 -0
  11. verbatim_core-0.1.9/verbatim_core/extractor_models/train.py +287 -0
  12. verbatim_core-0.1.9/verbatim_core/extractor_models/trainer.py +494 -0
  13. verbatim_core-0.1.9/verbatim_core/extractors.py +577 -0
  14. verbatim_core-0.1.9/verbatim_core/llm_client.py +439 -0
  15. verbatim_core-0.1.9/verbatim_core/models.py +65 -0
  16. verbatim_core-0.1.9/verbatim_core/providers.py +26 -0
  17. verbatim_core-0.1.9/verbatim_core/response_builder.py +182 -0
  18. verbatim_core-0.1.9/verbatim_core/templates/__init__.py +21 -0
  19. verbatim_core-0.1.9/verbatim_core/templates/base.py +91 -0
  20. verbatim_core-0.1.9/verbatim_core/templates/contextual.py +247 -0
  21. verbatim_core-0.1.9/verbatim_core/templates/filler.py +144 -0
  22. verbatim_core-0.1.9/verbatim_core/templates/manager.py +444 -0
  23. verbatim_core-0.1.9/verbatim_core/templates/question_specific.py +270 -0
  24. verbatim_core-0.1.9/verbatim_core/templates/random.py +244 -0
  25. verbatim_core-0.1.9/verbatim_core/templates/static.py +161 -0
  26. verbatim_core-0.1.9/verbatim_core/templates/structured.py +265 -0
  27. verbatim_core-0.1.9/verbatim_core/transform.py +161 -0
  28. verbatim_core-0.1.9/verbatim_core/types.py +7 -0
  29. verbatim_core-0.1.9/verbatim_core/universal_document.py +44 -0
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # PyPI configuration file
171
+ .pypirc
172
+
173
+ documents/
174
+ index/
175
+ templates.json
176
+ ui/
177
+ .ruff_cache/
178
+
179
+ data/
180
+ .qodo
181
+
182
+ # Frontend / Node.js
183
+ frontend/node_modules/
184
+ frontend/.env
185
+ frontend/.env.local
186
+ frontend/.env.development.local
187
+ frontend/.env.test.local
188
+ frontend/.env.production.local
189
+ frontend/build/
190
+ frontend/dist/
191
+ frontend/.next/
192
+ frontend/.nuxt/
193
+ frontend/.vite/
194
+ frontend/npm-debug.log*
195
+ frontend/yarn-debug.log*
196
+ frontend/yarn-error.log*
197
+ frontend/pnpm-debug.log*
198
+ frontend/lerna-debug.log*
199
+
200
+ # IDEs and editors
201
+ .vscode/
202
+ .idea/
203
+ *.swp
204
+ *.swo
205
+ *~
206
+
207
+ # OS generated files
208
+ .DS_Store
209
+ .DS_Store?
210
+ ._*
211
+ .Spotlight-V100
212
+ .Trashes
213
+ ehthumbs.db
214
+ Thumbs.db
215
+
216
+
217
+ mockup/
218
+ research-copilot/
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: verbatim-core
3
+ Version: 0.1.9
4
+ Summary: Lightweight verbatim span extraction -- the RAG-agnostic core of verbatim-rag
5
+ Project-URL: Homepage, https://github.com/krlabsorg/verbatim-rag
6
+ Project-URL: Bug Tracker, https://github.com/krlabsorg/verbatim-rag/issues
7
+ Author-email: Adam Kovacs <kovacs@krlabs.eu>
8
+ License: MIT
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: openai>=1.3.0
14
+ Requires-Dist: pydantic>=2.0.0
15
+ Provides-Extra: model
16
+ Requires-Dist: scikit-learn==1.6.1; extra == 'model'
17
+ Requires-Dist: torch>=2.6.0; extra == 'model'
18
+ Requires-Dist: transformers==4.53.3; extra == 'model'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # verbatim-core
22
+
23
+ Lightweight verbatim span extraction -- the RAG-agnostic core of [verbatim-rag](https://github.com/KRLabsOrg/verbatim-rag).
24
+
25
+ Extract exact, verbatim text spans from documents that answer a question. No vector databases, no embeddings, no heavy ML dependencies -- just `openai` and `pydantic`.
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install verbatim-core
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```python
36
+ from verbatim_core import VerbatimTransform
37
+
38
+ vt = VerbatimTransform()
39
+ response = vt.transform(
40
+ question="What is the main finding?",
41
+ context=[
42
+ {"content": "The study found that X leads to Y.", "title": "Paper A"},
43
+ {"content": "Results show Z is statistically significant.", "title": "Paper B"},
44
+ ],
45
+ )
46
+
47
+ print(response.answer)
48
+
49
+ # Access individual highlights and citations
50
+ for doc in response.documents:
51
+ for highlight in doc.highlights:
52
+ print(f" [{highlight.start}:{highlight.end}] {highlight.text}")
53
+ ```
54
+
55
+ ## What This Package Includes
56
+
57
+ - **VerbatimTransform** -- question + context -> cited, grounded answer
58
+ - **LLMSpanExtractor** -- extract verbatim spans using an LLM
59
+ - **LLMClient** -- unified OpenAI API wrapper (sync + async)
60
+ - **TemplateManager** -- response formatting with multiple template strategies
61
+ - **@verbatim_enhance** -- decorator to enhance existing RAG functions
62
+ - **CLI** (`verbatim-enhance`) -- batch processing from the command line
63
+
64
+ ## Model-Based Extraction
65
+
66
+ For ModernBERT or Zilliz semantic highlight extractors (adds torch, transformers):
67
+
68
+ ```bash
69
+ pip install verbatim-core[model]
70
+ ```
71
+
72
+ ## Environment
73
+
74
+ ```bash
75
+ export OPENAI_API_KEY=your_api_key_here
76
+ ```
77
+
78
+ ## Full RAG System
79
+
80
+ For the complete RAG pipeline with vector indexing, embeddings, and document processing, install the full package:
81
+
82
+ ```bash
83
+ pip install verbatim-rag
84
+ ```
@@ -0,0 +1,64 @@
1
+ # verbatim-core
2
+
3
+ Lightweight verbatim span extraction -- the RAG-agnostic core of [verbatim-rag](https://github.com/KRLabsOrg/verbatim-rag).
4
+
5
+ Extract exact, verbatim text spans from documents that answer a question. No vector databases, no embeddings, no heavy ML dependencies -- just `openai` and `pydantic`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install verbatim-core
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from verbatim_core import VerbatimTransform
17
+
18
+ vt = VerbatimTransform()
19
+ response = vt.transform(
20
+ question="What is the main finding?",
21
+ context=[
22
+ {"content": "The study found that X leads to Y.", "title": "Paper A"},
23
+ {"content": "Results show Z is statistically significant.", "title": "Paper B"},
24
+ ],
25
+ )
26
+
27
+ print(response.answer)
28
+
29
+ # Access individual highlights and citations
30
+ for doc in response.documents:
31
+ for highlight in doc.highlights:
32
+ print(f" [{highlight.start}:{highlight.end}] {highlight.text}")
33
+ ```
34
+
35
+ ## What This Package Includes
36
+
37
+ - **VerbatimTransform** -- question + context -> cited, grounded answer
38
+ - **LLMSpanExtractor** -- extract verbatim spans using an LLM
39
+ - **LLMClient** -- unified OpenAI API wrapper (sync + async)
40
+ - **TemplateManager** -- response formatting with multiple template strategies
41
+ - **@verbatim_enhance** -- decorator to enhance existing RAG functions
42
+ - **CLI** (`verbatim-enhance`) -- batch processing from the command line
43
+
44
+ ## Model-Based Extraction
45
+
46
+ For ModernBERT or Zilliz semantic highlight extractors (adds torch, transformers):
47
+
48
+ ```bash
49
+ pip install verbatim-core[model]
50
+ ```
51
+
52
+ ## Environment
53
+
54
+ ```bash
55
+ export OPENAI_API_KEY=your_api_key_here
56
+ ```
57
+
58
+ ## Full RAG System
59
+
60
+ For the complete RAG pipeline with vector indexing, embeddings, and document processing, install the full package:
61
+
62
+ ```bash
63
+ pip install verbatim-rag
64
+ ```
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "verbatim-core"
7
+ version = "0.1.9"
8
+ description = "Lightweight verbatim span extraction -- the RAG-agnostic core of verbatim-rag"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Adam Kovacs", email = "kovacs@krlabs.eu"},
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+ dependencies = [
21
+ "openai>=1.3.0",
22
+ "pydantic>=2.0.0",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ model = [
27
+ "torch>=2.6.0",
28
+ "transformers==4.53.3",
29
+ "scikit-learn==1.6.1",
30
+ ]
31
+
32
+ [project.urls]
33
+ "Homepage" = "https://github.com/krlabsorg/verbatim-rag"
34
+ "Bug Tracker" = "https://github.com/krlabsorg/verbatim-rag/issues"
35
+
36
+ [project.scripts]
37
+ verbatim-enhance = "verbatim_core.cli:main"
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["verbatim_core"]
@@ -0,0 +1,24 @@
1
+ """
2
+ Lightweight, RAG-agnostic core for verbatim transformation.
3
+
4
+ This subpackage provides:
5
+ - VerbatimTransform: question + context -> cited, grounded answer (sync/async)
6
+ - RAGProvider (interface): minimal retrieval contract (no index/Milvus deps)
7
+ - UniversalDocument: simple context container
8
+ - @verbatim_enhance decorator: drop-in enhancement for existing RAG fns
9
+ - CLI: `verbatim-enhance` for batch processing JSON(L)
10
+ """
11
+
12
+ from .enhance import verbatim_enhance
13
+ from .providers import RAGProvider
14
+ from .transform import VerbatimTransform, verbatim_query, verbatim_query_async
15
+ from .universal_document import UniversalDocument
16
+
17
+ __all__ = [
18
+ "VerbatimTransform",
19
+ "verbatim_query",
20
+ "verbatim_query_async",
21
+ "RAGProvider",
22
+ "UniversalDocument",
23
+ "verbatim_enhance",
24
+ ]
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from typing import Any, Dict, Iterable, List
7
+
8
+ from .transform import VerbatimTransform
9
+
10
+
11
+ def _iter_records(fp) -> Iterable[Dict[str, Any]]:
12
+ """Yield JSON objects from a file path or stdin. Supports JSONL or JSON array."""
13
+ try:
14
+ data = fp.read()
15
+ except Exception as e:
16
+ print(f"Error reading input: {e}", file=sys.stderr)
17
+ return
18
+ data = (data or "").strip()
19
+ if not data:
20
+ return
21
+ # Try JSONL first
22
+ if "\n" in data and not data.startswith("["):
23
+ for line in data.splitlines():
24
+ line = line.strip()
25
+ if not line:
26
+ continue
27
+ try:
28
+ yield json.loads(line)
29
+ except Exception as e:
30
+ print(f"Skipping malformed JSONL line: {e}", file=sys.stderr)
31
+ else:
32
+ try:
33
+ obj = json.loads(data)
34
+ except Exception as e:
35
+ print(f"Malformed JSON input: {e}", file=sys.stderr)
36
+ return
37
+ if isinstance(obj, list):
38
+ for item in obj:
39
+ yield item
40
+ else:
41
+ yield obj
42
+
43
+
44
+ def main(argv: List[str] | None = None) -> int:
45
+ p = argparse.ArgumentParser(description="Verbatim enhance JSON(L) records")
46
+ p.add_argument("--input", "-i", help="Input file (JSON or JSONL). Defaults to stdin.")
47
+ p.add_argument("--output", "-o", help="Output file (JSONL). Defaults to stdout.")
48
+ p.add_argument("--max-spans", type=int, default=5, help="Max display spans")
49
+ args = p.parse_args(argv)
50
+
51
+ fin = open(args.input, "r", encoding="utf-8") if args.input else sys.stdin
52
+ fout = open(args.output, "w", encoding="utf-8") if args.output else sys.stdout
53
+
54
+ vt = VerbatimTransform(max_display_spans=args.max_spans)
55
+
56
+ for rec in _iter_records(fin) or []:
57
+ question = rec.get("question") or ""
58
+ context = rec.get("context") or rec.get("sources") or []
59
+ answer = rec.get("answer")
60
+ resp = vt.transform(question=question, context=context, answer=answer)
61
+ fout.write(json.dumps(resp.model_dump()) + "\n")
62
+
63
+ if fin is not sys.stdin:
64
+ fin.close()
65
+ if fout is not sys.stdout:
66
+ fout.close()
67
+ return 0
68
+
69
+
70
+ if __name__ == "__main__":
71
+ raise SystemExit(main())
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import wraps
4
+ from typing import Any, Callable, Dict, Iterable, Mapping
5
+
6
+ from .transform import VerbatimTransform
7
+
8
+
9
+ def _to_context_dicts(obj: Any) -> list[dict]:
10
+ """Best-effort conversion of sources/context to context dicts."""
11
+ ctx: list[dict] = []
12
+ if obj is None:
13
+ return ctx
14
+ if isinstance(obj, Mapping):
15
+ # Single dict
16
+ data = dict(obj)
17
+ if "content" in data or "text" in data:
18
+ ctx.append(
19
+ {
20
+ "content": data.get("content") or data.get("text"),
21
+ "title": data.get("title", ""),
22
+ "source": data.get("source", ""),
23
+ "metadata": data.get("metadata") or {},
24
+ }
25
+ )
26
+ return ctx
27
+ if isinstance(obj, (list, tuple)):
28
+ for item in obj:
29
+ ctx.extend(_to_context_dicts(item))
30
+ return ctx
31
+ # Fallback: treat as raw text
32
+ if isinstance(obj, str) and obj.strip():
33
+ ctx.append({"content": obj})
34
+ return ctx
35
+
36
+
37
+ def verbatim_enhance(
38
+ max_display_spans: int = 5,
39
+ ) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
40
+ """Decorator to enhance existing RAG functions with verbatim transformation.
41
+
42
+ The wrapped function can return:
43
+ - dict with keys: 'question'?, 'answer'?, 'context' or 'sources'
44
+ - tuple: (answer, sources)
45
+ - or just 'sources' (context list/dict) if no answer
46
+ Currently, provided 'answer' is ignored; verbatim answer is derived from context.
47
+ """
48
+
49
+ def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
50
+ @wraps(fn)
51
+ def wrapper(*args, **kwargs):
52
+ result = fn(*args, **kwargs)
53
+ question = kwargs.get("question") or (args[0] if args else "")
54
+ answer = None
55
+ context: Iterable[Dict[str, Any]] = []
56
+
57
+ if isinstance(result, dict):
58
+ answer = result.get("answer")
59
+ context = result.get("context") or result.get("sources") or []
60
+ elif isinstance(result, (list, tuple)):
61
+ if len(result) == 2:
62
+ answer, context = result
63
+ else:
64
+ context = result
65
+ else:
66
+ context = result
67
+
68
+ context_dicts = _to_context_dicts(context)
69
+
70
+ vt = VerbatimTransform(max_display_spans=max_display_spans)
71
+ resp = vt.transform(question=question or "", context=context_dicts, answer=answer)
72
+ return resp
73
+
74
+ return wrapper
75
+
76
+ return decorator