paive-agents 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.
- paive_agents-0.1.0/PKG-INFO +81 -0
- paive_agents-0.1.0/README.md +71 -0
- paive_agents-0.1.0/pyproject.toml +18 -0
- paive_agents-0.1.0/setup.cfg +4 -0
- paive_agents-0.1.0/src/paive_agents/__init__.py +28 -0
- paive_agents-0.1.0/src/paive_agents/_payload.py +61 -0
- paive_agents-0.1.0/src/paive_agents/async_client.py +75 -0
- paive_agents-0.1.0/src/paive_agents/client.py +85 -0
- paive_agents-0.1.0/src/paive_agents/exceptions.py +75 -0
- paive_agents-0.1.0/src/paive_agents/models.py +17 -0
- paive_agents-0.1.0/src/paive_agents.egg-info/PKG-INFO +81 -0
- paive_agents-0.1.0/src/paive_agents.egg-info/SOURCES.txt +13 -0
- paive_agents-0.1.0/src/paive_agents.egg-info/dependency_links.txt +1 -0
- paive_agents-0.1.0/src/paive_agents.egg-info/requires.txt +2 -0
- paive_agents-0.1.0/src/paive_agents.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paive-agents
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Paive patent intelligence report API
|
|
5
|
+
License: Proprietary
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: requests>=2.28
|
|
9
|
+
Requires-Dist: httpx>=0.24
|
|
10
|
+
|
|
11
|
+
# paive-agents
|
|
12
|
+
|
|
13
|
+
Official Python SDK for the Paive patent intelligence report API.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install paive-agents
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Before publishing publicly
|
|
22
|
+
|
|
23
|
+
`src/paive_agents/client.py` currently defaults to a staging server:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
DEFAULT_BASE_URL = "http://34.29.194.252:8000"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This is a working staging link (plain HTTP, IP-based). Before publishing this package
|
|
30
|
+
anywhere public (PyPI, external customers), swap this for your real production domain
|
|
31
|
+
over HTTPS. Until then, this default is fine for internal testing.
|
|
32
|
+
|
|
33
|
+
## Sync usage
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from paive_agents import Client
|
|
37
|
+
|
|
38
|
+
client = Client(api_key="YOUR_API_KEY")
|
|
39
|
+
|
|
40
|
+
report = client.generate_report(
|
|
41
|
+
patent_id="US12093418B2",
|
|
42
|
+
tech_sector="Biotech / Therapeutics",
|
|
43
|
+
clp_factors=["Application Effect", "Benchmarking Data"],
|
|
44
|
+
market_factors=["Application Effect"],
|
|
45
|
+
licensing_factors=["Application Effect"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
print(report.pdf_file)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Async usage
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from paive_agents import AsyncClient
|
|
55
|
+
|
|
56
|
+
client = AsyncClient(api_key="YOUR_API_KEY")
|
|
57
|
+
report = await client.generate_report(patent_id="US12093418B2")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## PDF upload instead of patent_id
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
report = client.generate_report(pdf_path="/path/to/patent.pdf")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Errors
|
|
67
|
+
|
|
68
|
+
All errors subclass `paive_agents.PaiveError` and carry `.status_code` and `.response_body`:
|
|
69
|
+
|
|
70
|
+
- `AuthenticationError` — invalid/missing API key (401)
|
|
71
|
+
- `PermissionDeniedError` — user lacks permission (403)
|
|
72
|
+
- `InvalidRequestError` — bad request (400/404)
|
|
73
|
+
- `RateLimitError` — usage limit exceeded (429)
|
|
74
|
+
- `ServerError` — server-side failure (500+)
|
|
75
|
+
- `APIConnectionError` — network/connection failure
|
|
76
|
+
|
|
77
|
+
## What this SDK does NOT change
|
|
78
|
+
|
|
79
|
+
This package only talks to the existing `/api/keys/generate_report` endpoint over HTTP,
|
|
80
|
+
using the same field names and the same `X-API-Key` auth your Django backend already expects.
|
|
81
|
+
No backend files were modified to build this SDK.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# paive-agents
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the Paive patent intelligence report API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install paive-agents
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Before publishing publicly
|
|
12
|
+
|
|
13
|
+
`src/paive_agents/client.py` currently defaults to a staging server:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
DEFAULT_BASE_URL = "http://34.29.194.252:8000"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This is a working staging link (plain HTTP, IP-based). Before publishing this package
|
|
20
|
+
anywhere public (PyPI, external customers), swap this for your real production domain
|
|
21
|
+
over HTTPS. Until then, this default is fine for internal testing.
|
|
22
|
+
|
|
23
|
+
## Sync usage
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from paive_agents import Client
|
|
27
|
+
|
|
28
|
+
client = Client(api_key="YOUR_API_KEY")
|
|
29
|
+
|
|
30
|
+
report = client.generate_report(
|
|
31
|
+
patent_id="US12093418B2",
|
|
32
|
+
tech_sector="Biotech / Therapeutics",
|
|
33
|
+
clp_factors=["Application Effect", "Benchmarking Data"],
|
|
34
|
+
market_factors=["Application Effect"],
|
|
35
|
+
licensing_factors=["Application Effect"],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
print(report.pdf_file)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Async usage
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from paive_agents import AsyncClient
|
|
45
|
+
|
|
46
|
+
client = AsyncClient(api_key="YOUR_API_KEY")
|
|
47
|
+
report = await client.generate_report(patent_id="US12093418B2")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## PDF upload instead of patent_id
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
report = client.generate_report(pdf_path="/path/to/patent.pdf")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Errors
|
|
57
|
+
|
|
58
|
+
All errors subclass `paive_agents.PaiveError` and carry `.status_code` and `.response_body`:
|
|
59
|
+
|
|
60
|
+
- `AuthenticationError` — invalid/missing API key (401)
|
|
61
|
+
- `PermissionDeniedError` — user lacks permission (403)
|
|
62
|
+
- `InvalidRequestError` — bad request (400/404)
|
|
63
|
+
- `RateLimitError` — usage limit exceeded (429)
|
|
64
|
+
- `ServerError` — server-side failure (500+)
|
|
65
|
+
- `APIConnectionError` — network/connection failure
|
|
66
|
+
|
|
67
|
+
## What this SDK does NOT change
|
|
68
|
+
|
|
69
|
+
This package only talks to the existing `/api/keys/generate_report` endpoint over HTTP,
|
|
70
|
+
using the same field names and the same `X-API-Key` auth your Django backend already expects.
|
|
71
|
+
No backend files were modified to build this SDK.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "paive-agents"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Python SDK for the Paive patent intelligence report API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "Proprietary" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"requests>=2.28",
|
|
14
|
+
"httpx>=0.24",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[tool.setuptools.packages.find]
|
|
18
|
+
where = ["src"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from .client import Client, DEFAULT_BASE_URL
|
|
2
|
+
from .async_client import AsyncClient
|
|
3
|
+
from .models import Report
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
PaiveError,
|
|
6
|
+
AuthenticationError,
|
|
7
|
+
PermissionDeniedError,
|
|
8
|
+
InvalidRequestError,
|
|
9
|
+
RateLimitError,
|
|
10
|
+
ServerError,
|
|
11
|
+
APIConnectionError,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Client",
|
|
18
|
+
"AsyncClient",
|
|
19
|
+
"Report",
|
|
20
|
+
"DEFAULT_BASE_URL",
|
|
21
|
+
"PaiveError",
|
|
22
|
+
"AuthenticationError",
|
|
23
|
+
"PermissionDeniedError",
|
|
24
|
+
"InvalidRequestError",
|
|
25
|
+
"RateLimitError",
|
|
26
|
+
"ServerError",
|
|
27
|
+
"APIConnectionError",
|
|
28
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
LIST_FIELDS = (
|
|
2
|
+
"revenue_types",
|
|
3
|
+
"funding_sources",
|
|
4
|
+
"suspicion_triggers",
|
|
5
|
+
"clp_factors",
|
|
6
|
+
"market_factors",
|
|
7
|
+
"licensing_factors",
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
SCALAR_FIELDS = (
|
|
11
|
+
"patent_id",
|
|
12
|
+
"name",
|
|
13
|
+
"email",
|
|
14
|
+
"company",
|
|
15
|
+
"patent_numbers",
|
|
16
|
+
"patent_type",
|
|
17
|
+
"role",
|
|
18
|
+
"trl_level",
|
|
19
|
+
"prototype_exists",
|
|
20
|
+
"commercialization_focus",
|
|
21
|
+
"revenue_status",
|
|
22
|
+
"traction_type",
|
|
23
|
+
"customer_discovery",
|
|
24
|
+
"pilots_trials",
|
|
25
|
+
"industry_interest",
|
|
26
|
+
"rpp_stage",
|
|
27
|
+
"rpp_deal",
|
|
28
|
+
"capital_raised",
|
|
29
|
+
"competing_technologies",
|
|
30
|
+
"primary_advantage",
|
|
31
|
+
"infringement_suspected",
|
|
32
|
+
"primary_objective",
|
|
33
|
+
"timeline_sensitivity",
|
|
34
|
+
"report_type",
|
|
35
|
+
"tech_sector",
|
|
36
|
+
"website",
|
|
37
|
+
"invention_disclosure",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def build_form_fields(input_type, api_key, **kwargs):
|
|
42
|
+
fields = []
|
|
43
|
+
fields.append(("input_type", input_type))
|
|
44
|
+
fields.append(("api_key", api_key))
|
|
45
|
+
|
|
46
|
+
for name in SCALAR_FIELDS:
|
|
47
|
+
value = kwargs.get(name)
|
|
48
|
+
if value is None:
|
|
49
|
+
continue
|
|
50
|
+
fields.append((name, str(value)))
|
|
51
|
+
|
|
52
|
+
for name in LIST_FIELDS:
|
|
53
|
+
values = kwargs.get(name)
|
|
54
|
+
if not values:
|
|
55
|
+
continue
|
|
56
|
+
if isinstance(values, (str, bytes)):
|
|
57
|
+
values = [values]
|
|
58
|
+
for item in values:
|
|
59
|
+
fields.append((name, str(item)))
|
|
60
|
+
|
|
61
|
+
return fields
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
3
|
+
from ._payload import build_form_fields
|
|
4
|
+
from .exceptions import raise_for_status, APIConnectionError
|
|
5
|
+
from .models import Report
|
|
6
|
+
from .client import DEFAULT_BASE_URL, GENERATE_REPORT_PATH
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncClient:
|
|
10
|
+
def __init__(self, api_key, base_url=None, timeout=60):
|
|
11
|
+
if not api_key:
|
|
12
|
+
raise ValueError("api_key is required")
|
|
13
|
+
self.api_key = api_key
|
|
14
|
+
self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
|
|
15
|
+
self.timeout = timeout
|
|
16
|
+
|
|
17
|
+
async def generate_report(
|
|
18
|
+
self,
|
|
19
|
+
patent_id=None,
|
|
20
|
+
pdf_path=None,
|
|
21
|
+
report_type="brief_IP_decision_support_intelligence",
|
|
22
|
+
tech_sector=None,
|
|
23
|
+
clp_factors=None,
|
|
24
|
+
market_factors=None,
|
|
25
|
+
licensing_factors=None,
|
|
26
|
+
revenue_types=None,
|
|
27
|
+
funding_sources=None,
|
|
28
|
+
suspicion_triggers=None,
|
|
29
|
+
**kwargs,
|
|
30
|
+
):
|
|
31
|
+
if bool(patent_id) == bool(pdf_path):
|
|
32
|
+
raise ValueError("Provide exactly one of patent_id or pdf_path")
|
|
33
|
+
|
|
34
|
+
input_type = "patent_id" if patent_id else "pdf"
|
|
35
|
+
|
|
36
|
+
fields = build_form_fields(
|
|
37
|
+
input_type=input_type,
|
|
38
|
+
api_key=self.api_key,
|
|
39
|
+
patent_id=patent_id,
|
|
40
|
+
report_type=report_type,
|
|
41
|
+
tech_sector=tech_sector,
|
|
42
|
+
clp_factors=clp_factors,
|
|
43
|
+
market_factors=market_factors,
|
|
44
|
+
licensing_factors=licensing_factors,
|
|
45
|
+
revenue_types=revenue_types,
|
|
46
|
+
funding_sources=funding_sources,
|
|
47
|
+
suspicion_triggers=suspicion_triggers,
|
|
48
|
+
**kwargs,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
url = self.base_url + GENERATE_REPORT_PATH
|
|
52
|
+
headers = {"X-API-Key": self.api_key}
|
|
53
|
+
|
|
54
|
+
files = None
|
|
55
|
+
file_bytes = None
|
|
56
|
+
if pdf_path:
|
|
57
|
+
with open(pdf_path, "rb") as f:
|
|
58
|
+
file_bytes = f.read()
|
|
59
|
+
files = {"pdf_file": (pdf_path.split("/")[-1], file_bytes, "application/pdf")}
|
|
60
|
+
|
|
61
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
62
|
+
try:
|
|
63
|
+
response = await client.post(url, headers=headers, data=fields, files=files)
|
|
64
|
+
except httpx.HTTPError as exc:
|
|
65
|
+
raise APIConnectionError(f"Failed to reach {url}: {exc}") from exc
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
body = response.json()
|
|
69
|
+
except ValueError:
|
|
70
|
+
body = {"error": response.text}
|
|
71
|
+
|
|
72
|
+
if response.status_code >= 400:
|
|
73
|
+
raise_for_status(response.status_code, body)
|
|
74
|
+
|
|
75
|
+
return Report.from_response(body)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
from ._payload import build_form_fields
|
|
4
|
+
from .exceptions import raise_for_status, APIConnectionError
|
|
5
|
+
from .models import Report
|
|
6
|
+
|
|
7
|
+
DEFAULT_BASE_URL = "http://34.29.194.252:8000"
|
|
8
|
+
GENERATE_REPORT_PATH = "/api/keys/generate_report"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Client:
|
|
12
|
+
def __init__(self, api_key, base_url=None, timeout=60):
|
|
13
|
+
if not api_key:
|
|
14
|
+
raise ValueError("api_key is required")
|
|
15
|
+
self.api_key = api_key
|
|
16
|
+
self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
|
|
17
|
+
self.timeout = timeout
|
|
18
|
+
|
|
19
|
+
def generate_report(
|
|
20
|
+
self,
|
|
21
|
+
patent_id=None,
|
|
22
|
+
pdf_path=None,
|
|
23
|
+
report_type="brief_IP_decision_support_intelligence",
|
|
24
|
+
tech_sector=None,
|
|
25
|
+
clp_factors=None,
|
|
26
|
+
market_factors=None,
|
|
27
|
+
licensing_factors=None,
|
|
28
|
+
revenue_types=None,
|
|
29
|
+
funding_sources=None,
|
|
30
|
+
suspicion_triggers=None,
|
|
31
|
+
**kwargs,
|
|
32
|
+
):
|
|
33
|
+
if bool(patent_id) == bool(pdf_path):
|
|
34
|
+
raise ValueError("Provide exactly one of patent_id or pdf_path")
|
|
35
|
+
|
|
36
|
+
input_type = "patent_id" if patent_id else "pdf"
|
|
37
|
+
|
|
38
|
+
fields = build_form_fields(
|
|
39
|
+
input_type=input_type,
|
|
40
|
+
api_key=self.api_key,
|
|
41
|
+
patent_id=patent_id,
|
|
42
|
+
report_type=report_type,
|
|
43
|
+
tech_sector=tech_sector,
|
|
44
|
+
clp_factors=clp_factors,
|
|
45
|
+
market_factors=market_factors,
|
|
46
|
+
licensing_factors=licensing_factors,
|
|
47
|
+
revenue_types=revenue_types,
|
|
48
|
+
funding_sources=funding_sources,
|
|
49
|
+
suspicion_triggers=suspicion_triggers,
|
|
50
|
+
**kwargs,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
url = self.base_url + GENERATE_REPORT_PATH
|
|
54
|
+
headers = {"X-API-Key": self.api_key}
|
|
55
|
+
|
|
56
|
+
files = None
|
|
57
|
+
opened_file = None
|
|
58
|
+
try:
|
|
59
|
+
if pdf_path:
|
|
60
|
+
opened_file = open(pdf_path, "rb")
|
|
61
|
+
files = {"pdf_file": (pdf_path.split("/")[-1], opened_file, "application/pdf")}
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
response = requests.post(
|
|
65
|
+
url,
|
|
66
|
+
headers=headers,
|
|
67
|
+
data=fields,
|
|
68
|
+
files=files,
|
|
69
|
+
timeout=self.timeout,
|
|
70
|
+
)
|
|
71
|
+
except requests.RequestException as exc:
|
|
72
|
+
raise APIConnectionError(f"Failed to reach {url}: {exc}") from exc
|
|
73
|
+
finally:
|
|
74
|
+
if opened_file:
|
|
75
|
+
opened_file.close()
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
body = response.json()
|
|
79
|
+
except ValueError:
|
|
80
|
+
body = {"error": response.text}
|
|
81
|
+
|
|
82
|
+
if not response.ok:
|
|
83
|
+
raise_for_status(response.status_code, body)
|
|
84
|
+
|
|
85
|
+
return Report.from_response(body)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class PaiveError(Exception):
|
|
2
|
+
def __init__(self, message, status_code=None, response_body=None):
|
|
3
|
+
super().__init__(message)
|
|
4
|
+
self.message = message
|
|
5
|
+
self.status_code = status_code
|
|
6
|
+
self.response_body = response_body
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AuthenticationError(PaiveError):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PermissionDeniedError(PaiveError):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class InvalidRequestError(PaiveError):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class RateLimitError(PaiveError):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ServerError(PaiveError):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class APIConnectionError(PaiveError):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def raise_for_status(status_code, response_body):
|
|
34
|
+
if status_code == 401:
|
|
35
|
+
raise AuthenticationError(
|
|
36
|
+
_extract_message(response_body, "Invalid or missing API key."),
|
|
37
|
+
status_code,
|
|
38
|
+
response_body,
|
|
39
|
+
)
|
|
40
|
+
if status_code == 403:
|
|
41
|
+
raise PermissionDeniedError(
|
|
42
|
+
_extract_message(response_body, "You do not have permission to perform this action."),
|
|
43
|
+
status_code,
|
|
44
|
+
response_body,
|
|
45
|
+
)
|
|
46
|
+
if status_code == 400:
|
|
47
|
+
raise InvalidRequestError(
|
|
48
|
+
_extract_message(response_body, "Invalid request."),
|
|
49
|
+
status_code,
|
|
50
|
+
response_body,
|
|
51
|
+
)
|
|
52
|
+
if status_code == 404:
|
|
53
|
+
raise InvalidRequestError(
|
|
54
|
+
_extract_message(response_body, "Resource not found."),
|
|
55
|
+
status_code,
|
|
56
|
+
response_body,
|
|
57
|
+
)
|
|
58
|
+
if status_code == 429:
|
|
59
|
+
raise RateLimitError(
|
|
60
|
+
_extract_message(response_body, "Usage limit exceeded."),
|
|
61
|
+
status_code,
|
|
62
|
+
response_body,
|
|
63
|
+
)
|
|
64
|
+
if status_code >= 500:
|
|
65
|
+
raise ServerError(
|
|
66
|
+
_extract_message(response_body, "Server error, please try again later."),
|
|
67
|
+
status_code,
|
|
68
|
+
response_body,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _extract_message(response_body, default):
|
|
73
|
+
if isinstance(response_body, dict):
|
|
74
|
+
return response_body.get("error") or response_body.get("message") or default
|
|
75
|
+
return default
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class Report:
|
|
7
|
+
pdf_file: Optional[str] = None
|
|
8
|
+
escalation_report: Optional[str] = None
|
|
9
|
+
raw: Dict[str, Any] = field(default_factory=dict)
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def from_response(cls, data):
|
|
13
|
+
return cls(
|
|
14
|
+
pdf_file=data.get("pdf_file"),
|
|
15
|
+
escalation_report=data.get("escalation_report"),
|
|
16
|
+
raw=data,
|
|
17
|
+
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paive-agents
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Paive patent intelligence report API
|
|
5
|
+
License: Proprietary
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: requests>=2.28
|
|
9
|
+
Requires-Dist: httpx>=0.24
|
|
10
|
+
|
|
11
|
+
# paive-agents
|
|
12
|
+
|
|
13
|
+
Official Python SDK for the Paive patent intelligence report API.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install paive-agents
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Before publishing publicly
|
|
22
|
+
|
|
23
|
+
`src/paive_agents/client.py` currently defaults to a staging server:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
DEFAULT_BASE_URL = "http://34.29.194.252:8000"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This is a working staging link (plain HTTP, IP-based). Before publishing this package
|
|
30
|
+
anywhere public (PyPI, external customers), swap this for your real production domain
|
|
31
|
+
over HTTPS. Until then, this default is fine for internal testing.
|
|
32
|
+
|
|
33
|
+
## Sync usage
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from paive_agents import Client
|
|
37
|
+
|
|
38
|
+
client = Client(api_key="YOUR_API_KEY")
|
|
39
|
+
|
|
40
|
+
report = client.generate_report(
|
|
41
|
+
patent_id="US12093418B2",
|
|
42
|
+
tech_sector="Biotech / Therapeutics",
|
|
43
|
+
clp_factors=["Application Effect", "Benchmarking Data"],
|
|
44
|
+
market_factors=["Application Effect"],
|
|
45
|
+
licensing_factors=["Application Effect"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
print(report.pdf_file)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Async usage
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from paive_agents import AsyncClient
|
|
55
|
+
|
|
56
|
+
client = AsyncClient(api_key="YOUR_API_KEY")
|
|
57
|
+
report = await client.generate_report(patent_id="US12093418B2")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## PDF upload instead of patent_id
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
report = client.generate_report(pdf_path="/path/to/patent.pdf")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Errors
|
|
67
|
+
|
|
68
|
+
All errors subclass `paive_agents.PaiveError` and carry `.status_code` and `.response_body`:
|
|
69
|
+
|
|
70
|
+
- `AuthenticationError` — invalid/missing API key (401)
|
|
71
|
+
- `PermissionDeniedError` — user lacks permission (403)
|
|
72
|
+
- `InvalidRequestError` — bad request (400/404)
|
|
73
|
+
- `RateLimitError` — usage limit exceeded (429)
|
|
74
|
+
- `ServerError` — server-side failure (500+)
|
|
75
|
+
- `APIConnectionError` — network/connection failure
|
|
76
|
+
|
|
77
|
+
## What this SDK does NOT change
|
|
78
|
+
|
|
79
|
+
This package only talks to the existing `/api/keys/generate_report` endpoint over HTTP,
|
|
80
|
+
using the same field names and the same `X-API-Key` auth your Django backend already expects.
|
|
81
|
+
No backend files were modified to build this SDK.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/paive_agents/__init__.py
|
|
4
|
+
src/paive_agents/_payload.py
|
|
5
|
+
src/paive_agents/async_client.py
|
|
6
|
+
src/paive_agents/client.py
|
|
7
|
+
src/paive_agents/exceptions.py
|
|
8
|
+
src/paive_agents/models.py
|
|
9
|
+
src/paive_agents.egg-info/PKG-INFO
|
|
10
|
+
src/paive_agents.egg-info/SOURCES.txt
|
|
11
|
+
src/paive_agents.egg-info/dependency_links.txt
|
|
12
|
+
src/paive_agents.egg-info/requires.txt
|
|
13
|
+
src/paive_agents.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
paive_agents
|