Skip to content

Commit 4dc72c5

Browse files
feat(api): manual updates
1 parent 05d4432 commit 4dc72c5

7 files changed

Lines changed: 278 additions & 2 deletions

File tree

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 15
1+
configured_endpoints: 16
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f6fec0ae4fa4572aefa111e660f98f6acfb6149c22cbd413bd3defad6c100478.yml
33
openapi_spec_hash: a82bf07982eae3814e8a60eb368e0ce5
4-
config_hash: 6f10592c7d0c3bafefc1271472283217
4+
config_hash: c3aaaa9794dba44d524c06591ab17894

api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Types:
55
```python
66
from brand.dev.types import (
77
BrandRetrieveResponse,
8+
BrandAIProductResponse,
89
BrandAIProductsResponse,
910
BrandAIQueryResponse,
1011
BrandFontsResponse,
@@ -25,6 +26,7 @@ from brand.dev.types import (
2526
Methods:
2627

2728
- <code title="get /brand/retrieve">client.brand.<a href="./src/brand/dev/resources/brand.py">retrieve</a>(\*\*<a href="src/brand/dev/types/brand_retrieve_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_retrieve_response.py">BrandRetrieveResponse</a></code>
29+
- <code title="post /brand/ai/product">client.brand.<a href="./src/brand/dev/resources/brand.py">ai_product</a>(\*\*<a href="src/brand/dev/types/brand_ai_product_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_ai_product_response.py">BrandAIProductResponse</a></code>
2830
- <code title="post /brand/ai/products">client.brand.<a href="./src/brand/dev/resources/brand.py">ai_products</a>(\*\*<a href="src/brand/dev/types/brand_ai_products_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_ai_products_response.py">BrandAIProductsResponse</a></code>
2931
- <code title="post /brand/ai/query">client.brand.<a href="./src/brand/dev/resources/brand.py">ai_query</a>(\*\*<a href="src/brand/dev/types/brand_ai_query_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_ai_query_response.py">BrandAIQueryResponse</a></code>
3032
- <code title="get /brand/fonts">client.brand.<a href="./src/brand/dev/resources/brand.py">fonts</a>(\*\*<a href="src/brand/dev/types/brand_fonts_params.py">params</a>) -> <a href="./src/brand/dev/types/brand_fonts_response.py">BrandFontsResponse</a></code>

src/brand/dev/resources/brand.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
brand_ai_query_params,
1313
brand_prefetch_params,
1414
brand_retrieve_params,
15+
brand_ai_product_params,
1516
brand_screenshot_params,
1617
brand_styleguide_params,
1718
brand_ai_products_params,
@@ -39,6 +40,7 @@
3940
from ..types.brand_ai_query_response import BrandAIQueryResponse
4041
from ..types.brand_prefetch_response import BrandPrefetchResponse
4142
from ..types.brand_retrieve_response import BrandRetrieveResponse
43+
from ..types.brand_ai_product_response import BrandAIProductResponse
4244
from ..types.brand_screenshot_response import BrandScreenshotResponse
4345
from ..types.brand_styleguide_response import BrandStyleguideResponse
4446
from ..types.brand_ai_products_response import BrandAIProductsResponse
@@ -189,6 +191,52 @@ def retrieve(
189191
cast_to=BrandRetrieveResponse,
190192
)
191193

194+
def ai_product(
195+
self,
196+
*,
197+
url: str,
198+
timeout_ms: int | Omit = omit,
199+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
200+
# The extra values given here take precedence over values defined on the client or passed to this method.
201+
extra_headers: Headers | None = None,
202+
extra_query: Query | None = None,
203+
extra_body: Body | None = None,
204+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
205+
) -> BrandAIProductResponse:
206+
"""
207+
Beta feature: Given a single URL, determines if it is a product detail page,
208+
classifies the platform/product type, and extracts the product information.
209+
Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.
210+
211+
Args:
212+
url: The product page URL to extract product data from.
213+
214+
timeout_ms: Optional timeout in milliseconds for the request. Maximum allowed value is
215+
300000ms (5 minutes).
216+
217+
extra_headers: Send extra headers
218+
219+
extra_query: Add additional query parameters to the request
220+
221+
extra_body: Add additional JSON properties to the request
222+
223+
timeout: Override the client-level default timeout for this request, in seconds
224+
"""
225+
return self._post(
226+
"/brand/ai/product",
227+
body=maybe_transform(
228+
{
229+
"url": url,
230+
"timeout_ms": timeout_ms,
231+
},
232+
brand_ai_product_params.BrandAIProductParams,
233+
),
234+
options=make_request_options(
235+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
236+
),
237+
cast_to=BrandAIProductResponse,
238+
)
239+
192240
@overload
193241
def ai_products(
194242
self,
@@ -1785,6 +1833,52 @@ async def retrieve(
17851833
cast_to=BrandRetrieveResponse,
17861834
)
17871835

1836+
async def ai_product(
1837+
self,
1838+
*,
1839+
url: str,
1840+
timeout_ms: int | Omit = omit,
1841+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1842+
# The extra values given here take precedence over values defined on the client or passed to this method.
1843+
extra_headers: Headers | None = None,
1844+
extra_query: Query | None = None,
1845+
extra_body: Body | None = None,
1846+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
1847+
) -> BrandAIProductResponse:
1848+
"""
1849+
Beta feature: Given a single URL, determines if it is a product detail page,
1850+
classifies the platform/product type, and extracts the product information.
1851+
Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.
1852+
1853+
Args:
1854+
url: The product page URL to extract product data from.
1855+
1856+
timeout_ms: Optional timeout in milliseconds for the request. Maximum allowed value is
1857+
300000ms (5 minutes).
1858+
1859+
extra_headers: Send extra headers
1860+
1861+
extra_query: Add additional query parameters to the request
1862+
1863+
extra_body: Add additional JSON properties to the request
1864+
1865+
timeout: Override the client-level default timeout for this request, in seconds
1866+
"""
1867+
return await self._post(
1868+
"/brand/ai/product",
1869+
body=await async_maybe_transform(
1870+
{
1871+
"url": url,
1872+
"timeout_ms": timeout_ms,
1873+
},
1874+
brand_ai_product_params.BrandAIProductParams,
1875+
),
1876+
options=make_request_options(
1877+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
1878+
),
1879+
cast_to=BrandAIProductResponse,
1880+
)
1881+
17881882
@overload
17891883
async def ai_products(
17901884
self,
@@ -3253,6 +3347,9 @@ def __init__(self, brand: BrandResource) -> None:
32533347
self.retrieve = to_raw_response_wrapper(
32543348
brand.retrieve,
32553349
)
3350+
self.ai_product = to_raw_response_wrapper(
3351+
brand.ai_product,
3352+
)
32563353
self.ai_products = to_raw_response_wrapper(
32573354
brand.ai_products,
32583355
)
@@ -3304,6 +3401,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
33043401
self.retrieve = async_to_raw_response_wrapper(
33053402
brand.retrieve,
33063403
)
3404+
self.ai_product = async_to_raw_response_wrapper(
3405+
brand.ai_product,
3406+
)
33073407
self.ai_products = async_to_raw_response_wrapper(
33083408
brand.ai_products,
33093409
)
@@ -3355,6 +3455,9 @@ def __init__(self, brand: BrandResource) -> None:
33553455
self.retrieve = to_streamed_response_wrapper(
33563456
brand.retrieve,
33573457
)
3458+
self.ai_product = to_streamed_response_wrapper(
3459+
brand.ai_product,
3460+
)
33583461
self.ai_products = to_streamed_response_wrapper(
33593462
brand.ai_products,
33603463
)
@@ -3406,6 +3509,9 @@ def __init__(self, brand: AsyncBrandResource) -> None:
34063509
self.retrieve = async_to_streamed_response_wrapper(
34073510
brand.retrieve,
34083511
)
3512+
self.ai_product = async_to_streamed_response_wrapper(
3513+
brand.ai_product,
3514+
)
34093515
self.ai_products = async_to_streamed_response_wrapper(
34103516
brand.ai_products,
34113517
)

src/brand/dev/types/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
from .brand_ai_query_params import BrandAIQueryParams as BrandAIQueryParams
88
from .brand_prefetch_params import BrandPrefetchParams as BrandPrefetchParams
99
from .brand_retrieve_params import BrandRetrieveParams as BrandRetrieveParams
10+
from .brand_ai_product_params import BrandAIProductParams as BrandAIProductParams
1011
from .brand_ai_query_response import BrandAIQueryResponse as BrandAIQueryResponse
1112
from .brand_prefetch_response import BrandPrefetchResponse as BrandPrefetchResponse
1213
from .brand_retrieve_response import BrandRetrieveResponse as BrandRetrieveResponse
1314
from .brand_screenshot_params import BrandScreenshotParams as BrandScreenshotParams
1415
from .brand_styleguide_params import BrandStyleguideParams as BrandStyleguideParams
1516
from .brand_ai_products_params import BrandAIProductsParams as BrandAIProductsParams
17+
from .brand_ai_product_response import BrandAIProductResponse as BrandAIProductResponse
1618
from .brand_screenshot_response import BrandScreenshotResponse as BrandScreenshotResponse
1719
from .brand_styleguide_response import BrandStyleguideResponse as BrandStyleguideResponse
1820
from .brand_ai_products_response import BrandAIProductsResponse as BrandAIProductsResponse
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Required, Annotated, TypedDict
6+
7+
from .._utils import PropertyInfo
8+
9+
__all__ = ["BrandAIProductParams"]
10+
11+
12+
class BrandAIProductParams(TypedDict, total=False):
13+
url: Required[str]
14+
"""The product page URL to extract product data from."""
15+
16+
timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")]
17+
"""Optional timeout in milliseconds for the request.
18+
19+
Maximum allowed value is 300000ms (5 minutes).
20+
"""
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from typing import List, Optional
4+
from typing_extensions import Literal
5+
6+
from .._models import BaseModel
7+
8+
__all__ = ["BrandAIProductResponse", "Product"]
9+
10+
11+
class Product(BaseModel):
12+
"""The extracted product data, or null if not a product page"""
13+
14+
description: str
15+
"""Description of the product"""
16+
17+
features: List[str]
18+
"""List of product features"""
19+
20+
name: str
21+
"""Name of the product"""
22+
23+
tags: List[str]
24+
"""Tags associated with the product"""
25+
26+
target_audience: List[str]
27+
"""Target audience for the product (array of strings)"""
28+
29+
billing_frequency: Optional[Literal["monthly", "yearly", "one_time", "usage_based"]] = None
30+
"""Billing frequency for the product"""
31+
32+
category: Optional[str] = None
33+
"""Category of the product"""
34+
35+
currency: Optional[str] = None
36+
"""Currency code for the price (e.g., USD, EUR)"""
37+
38+
image_url: Optional[str] = None
39+
"""URL to the product image"""
40+
41+
price: Optional[float] = None
42+
"""Price of the product"""
43+
44+
pricing_model: Optional[Literal["per_seat", "flat", "tiered", "freemium", "custom"]] = None
45+
"""Pricing model for the product"""
46+
47+
url: Optional[str] = None
48+
"""URL to the product page"""
49+
50+
51+
class BrandAIProductResponse(BaseModel):
52+
is_product_page: Optional[bool] = None
53+
"""Whether the given URL is a product detail page"""
54+
55+
platform: Optional[Literal["amazon", "tiktok_shop", "etsy", "generic"]] = None
56+
"""The detected ecommerce platform, or null if not a product page"""
57+
58+
product: Optional[Product] = None
59+
"""The extracted product data, or null if not a product page"""

tests/api_resources/test_brand.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
BrandAIQueryResponse,
1515
BrandPrefetchResponse,
1616
BrandRetrieveResponse,
17+
BrandAIProductResponse,
1718
BrandAIProductsResponse,
1819
BrandScreenshotResponse,
1920
BrandStyleguideResponse,
@@ -78,6 +79,49 @@ def test_streaming_response_retrieve(self, client: BrandDev) -> None:
7879

7980
assert cast(Any, response.is_closed) is True
8081

82+
@pytest.mark.skip(reason="Prism tests are disabled")
83+
@parametrize
84+
def test_method_ai_product(self, client: BrandDev) -> None:
85+
brand = client.brand.ai_product(
86+
url="https://example.com",
87+
)
88+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
89+
90+
@pytest.mark.skip(reason="Prism tests are disabled")
91+
@parametrize
92+
def test_method_ai_product_with_all_params(self, client: BrandDev) -> None:
93+
brand = client.brand.ai_product(
94+
url="https://example.com",
95+
timeout_ms=1,
96+
)
97+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
98+
99+
@pytest.mark.skip(reason="Prism tests are disabled")
100+
@parametrize
101+
def test_raw_response_ai_product(self, client: BrandDev) -> None:
102+
response = client.brand.with_raw_response.ai_product(
103+
url="https://example.com",
104+
)
105+
106+
assert response.is_closed is True
107+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
108+
brand = response.parse()
109+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
110+
111+
@pytest.mark.skip(reason="Prism tests are disabled")
112+
@parametrize
113+
def test_streaming_response_ai_product(self, client: BrandDev) -> None:
114+
with client.brand.with_streaming_response.ai_product(
115+
url="https://example.com",
116+
) as response:
117+
assert not response.is_closed
118+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
119+
120+
brand = response.parse()
121+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
122+
123+
assert cast(Any, response.is_closed) is True
124+
81125
@pytest.mark.skip(reason="Prism tests are disabled")
82126
@parametrize
83127
def test_method_ai_products_overload_1(self, client: BrandDev) -> None:
@@ -844,6 +888,49 @@ async def test_streaming_response_retrieve(self, async_client: AsyncBrandDev) ->
844888

845889
assert cast(Any, response.is_closed) is True
846890

891+
@pytest.mark.skip(reason="Prism tests are disabled")
892+
@parametrize
893+
async def test_method_ai_product(self, async_client: AsyncBrandDev) -> None:
894+
brand = await async_client.brand.ai_product(
895+
url="https://example.com",
896+
)
897+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
898+
899+
@pytest.mark.skip(reason="Prism tests are disabled")
900+
@parametrize
901+
async def test_method_ai_product_with_all_params(self, async_client: AsyncBrandDev) -> None:
902+
brand = await async_client.brand.ai_product(
903+
url="https://example.com",
904+
timeout_ms=1,
905+
)
906+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
907+
908+
@pytest.mark.skip(reason="Prism tests are disabled")
909+
@parametrize
910+
async def test_raw_response_ai_product(self, async_client: AsyncBrandDev) -> None:
911+
response = await async_client.brand.with_raw_response.ai_product(
912+
url="https://example.com",
913+
)
914+
915+
assert response.is_closed is True
916+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
917+
brand = await response.parse()
918+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
919+
920+
@pytest.mark.skip(reason="Prism tests are disabled")
921+
@parametrize
922+
async def test_streaming_response_ai_product(self, async_client: AsyncBrandDev) -> None:
923+
async with async_client.brand.with_streaming_response.ai_product(
924+
url="https://example.com",
925+
) as response:
926+
assert not response.is_closed
927+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
928+
929+
brand = await response.parse()
930+
assert_matches_type(BrandAIProductResponse, brand, path=["response"])
931+
932+
assert cast(Any, response.is_closed) is True
933+
847934
@pytest.mark.skip(reason="Prism tests are disabled")
848935
@parametrize
849936
async def test_method_ai_products_overload_1(self, async_client: AsyncBrandDev) -> None:

0 commit comments

Comments
 (0)