pdf-reader-0jsfjf 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.
- pdf_reader_0jsfjf-0.1.0/.gitignore +202 -0
- pdf_reader_0jsfjf-0.1.0/PKG-INFO +67 -0
- pdf_reader_0jsfjf-0.1.0/README.md +45 -0
- pdf_reader_0jsfjf-0.1.0/pyproject.toml +77 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/__init__.py +45 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/core.py +150 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/index/__init__.py +370 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/index/page_store.py +191 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/index/tantivy_ext.py +142 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/ingest/__init__.py +979 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/ingest/clean.py +301 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/ingest/prompts.py +42 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/pdf/__init__.py +125 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/server/__init__.py +44 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/server/api.py +186 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/server/image.py +99 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/server/mcp.py +529 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/server/tools.py +321 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/service.py +254 -0
- pdf_reader_0jsfjf-0.1.0/src/pdf_reader/util.py +77 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# indexes
|
|
7
|
+
indexes/
|
|
8
|
+
|
|
9
|
+
# C extensions
|
|
10
|
+
*.so
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
MANIFEST
|
|
31
|
+
|
|
32
|
+
# PyInstaller
|
|
33
|
+
# Usually these files are written by a python script from a template
|
|
34
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
35
|
+
*.manifest
|
|
36
|
+
*.spec
|
|
37
|
+
|
|
38
|
+
# Installer logs
|
|
39
|
+
pip-log.txt
|
|
40
|
+
pip-delete-this-directory.txt
|
|
41
|
+
|
|
42
|
+
# Unit test / coverage reports
|
|
43
|
+
htmlcov/
|
|
44
|
+
.tox/
|
|
45
|
+
.nox/
|
|
46
|
+
.coverage
|
|
47
|
+
.coverage.*
|
|
48
|
+
.cache
|
|
49
|
+
nosetests.xml
|
|
50
|
+
coverage.xml
|
|
51
|
+
*.cover
|
|
52
|
+
*.py,cover
|
|
53
|
+
.hypothesis/
|
|
54
|
+
.pytest_cache/
|
|
55
|
+
cover/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Django stuff:
|
|
62
|
+
*.log
|
|
63
|
+
local_settings.py
|
|
64
|
+
db.sqlite3
|
|
65
|
+
db.sqlite3-journal
|
|
66
|
+
|
|
67
|
+
# Flask stuff:
|
|
68
|
+
instance/
|
|
69
|
+
.webassets-cache
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
.pybuilder/
|
|
79
|
+
target/
|
|
80
|
+
|
|
81
|
+
# Jupyter Notebook
|
|
82
|
+
.ipynb_checkpoints
|
|
83
|
+
|
|
84
|
+
# IPython
|
|
85
|
+
profile_default/
|
|
86
|
+
ipython_config.py
|
|
87
|
+
|
|
88
|
+
# pyenv
|
|
89
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
90
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
91
|
+
# .python-version
|
|
92
|
+
|
|
93
|
+
# pipenv
|
|
94
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
95
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
96
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
97
|
+
# install all needed dependencies.
|
|
98
|
+
#Pipfile.lock
|
|
99
|
+
|
|
100
|
+
# UV
|
|
101
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
102
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
103
|
+
# commonly ignored for libraries.
|
|
104
|
+
#uv.lock
|
|
105
|
+
|
|
106
|
+
# poetry
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
108
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
109
|
+
# commonly ignored for libraries.
|
|
110
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
111
|
+
#poetry.lock
|
|
112
|
+
|
|
113
|
+
# pdm
|
|
114
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
115
|
+
#pdm.lock
|
|
116
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
117
|
+
# in version control.
|
|
118
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
119
|
+
.pdm.toml
|
|
120
|
+
.pdm-python
|
|
121
|
+
.pdm-build/
|
|
122
|
+
|
|
123
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
124
|
+
__pypackages__/
|
|
125
|
+
|
|
126
|
+
# Celery stuff
|
|
127
|
+
celerybeat-schedule
|
|
128
|
+
celerybeat.pid
|
|
129
|
+
|
|
130
|
+
# SageMath parsed files
|
|
131
|
+
*.sage.py
|
|
132
|
+
|
|
133
|
+
# Environments
|
|
134
|
+
.env
|
|
135
|
+
.venv
|
|
136
|
+
env/
|
|
137
|
+
venv/
|
|
138
|
+
ENV/
|
|
139
|
+
env.bak/
|
|
140
|
+
venv.bak/
|
|
141
|
+
|
|
142
|
+
# Spyder project settings
|
|
143
|
+
.spyderproject
|
|
144
|
+
.spyproject
|
|
145
|
+
|
|
146
|
+
# Rope project settings
|
|
147
|
+
.ropeproject
|
|
148
|
+
|
|
149
|
+
# mkdocs documentation
|
|
150
|
+
/site
|
|
151
|
+
|
|
152
|
+
# mypy
|
|
153
|
+
.mypy_cache/
|
|
154
|
+
.dmypy.json
|
|
155
|
+
dmypy.json
|
|
156
|
+
|
|
157
|
+
# Pyre type checker
|
|
158
|
+
.pyre/
|
|
159
|
+
|
|
160
|
+
# pytype static type analyzer
|
|
161
|
+
.pytype/
|
|
162
|
+
|
|
163
|
+
# Cython debug symbols
|
|
164
|
+
cython_debug/
|
|
165
|
+
|
|
166
|
+
# PyCharm
|
|
167
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
168
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
169
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
170
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
171
|
+
#.idea/
|
|
172
|
+
|
|
173
|
+
# Abstra
|
|
174
|
+
# Abstra is an AI-powered process automation framework.
|
|
175
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
176
|
+
# Learn more at https://abstra.io/docs
|
|
177
|
+
.abstra/
|
|
178
|
+
|
|
179
|
+
# Visual Studio Code
|
|
180
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
181
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
182
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
183
|
+
# you could uncomment the following to ignore the enitre vscode folder
|
|
184
|
+
# .vscode/
|
|
185
|
+
|
|
186
|
+
# Ruff stuff:
|
|
187
|
+
.ruff_cache/
|
|
188
|
+
|
|
189
|
+
# PyPI configuration file
|
|
190
|
+
.pypirc
|
|
191
|
+
|
|
192
|
+
# Cursor
|
|
193
|
+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
|
194
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
195
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
196
|
+
.cursorignore
|
|
197
|
+
.cursorindexingignore
|
|
198
|
+
|
|
199
|
+
# Local-only data: real plan OCR output and logs (never commit)
|
|
200
|
+
.DS_Store
|
|
201
|
+
samples/
|
|
202
|
+
log_sample.json
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdf-reader-0jsfjf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PDF OCR, indexing and search tools for AI assistants
|
|
5
|
+
License: Proprietary
|
|
6
|
+
Classifier: License :: Other/Proprietary License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: aiohttp>=3.14.5
|
|
10
|
+
Requires-Dist: fastapi
|
|
11
|
+
Requires-Dist: fastmcp<4,>=3.4.11
|
|
12
|
+
Requires-Dist: lm-deluge
|
|
13
|
+
Requires-Dist: pdf2image
|
|
14
|
+
Requires-Dist: pillow>=13.0.0
|
|
15
|
+
Requires-Dist: pydantic
|
|
16
|
+
Requires-Dist: pypdf>=6.21.2
|
|
17
|
+
Requires-Dist: python-dotenv
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: tantivy
|
|
20
|
+
Requires-Dist: tesserocr
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# PDF Reader
|
|
24
|
+
|
|
25
|
+
A hybrid PDF indexing and search system designed for AI assistant integration via MCP (Model Context Protocol). Rather than dumping entire PDF content into context windows, this tool provides intelligent document processing, full-text search, and optimized image handling.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Hybrid Processing**: Local (tesserocr) and remote (Modal cloud) OCR processing
|
|
30
|
+
- **Smart Search**: Tantivy-based full-text search with BM25 ranking and query escaping
|
|
31
|
+
- **AI Enhancement**: LLM-generated document titles and page summaries
|
|
32
|
+
- **Provider Optimization**: Automatic image resizing for OpenAI/Anthropic API limits
|
|
33
|
+
- **MCP Integration**: RESTful API for seamless AI assistant integration
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Activate virtual environment
|
|
39
|
+
source .venv/bin/activate
|
|
40
|
+
|
|
41
|
+
# Example usage (if you have an existing index)
|
|
42
|
+
python -c "
|
|
43
|
+
from pdf_reader.index import PDFIndex
|
|
44
|
+
index = PDFIndex.load('indexes/index2')
|
|
45
|
+
results = index.search_pages(['your search term'])
|
|
46
|
+
print(f'Found {len(results)} results')
|
|
47
|
+
"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
The system uses a hybrid approach:
|
|
53
|
+
- **Tantivy**: Fast full-text search across OCR text and AI summaries
|
|
54
|
+
- **SQLite**: Blob storage for complete page data (text + images)
|
|
55
|
+
- **AI Enhancement**: Document titles and page summaries via LLM
|
|
56
|
+
- **Provider-Aware Images**: Optimized for different LLM API requirements
|
|
57
|
+
|
|
58
|
+
## MCP Tools
|
|
59
|
+
|
|
60
|
+
- `list_pdfs`: List available PDF documents
|
|
61
|
+
- `search_pdfs`: Keyword search across all documents
|
|
62
|
+
- `read_pdf`: Read specific pages from a document
|
|
63
|
+
- `read_pdfs`: Bulk read across multiple documents
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
See `CLAUDE.md` for detailed architecture documentation, development guidelines, and troubleshooting information.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# PDF Reader
|
|
2
|
+
|
|
3
|
+
A hybrid PDF indexing and search system designed for AI assistant integration via MCP (Model Context Protocol). Rather than dumping entire PDF content into context windows, this tool provides intelligent document processing, full-text search, and optimized image handling.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Hybrid Processing**: Local (tesserocr) and remote (Modal cloud) OCR processing
|
|
8
|
+
- **Smart Search**: Tantivy-based full-text search with BM25 ranking and query escaping
|
|
9
|
+
- **AI Enhancement**: LLM-generated document titles and page summaries
|
|
10
|
+
- **Provider Optimization**: Automatic image resizing for OpenAI/Anthropic API limits
|
|
11
|
+
- **MCP Integration**: RESTful API for seamless AI assistant integration
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Activate virtual environment
|
|
17
|
+
source .venv/bin/activate
|
|
18
|
+
|
|
19
|
+
# Example usage (if you have an existing index)
|
|
20
|
+
python -c "
|
|
21
|
+
from pdf_reader.index import PDFIndex
|
|
22
|
+
index = PDFIndex.load('indexes/index2')
|
|
23
|
+
results = index.search_pages(['your search term'])
|
|
24
|
+
print(f'Found {len(results)} results')
|
|
25
|
+
"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
The system uses a hybrid approach:
|
|
31
|
+
- **Tantivy**: Fast full-text search across OCR text and AI summaries
|
|
32
|
+
- **SQLite**: Blob storage for complete page data (text + images)
|
|
33
|
+
- **AI Enhancement**: Document titles and page summaries via LLM
|
|
34
|
+
- **Provider-Aware Images**: Optimized for different LLM API requirements
|
|
35
|
+
|
|
36
|
+
## MCP Tools
|
|
37
|
+
|
|
38
|
+
- `list_pdfs`: List available PDF documents
|
|
39
|
+
- `search_pdfs`: Keyword search across all documents
|
|
40
|
+
- `read_pdf`: Read specific pages from a document
|
|
41
|
+
- `read_pdfs`: Bulk read across multiple documents
|
|
42
|
+
|
|
43
|
+
## Development
|
|
44
|
+
|
|
45
|
+
See `CLAUDE.md` for detailed architecture documentation, development guidelines, and troubleshooting information.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling==1.27.0"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pdf-reader-0jsfjf"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "PDF OCR, indexing and search tools for AI assistants"
|
|
9
|
+
license = { text = "Proprietary" }
|
|
10
|
+
classifiers = [
|
|
11
|
+
"License :: Other/Proprietary License",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
]
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
requires-python = ">=3.12"
|
|
16
|
+
dependencies = [
|
|
17
|
+
"tesserocr",
|
|
18
|
+
"fastmcp>=3.4.11,<4",
|
|
19
|
+
"tantivy",
|
|
20
|
+
"pdf2image",
|
|
21
|
+
"pillow>=13.0.0",
|
|
22
|
+
"pydantic",
|
|
23
|
+
"aiohttp>=3.14.5",
|
|
24
|
+
"lm-deluge",
|
|
25
|
+
"pypdf>=6.21.2",
|
|
26
|
+
"requests",
|
|
27
|
+
"python-dotenv",
|
|
28
|
+
"fastapi"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[dependency-groups]
|
|
32
|
+
dev = [
|
|
33
|
+
"prek==0.4.14",
|
|
34
|
+
"ruff==0.17.2",
|
|
35
|
+
"ty==0.0.91",
|
|
36
|
+
"pytest==9.2.0",
|
|
37
|
+
"pip-audit==2.10.1",
|
|
38
|
+
"build==1.3.0",
|
|
39
|
+
"twine==6.2.0",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[tool.ruff]
|
|
43
|
+
exclude = ["unused", "modal_endpoints", "samples", ".claude"]
|
|
44
|
+
|
|
45
|
+
[tool.ruff.lint]
|
|
46
|
+
select = ["E4", "E7", "E9", "F"]
|
|
47
|
+
|
|
48
|
+
[tool.ty.environment]
|
|
49
|
+
# Always check against this repo's venv, not whatever VIRTUAL_ENV is active.
|
|
50
|
+
python = ".venv"
|
|
51
|
+
|
|
52
|
+
[tool.ty.src]
|
|
53
|
+
exclude = ["unused", "modal_endpoints", "samples", ".claude"]
|
|
54
|
+
|
|
55
|
+
[tool.ty.analysis]
|
|
56
|
+
# Modal is optional and only imported by remote OCR backends.
|
|
57
|
+
allowed-unresolved-imports = ["modal"]
|
|
58
|
+
|
|
59
|
+
[tool.ty.rules]
|
|
60
|
+
unused-type-ignore-comment = "ignore"
|
|
61
|
+
|
|
62
|
+
[[tool.ty.overrides]]
|
|
63
|
+
include = ["tests/**"]
|
|
64
|
+
|
|
65
|
+
[tool.ty.overrides.rules]
|
|
66
|
+
# Validation tests intentionally omit required fields; mock tools and legacy
|
|
67
|
+
# integration tests use values broader than their static annotations.
|
|
68
|
+
missing-argument = "ignore"
|
|
69
|
+
invalid-argument-type = "ignore"
|
|
70
|
+
|
|
71
|
+
# Published to PyPI under an obscured name; the import name stays `pdf_reader`.
|
|
72
|
+
[tool.hatch.build.targets.wheel]
|
|
73
|
+
packages = ["src/pdf_reader"]
|
|
74
|
+
|
|
75
|
+
# Keep the sdist to the package itself (no tests, tooling or local data).
|
|
76
|
+
[tool.hatch.build.targets.sdist]
|
|
77
|
+
only-include = ["src/pdf_reader", "README.md", "pyproject.toml"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PDF Reader - PDF indexing, search, and retrieval for AI applications.
|
|
3
|
+
|
|
4
|
+
This package provides:
|
|
5
|
+
- PDF/PDFPage: Data models for PDF documents and pages
|
|
6
|
+
- PDFIndex: Hybrid index combining Tantivy search with SQLite storage
|
|
7
|
+
- PDFService: Multi-index service layer for business logic
|
|
8
|
+
- Server implementations: REST API, MCP, and lm_deluge tools
|
|
9
|
+
- Formatting helpers: format_toc, format_ocr for LLM consumption
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .index import PDFIndex
|
|
13
|
+
from .pdf import PDF, PDFPage, format_toc, format_ocr
|
|
14
|
+
from .service import PDFService, PDFServiceConfig
|
|
15
|
+
from .ingest import ingest_pages_llm, iter_ingest_pages_llm
|
|
16
|
+
from .core import (
|
|
17
|
+
PDFIndexConfig,
|
|
18
|
+
SearchRequest,
|
|
19
|
+
SearchResponse,
|
|
20
|
+
ReadRequest,
|
|
21
|
+
ReadResponse,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
# Data models
|
|
26
|
+
"PDF",
|
|
27
|
+
"PDFPage",
|
|
28
|
+
# Index
|
|
29
|
+
"PDFIndex",
|
|
30
|
+
# Service
|
|
31
|
+
"PDFService",
|
|
32
|
+
"PDFServiceConfig",
|
|
33
|
+
# Config and API types
|
|
34
|
+
"PDFIndexConfig",
|
|
35
|
+
"SearchRequest",
|
|
36
|
+
"SearchResponse",
|
|
37
|
+
"ReadRequest",
|
|
38
|
+
"ReadResponse",
|
|
39
|
+
# Formatting helpers
|
|
40
|
+
"format_toc",
|
|
41
|
+
"format_ocr",
|
|
42
|
+
# Streaming OCR
|
|
43
|
+
"ingest_pages_llm",
|
|
44
|
+
"iter_ingest_pages_llm",
|
|
45
|
+
]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core types, models, and utilities shared across all PDF service implementations.
|
|
3
|
+
|
|
4
|
+
This module provides:
|
|
5
|
+
- PDFIndexConfig dataclass for index configuration
|
|
6
|
+
- Request/Response Pydantic models for the unified API
|
|
7
|
+
- Utility functions for data processing
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# =============================================================================
|
|
16
|
+
# Configuration
|
|
17
|
+
# =============================================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class PDFIndexConfig:
|
|
22
|
+
"""Configuration for a single PDF index."""
|
|
23
|
+
|
|
24
|
+
name: str
|
|
25
|
+
description: str = ""
|
|
26
|
+
root_path: str | None = None # Directory with search/, pages.db, manifest.json
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# =============================================================================
|
|
30
|
+
# Request/Response Models (Unified API)
|
|
31
|
+
# =============================================================================
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class SearchRequest(BaseModel):
|
|
35
|
+
"""Request model for search endpoint."""
|
|
36
|
+
|
|
37
|
+
index: str = Field(..., description="Name of the index to search")
|
|
38
|
+
queries: list[str] = Field(..., description="List of search query strings")
|
|
39
|
+
limit: int = Field(10, description="Maximum number of results to return")
|
|
40
|
+
pdf_filter: str | None = Field(
|
|
41
|
+
None, description="Optional PDF ID to filter results to a single document"
|
|
42
|
+
)
|
|
43
|
+
include_images: bool = Field(
|
|
44
|
+
False, description="If true, include page images in results"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PageResult(BaseModel):
|
|
49
|
+
"""A single page result from search."""
|
|
50
|
+
|
|
51
|
+
id: str = Field(..., description="Page ID in format 'pdf_id:page_index'")
|
|
52
|
+
pdf_id: str = Field(..., description="ID of the parent PDF")
|
|
53
|
+
page_index: int = Field(..., description="Zero-based page number")
|
|
54
|
+
text: str = Field("", description="OCR-extracted text")
|
|
55
|
+
summary: str | None = Field(None, description="AI-generated page summary")
|
|
56
|
+
caption: str | None = Field(
|
|
57
|
+
None, description="AI-generated caption for visual pages"
|
|
58
|
+
)
|
|
59
|
+
image: str | None = Field(None, description="Base64-encoded JPEG image")
|
|
60
|
+
preview: str | None = Field(None, description="Text preview for display")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class SearchResponse(BaseModel):
|
|
64
|
+
"""Response model for search endpoint."""
|
|
65
|
+
|
|
66
|
+
index: str
|
|
67
|
+
queries: list[str]
|
|
68
|
+
results: list[PageResult]
|
|
69
|
+
total: int
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ReadRequest(BaseModel):
|
|
73
|
+
"""Request model for read endpoint."""
|
|
74
|
+
|
|
75
|
+
index: str = Field(..., description="Name of the index to read from")
|
|
76
|
+
pdf_id: str = Field(..., description="ID of the PDF to read")
|
|
77
|
+
pages: list[int] | str = Field(
|
|
78
|
+
...,
|
|
79
|
+
description="List of page indices to read, or a range string like '1-5' or '-1' for all",
|
|
80
|
+
)
|
|
81
|
+
include_images: bool = Field(True, description="If true, include page images")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ReadResponse(BaseModel):
|
|
85
|
+
"""Response model for read endpoint."""
|
|
86
|
+
|
|
87
|
+
index: str
|
|
88
|
+
pdf_id: str
|
|
89
|
+
pages: list[PageResult]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class PDFInfo(BaseModel):
|
|
93
|
+
"""Information about a single PDF in an index."""
|
|
94
|
+
|
|
95
|
+
id: str
|
|
96
|
+
filename: str
|
|
97
|
+
title: str | None = None
|
|
98
|
+
summary: str | None = None
|
|
99
|
+
num_pages: int
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class ListPDFsResponse(BaseModel):
|
|
103
|
+
"""Response model for listing PDFs in an index."""
|
|
104
|
+
|
|
105
|
+
index: str
|
|
106
|
+
pdfs: list[PDFInfo]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class IndexInfo(BaseModel):
|
|
110
|
+
"""Information about a single index."""
|
|
111
|
+
|
|
112
|
+
name: str
|
|
113
|
+
description: str = ""
|
|
114
|
+
pdf_count: int = 0
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class IndicesResponse(BaseModel):
|
|
118
|
+
"""Response model for listing indices."""
|
|
119
|
+
|
|
120
|
+
indices: list[IndexInfo]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class HealthResponse(BaseModel):
|
|
124
|
+
"""Response model for health check."""
|
|
125
|
+
|
|
126
|
+
status: str
|
|
127
|
+
indices: list[str]
|
|
128
|
+
server: str | None = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# =============================================================================
|
|
132
|
+
# Exports
|
|
133
|
+
# =============================================================================
|
|
134
|
+
|
|
135
|
+
__all__ = [
|
|
136
|
+
# Configuration
|
|
137
|
+
"PDFIndexConfig",
|
|
138
|
+
# Request models
|
|
139
|
+
"SearchRequest",
|
|
140
|
+
"ReadRequest",
|
|
141
|
+
# Response models
|
|
142
|
+
"PageResult",
|
|
143
|
+
"SearchResponse",
|
|
144
|
+
"ReadResponse",
|
|
145
|
+
"PDFInfo",
|
|
146
|
+
"ListPDFsResponse",
|
|
147
|
+
"IndexInfo",
|
|
148
|
+
"IndicesResponse",
|
|
149
|
+
"HealthResponse",
|
|
150
|
+
]
|