lawsaathi 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.
- lawsaathi-1.0.0/LICENSE +21 -0
- lawsaathi-1.0.0/MANIFEST.in +4 -0
- lawsaathi-1.0.0/PKG-INFO +174 -0
- lawsaathi-1.0.0/README.md +129 -0
- lawsaathi-1.0.0/lawsaathi/__init__.py +40 -0
- lawsaathi-1.0.0/lawsaathi/client.py +390 -0
- lawsaathi-1.0.0/lawsaathi/exceptions.py +33 -0
- lawsaathi-1.0.0/lawsaathi.egg-info/PKG-INFO +174 -0
- lawsaathi-1.0.0/lawsaathi.egg-info/SOURCES.txt +13 -0
- lawsaathi-1.0.0/lawsaathi.egg-info/dependency_links.txt +1 -0
- lawsaathi-1.0.0/lawsaathi.egg-info/requires.txt +12 -0
- lawsaathi-1.0.0/lawsaathi.egg-info/top_level.txt +1 -0
- lawsaathi-1.0.0/pyproject.toml +57 -0
- lawsaathi-1.0.0/setup.cfg +4 -0
- lawsaathi-1.0.0/setup.py +41 -0
lawsaathi-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LawSaathi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lawsaathi-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lawsaathi
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for LawSaathi Legal AI API — DELTA
|
|
5
|
+
Home-page: https://github.com/lawsaathi/lawsaathi-python-sdk
|
|
6
|
+
Author: LawSaathi
|
|
7
|
+
Author-email: LawSaathi <support@lawsaathi.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://lawsaathi.com
|
|
10
|
+
Project-URL: Documentation, https://lawsaathi.com/docs
|
|
11
|
+
Project-URL: Repository, https://github.com/lawsaathi/lawsaathi-python-sdk
|
|
12
|
+
Project-URL: Dashboard, https://lawsaathi.com/developer
|
|
13
|
+
Project-URL: Bug Tracker, https://github.com/lawsaathi/lawsaathi-python-sdk/issues
|
|
14
|
+
Keywords: lawsaathi,legal-ai,indian-law,ipc,crpc,delta,ai-sdk,legal-tech,chatbot,api-client
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Operating System :: OS Independent
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: requests>=2.25.0
|
|
32
|
+
Provides-Extra: websocket
|
|
33
|
+
Requires-Dist: websocket-client>=1.0.0; extra == "websocket"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
37
|
+
Requires-Dist: black>=21.0; extra == "dev"
|
|
38
|
+
Requires-Dist: flake8>=3.9; extra == "dev"
|
|
39
|
+
Requires-Dist: build; extra == "dev"
|
|
40
|
+
Requires-Dist: twine; extra == "dev"
|
|
41
|
+
Dynamic: author
|
|
42
|
+
Dynamic: home-page
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: requires-python
|
|
45
|
+
|
|
46
|
+
# LawSaathi Python SDK
|
|
47
|
+
|
|
48
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
49
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
50
|
+
[](https://opensource.org/licenses/MIT)
|
|
51
|
+
|
|
52
|
+
Official Python client for the **LawSaathi Legal AI API** — powered by **DELTA**, India's most advanced Legal AI.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install lawsaathi
|
|
58
|
+
|
|
59
|
+
# With WebSocket streaming support:
|
|
60
|
+
pip install lawsaathi[websocket]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from lawsaathi import LawSaathi
|
|
67
|
+
|
|
68
|
+
client = LawSaathi(api_key="ls_live_your_api_key_here")
|
|
69
|
+
|
|
70
|
+
# Ask any legal question
|
|
71
|
+
response = client.chat("What is IPC Section 302?")
|
|
72
|
+
print(response['response'])
|
|
73
|
+
print(f"Tokens used: {response['usage']['total_tokens']}")
|
|
74
|
+
print(f"Cost: ₹{response['usage']['cost_rupees']}")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## File Attachments (OpenAI-style)
|
|
78
|
+
|
|
79
|
+
Attach files to your queries — just pass file paths. The SDK handles uploading automatically.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# Analyze a contract — just pass the file path!
|
|
83
|
+
response = client.chat(
|
|
84
|
+
"Summarize the key clauses in this contract",
|
|
85
|
+
files=["contract.pdf"]
|
|
86
|
+
)
|
|
87
|
+
print(response['response'])
|
|
88
|
+
|
|
89
|
+
# Multiple files work too
|
|
90
|
+
response = client.chat(
|
|
91
|
+
"Compare these two agreements",
|
|
92
|
+
files=["agreement_v1.pdf", "agreement_v2.pdf"]
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Streaming (WebSocket)
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# Requires: pip install lawsaathi[websocket]
|
|
100
|
+
for chunk in client.stream("Explain bail provisions under CrPC"):
|
|
101
|
+
print(chunk, end="", flush=True)
|
|
102
|
+
|
|
103
|
+
# Streaming with files
|
|
104
|
+
for chunk in client.stream("Analyze this document", files=["contract.pdf"]):
|
|
105
|
+
print(chunk, end="", flush=True)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Check Balance
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
balance = client.get_balance()
|
|
112
|
+
print(f"Balance: ₹{balance['balance_rupees']}")
|
|
113
|
+
print(f"Tokens available: {balance['tokens_available']:,}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Error Handling
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from lawsaathi import (
|
|
120
|
+
LawSaathi,
|
|
121
|
+
AuthenticationError,
|
|
122
|
+
RateLimitError,
|
|
123
|
+
InsufficientCreditsError,
|
|
124
|
+
APIError,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
client = LawSaathi(api_key="ls_live_your_key")
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
response = client.chat("Hello")
|
|
131
|
+
except AuthenticationError:
|
|
132
|
+
print("Invalid API key — check or regenerate it")
|
|
133
|
+
except InsufficientCreditsError as e:
|
|
134
|
+
print(f"Not enough credits. Balance: ₹{e.balance_rupees}")
|
|
135
|
+
except RateLimitError as e:
|
|
136
|
+
print(f"Rate limited. Retry after: {e.retry_after}s")
|
|
137
|
+
except APIError as e:
|
|
138
|
+
print(f"API error ({e.status_code}): {e}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Pricing
|
|
142
|
+
|
|
143
|
+
| | |
|
|
144
|
+
|---|---|
|
|
145
|
+
| **Cost per 1M tokens** | ₹998 |
|
|
146
|
+
| **Free credits on signup** | ₹100 |
|
|
147
|
+
| **Minimum topup** | ₹999 |
|
|
148
|
+
| **Credit expiry** | 150 days |
|
|
149
|
+
|
|
150
|
+
## Rate Limits
|
|
151
|
+
|
|
152
|
+
| Limit | Default |
|
|
153
|
+
|-------|---------|
|
|
154
|
+
| Requests/minute | 5 |
|
|
155
|
+
| Requests/day | 2,500 |
|
|
156
|
+
| Max file size | 100 MB |
|
|
157
|
+
|
|
158
|
+
Need higher limits? Contact support@lawsaathi.com.
|
|
159
|
+
|
|
160
|
+
## Requirements
|
|
161
|
+
|
|
162
|
+
- Python 3.8+
|
|
163
|
+
- `requests` library (installed automatically)
|
|
164
|
+
- `websocket-client` (optional, for streaming)
|
|
165
|
+
|
|
166
|
+
## Links
|
|
167
|
+
|
|
168
|
+
- **Dashboard**: [lawsaathi.com/developer](https://lawsaathi.com/developer)
|
|
169
|
+
- **API Docs**: [lawsaathi.com/docs](https://lawsaathi.com/docs)
|
|
170
|
+
- **Support**: support@lawsaathi.com
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# LawSaathi Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
4
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Official Python client for the **LawSaathi Legal AI API** — powered by **DELTA**, India's most advanced Legal AI.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install lawsaathi
|
|
13
|
+
|
|
14
|
+
# With WebSocket streaming support:
|
|
15
|
+
pip install lawsaathi[websocket]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from lawsaathi import LawSaathi
|
|
22
|
+
|
|
23
|
+
client = LawSaathi(api_key="ls_live_your_api_key_here")
|
|
24
|
+
|
|
25
|
+
# Ask any legal question
|
|
26
|
+
response = client.chat("What is IPC Section 302?")
|
|
27
|
+
print(response['response'])
|
|
28
|
+
print(f"Tokens used: {response['usage']['total_tokens']}")
|
|
29
|
+
print(f"Cost: ₹{response['usage']['cost_rupees']}")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## File Attachments (OpenAI-style)
|
|
33
|
+
|
|
34
|
+
Attach files to your queries — just pass file paths. The SDK handles uploading automatically.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
# Analyze a contract — just pass the file path!
|
|
38
|
+
response = client.chat(
|
|
39
|
+
"Summarize the key clauses in this contract",
|
|
40
|
+
files=["contract.pdf"]
|
|
41
|
+
)
|
|
42
|
+
print(response['response'])
|
|
43
|
+
|
|
44
|
+
# Multiple files work too
|
|
45
|
+
response = client.chat(
|
|
46
|
+
"Compare these two agreements",
|
|
47
|
+
files=["agreement_v1.pdf", "agreement_v2.pdf"]
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Streaming (WebSocket)
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# Requires: pip install lawsaathi[websocket]
|
|
55
|
+
for chunk in client.stream("Explain bail provisions under CrPC"):
|
|
56
|
+
print(chunk, end="", flush=True)
|
|
57
|
+
|
|
58
|
+
# Streaming with files
|
|
59
|
+
for chunk in client.stream("Analyze this document", files=["contract.pdf"]):
|
|
60
|
+
print(chunk, end="", flush=True)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Check Balance
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
balance = client.get_balance()
|
|
67
|
+
print(f"Balance: ₹{balance['balance_rupees']}")
|
|
68
|
+
print(f"Tokens available: {balance['tokens_available']:,}")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Error Handling
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from lawsaathi import (
|
|
75
|
+
LawSaathi,
|
|
76
|
+
AuthenticationError,
|
|
77
|
+
RateLimitError,
|
|
78
|
+
InsufficientCreditsError,
|
|
79
|
+
APIError,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
client = LawSaathi(api_key="ls_live_your_key")
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
response = client.chat("Hello")
|
|
86
|
+
except AuthenticationError:
|
|
87
|
+
print("Invalid API key — check or regenerate it")
|
|
88
|
+
except InsufficientCreditsError as e:
|
|
89
|
+
print(f"Not enough credits. Balance: ₹{e.balance_rupees}")
|
|
90
|
+
except RateLimitError as e:
|
|
91
|
+
print(f"Rate limited. Retry after: {e.retry_after}s")
|
|
92
|
+
except APIError as e:
|
|
93
|
+
print(f"API error ({e.status_code}): {e}")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Pricing
|
|
97
|
+
|
|
98
|
+
| | |
|
|
99
|
+
|---|---|
|
|
100
|
+
| **Cost per 1M tokens** | ₹998 |
|
|
101
|
+
| **Free credits on signup** | ₹100 |
|
|
102
|
+
| **Minimum topup** | ₹999 |
|
|
103
|
+
| **Credit expiry** | 150 days |
|
|
104
|
+
|
|
105
|
+
## Rate Limits
|
|
106
|
+
|
|
107
|
+
| Limit | Default |
|
|
108
|
+
|-------|---------|
|
|
109
|
+
| Requests/minute | 5 |
|
|
110
|
+
| Requests/day | 2,500 |
|
|
111
|
+
| Max file size | 100 MB |
|
|
112
|
+
|
|
113
|
+
Need higher limits? Contact support@lawsaathi.com.
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
- Python 3.8+
|
|
118
|
+
- `requests` library (installed automatically)
|
|
119
|
+
- `websocket-client` (optional, for streaming)
|
|
120
|
+
|
|
121
|
+
## Links
|
|
122
|
+
|
|
123
|
+
- **Dashboard**: [lawsaathi.com/developer](https://lawsaathi.com/developer)
|
|
124
|
+
- **API Docs**: [lawsaathi.com/docs](https://lawsaathi.com/docs)
|
|
125
|
+
- **Support**: support@lawsaathi.com
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# LawSaathi Python SDK
|
|
2
|
+
"""
|
|
3
|
+
Official Python SDK for LawSaathi Legal AI API.
|
|
4
|
+
|
|
5
|
+
Quick Start:
|
|
6
|
+
from lawsaathi import LawSaathi
|
|
7
|
+
|
|
8
|
+
client = LawSaathi(api_key="ls_live_xxxxx")
|
|
9
|
+
|
|
10
|
+
# Non-streaming (HTTP)
|
|
11
|
+
response = client.chat("What is IPC Section 302?")
|
|
12
|
+
print(response['response'])
|
|
13
|
+
|
|
14
|
+
# Streaming (WebSocket)
|
|
15
|
+
for chunk in client.stream("Explain bail under CrPC"):
|
|
16
|
+
print(chunk, end="", flush=True)
|
|
17
|
+
|
|
18
|
+
# Check balance
|
|
19
|
+
balance = client.get_balance()
|
|
20
|
+
print(f"₹{balance['balance_rupees']}")
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from .client import LawSaathi
|
|
24
|
+
from .exceptions import (
|
|
25
|
+
LawSaathiError,
|
|
26
|
+
AuthenticationError,
|
|
27
|
+
RateLimitError,
|
|
28
|
+
InsufficientCreditsError,
|
|
29
|
+
APIError,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
__version__ = "1.0.0"
|
|
33
|
+
__all__ = [
|
|
34
|
+
"LawSaathi",
|
|
35
|
+
"LawSaathiError",
|
|
36
|
+
"AuthenticationError",
|
|
37
|
+
"RateLimitError",
|
|
38
|
+
"InsufficientCreditsError",
|
|
39
|
+
"APIError",
|
|
40
|
+
]
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LawSaathi Python SDK — Main Client
|
|
3
|
+
====================================
|
|
4
|
+
Supports both non-streaming (HTTP) and streaming (WebSocket) modes.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from lawsaathi import LawSaathi
|
|
8
|
+
|
|
9
|
+
client = LawSaathi(api_key="ls_live_xxxxx")
|
|
10
|
+
|
|
11
|
+
# Non-streaming (HTTP POST)
|
|
12
|
+
response = client.chat("What is IPC Section 302?")
|
|
13
|
+
print(response['response'])
|
|
14
|
+
|
|
15
|
+
# Chat with file attachments (just pass file paths — like OpenAI)
|
|
16
|
+
response = client.chat(
|
|
17
|
+
"Summarize this contract",
|
|
18
|
+
files=["contract.pdf", "annexure.pdf"]
|
|
19
|
+
)
|
|
20
|
+
print(response['response'])
|
|
21
|
+
|
|
22
|
+
# Streaming (WebSocket)
|
|
23
|
+
for chunk in client.stream("Explain bail under CrPC"):
|
|
24
|
+
print(chunk, end="", flush=True)
|
|
25
|
+
|
|
26
|
+
# Check balance
|
|
27
|
+
print(client.get_balance())
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
import json
|
|
31
|
+
import time
|
|
32
|
+
import threading
|
|
33
|
+
import logging
|
|
34
|
+
from typing import Optional, List, Dict, Any, Generator
|
|
35
|
+
from urllib.parse import urljoin
|
|
36
|
+
|
|
37
|
+
import requests
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
import websocket as ws_lib # websocket-client
|
|
41
|
+
HAS_WEBSOCKET = True
|
|
42
|
+
except ImportError:
|
|
43
|
+
HAS_WEBSOCKET = False
|
|
44
|
+
|
|
45
|
+
from .exceptions import (
|
|
46
|
+
LawSaathiError,
|
|
47
|
+
AuthenticationError,
|
|
48
|
+
RateLimitError,
|
|
49
|
+
InsufficientCreditsError,
|
|
50
|
+
APIError,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__version__ = "1.0.0"
|
|
54
|
+
logger = logging.getLogger("lawsaathi")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class LawSaathi:
|
|
58
|
+
"""
|
|
59
|
+
Official LawSaathi Python SDK client.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
api_key: Your API key (starts with 'ls_live_').
|
|
63
|
+
base_url: Base HTTP URL (default: https://api.lawsaathi.com).
|
|
64
|
+
ws_url: Base WebSocket URL (default: wss://api.lawsaathi.com).
|
|
65
|
+
timeout: HTTP request timeout in seconds (default: 120).
|
|
66
|
+
max_retries: Max retries on transient failures (default: 2).
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
api_key: str,
|
|
72
|
+
base_url: str = "https://api.lawsaathi.com",
|
|
73
|
+
ws_url: str = "wss://api.lawsaathi.com",
|
|
74
|
+
timeout: int = 120,
|
|
75
|
+
max_retries: int = 2,
|
|
76
|
+
):
|
|
77
|
+
if not api_key or not api_key.startswith("ls_live_"):
|
|
78
|
+
raise ValueError("Invalid API key. Must start with 'ls_live_'.")
|
|
79
|
+
|
|
80
|
+
self.api_key = api_key
|
|
81
|
+
self.base_url = base_url.rstrip("/")
|
|
82
|
+
self.ws_url = ws_url.rstrip("/")
|
|
83
|
+
self.timeout = timeout
|
|
84
|
+
self.max_retries = max_retries
|
|
85
|
+
|
|
86
|
+
self._session = requests.Session()
|
|
87
|
+
self._session.headers.update({
|
|
88
|
+
"X-API-Key": api_key,
|
|
89
|
+
"Content-Type": "application/json",
|
|
90
|
+
"User-Agent": f"LawSaathi-Python-SDK/{__version__}",
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
# =========================================================================
|
|
94
|
+
# Non-Streaming Chat (HTTP POST)
|
|
95
|
+
# =========================================================================
|
|
96
|
+
|
|
97
|
+
def chat(
|
|
98
|
+
self,
|
|
99
|
+
message: str,
|
|
100
|
+
files: Optional[List[str]] = None,
|
|
101
|
+
file_uris: Optional[List[str]] = None,
|
|
102
|
+
session_id: Optional[str] = None,
|
|
103
|
+
) -> Dict[str, Any]:
|
|
104
|
+
"""
|
|
105
|
+
Send a message to DELTA and get a complete response (non-streaming).
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
message: Your question or prompt.
|
|
109
|
+
files: Optional list of file paths to attach (PDF, DOCX, TXT, JPG, PNG).
|
|
110
|
+
Files are uploaded automatically — you never need to manage URIs.
|
|
111
|
+
file_uris: Optional list of pre-uploaded GCS URIs (advanced use only).
|
|
112
|
+
session_id: Optional session ID for conversation continuity.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dict with 'response', 'usage', 'response_time_ms', 'balance_remaining_rupees'.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
# Simple query
|
|
119
|
+
response = client.chat("What is IPC Section 302?")
|
|
120
|
+
|
|
121
|
+
# With file attachments (just pass paths!)
|
|
122
|
+
response = client.chat(
|
|
123
|
+
"Summarize this contract",
|
|
124
|
+
files=["contract.pdf"]
|
|
125
|
+
)
|
|
126
|
+
"""
|
|
127
|
+
# Auto-upload files if provided
|
|
128
|
+
all_uris = list(file_uris or [])
|
|
129
|
+
if files:
|
|
130
|
+
for file_path in files:
|
|
131
|
+
upload_result = self.upload_file(file_path)
|
|
132
|
+
all_uris.append(upload_result['file_ref'])
|
|
133
|
+
|
|
134
|
+
payload = {"message": message}
|
|
135
|
+
if all_uris:
|
|
136
|
+
payload["file_uris"] = all_uris
|
|
137
|
+
if session_id:
|
|
138
|
+
payload["session_id"] = session_id
|
|
139
|
+
|
|
140
|
+
return self._request("POST", "/api/sdk/chat/", json=payload)
|
|
141
|
+
|
|
142
|
+
# =========================================================================
|
|
143
|
+
# Streaming Chat (WebSocket)
|
|
144
|
+
# =========================================================================
|
|
145
|
+
|
|
146
|
+
def stream(
|
|
147
|
+
self,
|
|
148
|
+
message: str,
|
|
149
|
+
files: Optional[List[str]] = None,
|
|
150
|
+
file_uris: Optional[List[str]] = None,
|
|
151
|
+
session_id: Optional[str] = None,
|
|
152
|
+
) -> Generator[str, None, Dict[str, Any]]:
|
|
153
|
+
"""
|
|
154
|
+
Stream a DELTA response via WebSocket. Yields text chunks.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
message: Your question or prompt.
|
|
158
|
+
files: Optional list of file paths to attach (auto-uploaded).
|
|
159
|
+
file_uris: Optional list of pre-uploaded GCS URIs (advanced).
|
|
160
|
+
session_id: Optional session ID.
|
|
161
|
+
|
|
162
|
+
Yields:
|
|
163
|
+
Text chunks as they arrive.
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
for chunk in client.stream("Explain Article 21"):
|
|
167
|
+
print(chunk, end="", flush=True)
|
|
168
|
+
|
|
169
|
+
# With files
|
|
170
|
+
for chunk in client.stream("Summarize this", files=["doc.pdf"]):
|
|
171
|
+
print(chunk, end="", flush=True)
|
|
172
|
+
"""
|
|
173
|
+
if not HAS_WEBSOCKET:
|
|
174
|
+
raise LawSaathiError(
|
|
175
|
+
"WebSocket streaming requires 'websocket-client'. "
|
|
176
|
+
"Install it: pip install websocket-client"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Auto-upload files if provided
|
|
180
|
+
all_uris = list(file_uris or [])
|
|
181
|
+
if files:
|
|
182
|
+
for file_path in files:
|
|
183
|
+
upload_result = self.upload_file(file_path)
|
|
184
|
+
all_uris.append(upload_result['file_ref'])
|
|
185
|
+
file_uris = all_uris or None
|
|
186
|
+
|
|
187
|
+
ws_endpoint = f"{self.ws_url}/ws/sdk/delta/?api_key={self.api_key}"
|
|
188
|
+
chunks = []
|
|
189
|
+
usage_info = {}
|
|
190
|
+
error_msg = None
|
|
191
|
+
done_event = threading.Event()
|
|
192
|
+
|
|
193
|
+
def on_message(ws_conn, raw):
|
|
194
|
+
nonlocal usage_info, error_msg
|
|
195
|
+
try:
|
|
196
|
+
data = json.loads(raw)
|
|
197
|
+
msg_type = data.get("type", "")
|
|
198
|
+
if msg_type == "chunk":
|
|
199
|
+
chunks.append(data.get("text", ""))
|
|
200
|
+
elif msg_type == "done":
|
|
201
|
+
usage_info = data
|
|
202
|
+
done_event.set()
|
|
203
|
+
ws_conn.close()
|
|
204
|
+
elif msg_type == "error":
|
|
205
|
+
error_msg = data.get("error", "Unknown error")
|
|
206
|
+
done_event.set()
|
|
207
|
+
ws_conn.close()
|
|
208
|
+
elif msg_type == "status":
|
|
209
|
+
pass # Processing status, ignore
|
|
210
|
+
except json.JSONDecodeError:
|
|
211
|
+
pass
|
|
212
|
+
|
|
213
|
+
def on_error(ws_conn, err):
|
|
214
|
+
nonlocal error_msg
|
|
215
|
+
error_msg = str(err)
|
|
216
|
+
done_event.set()
|
|
217
|
+
|
|
218
|
+
def on_open(ws_conn):
|
|
219
|
+
payload = {"message": message}
|
|
220
|
+
if file_uris:
|
|
221
|
+
payload["file_uris"] = file_uris
|
|
222
|
+
if session_id:
|
|
223
|
+
payload["session_id"] = session_id
|
|
224
|
+
ws_conn.send(json.dumps(payload))
|
|
225
|
+
|
|
226
|
+
def on_close(ws_conn, close_status_code, close_msg):
|
|
227
|
+
done_event.set()
|
|
228
|
+
|
|
229
|
+
ws_app = ws_lib.WebSocketApp(
|
|
230
|
+
ws_endpoint,
|
|
231
|
+
on_open=on_open,
|
|
232
|
+
on_message=on_message,
|
|
233
|
+
on_error=on_error,
|
|
234
|
+
on_close=on_close,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Run WebSocket in a background thread
|
|
238
|
+
ws_thread = threading.Thread(target=ws_app.run_forever, daemon=True)
|
|
239
|
+
ws_thread.start()
|
|
240
|
+
|
|
241
|
+
# Yield chunks as they arrive
|
|
242
|
+
yielded = 0
|
|
243
|
+
while not done_event.is_set() or yielded < len(chunks):
|
|
244
|
+
if yielded < len(chunks):
|
|
245
|
+
yield chunks[yielded]
|
|
246
|
+
yielded += 1
|
|
247
|
+
else:
|
|
248
|
+
done_event.wait(timeout=0.05)
|
|
249
|
+
|
|
250
|
+
# Yield any remaining chunks
|
|
251
|
+
while yielded < len(chunks):
|
|
252
|
+
yield chunks[yielded]
|
|
253
|
+
yielded += 1
|
|
254
|
+
|
|
255
|
+
ws_thread.join(timeout=5)
|
|
256
|
+
|
|
257
|
+
if error_msg:
|
|
258
|
+
if "Insufficient credits" in error_msg:
|
|
259
|
+
raise InsufficientCreditsError(error_msg)
|
|
260
|
+
elif "Rate limit" in error_msg:
|
|
261
|
+
raise RateLimitError(error_msg)
|
|
262
|
+
else:
|
|
263
|
+
raise APIError(error_msg)
|
|
264
|
+
|
|
265
|
+
return usage_info
|
|
266
|
+
|
|
267
|
+
# =========================================================================
|
|
268
|
+
# File Upload (handled internally — users don't need to call this directly)
|
|
269
|
+
# =========================================================================
|
|
270
|
+
|
|
271
|
+
def upload_file(self, file_path: str) -> Dict[str, Any]:
|
|
272
|
+
"""
|
|
273
|
+
Upload a file via HTTP. Returns a file reference for use in queries.
|
|
274
|
+
|
|
275
|
+
You usually don't need to call this directly — just pass `files=["path"]`
|
|
276
|
+
to `chat()` or `stream()` and it's handled automatically.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
file_path: Path to file (PDF, DOCX, TXT, JPG, PNG).
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Dict with 'file_ref', 'file_id', 'filename', 'size'.
|
|
283
|
+
"""
|
|
284
|
+
import os
|
|
285
|
+
if not os.path.exists(file_path):
|
|
286
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
287
|
+
|
|
288
|
+
filename = os.path.basename(file_path)
|
|
289
|
+
url = f"{self.base_url}/api/sdk/upload/"
|
|
290
|
+
|
|
291
|
+
# Use a fresh request (NOT the session, which has Content-Type: application/json)
|
|
292
|
+
with open(file_path, "rb") as f:
|
|
293
|
+
response = requests.post(
|
|
294
|
+
url,
|
|
295
|
+
files={"file": (filename, f)},
|
|
296
|
+
headers={
|
|
297
|
+
"X-API-Key": self.api_key,
|
|
298
|
+
"User-Agent": f"LawSaathi-Python-SDK/{__version__}",
|
|
299
|
+
},
|
|
300
|
+
timeout=self.timeout,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
return self._handle_response(response)
|
|
304
|
+
|
|
305
|
+
# =========================================================================
|
|
306
|
+
# Balance & Health
|
|
307
|
+
# =========================================================================
|
|
308
|
+
|
|
309
|
+
def get_balance(self) -> Dict[str, Any]:
|
|
310
|
+
"""
|
|
311
|
+
Check remaining wallet balance and token availability.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Dict with 'balance_rupees', 'tokens_available', etc.
|
|
315
|
+
"""
|
|
316
|
+
return self._request("GET", "/api/sdk/balance/")
|
|
317
|
+
|
|
318
|
+
def health(self) -> Dict[str, Any]:
|
|
319
|
+
"""
|
|
320
|
+
Check API health and your auth status.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Dict with 'status', 'version', 'authenticated', etc.
|
|
324
|
+
"""
|
|
325
|
+
return self._request("GET", "/api/sdk/health/")
|
|
326
|
+
|
|
327
|
+
# =========================================================================
|
|
328
|
+
# Internal HTTP helpers
|
|
329
|
+
# =========================================================================
|
|
330
|
+
|
|
331
|
+
def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
|
|
332
|
+
"""Make an HTTP request with retry logic."""
|
|
333
|
+
url = f"{self.base_url}{endpoint}"
|
|
334
|
+
last_error = None
|
|
335
|
+
|
|
336
|
+
for attempt in range(self.max_retries + 1):
|
|
337
|
+
try:
|
|
338
|
+
response = self._session.request(
|
|
339
|
+
method=method,
|
|
340
|
+
url=url,
|
|
341
|
+
timeout=self.timeout,
|
|
342
|
+
**kwargs,
|
|
343
|
+
)
|
|
344
|
+
return self._handle_response(response)
|
|
345
|
+
|
|
346
|
+
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e:
|
|
347
|
+
last_error = e
|
|
348
|
+
if attempt < self.max_retries:
|
|
349
|
+
wait = (attempt + 1) * 2
|
|
350
|
+
logger.warning(f"Request failed (attempt {attempt + 1}), retrying in {wait}s: {e}")
|
|
351
|
+
time.sleep(wait)
|
|
352
|
+
continue
|
|
353
|
+
raise APIError(f"Request failed after {self.max_retries + 1} attempts: {e}")
|
|
354
|
+
|
|
355
|
+
except (AuthenticationError, RateLimitError, InsufficientCreditsError):
|
|
356
|
+
raise # Don't retry auth/rate/credit errors
|
|
357
|
+
|
|
358
|
+
except requests.exceptions.RequestException as e:
|
|
359
|
+
raise APIError(f"Request failed: {e}")
|
|
360
|
+
|
|
361
|
+
raise APIError(f"Request failed: {last_error}")
|
|
362
|
+
|
|
363
|
+
def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
|
|
364
|
+
"""Handle HTTP response, raising appropriate exceptions."""
|
|
365
|
+
if response.status_code == 401:
|
|
366
|
+
raise AuthenticationError("Invalid or expired API key.")
|
|
367
|
+
if response.status_code == 402:
|
|
368
|
+
data = response.json() if response.content else {}
|
|
369
|
+
raise InsufficientCreditsError(
|
|
370
|
+
data.get("message", "Insufficient credits."),
|
|
371
|
+
balance_rupees=data.get("balance_rupees"),
|
|
372
|
+
)
|
|
373
|
+
if response.status_code == 429:
|
|
374
|
+
data = response.json() if response.content else {}
|
|
375
|
+
raise RateLimitError(
|
|
376
|
+
data.get("message", "Rate limit exceeded."),
|
|
377
|
+
retry_after=response.headers.get("Retry-After"),
|
|
378
|
+
)
|
|
379
|
+
if response.status_code >= 400:
|
|
380
|
+
try:
|
|
381
|
+
data = response.json()
|
|
382
|
+
msg = data.get("error", data.get("message", response.text))
|
|
383
|
+
except Exception:
|
|
384
|
+
msg = response.text
|
|
385
|
+
raise APIError(msg, status_code=response.status_code, response=response)
|
|
386
|
+
|
|
387
|
+
return response.json()
|
|
388
|
+
|
|
389
|
+
def __repr__(self):
|
|
390
|
+
return f"LawSaathi(api_key='{self.api_key[:12]}...', base_url='{self.base_url}')"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Custom exceptions for LawSaathi SDK."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class LawSaathiError(Exception):
|
|
5
|
+
"""Base exception for all LawSaathi SDK errors."""
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuthenticationError(LawSaathiError):
|
|
10
|
+
"""Raised when API key authentication fails (401)."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RateLimitError(LawSaathiError):
|
|
15
|
+
"""Raised when rate limit is exceeded (429)."""
|
|
16
|
+
def __init__(self, message, retry_after=None):
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
self.retry_after = retry_after
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InsufficientCreditsError(LawSaathiError):
|
|
22
|
+
"""Raised when wallet balance is insufficient (402)."""
|
|
23
|
+
def __init__(self, message, balance_rupees=None):
|
|
24
|
+
super().__init__(message)
|
|
25
|
+
self.balance_rupees = balance_rupees
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class APIError(LawSaathiError):
|
|
29
|
+
"""Raised for general API errors (4xx/5xx)."""
|
|
30
|
+
def __init__(self, message, status_code=None, response=None):
|
|
31
|
+
super().__init__(message)
|
|
32
|
+
self.status_code = status_code
|
|
33
|
+
self.response = response
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lawsaathi
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for LawSaathi Legal AI API — DELTA
|
|
5
|
+
Home-page: https://github.com/lawsaathi/lawsaathi-python-sdk
|
|
6
|
+
Author: LawSaathi
|
|
7
|
+
Author-email: LawSaathi <support@lawsaathi.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://lawsaathi.com
|
|
10
|
+
Project-URL: Documentation, https://lawsaathi.com/docs
|
|
11
|
+
Project-URL: Repository, https://github.com/lawsaathi/lawsaathi-python-sdk
|
|
12
|
+
Project-URL: Dashboard, https://lawsaathi.com/developer
|
|
13
|
+
Project-URL: Bug Tracker, https://github.com/lawsaathi/lawsaathi-python-sdk/issues
|
|
14
|
+
Keywords: lawsaathi,legal-ai,indian-law,ipc,crpc,delta,ai-sdk,legal-tech,chatbot,api-client
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Operating System :: OS Independent
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: requests>=2.25.0
|
|
32
|
+
Provides-Extra: websocket
|
|
33
|
+
Requires-Dist: websocket-client>=1.0.0; extra == "websocket"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
37
|
+
Requires-Dist: black>=21.0; extra == "dev"
|
|
38
|
+
Requires-Dist: flake8>=3.9; extra == "dev"
|
|
39
|
+
Requires-Dist: build; extra == "dev"
|
|
40
|
+
Requires-Dist: twine; extra == "dev"
|
|
41
|
+
Dynamic: author
|
|
42
|
+
Dynamic: home-page
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: requires-python
|
|
45
|
+
|
|
46
|
+
# LawSaathi Python SDK
|
|
47
|
+
|
|
48
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
49
|
+
[](https://pypi.org/project/lawsaathi/)
|
|
50
|
+
[](https://opensource.org/licenses/MIT)
|
|
51
|
+
|
|
52
|
+
Official Python client for the **LawSaathi Legal AI API** — powered by **DELTA**, India's most advanced Legal AI.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install lawsaathi
|
|
58
|
+
|
|
59
|
+
# With WebSocket streaming support:
|
|
60
|
+
pip install lawsaathi[websocket]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from lawsaathi import LawSaathi
|
|
67
|
+
|
|
68
|
+
client = LawSaathi(api_key="ls_live_your_api_key_here")
|
|
69
|
+
|
|
70
|
+
# Ask any legal question
|
|
71
|
+
response = client.chat("What is IPC Section 302?")
|
|
72
|
+
print(response['response'])
|
|
73
|
+
print(f"Tokens used: {response['usage']['total_tokens']}")
|
|
74
|
+
print(f"Cost: ₹{response['usage']['cost_rupees']}")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## File Attachments (OpenAI-style)
|
|
78
|
+
|
|
79
|
+
Attach files to your queries — just pass file paths. The SDK handles uploading automatically.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# Analyze a contract — just pass the file path!
|
|
83
|
+
response = client.chat(
|
|
84
|
+
"Summarize the key clauses in this contract",
|
|
85
|
+
files=["contract.pdf"]
|
|
86
|
+
)
|
|
87
|
+
print(response['response'])
|
|
88
|
+
|
|
89
|
+
# Multiple files work too
|
|
90
|
+
response = client.chat(
|
|
91
|
+
"Compare these two agreements",
|
|
92
|
+
files=["agreement_v1.pdf", "agreement_v2.pdf"]
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Streaming (WebSocket)
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# Requires: pip install lawsaathi[websocket]
|
|
100
|
+
for chunk in client.stream("Explain bail provisions under CrPC"):
|
|
101
|
+
print(chunk, end="", flush=True)
|
|
102
|
+
|
|
103
|
+
# Streaming with files
|
|
104
|
+
for chunk in client.stream("Analyze this document", files=["contract.pdf"]):
|
|
105
|
+
print(chunk, end="", flush=True)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Check Balance
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
balance = client.get_balance()
|
|
112
|
+
print(f"Balance: ₹{balance['balance_rupees']}")
|
|
113
|
+
print(f"Tokens available: {balance['tokens_available']:,}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Error Handling
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from lawsaathi import (
|
|
120
|
+
LawSaathi,
|
|
121
|
+
AuthenticationError,
|
|
122
|
+
RateLimitError,
|
|
123
|
+
InsufficientCreditsError,
|
|
124
|
+
APIError,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
client = LawSaathi(api_key="ls_live_your_key")
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
response = client.chat("Hello")
|
|
131
|
+
except AuthenticationError:
|
|
132
|
+
print("Invalid API key — check or regenerate it")
|
|
133
|
+
except InsufficientCreditsError as e:
|
|
134
|
+
print(f"Not enough credits. Balance: ₹{e.balance_rupees}")
|
|
135
|
+
except RateLimitError as e:
|
|
136
|
+
print(f"Rate limited. Retry after: {e.retry_after}s")
|
|
137
|
+
except APIError as e:
|
|
138
|
+
print(f"API error ({e.status_code}): {e}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Pricing
|
|
142
|
+
|
|
143
|
+
| | |
|
|
144
|
+
|---|---|
|
|
145
|
+
| **Cost per 1M tokens** | ₹998 |
|
|
146
|
+
| **Free credits on signup** | ₹100 |
|
|
147
|
+
| **Minimum topup** | ₹999 |
|
|
148
|
+
| **Credit expiry** | 150 days |
|
|
149
|
+
|
|
150
|
+
## Rate Limits
|
|
151
|
+
|
|
152
|
+
| Limit | Default |
|
|
153
|
+
|-------|---------|
|
|
154
|
+
| Requests/minute | 5 |
|
|
155
|
+
| Requests/day | 2,500 |
|
|
156
|
+
| Max file size | 100 MB |
|
|
157
|
+
|
|
158
|
+
Need higher limits? Contact support@lawsaathi.com.
|
|
159
|
+
|
|
160
|
+
## Requirements
|
|
161
|
+
|
|
162
|
+
- Python 3.8+
|
|
163
|
+
- `requests` library (installed automatically)
|
|
164
|
+
- `websocket-client` (optional, for streaming)
|
|
165
|
+
|
|
166
|
+
## Links
|
|
167
|
+
|
|
168
|
+
- **Dashboard**: [lawsaathi.com/developer](https://lawsaathi.com/developer)
|
|
169
|
+
- **API Docs**: [lawsaathi.com/docs](https://lawsaathi.com/docs)
|
|
170
|
+
- **Support**: support@lawsaathi.com
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
lawsaathi/__init__.py
|
|
7
|
+
lawsaathi/client.py
|
|
8
|
+
lawsaathi/exceptions.py
|
|
9
|
+
lawsaathi.egg-info/PKG-INFO
|
|
10
|
+
lawsaathi.egg-info/SOURCES.txt
|
|
11
|
+
lawsaathi.egg-info/dependency_links.txt
|
|
12
|
+
lawsaathi.egg-info/requires.txt
|
|
13
|
+
lawsaathi.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lawsaathi
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "lawsaathi"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Official Python SDK for LawSaathi Legal AI API — DELTA"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "LawSaathi", email = "support@lawsaathi.com"},
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"lawsaathi", "legal-ai", "indian-law", "ipc", "crpc",
|
|
17
|
+
"delta", "ai-sdk", "legal-tech", "chatbot", "api-client",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.8",
|
|
27
|
+
"Programming Language :: Python :: 3.9",
|
|
28
|
+
"Programming Language :: Python :: 3.10",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Operating System :: OS Independent",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"requests>=2.25.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
websocket = ["websocket-client>=1.0.0"]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=6.0",
|
|
42
|
+
"pytest-cov>=2.0",
|
|
43
|
+
"black>=21.0",
|
|
44
|
+
"flake8>=3.9",
|
|
45
|
+
"build",
|
|
46
|
+
"twine",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[project.urls]
|
|
50
|
+
Homepage = "https://lawsaathi.com"
|
|
51
|
+
Documentation = "https://lawsaathi.com/docs"
|
|
52
|
+
Repository = "https://github.com/lawsaathi/lawsaathi-python-sdk"
|
|
53
|
+
Dashboard = "https://lawsaathi.com/developer"
|
|
54
|
+
"Bug Tracker" = "https://github.com/lawsaathi/lawsaathi-python-sdk/issues"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
include = ["lawsaathi*"]
|
lawsaathi-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="lawsaathi",
|
|
8
|
+
version="1.0.0",
|
|
9
|
+
author="LawSaathi",
|
|
10
|
+
author_email="support@lawsaathi.com",
|
|
11
|
+
description="Official Python SDK for LawSaathi Legal AI API — DELTA",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/lawsaathi/lawsaathi-python-sdk",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.8",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
],
|
|
28
|
+
python_requires=">=3.8",
|
|
29
|
+
install_requires=[
|
|
30
|
+
"requests>=2.25.0",
|
|
31
|
+
],
|
|
32
|
+
extras_require={
|
|
33
|
+
"websocket": ["websocket-client>=1.0.0"],
|
|
34
|
+
"dev": [
|
|
35
|
+
"pytest>=6.0",
|
|
36
|
+
"pytest-cov>=2.0",
|
|
37
|
+
"black>=21.0",
|
|
38
|
+
"flake8>=3.9",
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
)
|