visionai-sdk-python 0.1.0__tar.gz → 1.0.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.
- visionai_sdk_python-1.0.0/.github/workflows/publish.yml +54 -0
- visionai_sdk_python-1.0.0/.gitignore +69 -0
- visionai_sdk_python-1.0.0/PKG-INFO +274 -0
- visionai_sdk_python-1.0.0/README.md +262 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/pyproject.toml +5 -3
- visionai_sdk_python-1.0.0/setup.cfg +4 -0
- visionai_sdk_python-1.0.0/src/visionai_sdk_python.egg-info/PKG-INFO +274 -0
- visionai_sdk_python-1.0.0/src/visionai_sdk_python.egg-info/SOURCES.txt +25 -0
- visionai_sdk_python-1.0.0/src/visionai_sdk_python.egg-info/dependency_links.txt +1 -0
- visionai_sdk_python-1.0.0/src/visionai_sdk_python.egg-info/requires.txt +4 -0
- visionai_sdk_python-1.0.0/src/visionai_sdk_python.egg-info/top_level.txt +1 -0
- visionai_sdk_python-1.0.0/tests/__init__.py +0 -0
- visionai_sdk_python-1.0.0/tests/constants.py +19 -0
- visionai_sdk_python-1.0.0/tests/test__base.py +100 -0
- visionai_sdk_python-1.0.0/tests/test_async_client.py +646 -0
- visionai_sdk_python-1.0.0/tests/test_client.py +561 -0
- visionai_sdk_python-1.0.0/uv.lock +469 -0
- visionai_sdk_python-0.1.0/PKG-INFO +0 -14
- visionai_sdk_python-0.1.0/README.md +0 -1
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/__init__.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/_base.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/_jwt_verifier.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/async_client.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/client.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/constants.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/endpoints.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/exceptions.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/models.py +0 -0
- {visionai_sdk_python-0.1.0 → visionai_sdk_python-1.0.0}/src/visionai_sdk_python/py.typed +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distribution
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v5
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version-file: "pyproject.toml"
|
|
27
|
+
|
|
28
|
+
- name: Build package
|
|
29
|
+
run: uv build
|
|
30
|
+
|
|
31
|
+
- name: Upload distribution artifacts
|
|
32
|
+
uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: python-package-distributions
|
|
35
|
+
path: dist/
|
|
36
|
+
|
|
37
|
+
publish:
|
|
38
|
+
name: Publish to PyPI
|
|
39
|
+
needs: build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
environment:
|
|
42
|
+
name: pypi
|
|
43
|
+
url: https://pypi.org/project/visionai-sdk-python/
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download distribution artifacts
|
|
46
|
+
uses: actions/download-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: python-package-distributions
|
|
49
|
+
path: dist/
|
|
50
|
+
|
|
51
|
+
- name: Publish to PyPI
|
|
52
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
53
|
+
with:
|
|
54
|
+
password: ${{ secrets.PYPI_TOKEN }}
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
pip-wheel-metadata/
|
|
20
|
+
share/python-wheels/
|
|
21
|
+
*.egg-info/
|
|
22
|
+
.installed.cfg
|
|
23
|
+
*.egg
|
|
24
|
+
MANIFEST
|
|
25
|
+
|
|
26
|
+
# Virtual environments
|
|
27
|
+
venv/
|
|
28
|
+
env/
|
|
29
|
+
ENV/
|
|
30
|
+
env.bak/
|
|
31
|
+
venv.bak/
|
|
32
|
+
.venv/
|
|
33
|
+
|
|
34
|
+
# IDEs
|
|
35
|
+
.vscode/
|
|
36
|
+
.idea/
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
*~
|
|
40
|
+
.DS_Store
|
|
41
|
+
|
|
42
|
+
# Testing
|
|
43
|
+
.pytest_cache/
|
|
44
|
+
.coverage
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
|
|
49
|
+
# Type checking
|
|
50
|
+
.mypy_cache/
|
|
51
|
+
.dmypy.json
|
|
52
|
+
dmypy.json
|
|
53
|
+
.pytype/
|
|
54
|
+
|
|
55
|
+
# Jupyter
|
|
56
|
+
.ipynb_checkpoints
|
|
57
|
+
|
|
58
|
+
# Environment variables
|
|
59
|
+
.env
|
|
60
|
+
.env.local
|
|
61
|
+
.env.*.local
|
|
62
|
+
|
|
63
|
+
# Project specific
|
|
64
|
+
*.log
|
|
65
|
+
.python-version
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# Claude
|
|
69
|
+
.claude/
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: visionai-sdk-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: VisionAI SDK for Python
|
|
5
|
+
Author-email: Tony Yang <tonyyang@linkervision.com>
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
|
9
|
+
Requires-Dist: pydantic>=2.12.5
|
|
10
|
+
Requires-Dist: cryptography>=46.0.5
|
|
11
|
+
Requires-Dist: PyJWT[cryptography]>=2.8.0
|
|
12
|
+
|
|
13
|
+
# VisionAI SDK for Python
|
|
14
|
+
|
|
15
|
+
Python client library for VisionAI authentication and Vision Language Model (VLM) inference services.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **Dual Authentication**: Email/password login or OAuth client credentials
|
|
20
|
+
- **Auto Token Management**: Automatic token refresh before expiration
|
|
21
|
+
- **JWT Validation**: Built-in token signature and expiration verification
|
|
22
|
+
- **VLM Inference**: Submit and poll vision-language model tasks
|
|
23
|
+
- **Async Support**: Full async/await support with `AsyncClient`
|
|
24
|
+
- **Type Safe**: Full type hints with Pydantic validation
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install visionai-sdk-python
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Synchronous Usage
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from visionai_sdk_python import Client
|
|
38
|
+
|
|
39
|
+
# Initialize client
|
|
40
|
+
client = Client(
|
|
41
|
+
auth_url="https://auth.visionai.example.com",
|
|
42
|
+
vlm_url="https://vlm.visionai.example.com"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Login with email/password
|
|
46
|
+
token = client.login("user@example.com", "your-password")
|
|
47
|
+
|
|
48
|
+
# Submit VLM inference request
|
|
49
|
+
response = client.chat({
|
|
50
|
+
"img": "examplebase64",
|
|
51
|
+
"prompt": "Describe this image",
|
|
52
|
+
"temperature": 0.7,
|
|
53
|
+
"max_tokens": 500
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
print(f"Chat ID: {response.chat_id}")
|
|
57
|
+
print(f"Status: {response.status}")
|
|
58
|
+
|
|
59
|
+
# Poll for results
|
|
60
|
+
result = client.get_chat(response.chat_id)
|
|
61
|
+
if result.status == "completed":
|
|
62
|
+
print(f"Result: {result.message}")
|
|
63
|
+
|
|
64
|
+
# Close client when done
|
|
65
|
+
client.close()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Asynchronous Usage
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import asyncio
|
|
72
|
+
from visionai_sdk_python import AsyncClient
|
|
73
|
+
|
|
74
|
+
async def main():
|
|
75
|
+
async with AsyncClient(
|
|
76
|
+
auth_url="https://auth.visionai.example.com",
|
|
77
|
+
vlm_url="https://vlm.visionai.example.com"
|
|
78
|
+
) as client:
|
|
79
|
+
# OAuth client credentials flow
|
|
80
|
+
await client.get_access_token(
|
|
81
|
+
client_id="your-client-id",
|
|
82
|
+
client_secret="your-client-secret"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Submit inference
|
|
86
|
+
response = await client.chat({
|
|
87
|
+
"img": "examplebase64",
|
|
88
|
+
"prompt": "What objects are in this image?",
|
|
89
|
+
"temperature": 0.2
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
# Poll until completed
|
|
93
|
+
while True:
|
|
94
|
+
result = await client.get_chat(response.chat_id)
|
|
95
|
+
if result.status in ("completed", "failed", "timeout"):
|
|
96
|
+
break
|
|
97
|
+
await asyncio.sleep(1)
|
|
98
|
+
|
|
99
|
+
if result.status == "completed":
|
|
100
|
+
print(f"Answer: {result.message}")
|
|
101
|
+
else:
|
|
102
|
+
print(f"Error: {result.error}")
|
|
103
|
+
|
|
104
|
+
asyncio.run(main())
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Authentication
|
|
108
|
+
|
|
109
|
+
### Email/Password Login
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
client = Client(auth_url="...", vlm_url="...")
|
|
113
|
+
token = client.login("user@example.com", "password")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### OAuth Client Credentials
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
client = Client(auth_url="...", vlm_url="...")
|
|
120
|
+
token = client.get_access_token(
|
|
121
|
+
client_id="your-client-id",
|
|
122
|
+
client_secret="your-client-secret"
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Tokens are stored internally and automatically refreshed before expiration.
|
|
127
|
+
|
|
128
|
+
## VLM Inference
|
|
129
|
+
|
|
130
|
+
### Submit Chat Request
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from visionai_sdk_python.models import NIMRequestModel
|
|
134
|
+
|
|
135
|
+
# Using dict
|
|
136
|
+
response = client.chat({
|
|
137
|
+
"img": "examplebase64",
|
|
138
|
+
"prompt": "Analyze this image",
|
|
139
|
+
"temperature": 0.7,
|
|
140
|
+
"max_tokens": 1000,
|
|
141
|
+
"top_p": 0.9
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
# Using typed model
|
|
145
|
+
request = NIMRequestModel(
|
|
146
|
+
img=["examplebase64"],
|
|
147
|
+
prompt="Compare these images",
|
|
148
|
+
temperature=0.5,
|
|
149
|
+
max_tokens=500
|
|
150
|
+
)
|
|
151
|
+
response = client.chat(request)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Check Result
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
result = client.get_chat(response.chat_id)
|
|
158
|
+
|
|
159
|
+
if result.status == "completed":
|
|
160
|
+
print(result.message)
|
|
161
|
+
elif result.status in ("failed", "timeout"):
|
|
162
|
+
print(f"Error: {result.error}")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Response Status:**
|
|
166
|
+
- `pending`: Request queued
|
|
167
|
+
- `running`: Processing
|
|
168
|
+
- `completed`: Success, check `message`
|
|
169
|
+
- `failed`: Error, check `error`
|
|
170
|
+
- `timeout`: Request timeout
|
|
171
|
+
|
|
172
|
+
## Token Validation
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# Validate any JWT token
|
|
176
|
+
is_valid = client.is_token_valid("eyJhbGci...")
|
|
177
|
+
if is_valid:
|
|
178
|
+
print("Token is valid")
|
|
179
|
+
else:
|
|
180
|
+
print("Token is expired or invalid")
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Configuration
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
client = Client(
|
|
187
|
+
auth_url="https://auth.example.com",
|
|
188
|
+
vlm_url="https://vlm.example.com",
|
|
189
|
+
allowed_issuers=["https://auth.example.com"], # Optional: restrict token issuers
|
|
190
|
+
verify_ssl=True, # SSL verification
|
|
191
|
+
timeout=10.0, # Request timeout in seconds
|
|
192
|
+
max_connections=100, # Connection pool size
|
|
193
|
+
max_keepalive_connections=20 # Keepalive connections
|
|
194
|
+
)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Error Handling
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from visionai_sdk_python import (
|
|
201
|
+
VisionaiSDKError,
|
|
202
|
+
AuthenticationError,
|
|
203
|
+
NetworkError,
|
|
204
|
+
ClientError,
|
|
205
|
+
ServerError
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
client.login("user@example.com", "wrong-password")
|
|
210
|
+
except AuthenticationError as e:
|
|
211
|
+
print(f"Auth failed: {e}")
|
|
212
|
+
except NetworkError as e:
|
|
213
|
+
print(f"Network error: {e}")
|
|
214
|
+
except VisionaiSDKError as e:
|
|
215
|
+
print(f"SDK error: {e}")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Exception Hierarchy:**
|
|
219
|
+
- `VisionaiSDKError`: Base exception
|
|
220
|
+
- `AuthenticationError`: 401 Unauthorized
|
|
221
|
+
- `PermissionDeniedError`: 403 Forbidden
|
|
222
|
+
- `ClientError`: 4xx client errors
|
|
223
|
+
- `ServerError`: 5xx server errors
|
|
224
|
+
- `NetworkError`: Connection/timeout errors
|
|
225
|
+
- `JwksDiscoveryError`: OIDC discovery failures
|
|
226
|
+
|
|
227
|
+
## Context Manager Usage
|
|
228
|
+
|
|
229
|
+
Recommended for automatic resource cleanup:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Sync
|
|
233
|
+
with Client(auth_url="...", vlm_url="...") as client:
|
|
234
|
+
client.login("user@example.com", "password")
|
|
235
|
+
response = client.chat({"img": "...", "prompt": "..."})
|
|
236
|
+
# client.close() called automatically
|
|
237
|
+
|
|
238
|
+
# Async
|
|
239
|
+
async with AsyncClient(auth_url="...", vlm_url="...") as client:
|
|
240
|
+
await client.login("user@example.com", "password")
|
|
241
|
+
response = await client.chat({"img": "...", "prompt": "..."})
|
|
242
|
+
# client.close() called automatically
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Development
|
|
246
|
+
|
|
247
|
+
### Install Dependencies
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# Using uv (recommended)
|
|
251
|
+
uv sync
|
|
252
|
+
|
|
253
|
+
# Or with pip
|
|
254
|
+
pip install -e ".[dev]"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Run Tests
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
pytest
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Requirements
|
|
264
|
+
|
|
265
|
+
- Python >= 3.11
|
|
266
|
+
- httpx >= 0.28.1
|
|
267
|
+
- pydantic >= 2.12.5
|
|
268
|
+
- cryptography >= 46.0.5
|
|
269
|
+
- PyJWT[cryptography] >= 2.8.0
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
## Support
|
|
273
|
+
|
|
274
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# VisionAI SDK for Python
|
|
2
|
+
|
|
3
|
+
Python client library for VisionAI authentication and Vision Language Model (VLM) inference services.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Dual Authentication**: Email/password login or OAuth client credentials
|
|
8
|
+
- **Auto Token Management**: Automatic token refresh before expiration
|
|
9
|
+
- **JWT Validation**: Built-in token signature and expiration verification
|
|
10
|
+
- **VLM Inference**: Submit and poll vision-language model tasks
|
|
11
|
+
- **Async Support**: Full async/await support with `AsyncClient`
|
|
12
|
+
- **Type Safe**: Full type hints with Pydantic validation
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install visionai-sdk-python
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### Synchronous Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from visionai_sdk_python import Client
|
|
26
|
+
|
|
27
|
+
# Initialize client
|
|
28
|
+
client = Client(
|
|
29
|
+
auth_url="https://auth.visionai.example.com",
|
|
30
|
+
vlm_url="https://vlm.visionai.example.com"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Login with email/password
|
|
34
|
+
token = client.login("user@example.com", "your-password")
|
|
35
|
+
|
|
36
|
+
# Submit VLM inference request
|
|
37
|
+
response = client.chat({
|
|
38
|
+
"img": "examplebase64",
|
|
39
|
+
"prompt": "Describe this image",
|
|
40
|
+
"temperature": 0.7,
|
|
41
|
+
"max_tokens": 500
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
print(f"Chat ID: {response.chat_id}")
|
|
45
|
+
print(f"Status: {response.status}")
|
|
46
|
+
|
|
47
|
+
# Poll for results
|
|
48
|
+
result = client.get_chat(response.chat_id)
|
|
49
|
+
if result.status == "completed":
|
|
50
|
+
print(f"Result: {result.message}")
|
|
51
|
+
|
|
52
|
+
# Close client when done
|
|
53
|
+
client.close()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Asynchronous Usage
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
from visionai_sdk_python import AsyncClient
|
|
61
|
+
|
|
62
|
+
async def main():
|
|
63
|
+
async with AsyncClient(
|
|
64
|
+
auth_url="https://auth.visionai.example.com",
|
|
65
|
+
vlm_url="https://vlm.visionai.example.com"
|
|
66
|
+
) as client:
|
|
67
|
+
# OAuth client credentials flow
|
|
68
|
+
await client.get_access_token(
|
|
69
|
+
client_id="your-client-id",
|
|
70
|
+
client_secret="your-client-secret"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Submit inference
|
|
74
|
+
response = await client.chat({
|
|
75
|
+
"img": "examplebase64",
|
|
76
|
+
"prompt": "What objects are in this image?",
|
|
77
|
+
"temperature": 0.2
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
# Poll until completed
|
|
81
|
+
while True:
|
|
82
|
+
result = await client.get_chat(response.chat_id)
|
|
83
|
+
if result.status in ("completed", "failed", "timeout"):
|
|
84
|
+
break
|
|
85
|
+
await asyncio.sleep(1)
|
|
86
|
+
|
|
87
|
+
if result.status == "completed":
|
|
88
|
+
print(f"Answer: {result.message}")
|
|
89
|
+
else:
|
|
90
|
+
print(f"Error: {result.error}")
|
|
91
|
+
|
|
92
|
+
asyncio.run(main())
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Authentication
|
|
96
|
+
|
|
97
|
+
### Email/Password Login
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
client = Client(auth_url="...", vlm_url="...")
|
|
101
|
+
token = client.login("user@example.com", "password")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### OAuth Client Credentials
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
client = Client(auth_url="...", vlm_url="...")
|
|
108
|
+
token = client.get_access_token(
|
|
109
|
+
client_id="your-client-id",
|
|
110
|
+
client_secret="your-client-secret"
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Tokens are stored internally and automatically refreshed before expiration.
|
|
115
|
+
|
|
116
|
+
## VLM Inference
|
|
117
|
+
|
|
118
|
+
### Submit Chat Request
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from visionai_sdk_python.models import NIMRequestModel
|
|
122
|
+
|
|
123
|
+
# Using dict
|
|
124
|
+
response = client.chat({
|
|
125
|
+
"img": "examplebase64",
|
|
126
|
+
"prompt": "Analyze this image",
|
|
127
|
+
"temperature": 0.7,
|
|
128
|
+
"max_tokens": 1000,
|
|
129
|
+
"top_p": 0.9
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
# Using typed model
|
|
133
|
+
request = NIMRequestModel(
|
|
134
|
+
img=["examplebase64"],
|
|
135
|
+
prompt="Compare these images",
|
|
136
|
+
temperature=0.5,
|
|
137
|
+
max_tokens=500
|
|
138
|
+
)
|
|
139
|
+
response = client.chat(request)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Check Result
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
result = client.get_chat(response.chat_id)
|
|
146
|
+
|
|
147
|
+
if result.status == "completed":
|
|
148
|
+
print(result.message)
|
|
149
|
+
elif result.status in ("failed", "timeout"):
|
|
150
|
+
print(f"Error: {result.error}")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Response Status:**
|
|
154
|
+
- `pending`: Request queued
|
|
155
|
+
- `running`: Processing
|
|
156
|
+
- `completed`: Success, check `message`
|
|
157
|
+
- `failed`: Error, check `error`
|
|
158
|
+
- `timeout`: Request timeout
|
|
159
|
+
|
|
160
|
+
## Token Validation
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# Validate any JWT token
|
|
164
|
+
is_valid = client.is_token_valid("eyJhbGci...")
|
|
165
|
+
if is_valid:
|
|
166
|
+
print("Token is valid")
|
|
167
|
+
else:
|
|
168
|
+
print("Token is expired or invalid")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Configuration
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
client = Client(
|
|
175
|
+
auth_url="https://auth.example.com",
|
|
176
|
+
vlm_url="https://vlm.example.com",
|
|
177
|
+
allowed_issuers=["https://auth.example.com"], # Optional: restrict token issuers
|
|
178
|
+
verify_ssl=True, # SSL verification
|
|
179
|
+
timeout=10.0, # Request timeout in seconds
|
|
180
|
+
max_connections=100, # Connection pool size
|
|
181
|
+
max_keepalive_connections=20 # Keepalive connections
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Error Handling
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from visionai_sdk_python import (
|
|
189
|
+
VisionaiSDKError,
|
|
190
|
+
AuthenticationError,
|
|
191
|
+
NetworkError,
|
|
192
|
+
ClientError,
|
|
193
|
+
ServerError
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
client.login("user@example.com", "wrong-password")
|
|
198
|
+
except AuthenticationError as e:
|
|
199
|
+
print(f"Auth failed: {e}")
|
|
200
|
+
except NetworkError as e:
|
|
201
|
+
print(f"Network error: {e}")
|
|
202
|
+
except VisionaiSDKError as e:
|
|
203
|
+
print(f"SDK error: {e}")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Exception Hierarchy:**
|
|
207
|
+
- `VisionaiSDKError`: Base exception
|
|
208
|
+
- `AuthenticationError`: 401 Unauthorized
|
|
209
|
+
- `PermissionDeniedError`: 403 Forbidden
|
|
210
|
+
- `ClientError`: 4xx client errors
|
|
211
|
+
- `ServerError`: 5xx server errors
|
|
212
|
+
- `NetworkError`: Connection/timeout errors
|
|
213
|
+
- `JwksDiscoveryError`: OIDC discovery failures
|
|
214
|
+
|
|
215
|
+
## Context Manager Usage
|
|
216
|
+
|
|
217
|
+
Recommended for automatic resource cleanup:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
# Sync
|
|
221
|
+
with Client(auth_url="...", vlm_url="...") as client:
|
|
222
|
+
client.login("user@example.com", "password")
|
|
223
|
+
response = client.chat({"img": "...", "prompt": "..."})
|
|
224
|
+
# client.close() called automatically
|
|
225
|
+
|
|
226
|
+
# Async
|
|
227
|
+
async with AsyncClient(auth_url="...", vlm_url="...") as client:
|
|
228
|
+
await client.login("user@example.com", "password")
|
|
229
|
+
response = await client.chat({"img": "...", "prompt": "..."})
|
|
230
|
+
# client.close() called automatically
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
### Install Dependencies
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Using uv (recommended)
|
|
239
|
+
uv sync
|
|
240
|
+
|
|
241
|
+
# Or with pip
|
|
242
|
+
pip install -e ".[dev]"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Run Tests
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
pytest
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Requirements
|
|
252
|
+
|
|
253
|
+
- Python >= 3.11
|
|
254
|
+
- httpx >= 0.28.1
|
|
255
|
+
- pydantic >= 2.12.5
|
|
256
|
+
- cryptography >= 46.0.5
|
|
257
|
+
- PyJWT[cryptography] >= 2.8.0
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
## Support
|
|
261
|
+
|
|
262
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "visionai-sdk-python"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
description = "VisionAI SDK for Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -15,8 +15,10 @@ dependencies = [
|
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
[build-system]
|
|
18
|
-
requires = ["
|
|
19
|
-
build-backend = "
|
|
18
|
+
requires = ["setuptools>=64", "setuptools-scm>=8"]
|
|
19
|
+
build-backend = "setuptools.build_meta"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools_scm]
|
|
20
22
|
|
|
21
23
|
[dependency-groups]
|
|
22
24
|
dev = [
|