-
Notifications
You must be signed in to change notification settings - Fork 44.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into ntindle/open-1865-add-docs-on-playwright-test…
…ing-and-what-we-care-about
- Loading branch information
Showing
13 changed files
with
961 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
from enum import Enum | ||
from typing import Literal | ||
|
||
from pydantic import BaseModel, SecretStr | ||
|
||
from backend.data.model import APIKeyCredentials, CredentialsField, CredentialsMetaInput | ||
|
||
Slant3DCredentialsInput = CredentialsMetaInput[Literal["slant3d"], Literal["api_key"]] | ||
|
||
|
||
def Slant3DCredentialsField() -> Slant3DCredentialsInput: | ||
return CredentialsField( | ||
provider="slant3d", | ||
supported_credential_types={"api_key"}, | ||
description="Slant3D API key for authentication", | ||
) | ||
|
||
|
||
TEST_CREDENTIALS = APIKeyCredentials( | ||
id="01234567-89ab-cdef-0123-456789abcdef", | ||
provider="slant3d", | ||
api_key=SecretStr("mock-slant3d-api-key"), | ||
title="Mock Slant3D API key", | ||
expires_at=None, | ||
) | ||
|
||
TEST_CREDENTIALS_INPUT = { | ||
"provider": TEST_CREDENTIALS.provider, | ||
"id": TEST_CREDENTIALS.id, | ||
"type": TEST_CREDENTIALS.type, | ||
"title": TEST_CREDENTIALS.title, | ||
} | ||
|
||
|
||
class CustomerDetails(BaseModel): | ||
name: str | ||
email: str | ||
phone: str | ||
address: str | ||
city: str | ||
state: str | ||
zip: str | ||
country_iso: str = "US" | ||
is_residential: bool = True | ||
|
||
|
||
class Color(Enum): | ||
WHITE = "white" | ||
BLACK = "black" | ||
|
||
|
||
class Profile(Enum): | ||
PLA = "PLA" | ||
PETG = "PETG" | ||
|
||
|
||
class OrderItem(BaseModel): | ||
# filename: str | ||
file_url: str | ||
quantity: str # String as per API spec | ||
color: Color = Color.WHITE | ||
profile: Profile = Profile.PLA | ||
# image_url: str = "" | ||
# sku: str = "" | ||
|
||
|
||
class Filament(BaseModel): | ||
filament: str | ||
hexColor: str | ||
colorTag: str | ||
profile: str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
from typing import Any, Dict | ||
|
||
from backend.data.block import Block | ||
from backend.util.request import requests | ||
|
||
from ._api import Color, CustomerDetails, OrderItem, Profile | ||
|
||
|
||
class Slant3DBlockBase(Block): | ||
"""Base block class for Slant3D API interactions""" | ||
|
||
BASE_URL = "https://www.slant3dapi.com/api" | ||
|
||
def _get_headers(self, api_key: str) -> Dict[str, str]: | ||
return {"api-key": api_key, "Content-Type": "application/json"} | ||
|
||
def _make_request(self, method: str, endpoint: str, api_key: str, **kwargs) -> Dict: | ||
url = f"{self.BASE_URL}/{endpoint}" | ||
response = requests.request( | ||
method=method, url=url, headers=self._get_headers(api_key), **kwargs | ||
) | ||
|
||
if not response.ok: | ||
error_msg = response.json().get("error", "Unknown error") | ||
raise RuntimeError(f"API request failed: {error_msg}") | ||
|
||
return response.json() | ||
|
||
def _check_valid_color(self, profile: Profile, color: Color, api_key: str) -> str: | ||
response = self._make_request( | ||
"GET", | ||
"filament", | ||
api_key, | ||
params={"profile": profile.value, "color": color.value}, | ||
) | ||
if profile == Profile.PLA: | ||
color_tag = color.value | ||
else: | ||
color_tag = f"{profile.value.lower()}{color.value.capitalize()}" | ||
valid_tags = [filament["colorTag"] for filament in response["filaments"]] | ||
|
||
if color_tag not in valid_tags: | ||
raise ValueError( | ||
f"""Invalid color profile combination {color_tag}. | ||
Valid colors for {profile.value} are: | ||
{','.join([filament['colorTag'].replace(profile.value.lower(), '') for filament in response['filaments'] if filament['profile'] == profile.value])} | ||
""" | ||
) | ||
return color_tag | ||
|
||
def _convert_to_color(self, profile: Profile, color: Color, api_key: str) -> str: | ||
return self._check_valid_color(profile, color, api_key) | ||
|
||
def _format_order_data( | ||
self, | ||
customer: CustomerDetails, | ||
order_number: str, | ||
items: list[OrderItem], | ||
api_key: str, | ||
) -> list[dict[str, Any]]: | ||
"""Helper function to format order data for API requests""" | ||
orders = [] | ||
for item in items: | ||
order_data = { | ||
"email": customer.email, | ||
"phone": customer.phone, | ||
"name": customer.name, | ||
"orderNumber": order_number, | ||
"filename": item.file_url, | ||
"fileURL": item.file_url, | ||
"bill_to_street_1": customer.address, | ||
"bill_to_city": customer.city, | ||
"bill_to_state": customer.state, | ||
"bill_to_zip": customer.zip, | ||
"bill_to_country_as_iso": customer.country_iso, | ||
"bill_to_is_US_residential": str(customer.is_residential).lower(), | ||
"ship_to_name": customer.name, | ||
"ship_to_street_1": customer.address, | ||
"ship_to_city": customer.city, | ||
"ship_to_state": customer.state, | ||
"ship_to_zip": customer.zip, | ||
"ship_to_country_as_iso": customer.country_iso, | ||
"ship_to_is_US_residential": str(customer.is_residential).lower(), | ||
"order_item_name": item.file_url, | ||
"order_quantity": item.quantity, | ||
"order_image_url": "", | ||
"order_sku": "NOT_USED", | ||
"order_item_color": self._convert_to_color( | ||
item.profile, item.color, api_key | ||
), | ||
"profile": item.profile.value, | ||
} | ||
orders.append(order_data) | ||
return orders |
85 changes: 85 additions & 0 deletions
85
autogpt_platform/backend/backend/blocks/slant3d/filament.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
from typing import List | ||
|
||
from backend.data.block import BlockOutput, BlockSchema | ||
from backend.data.model import APIKeyCredentials, SchemaField | ||
|
||
from ._api import ( | ||
TEST_CREDENTIALS, | ||
TEST_CREDENTIALS_INPUT, | ||
Filament, | ||
Slant3DCredentialsField, | ||
Slant3DCredentialsInput, | ||
) | ||
from .base import Slant3DBlockBase | ||
|
||
|
||
class Slant3DFilamentBlock(Slant3DBlockBase): | ||
"""Block for retrieving available filaments""" | ||
|
||
class Input(BlockSchema): | ||
credentials: Slant3DCredentialsInput = Slant3DCredentialsField() | ||
|
||
class Output(BlockSchema): | ||
filaments: List[Filament] = SchemaField( | ||
description="List of available filaments" | ||
) | ||
error: str = SchemaField(description="Error message if request failed") | ||
|
||
def __init__(self): | ||
super().__init__( | ||
id="7cc416f4-f305-4606-9b3b-452b8a81031c", | ||
description="Get list of available filaments", | ||
input_schema=self.Input, | ||
output_schema=self.Output, | ||
test_input={"credentials": TEST_CREDENTIALS_INPUT}, | ||
test_credentials=TEST_CREDENTIALS, | ||
test_output=[ | ||
( | ||
"filaments", | ||
[ | ||
{ | ||
"filament": "PLA BLACK", | ||
"hexColor": "000000", | ||
"colorTag": "black", | ||
"profile": "PLA", | ||
}, | ||
{ | ||
"filament": "PLA WHITE", | ||
"hexColor": "ffffff", | ||
"colorTag": "white", | ||
"profile": "PLA", | ||
}, | ||
], | ||
) | ||
], | ||
test_mock={ | ||
"_make_request": lambda *args, **kwargs: { | ||
"filaments": [ | ||
{ | ||
"filament": "PLA BLACK", | ||
"hexColor": "000000", | ||
"colorTag": "black", | ||
"profile": "PLA", | ||
}, | ||
{ | ||
"filament": "PLA WHITE", | ||
"hexColor": "ffffff", | ||
"colorTag": "white", | ||
"profile": "PLA", | ||
}, | ||
] | ||
} | ||
}, | ||
) | ||
|
||
def run( | ||
self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs | ||
) -> BlockOutput: | ||
try: | ||
result = self._make_request( | ||
"GET", "filament", credentials.api_key.get_secret_value() | ||
) | ||
yield "filaments", result["filaments"] | ||
except Exception as e: | ||
yield "error", str(e) | ||
raise |
Oops, something went wrong.