veriis 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.
- veriis-0.1.0/.gitignore +82 -0
- veriis-0.1.0/CHANGELOG.md +14 -0
- veriis-0.1.0/LICENSE +6 -0
- veriis-0.1.0/PKG-INFO +299 -0
- veriis-0.1.0/README.md +262 -0
- veriis-0.1.0/examples/async_document.py +16 -0
- veriis-0.1.0/examples/basic.py +13 -0
- veriis-0.1.0/pyproject.toml +113 -0
- veriis-0.1.0/scripts/check_dist.py +194 -0
- veriis-0.1.0/src/veriis/__init__.py +129 -0
- veriis-0.1.0/src/veriis/_client_config.py +51 -0
- veriis-0.1.0/src/veriis/_transport.py +321 -0
- veriis-0.1.0/src/veriis/_version.py +3 -0
- veriis-0.1.0/src/veriis/async_client.py +60 -0
- veriis-0.1.0/src/veriis/client.py +60 -0
- veriis-0.1.0/src/veriis/errors.py +169 -0
- veriis-0.1.0/src/veriis/files.py +164 -0
- veriis-0.1.0/src/veriis/models.py +349 -0
- veriis-0.1.0/src/veriis/py.typed +1 -0
- veriis-0.1.0/src/veriis/resources.py +557 -0
- veriis-0.1.0/tests/__init__.py +1 -0
- veriis-0.1.0/tests/_payloads.py +95 -0
- veriis-0.1.0/tests/test_async_client.py +334 -0
- veriis-0.1.0/tests/test_client.py +645 -0
- veriis-0.1.0/tests/test_files.py +137 -0
- veriis-0.1.0/tests/test_models.py +154 -0
- veriis-0.1.0/tests/test_public_api.py +19 -0
veriis-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
# Anchored to repo root: these are Python build/venv artifacts. Unanchored
|
|
14
|
+
# (`lib/`) they also match nested JS dirs like frontend/src/lib — which silently
|
|
15
|
+
# dropped the frontend's lib/ from git and broke the CI build.
|
|
16
|
+
/lib/
|
|
17
|
+
/lib64/
|
|
18
|
+
parts/
|
|
19
|
+
sdist/
|
|
20
|
+
var/
|
|
21
|
+
wheels/
|
|
22
|
+
share/python-wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
MANIFEST
|
|
27
|
+
|
|
28
|
+
# uv
|
|
29
|
+
.venv/
|
|
30
|
+
venv/
|
|
31
|
+
ENV/
|
|
32
|
+
env/
|
|
33
|
+
|
|
34
|
+
# Testing
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.coverage
|
|
37
|
+
.coverage.*
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
coverage.xml
|
|
42
|
+
*.cover
|
|
43
|
+
.hypothesis/
|
|
44
|
+
|
|
45
|
+
# mypy
|
|
46
|
+
.mypy_cache/
|
|
47
|
+
.dmypy.json
|
|
48
|
+
dmypy.json
|
|
49
|
+
|
|
50
|
+
# Ruff
|
|
51
|
+
.ruff_cache/
|
|
52
|
+
|
|
53
|
+
# Environments
|
|
54
|
+
.env
|
|
55
|
+
.env.local
|
|
56
|
+
.env.*.local
|
|
57
|
+
|
|
58
|
+
# IDEs
|
|
59
|
+
.idea/
|
|
60
|
+
.vscode/
|
|
61
|
+
*.swp
|
|
62
|
+
*.swo
|
|
63
|
+
.DS_Store
|
|
64
|
+
|
|
65
|
+
# Logs
|
|
66
|
+
*.log
|
|
67
|
+
logs/
|
|
68
|
+
|
|
69
|
+
# Tessdata downloads (built into image, not committed)
|
|
70
|
+
assets/tessdata/*.traineddata
|
|
71
|
+
|
|
72
|
+
# OS
|
|
73
|
+
Thumbs.db
|
|
74
|
+
|
|
75
|
+
# Docker
|
|
76
|
+
.docker/
|
|
77
|
+
|
|
78
|
+
# Superpowers brainstorming companion (local mockups, not committed)
|
|
79
|
+
.superpowers/
|
|
80
|
+
|
|
81
|
+
# Local Codex/runtime scratch files and UI migration backups
|
|
82
|
+
.tmp/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Veris OCR Python client are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.1.0
|
|
6
|
+
|
|
7
|
+
- Initial synchronous and asynchronous Python clients.
|
|
8
|
+
- Passport, document, resume, history, admin, and health resources.
|
|
9
|
+
- Typed Pydantic response models.
|
|
10
|
+
- File-path, bytes, file-object, and explicit file-descriptor inputs.
|
|
11
|
+
- Typed API, connection, timeout, validation, and rate-limit errors.
|
|
12
|
+
- Bounded retries for idempotent requests on rate limits and transient service
|
|
13
|
+
failures.
|
|
14
|
+
- Redirect blocking to prevent forwarding API credentials to another origin.
|
veriis-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Copyright (c) 2026 RecursAI Technologies. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software is proprietary and confidential. No permission is granted to
|
|
4
|
+
use, copy, modify, merge, publish, distribute, sublicense, or sell copies of
|
|
5
|
+
the software except under a separate written agreement with RecursAI
|
|
6
|
+
Technologies.
|
veriis-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: veriis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client for the Veris OCR API.
|
|
5
|
+
Project-URL: Homepage, https://github.com/MohamedNasirS/veris-ocr-recursai
|
|
6
|
+
Project-URL: Documentation, https://github.com/MohamedNasirS/veris-ocr-recursai/tree/main/clients/python
|
|
7
|
+
Project-URL: Repository, https://github.com/MohamedNasirS/veris-ocr-recursai.git
|
|
8
|
+
Project-URL: Issues, https://github.com/MohamedNasirS/veris-ocr-recursai/issues
|
|
9
|
+
Author-email: RecursAI Technologies <founders@recursai.com>
|
|
10
|
+
License-Expression: LicenseRef-Proprietary
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: document,mrz,ocr,passport,recursai,resume,veris
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: <3.15,>=3.10
|
|
25
|
+
Requires-Dist: httpx<1,>=0.27
|
|
26
|
+
Requires-Dist: pydantic<3,>=2.8
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
29
|
+
Requires-Dist: hatchling<2,>=1.27; extra == 'dev'
|
|
30
|
+
Requires-Dist: mypy<2,>=1.13; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov>=6; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
35
|
+
Requires-Dist: twine>=6; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# veriis
|
|
39
|
+
|
|
40
|
+
Official Python client for the Veris OCR API by RecursAI Technologies. The
|
|
41
|
+
service performs passport MRZ extraction, general document OCR, and structured
|
|
42
|
+
resume parsing; this package provides a small typed client for calling it.
|
|
43
|
+
|
|
44
|
+
- Synchronous and asynchronous clients
|
|
45
|
+
- Typed Pydantic response models
|
|
46
|
+
- File paths, raw bytes, binary file objects, and explicit file descriptors
|
|
47
|
+
- Typed errors, request timeouts, and bounded retries
|
|
48
|
+
- Python 3.10–3.14
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install veriis
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quickstart
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from veriis import VerisOCR
|
|
60
|
+
|
|
61
|
+
with VerisOCR(
|
|
62
|
+
base_url="https://veris.recursai.in",
|
|
63
|
+
api_key="pk_live_...",
|
|
64
|
+
) as client:
|
|
65
|
+
passport = client.passport.extract("passport.jpg")
|
|
66
|
+
print(passport.mrz.passport_number, passport.mrz.expiry_date)
|
|
67
|
+
|
|
68
|
+
document = client.document.extract("invoice.pdf", lang="eng+fra")
|
|
69
|
+
print(document.page_count, document.pages[0].text)
|
|
70
|
+
|
|
71
|
+
resume = client.resume.extract("cv.pdf")
|
|
72
|
+
print(resume.name, resume.total_experience_human, resume.skills)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The same settings can come from the environment:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
export VERIS_OCR_BASE_URL=https://veris.recursai.in
|
|
79
|
+
export VERIS_OCR_API_KEY=pk_live_...
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from veriis import VerisOCR
|
|
84
|
+
|
|
85
|
+
client = VerisOCR()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Async client
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import asyncio
|
|
92
|
+
|
|
93
|
+
from veriis import AsyncVerisOCR
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async def main() -> None:
|
|
97
|
+
async with AsyncVerisOCR(
|
|
98
|
+
base_url="https://veris.recursai.in",
|
|
99
|
+
api_key="pk_live_...",
|
|
100
|
+
) as client:
|
|
101
|
+
result = await client.document.extract("invoice.pdf", lang="eng")
|
|
102
|
+
print(result.pages[0].text)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
asyncio.run(main())
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
client = VerisOCR(
|
|
112
|
+
base_url="https://veris.recursai.in", # or VERIS_OCR_BASE_URL
|
|
113
|
+
api_key="pk_live_...", # or VERIS_OCR_API_KEY
|
|
114
|
+
admin_token="...", # or VERIS_OCR_ADMIN_TOKEN
|
|
115
|
+
timeout=120.0, # seconds; OCR can be slow
|
|
116
|
+
max_retries=2, # transient failures on idempotent operations
|
|
117
|
+
headers={"X-Application": "billing"},
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Every resource method also accepts `timeout=` and `max_retries=` overrides.
|
|
122
|
+
Retries apply to idempotent health, history, admin-list, and key-revoke
|
|
123
|
+
operations. Extraction and key-creation requests are never automatically
|
|
124
|
+
retried because repeating them could create duplicate work or keys. Redirects
|
|
125
|
+
are surfaced as errors so API credentials are never forwarded to another
|
|
126
|
+
origin. Async requests can be cancelled with normal asyncio task cancellation.
|
|
127
|
+
|
|
128
|
+
## File inputs
|
|
129
|
+
|
|
130
|
+
Extraction methods accept:
|
|
131
|
+
|
|
132
|
+
- a `str` or `pathlib.Path` filesystem path;
|
|
133
|
+
- `bytes`, `bytearray`, or `memoryview`;
|
|
134
|
+
- a binary file object such as an open file or `io.BytesIO`;
|
|
135
|
+
- `FileDescriptor(data=..., filename=..., content_type=...)`.
|
|
136
|
+
|
|
137
|
+
The SDK detects JPEG, PNG, WEBP, PDF, GIF, BMP, and TIFF signatures. The Veris
|
|
138
|
+
OCR server currently accepts JPEG, PNG, WEBP, and PDF extraction uploads.
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from veriis import FileDescriptor
|
|
142
|
+
|
|
143
|
+
result = client.passport.extract(
|
|
144
|
+
FileDescriptor(
|
|
145
|
+
data=image_bytes,
|
|
146
|
+
filename="passport-front.jpg",
|
|
147
|
+
content_type="image/jpeg",
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Resources
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
client.passport.extract(file)
|
|
156
|
+
client.document.extract(file, lang="eng")
|
|
157
|
+
client.resume.extract(file)
|
|
158
|
+
|
|
159
|
+
client.history.list(mode="passport", limit=50, offset=0)
|
|
160
|
+
client.history.get(item_id)
|
|
161
|
+
client.history.delete(item_id)
|
|
162
|
+
client.history.clear()
|
|
163
|
+
|
|
164
|
+
client.health.check() # no API key required
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Admin operations use `admin_token`, not `api_key`:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
created = client.admin.create_key(
|
|
171
|
+
customer_email="developer@example.com",
|
|
172
|
+
customer_name="Example Developer",
|
|
173
|
+
key_name="production",
|
|
174
|
+
allowed_ocr_modes=["passport", "document"],
|
|
175
|
+
)
|
|
176
|
+
print(created.key) # returned only once
|
|
177
|
+
|
|
178
|
+
keys = client.admin.list_keys(include_revoked=False)
|
|
179
|
+
client.admin.revoke_key(created.api_key_id)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Response models
|
|
183
|
+
|
|
184
|
+
Successful responses are Pydantic models. Access fields as attributes or
|
|
185
|
+
convert them back to JSON-compatible dictionaries:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
result = client.passport.extract("passport.jpg")
|
|
189
|
+
print(result.request_id)
|
|
190
|
+
print(result.model_dump(mode="json"))
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Models allow unknown response fields so compatible server additions do not
|
|
194
|
+
break older client versions.
|
|
195
|
+
|
|
196
|
+
## Errors
|
|
197
|
+
|
|
198
|
+
HTTP, timeout, connection, and invalid-response failures derive from
|
|
199
|
+
`VerisOCRError`:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from veriis import VerisOCRBadRequestError, VerisOCRRateLimitError
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
client.passport.extract("passport.jpg")
|
|
206
|
+
except VerisOCRRateLimitError as exc:
|
|
207
|
+
print(f"Retry after {exc.retry_after} seconds")
|
|
208
|
+
except VerisOCRBadRequestError as exc:
|
|
209
|
+
print(exc.code, exc.request_id, str(exc))
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Available subclasses:
|
|
213
|
+
|
|
214
|
+
- `VerisOCRBadRequestError` for 400 and 413
|
|
215
|
+
- `VerisOCRAuthenticationError` for 401 and 403
|
|
216
|
+
- `VerisOCRNotFoundError` for 404
|
|
217
|
+
- `VerisOCRValidationError` for 422
|
|
218
|
+
- `VerisOCRRateLimitError` for 429
|
|
219
|
+
- `VerisOCRServerError` for 5xx
|
|
220
|
+
- `VerisOCRTimeoutError` for request timeouts
|
|
221
|
+
- `VerisOCRConnectionError` for network and connection failures
|
|
222
|
+
|
|
223
|
+
Local input failures stay idiomatic: missing paths raise `FileNotFoundError`,
|
|
224
|
+
unsupported file values raise `TypeError`, and invalid admin-key parameters
|
|
225
|
+
raise Pydantic `ValidationError` before any request is sent.
|
|
226
|
+
|
|
227
|
+
## Development and release
|
|
228
|
+
|
|
229
|
+
Run these commands from `clients/python`. The locked environment is the source
|
|
230
|
+
of the build tools used to create release artifacts:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
uv sync --locked --extra dev --python 3.12
|
|
234
|
+
uv run --locked ruff format --check .
|
|
235
|
+
uv run --locked ruff check .
|
|
236
|
+
uv run --locked mypy
|
|
237
|
+
uv run --locked pytest --cov
|
|
238
|
+
uv run --locked python -m build --no-isolation
|
|
239
|
+
uv run --locked twine check --strict dist/*
|
|
240
|
+
uv run --locked python scripts/check_dist.py
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Remove existing files from `dist/` before making a release build so the
|
|
244
|
+
distribution validator sees exactly one wheel and one source distribution.
|
|
245
|
+
|
|
246
|
+
TestPyPI can be used as an optional manual validation step. Configure a
|
|
247
|
+
TestPyPI API token for Twine, upload the freshly validated artifacts, install
|
|
248
|
+
the exact candidate version, and run an import smoke test:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
python -m twine upload --repository testpypi dist/*
|
|
252
|
+
python -m pip install --index-url https://test.pypi.org/simple/ \
|
|
253
|
+
--extra-index-url https://pypi.org/simple/ veriis==0.1.0
|
|
254
|
+
python -c "from veriis import VerisOCR, __version__; print(__version__)"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Production releases use only the repository's Trusted Publishing workflow; do
|
|
258
|
+
not upload production artifacts manually. Because the bundled license permits
|
|
259
|
+
use and redistribution only under a separate written agreement, obtain the
|
|
260
|
+
appropriate business/legal approval before making the artifacts public.
|
|
261
|
+
Before the first automated release, create the `veriis` project on
|
|
262
|
+
PyPI or configure a pending publisher with these exact settings:
|
|
263
|
+
|
|
264
|
+
- GitHub owner: `MohamedNasirS`
|
|
265
|
+
- Repository: `veris-ocr-recursai`
|
|
266
|
+
- Workflow: `python-client-release.yml`
|
|
267
|
+
- Environment: `pypi`
|
|
268
|
+
|
|
269
|
+
A pending publisher does not reserve the project name until its first
|
|
270
|
+
successful upload. Protect the GitHub `pypi` environment with a required
|
|
271
|
+
reviewer. Also add a repository ruleset for tags matching `python-v*` that
|
|
272
|
+
restricts tag creation, updates, and deletion to release maintainers.
|
|
273
|
+
|
|
274
|
+
For each release:
|
|
275
|
+
|
|
276
|
+
1. Update `src/veriis/_version.py` and `CHANGELOG.md`.
|
|
277
|
+
2. Regenerate `uv.lock` if dependency metadata changed, then run
|
|
278
|
+
`uv lock --check`.
|
|
279
|
+
3. Remove old artifacts, run the development and distribution checks above,
|
|
280
|
+
and verify both clean-environment smoke installs.
|
|
281
|
+
4. Merge the release commit to protected `main` and wait for Python client CI
|
|
282
|
+
to pass.
|
|
283
|
+
5. Create and push an annotated tag whose version exactly matches
|
|
284
|
+
`__version__`:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
git tag -a python-v0.1.0 -m "Python client 0.1.0"
|
|
288
|
+
git push origin python-v0.1.0
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
The workflow rejects release commits that are not reachable from `main`,
|
|
292
|
+
checks that the tag equals `__version__`, runs linting, typing, and tests,
|
|
293
|
+
builds and validates the wheel and source distribution once, smoke-installs
|
|
294
|
+
both artifacts, and publishes that exact artifact through PyPI's OpenID
|
|
295
|
+
Connect trusted-publisher flow.
|
|
296
|
+
|
|
297
|
+
## License
|
|
298
|
+
|
|
299
|
+
Proprietary — © RecursAI Technologies.
|
veriis-0.1.0/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# veriis
|
|
2
|
+
|
|
3
|
+
Official Python client for the Veris OCR API by RecursAI Technologies. The
|
|
4
|
+
service performs passport MRZ extraction, general document OCR, and structured
|
|
5
|
+
resume parsing; this package provides a small typed client for calling it.
|
|
6
|
+
|
|
7
|
+
- Synchronous and asynchronous clients
|
|
8
|
+
- Typed Pydantic response models
|
|
9
|
+
- File paths, raw bytes, binary file objects, and explicit file descriptors
|
|
10
|
+
- Typed errors, request timeouts, and bounded retries
|
|
11
|
+
- Python 3.10–3.14
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install veriis
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from veriis import VerisOCR
|
|
23
|
+
|
|
24
|
+
with VerisOCR(
|
|
25
|
+
base_url="https://veris.recursai.in",
|
|
26
|
+
api_key="pk_live_...",
|
|
27
|
+
) as client:
|
|
28
|
+
passport = client.passport.extract("passport.jpg")
|
|
29
|
+
print(passport.mrz.passport_number, passport.mrz.expiry_date)
|
|
30
|
+
|
|
31
|
+
document = client.document.extract("invoice.pdf", lang="eng+fra")
|
|
32
|
+
print(document.page_count, document.pages[0].text)
|
|
33
|
+
|
|
34
|
+
resume = client.resume.extract("cv.pdf")
|
|
35
|
+
print(resume.name, resume.total_experience_human, resume.skills)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The same settings can come from the environment:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export VERIS_OCR_BASE_URL=https://veris.recursai.in
|
|
42
|
+
export VERIS_OCR_API_KEY=pk_live_...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from veriis import VerisOCR
|
|
47
|
+
|
|
48
|
+
client = VerisOCR()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Async client
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import asyncio
|
|
55
|
+
|
|
56
|
+
from veriis import AsyncVerisOCR
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def main() -> None:
|
|
60
|
+
async with AsyncVerisOCR(
|
|
61
|
+
base_url="https://veris.recursai.in",
|
|
62
|
+
api_key="pk_live_...",
|
|
63
|
+
) as client:
|
|
64
|
+
result = await client.document.extract("invoice.pdf", lang="eng")
|
|
65
|
+
print(result.pages[0].text)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
client = VerisOCR(
|
|
75
|
+
base_url="https://veris.recursai.in", # or VERIS_OCR_BASE_URL
|
|
76
|
+
api_key="pk_live_...", # or VERIS_OCR_API_KEY
|
|
77
|
+
admin_token="...", # or VERIS_OCR_ADMIN_TOKEN
|
|
78
|
+
timeout=120.0, # seconds; OCR can be slow
|
|
79
|
+
max_retries=2, # transient failures on idempotent operations
|
|
80
|
+
headers={"X-Application": "billing"},
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Every resource method also accepts `timeout=` and `max_retries=` overrides.
|
|
85
|
+
Retries apply to idempotent health, history, admin-list, and key-revoke
|
|
86
|
+
operations. Extraction and key-creation requests are never automatically
|
|
87
|
+
retried because repeating them could create duplicate work or keys. Redirects
|
|
88
|
+
are surfaced as errors so API credentials are never forwarded to another
|
|
89
|
+
origin. Async requests can be cancelled with normal asyncio task cancellation.
|
|
90
|
+
|
|
91
|
+
## File inputs
|
|
92
|
+
|
|
93
|
+
Extraction methods accept:
|
|
94
|
+
|
|
95
|
+
- a `str` or `pathlib.Path` filesystem path;
|
|
96
|
+
- `bytes`, `bytearray`, or `memoryview`;
|
|
97
|
+
- a binary file object such as an open file or `io.BytesIO`;
|
|
98
|
+
- `FileDescriptor(data=..., filename=..., content_type=...)`.
|
|
99
|
+
|
|
100
|
+
The SDK detects JPEG, PNG, WEBP, PDF, GIF, BMP, and TIFF signatures. The Veris
|
|
101
|
+
OCR server currently accepts JPEG, PNG, WEBP, and PDF extraction uploads.
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from veriis import FileDescriptor
|
|
105
|
+
|
|
106
|
+
result = client.passport.extract(
|
|
107
|
+
FileDescriptor(
|
|
108
|
+
data=image_bytes,
|
|
109
|
+
filename="passport-front.jpg",
|
|
110
|
+
content_type="image/jpeg",
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Resources
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
client.passport.extract(file)
|
|
119
|
+
client.document.extract(file, lang="eng")
|
|
120
|
+
client.resume.extract(file)
|
|
121
|
+
|
|
122
|
+
client.history.list(mode="passport", limit=50, offset=0)
|
|
123
|
+
client.history.get(item_id)
|
|
124
|
+
client.history.delete(item_id)
|
|
125
|
+
client.history.clear()
|
|
126
|
+
|
|
127
|
+
client.health.check() # no API key required
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Admin operations use `admin_token`, not `api_key`:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
created = client.admin.create_key(
|
|
134
|
+
customer_email="developer@example.com",
|
|
135
|
+
customer_name="Example Developer",
|
|
136
|
+
key_name="production",
|
|
137
|
+
allowed_ocr_modes=["passport", "document"],
|
|
138
|
+
)
|
|
139
|
+
print(created.key) # returned only once
|
|
140
|
+
|
|
141
|
+
keys = client.admin.list_keys(include_revoked=False)
|
|
142
|
+
client.admin.revoke_key(created.api_key_id)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Response models
|
|
146
|
+
|
|
147
|
+
Successful responses are Pydantic models. Access fields as attributes or
|
|
148
|
+
convert them back to JSON-compatible dictionaries:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
result = client.passport.extract("passport.jpg")
|
|
152
|
+
print(result.request_id)
|
|
153
|
+
print(result.model_dump(mode="json"))
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Models allow unknown response fields so compatible server additions do not
|
|
157
|
+
break older client versions.
|
|
158
|
+
|
|
159
|
+
## Errors
|
|
160
|
+
|
|
161
|
+
HTTP, timeout, connection, and invalid-response failures derive from
|
|
162
|
+
`VerisOCRError`:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from veriis import VerisOCRBadRequestError, VerisOCRRateLimitError
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
client.passport.extract("passport.jpg")
|
|
169
|
+
except VerisOCRRateLimitError as exc:
|
|
170
|
+
print(f"Retry after {exc.retry_after} seconds")
|
|
171
|
+
except VerisOCRBadRequestError as exc:
|
|
172
|
+
print(exc.code, exc.request_id, str(exc))
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Available subclasses:
|
|
176
|
+
|
|
177
|
+
- `VerisOCRBadRequestError` for 400 and 413
|
|
178
|
+
- `VerisOCRAuthenticationError` for 401 and 403
|
|
179
|
+
- `VerisOCRNotFoundError` for 404
|
|
180
|
+
- `VerisOCRValidationError` for 422
|
|
181
|
+
- `VerisOCRRateLimitError` for 429
|
|
182
|
+
- `VerisOCRServerError` for 5xx
|
|
183
|
+
- `VerisOCRTimeoutError` for request timeouts
|
|
184
|
+
- `VerisOCRConnectionError` for network and connection failures
|
|
185
|
+
|
|
186
|
+
Local input failures stay idiomatic: missing paths raise `FileNotFoundError`,
|
|
187
|
+
unsupported file values raise `TypeError`, and invalid admin-key parameters
|
|
188
|
+
raise Pydantic `ValidationError` before any request is sent.
|
|
189
|
+
|
|
190
|
+
## Development and release
|
|
191
|
+
|
|
192
|
+
Run these commands from `clients/python`. The locked environment is the source
|
|
193
|
+
of the build tools used to create release artifacts:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
uv sync --locked --extra dev --python 3.12
|
|
197
|
+
uv run --locked ruff format --check .
|
|
198
|
+
uv run --locked ruff check .
|
|
199
|
+
uv run --locked mypy
|
|
200
|
+
uv run --locked pytest --cov
|
|
201
|
+
uv run --locked python -m build --no-isolation
|
|
202
|
+
uv run --locked twine check --strict dist/*
|
|
203
|
+
uv run --locked python scripts/check_dist.py
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Remove existing files from `dist/` before making a release build so the
|
|
207
|
+
distribution validator sees exactly one wheel and one source distribution.
|
|
208
|
+
|
|
209
|
+
TestPyPI can be used as an optional manual validation step. Configure a
|
|
210
|
+
TestPyPI API token for Twine, upload the freshly validated artifacts, install
|
|
211
|
+
the exact candidate version, and run an import smoke test:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
python -m twine upload --repository testpypi dist/*
|
|
215
|
+
python -m pip install --index-url https://test.pypi.org/simple/ \
|
|
216
|
+
--extra-index-url https://pypi.org/simple/ veriis==0.1.0
|
|
217
|
+
python -c "from veriis import VerisOCR, __version__; print(__version__)"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Production releases use only the repository's Trusted Publishing workflow; do
|
|
221
|
+
not upload production artifacts manually. Because the bundled license permits
|
|
222
|
+
use and redistribution only under a separate written agreement, obtain the
|
|
223
|
+
appropriate business/legal approval before making the artifacts public.
|
|
224
|
+
Before the first automated release, create the `veriis` project on
|
|
225
|
+
PyPI or configure a pending publisher with these exact settings:
|
|
226
|
+
|
|
227
|
+
- GitHub owner: `MohamedNasirS`
|
|
228
|
+
- Repository: `veris-ocr-recursai`
|
|
229
|
+
- Workflow: `python-client-release.yml`
|
|
230
|
+
- Environment: `pypi`
|
|
231
|
+
|
|
232
|
+
A pending publisher does not reserve the project name until its first
|
|
233
|
+
successful upload. Protect the GitHub `pypi` environment with a required
|
|
234
|
+
reviewer. Also add a repository ruleset for tags matching `python-v*` that
|
|
235
|
+
restricts tag creation, updates, and deletion to release maintainers.
|
|
236
|
+
|
|
237
|
+
For each release:
|
|
238
|
+
|
|
239
|
+
1. Update `src/veriis/_version.py` and `CHANGELOG.md`.
|
|
240
|
+
2. Regenerate `uv.lock` if dependency metadata changed, then run
|
|
241
|
+
`uv lock --check`.
|
|
242
|
+
3. Remove old artifacts, run the development and distribution checks above,
|
|
243
|
+
and verify both clean-environment smoke installs.
|
|
244
|
+
4. Merge the release commit to protected `main` and wait for Python client CI
|
|
245
|
+
to pass.
|
|
246
|
+
5. Create and push an annotated tag whose version exactly matches
|
|
247
|
+
`__version__`:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
git tag -a python-v0.1.0 -m "Python client 0.1.0"
|
|
251
|
+
git push origin python-v0.1.0
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The workflow rejects release commits that are not reachable from `main`,
|
|
255
|
+
checks that the tag equals `__version__`, runs linting, typing, and tests,
|
|
256
|
+
builds and validates the wheel and source distribution once, smoke-installs
|
|
257
|
+
both artifacts, and publishes that exact artifact through PyPI's OpenID
|
|
258
|
+
Connect trusted-publisher flow.
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
Proprietary — © RecursAI Technologies.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Extract document text asynchronously."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from veriis import AsyncVerisOCR
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def main() -> None:
|
|
9
|
+
async with AsyncVerisOCR() as client:
|
|
10
|
+
result = await client.document.extract("document.pdf", lang="eng")
|
|
11
|
+
for page in result.pages:
|
|
12
|
+
print(page.text)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Extract passport data with settings supplied through environment variables."""
|
|
2
|
+
|
|
3
|
+
from veriis import VerisOCR
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main() -> None:
|
|
7
|
+
with VerisOCR() as client:
|
|
8
|
+
result = client.passport.extract("passport.jpg")
|
|
9
|
+
print(result.model_dump_json(indent=2))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
main()
|