zelf-sdk 1.0.0__py3-none-any.whl

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.
zelf/__init__.py ADDED
@@ -0,0 +1,218 @@
1
+ # Generated by codegen. Do not edit by hand.
2
+
3
+ """Python client for the ZelfAI APIs (spec version 1.0.0)."""
4
+
5
+ from . import webhooks
6
+ from ._client import AsyncZelfAPIClient, ZelfAPIClient, ZelfAPIClientAsync
7
+ from ._exceptions import (
8
+ AuthenticationError,
9
+ BadRequestError,
10
+ ConflictError,
11
+ ErrorCode,
12
+ InternalServerError,
13
+ NotAcceptableError,
14
+ NotFoundError,
15
+ PermissionDeniedError,
16
+ RateLimitError,
17
+ ResponseParseError,
18
+ ServiceUnavailableError,
19
+ ZelfAPIError,
20
+ ZelfConnectionError,
21
+ ZelfError,
22
+ ZelfTimeoutError,
23
+ )
24
+ from ._models import (
25
+ AiAnalysis,
26
+ AiAnalysisCreateRequest,
27
+ AiAnalysisResult,
28
+ AiAnalysisRun,
29
+ Brand,
30
+ BrandAccount,
31
+ BrandAccountGroups,
32
+ BrandAccountsWriteRequest,
33
+ BrandCatalog,
34
+ BrandCatalogItem,
35
+ BrandCreateSubBrandRequest,
36
+ BrandKeywords,
37
+ Comment,
38
+ CommentAuthor,
39
+ Content,
40
+ ContentActionRequestRequest,
41
+ ContentActionResponse,
42
+ ContentCreator,
43
+ ContentDiscovery,
44
+ ContentDiscoveryRequestRequest,
45
+ ContentFilterInputRequest,
46
+ ContentScopeRequest,
47
+ ContentStatistics,
48
+ Creator,
49
+ CreatorSync,
50
+ CreatorSyncCreateRequest,
51
+ CreatorVetting,
52
+ CreatorVettingRequest,
53
+ CreatorVettingResult,
54
+ CreatorVettingRun,
55
+ Detection,
56
+ DetectionBrandHint,
57
+ DetectionBrandHintRequest,
58
+ DetectionBrandResult,
59
+ DetectionBrandSummary,
60
+ DetectionContext,
61
+ DetectionContextInputRequest,
62
+ DetectionCreateRequest,
63
+ DetectionHints,
64
+ DetectionHintsRequest,
65
+ DetectionPlacement,
66
+ DetectionResult,
67
+ DetectionSummary,
68
+ DetectionVideo,
69
+ Error,
70
+ Error1,
71
+ Error2,
72
+ Error3,
73
+ Error4,
74
+ Error5,
75
+ Error6,
76
+ Error7,
77
+ Error400,
78
+ Error401,
79
+ Error403,
80
+ Error404,
81
+ Error406,
82
+ Error429,
83
+ Error500,
84
+ Error503,
85
+ PatchedBrandUpdateRequest,
86
+ PatchedWebhookSubscriptionUpdateRequest,
87
+ ResultFile,
88
+ SafetyCheckRequest,
89
+ Usage,
90
+ UsageScope,
91
+ UsageWindow,
92
+ WebhookAvailableEvent,
93
+ WebhookData,
94
+ WebhookDeleteAcknowledgement,
95
+ WebhookDelivery,
96
+ WebhookFile,
97
+ WebhookPush,
98
+ WebhookSecret,
99
+ WebhookSecretCreated,
100
+ WebhookSecretCreateRequest,
101
+ WebhookSubscription,
102
+ WebhookSubscriptionCreated,
103
+ WebhookSubscriptionCreateRequest,
104
+ )
105
+ from ._pagination import AsyncPage, Envelope, Page
106
+ from ._types import NOT_GIVEN, NotGiven
107
+ from ._version import __version__
108
+ from .webhooks import EventType, WebhookEvent, WebhookHandler
109
+
110
+ __all__ = [
111
+ "AiAnalysis",
112
+ "AiAnalysisCreateRequest",
113
+ "AiAnalysisResult",
114
+ "AiAnalysisRun",
115
+ "AsyncPage",
116
+ "AsyncZelfAPIClient",
117
+ "AuthenticationError",
118
+ "BadRequestError",
119
+ "Brand",
120
+ "BrandAccount",
121
+ "BrandAccountGroups",
122
+ "BrandAccountsWriteRequest",
123
+ "BrandCatalog",
124
+ "BrandCatalogItem",
125
+ "BrandCreateSubBrandRequest",
126
+ "BrandKeywords",
127
+ "Comment",
128
+ "CommentAuthor",
129
+ "ConflictError",
130
+ "Content",
131
+ "ContentActionRequestRequest",
132
+ "ContentActionResponse",
133
+ "ContentCreator",
134
+ "ContentDiscovery",
135
+ "ContentDiscoveryRequestRequest",
136
+ "ContentFilterInputRequest",
137
+ "ContentScopeRequest",
138
+ "ContentStatistics",
139
+ "Creator",
140
+ "CreatorSync",
141
+ "CreatorSyncCreateRequest",
142
+ "CreatorVetting",
143
+ "CreatorVettingRequest",
144
+ "CreatorVettingResult",
145
+ "CreatorVettingRun",
146
+ "Detection",
147
+ "DetectionBrandHint",
148
+ "DetectionBrandHintRequest",
149
+ "DetectionBrandResult",
150
+ "DetectionBrandSummary",
151
+ "DetectionContext",
152
+ "DetectionContextInputRequest",
153
+ "DetectionCreateRequest",
154
+ "DetectionHints",
155
+ "DetectionHintsRequest",
156
+ "DetectionPlacement",
157
+ "DetectionResult",
158
+ "DetectionSummary",
159
+ "DetectionVideo",
160
+ "Envelope",
161
+ "Error",
162
+ "Error1",
163
+ "Error2",
164
+ "Error3",
165
+ "Error4",
166
+ "Error400",
167
+ "Error401",
168
+ "Error403",
169
+ "Error404",
170
+ "Error406",
171
+ "Error429",
172
+ "Error5",
173
+ "Error500",
174
+ "Error503",
175
+ "Error6",
176
+ "Error7",
177
+ "ErrorCode",
178
+ "EventType",
179
+ "InternalServerError",
180
+ "NOT_GIVEN",
181
+ "NotAcceptableError",
182
+ "NotFoundError",
183
+ "NotGiven",
184
+ "Page",
185
+ "PatchedBrandUpdateRequest",
186
+ "PatchedWebhookSubscriptionUpdateRequest",
187
+ "PermissionDeniedError",
188
+ "RateLimitError",
189
+ "ResponseParseError",
190
+ "ResultFile",
191
+ "SafetyCheckRequest",
192
+ "ServiceUnavailableError",
193
+ "Usage",
194
+ "UsageScope",
195
+ "UsageWindow",
196
+ "WebhookAvailableEvent",
197
+ "WebhookData",
198
+ "WebhookDeleteAcknowledgement",
199
+ "WebhookDelivery",
200
+ "WebhookEvent",
201
+ "WebhookFile",
202
+ "WebhookHandler",
203
+ "WebhookPush",
204
+ "WebhookSecret",
205
+ "WebhookSecretCreateRequest",
206
+ "WebhookSecretCreated",
207
+ "WebhookSubscription",
208
+ "WebhookSubscriptionCreateRequest",
209
+ "WebhookSubscriptionCreated",
210
+ "ZelfAPIClient",
211
+ "ZelfAPIClientAsync",
212
+ "ZelfAPIError",
213
+ "ZelfConnectionError",
214
+ "ZelfError",
215
+ "ZelfTimeoutError",
216
+ "webhooks",
217
+ "__version__",
218
+ ]
zelf/_client.py ADDED
@@ -0,0 +1,146 @@
1
+ # Generated by codegen. Do not edit by hand.
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from collections.abc import Mapping
7
+ from typing import Any
8
+
9
+ import httpx
10
+
11
+ from ._transport import AsyncTransport, SyncTransport
12
+ from .resources.ai_analysis import AiAnalysisResource, AsyncAiAnalysisResource
13
+ from .resources.brand_accounts import AsyncBrandAccountsResource, BrandAccountsResource
14
+ from .resources.brands import AsyncBrandsResource, BrandsResource
15
+ from .resources.comments import AsyncCommentsResource, CommentsResource
16
+ from .resources.content import AsyncContentResource, ContentResource
17
+ from .resources.creator_sync import AsyncCreatorSyncResource, CreatorSyncResource
18
+ from .resources.creator_vetting import AsyncCreatorVettingResource, CreatorVettingResource
19
+ from .resources.creators import AsyncCreatorsResource, CreatorsResource
20
+ from .resources.detection import AsyncDetectionResource, DetectionResource
21
+ from .resources.sub_brands import AsyncSubBrandsResource, SubBrandsResource
22
+ from .resources.usage import AsyncUsageResource, UsageResource
23
+ from .resources.webhooks import AsyncWebhooksResource, WebhooksResource
24
+
25
+ DEFAULT_BASE_URL = "https://api.hellozelf.com"
26
+ BASE_URL_ENV = "ZELF_BASE_URL"
27
+
28
+
29
+ def default_base_url() -> str:
30
+ """The explicit argument wins, then ZELF_BASE_URL, then the production API."""
31
+ return os.environ.get(BASE_URL_ENV) or DEFAULT_BASE_URL
32
+
33
+
34
+ API_KEY_ENV = "ZELF_API_KEY"
35
+
36
+
37
+ class ZelfAPIClient:
38
+ """Synchronous client for the ZelfAI APIs.
39
+
40
+ The key is read from the `api_key` argument, falling back to the
41
+ `ZELF_API_KEY` environment variable. It is sent as the `x-api-key`
42
+ header and is kept out of `repr()` output.
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ api_key: str | None = None,
48
+ *,
49
+ base_url: str | None = None,
50
+ timeout: float = 60.0,
51
+ max_retries: int = 2,
52
+ retry_writes: bool = False,
53
+ default_headers: Mapping[str, str] | None = None,
54
+ http_client: httpx.Client | None = None,
55
+ ) -> None:
56
+ self._transport = SyncTransport(
57
+ api_key or os.environ.get(API_KEY_ENV, ""),
58
+ base_url=base_url or default_base_url(),
59
+ timeout=timeout,
60
+ max_retries=max_retries,
61
+ retry_writes=retry_writes,
62
+ default_headers=default_headers,
63
+ http_client=http_client,
64
+ )
65
+ self.ai_analysis = AiAnalysisResource(self._transport)
66
+ self.brand_accounts = BrandAccountsResource(self._transport)
67
+ self.brands = BrandsResource(self._transport)
68
+ self.comments = CommentsResource(self._transport)
69
+ self.content = ContentResource(self._transport)
70
+ self.creator_sync = CreatorSyncResource(self._transport)
71
+ self.creator_vetting = CreatorVettingResource(self._transport)
72
+ self.creators = CreatorsResource(self._transport)
73
+ self.detection = DetectionResource(self._transport)
74
+ self.sub_brands = SubBrandsResource(self._transport)
75
+ self.usage = UsageResource(self._transport)
76
+ self.webhooks = WebhooksResource(self._transport)
77
+
78
+ def __repr__(self) -> str:
79
+ return f"ZelfAPIClient(base_url={self._transport.base_url!r}, api_key='***')"
80
+
81
+ def close(self) -> None:
82
+ self._transport.close()
83
+
84
+ def __enter__(self) -> ZelfAPIClient:
85
+ return self
86
+
87
+ def __exit__(self, *_: Any) -> None:
88
+ self.close()
89
+
90
+
91
+ class ZelfAPIClientAsync:
92
+ """Asynchronous client for the ZelfAI APIs.
93
+
94
+ The key is read from the `api_key` argument, falling back to the
95
+ `ZELF_API_KEY` environment variable. It is sent as the `x-api-key`
96
+ header and is kept out of `repr()` output.
97
+ """
98
+
99
+ def __init__(
100
+ self,
101
+ api_key: str | None = None,
102
+ *,
103
+ base_url: str | None = None,
104
+ timeout: float = 60.0,
105
+ max_retries: int = 2,
106
+ retry_writes: bool = False,
107
+ default_headers: Mapping[str, str] | None = None,
108
+ http_client: httpx.AsyncClient | None = None,
109
+ ) -> None:
110
+ self._transport = AsyncTransport(
111
+ api_key or os.environ.get(API_KEY_ENV, ""),
112
+ base_url=base_url or default_base_url(),
113
+ timeout=timeout,
114
+ max_retries=max_retries,
115
+ retry_writes=retry_writes,
116
+ default_headers=default_headers,
117
+ http_client=http_client,
118
+ )
119
+ self.ai_analysis = AsyncAiAnalysisResource(self._transport)
120
+ self.brand_accounts = AsyncBrandAccountsResource(self._transport)
121
+ self.brands = AsyncBrandsResource(self._transport)
122
+ self.comments = AsyncCommentsResource(self._transport)
123
+ self.content = AsyncContentResource(self._transport)
124
+ self.creator_sync = AsyncCreatorSyncResource(self._transport)
125
+ self.creator_vetting = AsyncCreatorVettingResource(self._transport)
126
+ self.creators = AsyncCreatorsResource(self._transport)
127
+ self.detection = AsyncDetectionResource(self._transport)
128
+ self.sub_brands = AsyncSubBrandsResource(self._transport)
129
+ self.usage = AsyncUsageResource(self._transport)
130
+ self.webhooks = AsyncWebhooksResource(self._transport)
131
+
132
+ def __repr__(self) -> str:
133
+ return f"ZelfAPIClientAsync(base_url={self._transport.base_url!r}, api_key='***')"
134
+
135
+ async def close(self) -> None:
136
+ await self._transport.close()
137
+
138
+ async def __aenter__(self) -> ZelfAPIClientAsync:
139
+ return self
140
+
141
+ async def __aexit__(self, *_: Any) -> None:
142
+ await self.close()
143
+
144
+
145
+ # The earlier name for the asynchronous client; both are the same class.
146
+ AsyncZelfAPIClient = ZelfAPIClientAsync
zelf/_exceptions.py ADDED
@@ -0,0 +1,190 @@
1
+ # Generated by codegen. Do not edit by hand.
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, Literal
5
+
6
+ import httpx
7
+
8
+
9
+ class ZelfError(Exception):
10
+ pass
11
+
12
+
13
+ class ZelfConnectionError(ZelfError):
14
+ def __init__(self, message: str = "Could not reach the ZelfAI API.") -> None:
15
+ super().__init__(message)
16
+
17
+
18
+ class ZelfTimeoutError(ZelfConnectionError):
19
+ def __init__(self, message: str = "Request to the ZelfAI API timed out.") -> None:
20
+ super().__init__(message)
21
+
22
+
23
+ class ResponseParseError(ZelfError):
24
+ """A row in a 2xx response did not match the model the SDK expects.
25
+
26
+ The call reached the API and the API answered, so this is not an APIError.
27
+ The field that failed and the response's log_id are carried so the call can
28
+ be reported, and the pydantic error stays on `__cause__`.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ message: str,
34
+ *,
35
+ field: str | None = None,
36
+ log_id: str | None = None,
37
+ ) -> None:
38
+ super().__init__(message)
39
+ self.message = message
40
+ self.field = field
41
+ self.log_id = log_id
42
+
43
+ def __str__(self) -> str:
44
+ parts = [self.message]
45
+ if self.field:
46
+ parts.append(f"(field={self.field})")
47
+ if self.log_id:
48
+ parts.append(f"(log_id={self.log_id})")
49
+ return " ".join(parts)
50
+
51
+
52
+ class ZelfAPIError(ZelfError):
53
+ status_code: int = 0
54
+
55
+ def __init__(
56
+ self,
57
+ message: str,
58
+ *,
59
+ status_code: int,
60
+ code: str | None = None,
61
+ details: dict[str, Any] | None = None,
62
+ log_id: str | None = None,
63
+ response: httpx.Response | None = None,
64
+ ) -> None:
65
+ super().__init__(message)
66
+ self.message = message
67
+ self.status_code = status_code
68
+ self.code = code
69
+ self.details = details or {}
70
+ self.log_id = log_id
71
+ self.response = response
72
+
73
+ def __str__(self) -> str:
74
+ parts = [f"{self.status_code}"]
75
+ if self.code:
76
+ parts.append(self.code)
77
+ parts.append(self.message)
78
+ if self.log_id:
79
+ parts.append(f"(log_id={self.log_id})")
80
+ return " ".join(parts)
81
+
82
+
83
+ def parse(response: httpx.Response) -> ZelfAPIError:
84
+ code = message = log_id = None
85
+ details: dict[str, Any] = {}
86
+ try:
87
+ body = response.json()
88
+ except ValueError:
89
+ body = None
90
+ if isinstance(body, dict):
91
+ log_id = body.get("log_id")
92
+ error = body.get("error")
93
+ if isinstance(error, dict):
94
+ code = error.get("code")
95
+ message = error.get("message")
96
+ details = error.get("details") or {}
97
+ cls = STATUS_MAP.get(response.status_code, ZelfAPIError)
98
+ return cls(
99
+ message or f"HTTP {response.status_code} from the ZelfAI API.",
100
+ status_code=response.status_code,
101
+ code=code,
102
+ details=details,
103
+ log_id=log_id,
104
+ response=response,
105
+ )
106
+
107
+
108
+ class BadRequestError(ZelfAPIError):
109
+ """`VALIDATION_ERROR`, `INVALID_ID`, `BRAND_ID_REQUIRED`."""
110
+
111
+ status_code = 400
112
+
113
+
114
+ class AuthenticationError(ZelfAPIError):
115
+ """`INVALID_API_KEY`, `EXPIRED_API_KEY`, `REVOKED_API_KEY`."""
116
+
117
+ status_code = 401
118
+
119
+
120
+ class PermissionDeniedError(ZelfAPIError):
121
+ """`PERMISSION_DENIED`."""
122
+
123
+ status_code = 403
124
+
125
+
126
+ class NotFoundError(ZelfAPIError):
127
+ """`NOT_FOUND`."""
128
+
129
+ status_code = 404
130
+
131
+
132
+ class NotAcceptableError(ZelfAPIError):
133
+ """`NOT_ACCEPTABLE`."""
134
+
135
+ status_code = 406
136
+
137
+
138
+ class ConflictError(ZelfAPIError):
139
+ status_code = 409
140
+
141
+
142
+ class RateLimitError(ZelfAPIError):
143
+ """`RATE_LIMIT_EXCEEDED`."""
144
+
145
+ status_code = 429
146
+
147
+
148
+ class InternalServerError(ZelfAPIError):
149
+ """`INTERNAL_ERROR`."""
150
+
151
+ status_code = 500
152
+
153
+
154
+ class ServiceUnavailableError(ZelfAPIError):
155
+ """`SERVICE_UNAVAILABLE`."""
156
+
157
+ status_code = 503
158
+
159
+
160
+ class EmptyResultError(NotFoundError):
161
+ """A single-object read matched nothing. The API returns 200 with an
162
+ empty `results` array instead of a 404, so the SDK raises this."""
163
+
164
+
165
+ STATUS_MAP: dict[int, type[ZelfAPIError]] = {
166
+ 400: BadRequestError,
167
+ 401: AuthenticationError,
168
+ 403: PermissionDeniedError,
169
+ 404: NotFoundError,
170
+ 406: NotAcceptableError,
171
+ 409: ConflictError,
172
+ 429: RateLimitError,
173
+ 500: InternalServerError,
174
+ 503: ServiceUnavailableError,
175
+ }
176
+
177
+ ErrorCode = Literal[
178
+ "BRAND_ID_REQUIRED",
179
+ "EXPIRED_API_KEY",
180
+ "INTERNAL_ERROR",
181
+ "INVALID_API_KEY",
182
+ "INVALID_ID",
183
+ "NOT_ACCEPTABLE",
184
+ "NOT_FOUND",
185
+ "PERMISSION_DENIED",
186
+ "RATE_LIMIT_EXCEEDED",
187
+ "REVOKED_API_KEY",
188
+ "SERVICE_UNAVAILABLE",
189
+ "VALIDATION_ERROR",
190
+ ]