sensoit 1.2.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.
- sensoit-1.2.0/PKG-INFO +510 -0
- sensoit-1.2.0/README.md +459 -0
- sensoit-1.2.0/sensoit/__init__.py +249 -0
- sensoit-1.2.0/sensoit/cache.py +281 -0
- sensoit-1.2.0/sensoit/client.py +915 -0
- sensoit-1.2.0/sensoit/exceptions.py +274 -0
- sensoit-1.2.0/sensoit/langchain.py +179 -0
- sensoit-1.2.0/sensoit/llamaindex.py +256 -0
- sensoit-1.2.0/sensoit/middleware.py +520 -0
- sensoit-1.2.0/sensoit/resources/__init__.py +19 -0
- sensoit-1.2.0/sensoit/resources/agents.py +173 -0
- sensoit-1.2.0/sensoit/resources/deployments.py +200 -0
- sensoit-1.2.0/sensoit/resources/evals.py +115 -0
- sensoit-1.2.0/sensoit/resources/guardrails.py +309 -0
- sensoit-1.2.0/sensoit/resources/monitoring.py +219 -0
- sensoit-1.2.0/sensoit/resources/prompts.py +175 -0
- sensoit-1.2.0/sensoit/resources/test_cases.py +157 -0
- sensoit-1.2.0/sensoit/types.py +1120 -0
- sensoit-1.2.0/sensoit.egg-info/PKG-INFO +510 -0
- sensoit-1.2.0/sensoit.egg-info/SOURCES.txt +24 -0
- sensoit-1.2.0/sensoit.egg-info/dependency_links.txt +1 -0
- sensoit-1.2.0/sensoit.egg-info/requires.txt +28 -0
- sensoit-1.2.0/sensoit.egg-info/top_level.txt +1 -0
- sensoit-1.2.0/setup.cfg +4 -0
- sensoit-1.2.0/setup.py +90 -0
- sensoit-1.2.0/tests/test_client.py +433 -0
sensoit-1.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: sensoit
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Official Python SDK for Sensoit - AI Prompt Security & Management
|
|
5
|
+
Home-page: https://github.com/sensoit/sensoit-sdk
|
|
6
|
+
Author: Sensoit
|
|
7
|
+
Author-email: support@sensoit.io
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/sensoit/sensoit-sdk/issues
|
|
9
|
+
Project-URL: Documentation, https://docs.sensoit.io
|
|
10
|
+
Project-URL: Homepage, https://sensoit.io
|
|
11
|
+
Project-URL: Source, https://github.com/sensoit/sensoit-sdk/tree/main/python-sdk
|
|
12
|
+
Keywords: sensoit,ai,llm,prompt,security,guardrails,openai,anthropic,gpt,claude,sdk,pii,toxicity,moderation
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Classifier: Framework :: AsyncIO
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
Requires-Dist: httpx>=0.26.0
|
|
29
|
+
Requires-Dist: pydantic>=2.0.0
|
|
30
|
+
Requires-Dist: tenacity>=8.0.0
|
|
31
|
+
Provides-Extra: fastapi
|
|
32
|
+
Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
|
|
33
|
+
Requires-Dist: starlette>=0.27.0; extra == "fastapi"
|
|
34
|
+
Provides-Extra: flask
|
|
35
|
+
Requires-Dist: flask>=2.0.0; extra == "flask"
|
|
36
|
+
Provides-Extra: django
|
|
37
|
+
Requires-Dist: django>=4.0.0; extra == "django"
|
|
38
|
+
Provides-Extra: all
|
|
39
|
+
Requires-Dist: fastapi>=0.100.0; extra == "all"
|
|
40
|
+
Requires-Dist: starlette>=0.27.0; extra == "all"
|
|
41
|
+
Requires-Dist: flask>=2.0.0; extra == "all"
|
|
42
|
+
Requires-Dist: django>=4.0.0; extra == "all"
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
47
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
48
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
49
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
50
|
+
Requires-Dist: respx>=0.20.0; extra == "dev"
|
|
51
|
+
|
|
52
|
+
# Sensoit Python SDK
|
|
53
|
+
|
|
54
|
+
Official Python SDK for [Sensoit](https://sensoit.io) - AI Prompt Security & Management Platform.
|
|
55
|
+
|
|
56
|
+
Sensoit provides enterprise-grade guardrails for AI applications, including PII detection, toxicity filtering, keyword blocking, and custom policy enforcement.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install sensoit-sdk
|
|
62
|
+
|
|
63
|
+
# With framework integrations
|
|
64
|
+
pip install sensoit-sdk[fastapi]
|
|
65
|
+
pip install sensoit-sdk[flask]
|
|
66
|
+
pip install sensoit-sdk[django]
|
|
67
|
+
pip install sensoit-sdk[all] # All frameworks
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### Async Usage
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from sensoit import Sensoit
|
|
76
|
+
|
|
77
|
+
async def main():
|
|
78
|
+
async with Sensoit(api_key="gf_live_xxx") as gf:
|
|
79
|
+
result = await gf.run(
|
|
80
|
+
"customer-support",
|
|
81
|
+
input="I need help with my order #12345",
|
|
82
|
+
variables={"customer_name": "John"},
|
|
83
|
+
session_id="session_abc",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if result.blocked:
|
|
87
|
+
print(f"Blocked: {result.violations}")
|
|
88
|
+
else:
|
|
89
|
+
print(f"Response: {result.output}")
|
|
90
|
+
|
|
91
|
+
import asyncio
|
|
92
|
+
asyncio.run(main())
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Sync Usage
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from sensoit import Sensoit
|
|
99
|
+
|
|
100
|
+
gf = Sensoit(api_key="gf_live_xxx")
|
|
101
|
+
|
|
102
|
+
result = gf.run_sync(
|
|
103
|
+
"customer-support",
|
|
104
|
+
input="I need help with my order #12345",
|
|
105
|
+
variables={"customer_name": "John"},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
print(f"Response: {result.output}")
|
|
109
|
+
print(f"Tokens: {result.tokens_used}")
|
|
110
|
+
print(f"Cost: ${result.cost_usd}")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Configuration
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
gf = Sensoit(
|
|
117
|
+
# Required: Your API key
|
|
118
|
+
api_key="gf_live_xxx",
|
|
119
|
+
|
|
120
|
+
# Optional: API base URL (default: https://api.sensoit.io)
|
|
121
|
+
base_url="https://api.sensoit.io",
|
|
122
|
+
|
|
123
|
+
# Optional: Request timeout in seconds (default: 30.0)
|
|
124
|
+
timeout=30.0,
|
|
125
|
+
|
|
126
|
+
# Optional: Max retry attempts (default: 3)
|
|
127
|
+
max_retries=3,
|
|
128
|
+
|
|
129
|
+
# Optional: Enable debug logging (default: False)
|
|
130
|
+
debug=True,
|
|
131
|
+
|
|
132
|
+
# Optional: Enable caching (default: True)
|
|
133
|
+
cache_enabled=True,
|
|
134
|
+
|
|
135
|
+
# Optional: Cache TTL in seconds (default: 60)
|
|
136
|
+
cache_ttl_seconds=60,
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Option | Type | Default | Description |
|
|
141
|
+
|--------|------|---------|-------------|
|
|
142
|
+
| `api_key` | `str` | *required* | Your Sensoit API key |
|
|
143
|
+
| `base_url` | `str` | `https://api.sensoit.io` | API base URL |
|
|
144
|
+
| `timeout` | `float` | `30.0` | Request timeout in seconds |
|
|
145
|
+
| `max_retries` | `int` | `3` | Max retry attempts |
|
|
146
|
+
| `debug` | `bool` | `False` | Enable debug logging |
|
|
147
|
+
| `cache_enabled` | `bool` | `True` | Enable prompt caching |
|
|
148
|
+
| `cache_ttl_seconds` | `int` | `60` | Cache TTL in seconds |
|
|
149
|
+
|
|
150
|
+
## Core Methods
|
|
151
|
+
|
|
152
|
+
### `run()` / `run_sync()`
|
|
153
|
+
|
|
154
|
+
Run a prompt through Sensoit with guardrail protection.
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Async
|
|
158
|
+
result = await gf.run(
|
|
159
|
+
"support-assistant",
|
|
160
|
+
input="I need help with my order",
|
|
161
|
+
variables={"customer_name": "John"},
|
|
162
|
+
session_id="session_123",
|
|
163
|
+
force_refresh=False,
|
|
164
|
+
dry_run=False,
|
|
165
|
+
timeout=60.0,
|
|
166
|
+
metadata={"source": "web"},
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Sync
|
|
170
|
+
result = gf.run_sync("support-assistant", input="Hello")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Return Type: `RunResult`**
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
@dataclass
|
|
177
|
+
class RunResult:
|
|
178
|
+
output: str # Generated response
|
|
179
|
+
allowed: bool # Request passed guardrails
|
|
180
|
+
blocked: bool # Request was blocked
|
|
181
|
+
escalated: bool # Request needs human review
|
|
182
|
+
violations: list # Policy violations
|
|
183
|
+
tokens_used: int # Total tokens (in + out)
|
|
184
|
+
tokens_in: int # Input tokens
|
|
185
|
+
tokens_out: int # Output tokens
|
|
186
|
+
latency_ms: int # Total latency
|
|
187
|
+
cost_usd: float # Estimated cost
|
|
188
|
+
prompt_version: int # Prompt version used
|
|
189
|
+
model: str # LLM model used
|
|
190
|
+
provider: str # LLM provider
|
|
191
|
+
cached: bool # Served from cache
|
|
192
|
+
request_id: str # Unique request ID
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `run_batch()` / `run_batch_sync()`
|
|
196
|
+
|
|
197
|
+
Run multiple prompts in parallel.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# Async
|
|
201
|
+
batch_result = await gf.run_batch([
|
|
202
|
+
{"prompt": "translator", "options": {"input": "Hello", "variables": {"lang": "es"}}},
|
|
203
|
+
{"prompt": "translator", "options": {"input": "Goodbye", "variables": {"lang": "fr"}}},
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
# Sync
|
|
207
|
+
batch_result = gf.run_batch_sync([...])
|
|
208
|
+
|
|
209
|
+
print(f"Total: {batch_result.summary.total}")
|
|
210
|
+
print(f"Allowed: {batch_result.summary.allowed}")
|
|
211
|
+
print(f"Blocked: {batch_result.summary.blocked}")
|
|
212
|
+
|
|
213
|
+
for result in batch_result.results:
|
|
214
|
+
print(f"{result.prompt}: {result.output}")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `invalidate_cache()`
|
|
218
|
+
|
|
219
|
+
Clear cached prompt data.
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
# Clear cache for specific prompt
|
|
223
|
+
gf.invalidate_cache("support-assistant")
|
|
224
|
+
|
|
225
|
+
# Clear all cache
|
|
226
|
+
gf.invalidate_cache()
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## FastAPI Integration
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
from fastapi import FastAPI, Request
|
|
233
|
+
from sensoit import Sensoit
|
|
234
|
+
from sensoit.middleware import SensoitMiddleware
|
|
235
|
+
|
|
236
|
+
app = FastAPI()
|
|
237
|
+
gf = Sensoit(api_key="gf_live_xxx")
|
|
238
|
+
|
|
239
|
+
# Add middleware to protect routes
|
|
240
|
+
app.add_middleware(
|
|
241
|
+
SensoitMiddleware,
|
|
242
|
+
client=gf,
|
|
243
|
+
prompt="support-bot",
|
|
244
|
+
protected_paths=["/api/chat", "/api/ask"],
|
|
245
|
+
blocked_response={"error": "Cannot help with that request"},
|
|
246
|
+
blocked_status_code=200,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
@app.post("/api/chat")
|
|
250
|
+
async def chat(request: Request):
|
|
251
|
+
# Access Sensoit result
|
|
252
|
+
result = request.scope.get("sensoit")
|
|
253
|
+
return {"reply": result.output if result else "No response"}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Flask Integration
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from flask import Flask, request, jsonify
|
|
260
|
+
from sensoit import Sensoit
|
|
261
|
+
from sensoit.middleware import flask_protect
|
|
262
|
+
|
|
263
|
+
app = Flask(__name__)
|
|
264
|
+
gf = Sensoit(api_key="gf_live_xxx")
|
|
265
|
+
|
|
266
|
+
@app.route("/chat", methods=["POST"])
|
|
267
|
+
@flask_protect(gf, prompt="support-bot")
|
|
268
|
+
def chat():
|
|
269
|
+
# Access Sensoit result
|
|
270
|
+
result = request.sensoit
|
|
271
|
+
return jsonify({"reply": result.output})
|
|
272
|
+
|
|
273
|
+
# With custom options
|
|
274
|
+
@app.route("/ask", methods=["POST"])
|
|
275
|
+
@flask_protect(
|
|
276
|
+
gf,
|
|
277
|
+
prompt="qa-bot",
|
|
278
|
+
extract_input=lambda: request.json.get("question"),
|
|
279
|
+
extract_variables=lambda: {"user_id": request.json.get("user_id")},
|
|
280
|
+
blocked_response={"error": "Question not allowed"},
|
|
281
|
+
)
|
|
282
|
+
def ask():
|
|
283
|
+
return jsonify({"answer": request.sensoit.output})
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Django Integration
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
# settings.py
|
|
290
|
+
MIDDLEWARE = [
|
|
291
|
+
# ... other middleware
|
|
292
|
+
'sensoit.middleware.DjangoSensoitMiddleware',
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
SENSOIT = {
|
|
296
|
+
'API_KEY': 'gf_live_xxx',
|
|
297
|
+
'PROMPT': 'support-bot',
|
|
298
|
+
'PROTECTED_PATHS': ['/api/chat/', '/api/ask/'],
|
|
299
|
+
'BASE_URL': 'https://api.sensoit.io', # Optional
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# views.py
|
|
303
|
+
from django.http import JsonResponse
|
|
304
|
+
|
|
305
|
+
def chat(request):
|
|
306
|
+
# Access Sensoit result
|
|
307
|
+
result = getattr(request, "sensoit", None)
|
|
308
|
+
if result:
|
|
309
|
+
return JsonResponse({"reply": result.output})
|
|
310
|
+
return JsonResponse({"error": "No response"})
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Error Handling
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
from sensoit import (
|
|
317
|
+
Sensoit,
|
|
318
|
+
BlockedError,
|
|
319
|
+
EscalatedError,
|
|
320
|
+
RateLimitError,
|
|
321
|
+
AuthError,
|
|
322
|
+
TimeoutError,
|
|
323
|
+
ValidationError,
|
|
324
|
+
is_retryable_error,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
gf = Sensoit(api_key="gf_live_xxx")
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
result = await gf.run("my-prompt", input="Hello")
|
|
331
|
+
print(result.output)
|
|
332
|
+
|
|
333
|
+
except BlockedError as e:
|
|
334
|
+
print(f"Blocked by: {[v['policyName'] for v in e.violations]}")
|
|
335
|
+
print(f"Has critical: {e.has_critical_violation()}")
|
|
336
|
+
|
|
337
|
+
except EscalatedError as e:
|
|
338
|
+
print(f"Escalated: {e.reason}")
|
|
339
|
+
|
|
340
|
+
except RateLimitError as e:
|
|
341
|
+
print(f"Rate limited, retry after: {e.retry_after_seconds}s")
|
|
342
|
+
|
|
343
|
+
except AuthError as e:
|
|
344
|
+
print(f"Auth error: {e.message}")
|
|
345
|
+
|
|
346
|
+
except TimeoutError as e:
|
|
347
|
+
print(f"Timed out after: {e.timeout_seconds}s")
|
|
348
|
+
|
|
349
|
+
except ValidationError as e:
|
|
350
|
+
print(f"Validation errors: {e.field_errors}")
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Error Classes
|
|
354
|
+
|
|
355
|
+
| Error | Code | Status | Description |
|
|
356
|
+
|-------|------|--------|-------------|
|
|
357
|
+
| `BlockedError` | `BLOCKED` | 200 | Response blocked by guardrails |
|
|
358
|
+
| `EscalatedError` | `ESCALATED` | 200 | Response needs human review |
|
|
359
|
+
| `RateLimitError` | `RATE_LIMIT` | 429 | Rate limit exceeded |
|
|
360
|
+
| `AuthError` | `AUTH_ERROR` | 401 | Invalid API key |
|
|
361
|
+
| `TimeoutError` | `TIMEOUT` | - | Request timed out |
|
|
362
|
+
| `ValidationError` | `VALIDATION_ERROR` | 400 | Invalid input |
|
|
363
|
+
| `PromptNotFoundError` | `PROMPT_NOT_FOUND` | 404 | Prompt doesn't exist |
|
|
364
|
+
| `NetworkError` | `NETWORK_ERROR` | - | Network failure |
|
|
365
|
+
| `SensoitAPIError` | `API_ERROR` | varies | General API error |
|
|
366
|
+
|
|
367
|
+
## Event Callbacks
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
gf = Sensoit(api_key="gf_live_xxx")
|
|
371
|
+
|
|
372
|
+
# Register event handlers
|
|
373
|
+
@gf.on_blocked
|
|
374
|
+
def handle_blocked(prompt_name, violations, request_id):
|
|
375
|
+
print(f"Blocked: {prompt_name}")
|
|
376
|
+
for v in violations:
|
|
377
|
+
print(f" - {v['policyName']}: {v['detail']}")
|
|
378
|
+
|
|
379
|
+
@gf.on_escalated
|
|
380
|
+
def handle_escalated(prompt_name, request_id, reason):
|
|
381
|
+
print(f"Escalated: {prompt_name} - {reason}")
|
|
382
|
+
|
|
383
|
+
@gf.on_error
|
|
384
|
+
def handle_error(prompt_name, error, request_id):
|
|
385
|
+
print(f"Error in {prompt_name}: {error}")
|
|
386
|
+
|
|
387
|
+
@gf.on_complete
|
|
388
|
+
def handle_complete(prompt_name, result):
|
|
389
|
+
print(f"Completed: {prompt_name}")
|
|
390
|
+
print(f" Tokens: {result.tokens_used}")
|
|
391
|
+
print(f" Cost: ${result.cost_usd}")
|
|
392
|
+
|
|
393
|
+
@gf.on_retry
|
|
394
|
+
def handle_retry(prompt_name, attempt, max_attempts):
|
|
395
|
+
print(f"Retry {attempt}/{max_attempts} for {prompt_name}")
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Type Hints
|
|
399
|
+
|
|
400
|
+
All types are exported for type checking:
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
from sensoit import (
|
|
404
|
+
# Configuration
|
|
405
|
+
SensoitConfig,
|
|
406
|
+
CacheConfig,
|
|
407
|
+
|
|
408
|
+
# Run operations
|
|
409
|
+
RunOptions,
|
|
410
|
+
RunResult,
|
|
411
|
+
|
|
412
|
+
# Batch operations
|
|
413
|
+
BatchRunInput,
|
|
414
|
+
BatchRunResult,
|
|
415
|
+
BatchRunItemResult,
|
|
416
|
+
BatchRunSummary,
|
|
417
|
+
|
|
418
|
+
# Guardrails
|
|
419
|
+
GuardrailViolation,
|
|
420
|
+
GuardrailViolationType,
|
|
421
|
+
ViolationSeverity,
|
|
422
|
+
ViolationAction,
|
|
423
|
+
)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Caching
|
|
427
|
+
|
|
428
|
+
The SDK includes built-in caching for prompt responses:
|
|
429
|
+
|
|
430
|
+
```python
|
|
431
|
+
gf = Sensoit(
|
|
432
|
+
api_key="gf_live_xxx",
|
|
433
|
+
cache_enabled=True,
|
|
434
|
+
cache_ttl_seconds=60,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
# First call - makes API request
|
|
438
|
+
result1 = await gf.run("prompt", input="Hello")
|
|
439
|
+
print(result1.cached) # False
|
|
440
|
+
|
|
441
|
+
# Second call - served from cache
|
|
442
|
+
result2 = await gf.run("prompt", input="Hello")
|
|
443
|
+
print(result2.cached) # True
|
|
444
|
+
|
|
445
|
+
# Force fresh request
|
|
446
|
+
result3 = await gf.run("prompt", input="Hello", force_refresh=True)
|
|
447
|
+
print(result3.cached) # False
|
|
448
|
+
|
|
449
|
+
# Invalidate cache
|
|
450
|
+
gf.invalidate_cache("prompt")
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Health Check
|
|
454
|
+
|
|
455
|
+
```python
|
|
456
|
+
# Async
|
|
457
|
+
health = await gf.health()
|
|
458
|
+
|
|
459
|
+
# Sync
|
|
460
|
+
health = gf.health_sync()
|
|
461
|
+
|
|
462
|
+
print(health)
|
|
463
|
+
# {'status': 'ok', 'service': 'sensoit', 'timestamp': '...'}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## Context Manager
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
# Async
|
|
470
|
+
async with Sensoit(api_key="gf_live_xxx") as gf:
|
|
471
|
+
result = await gf.run("prompt", input="Hello")
|
|
472
|
+
|
|
473
|
+
# Sync
|
|
474
|
+
with Sensoit(api_key="gf_live_xxx") as gf:
|
|
475
|
+
result = gf.run_sync("prompt", input="Hello")
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Environment Variables
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
export SENSOIT_API_KEY=gf_live_xxx
|
|
482
|
+
export SENSOIT_BASE_URL=https://api.sensoit.io
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
```python
|
|
486
|
+
import os
|
|
487
|
+
from sensoit import Sensoit
|
|
488
|
+
|
|
489
|
+
gf = Sensoit(
|
|
490
|
+
api_key=os.environ["SENSOIT_API_KEY"],
|
|
491
|
+
base_url=os.environ.get("SENSOIT_BASE_URL", "https://api.sensoit.io"),
|
|
492
|
+
)
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## Requirements
|
|
496
|
+
|
|
497
|
+
- Python 3.9 or higher
|
|
498
|
+
- httpx >= 0.26.0
|
|
499
|
+
- pydantic >= 2.0.0
|
|
500
|
+
- tenacity >= 8.0.0
|
|
501
|
+
|
|
502
|
+
## License
|
|
503
|
+
|
|
504
|
+
MIT
|
|
505
|
+
|
|
506
|
+
## Support
|
|
507
|
+
|
|
508
|
+
- Documentation: [https://docs.sensoit.io](https://docs.sensoit.io)
|
|
509
|
+
- Issues: [https://github.com/sensoit/sensoit-sdk/issues](https://github.com/sensoit/sensoit-sdk/issues)
|
|
510
|
+
- Email: support@sensoit.io
|