Skip to content

Introducing image_generation to Jigsawstack-python: #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"files": {
"ignoreUnknown": false,
"ignore": []
},
"formatter": {
"enabled": true,
"useEditorconfig": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 150,
"attributePosition": "auto",
"bracketSpacing": true
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": false
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "es5",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSameLine": false,
"quoteStyle": "double",
"attributePosition": "auto",
"bracketSpacing": true
}
}
}
14 changes: 14 additions & 0 deletions jigsawstack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
from .prompt_engine import PromptEngine, AsyncPromptEngine
from .embedding import Embedding, AsyncEmbedding
from .exceptions import JigsawStackError
from .image_generation import ImageGeneration, AsyncImageGeneration


class JigsawStack:
audio: Audio
vision: Vision
image_generation: ImageGeneration
file: Store
web: Web
search: Search
Expand Down Expand Up @@ -116,6 +118,11 @@ def __init__(
api_url=api_url,
disable_request_logging=disable_request_logging,
).execute
self.image_generation = ImageGeneration(
api_key=api_key,
api_url=api_url,
disable_request_logging=disable_request_logging,
).image_generation


class AsyncJigsawStack:
Expand All @@ -124,6 +131,7 @@ class AsyncJigsawStack:
web: AsyncWeb
audio: AsyncAudio
vision: AsyncVision
image_generation: AsyncImageGeneration
store: AsyncStore
prompt_engine: AsyncPromptEngine
api_key: str
Expand Down Expand Up @@ -227,6 +235,12 @@ def __init__(
disable_request_logging=disable_request_logging,
).execute

self.image_generation = AsyncImageGeneration(
api_key=api_key,
api_url=api_url,
disable_request_logging=disable_request_logging,
).image_generation


# Create a global instance of the Web class
__all__ = ["JigsawStack", "Search", "JigsawStackError", "AsyncJigsawStack"]
103 changes: 103 additions & 0 deletions jigsawstack/image_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from typing import Any, Dict, List, Union, cast
from typing_extensions import NotRequired, TypedDict, Literal, Required
from .request import Request, RequestConfig
from .async_request import AsyncRequest

from typing import List, Union
from ._config import ClientConfig

class ImageGenerationParams(TypedDict):
prompt: Required[str]
""""
The text to generate the image from."
"""
aspect_ratio: NotRequired[Literal["1:1", "16:9", "21:9", "3:2", "2:3", "4:5", "5:4", "3:4", "4:3", "9:16", "9:21"]]
"""
The aspect ratio of the image. The default is 1:1.
"""
width: NotRequired[int]
""""
The width of the image. The default is 512."
"""
height: NotRequired[int]
"""
The height of the image. The default is 512."
"""
steps: NotRequired[int]
""""
The number of steps to generate the image.""
"""
advance_config: NotRequired[Dict[str, Union[int, str]]]
"""
The advance configuration for the image generation. The default is None.
You can pass the following:
- `seed`: The seed for the image generation. The default is None.
- `guidance`: The guidance for the image generation. The default is None.
- `negative_prompt`: The negative prompt for the image generation. The default is None.
"""

class ImageGenerationResponse(TypedDict):
success: bool
"""
Indicates whether the image generation was successful.
"""
image: bytes
"""
The generated image as a blob.
"""

class ImageGeneration(ClientConfig):
config: RequestConfig

def __init__(
self,
api_key: str,
api_url: str,
disable_request_logging: Union[bool, None] = False,
):
super().__init__(api_key, api_url, disable_request_logging=disable_request_logging)
self.config = RequestConfig(
api_url=api_url,
api_key=api_key,
disable_request_logging=disable_request_logging,
)

def image_generation(self, params: ImageGenerationParams) -> ImageGenerationResponse:
path = "/ai/image_generation"
resp = Request(
config=self.config,
path=path,
params=cast(Dict[Any, Any], params), # type: ignore
verb="post",
).perform()
return resp

class AsyncImageGeneration(ClientConfig):
config: RequestConfig

def __init__(
self,
api_key: str,
api_url: str,
disable_request_logging: Union[bool, None] = False,
):
super().__init__(api_key, api_url, disable_request_logging=disable_request_logging)
self.config = RequestConfig(
api_url=api_url,
api_key=api_key,
disable_request_logging=disable_request_logging,
)

async def image_generation(self, params: ImageGenerationParams) -> ImageGenerationResponse:
path = "/ai/image_generation"
resp = await AsyncRequest(
config=self.config,
path=path,
params=cast(Dict[Any, Any], params), # type: ignore
verb="post",
).perform()
return resp




8 changes: 5 additions & 3 deletions jigsawstack/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ def perform(self) -> Union[T, None]:

# this is a safety net, if we get here it means the JigsawStack API is having issues
# and most likely the gateway is returning htmls
if "application/json" not in resp.headers["content-type"] and "audio/wav" not in resp.headers["content-type"]:
if "application/json" not in resp.headers["content-type"] \
and "audio/wav" not in resp.headers["content-type"] \
and "image/png" not in resp.headers["content-type"]:
raise_for_code_and_type(
code=500,
message="Failed to parse JigsawStack API response. Please try again.",
Expand All @@ -72,9 +74,9 @@ def perform(self) -> Union[T, None]:
err=error.get("error"),
)

if "audio/wav" in resp.headers["content-type"]:
if "audio/wav" or "image/png" in resp.headers["content-type"]:
return cast(T, resp) # we return the response object, instead of the json

return cast(T, resp.json())

def perform_file(self) -> Union[T, None]:
Expand Down
38 changes: 7 additions & 31 deletions jigsawstack/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,22 @@
from .request import Request, RequestConfig
from .async_request import AsyncRequest, AsyncRequestConfig
from ._config import ClientConfig
from typing import Any, Dict, List, cast
from typing_extensions import NotRequired, TypedDict


class FileDeleteResponse(TypedDict):
success: bool


class KVGetParams(TypedDict):
key: str


class KVGetResponse(TypedDict):
class FileDeleteResponse(TypedDict):
success: bool
value: str


class KVAddParams(TypedDict):
key: str
value: str
encrypt: NotRequired[bool]
byo_secret: NotRequired[str]


class KVAddResponse(TypedDict):
success: bool


class FileUploadParams(TypedDict):
overwrite: bool
filename: str
content_type: NotRequired[str]


class KV(ClientConfig):


config: RequestConfig

Expand Down Expand Up @@ -83,7 +64,6 @@ def delete(self, key: str) -> KVGetResponse:
class Store(ClientConfig):

config: RequestConfig
kv: KV

def __init__(
self,
Expand All @@ -98,8 +78,6 @@ def __init__(
disable_request_logging=disable_request_logging,
)

self.kv = KV(api_key, api_url, disable_request_logging)

def upload(self, file: bytes, options=FileUploadParams) -> Any:
overwrite = options.get("overwrite")
filename = options.get("filename")
Expand All @@ -121,7 +99,7 @@ def upload(self, file: bytes, options=FileUploadParams) -> Any:
return resp

def get(self, key: str) -> Any:
path = f"/store/file/{key}"
path = f"/store/file/read/{key}"
resp = Request(
config=self.config,
path=path,
Expand All @@ -131,7 +109,7 @@ def get(self, key: str) -> Any:
return resp

def delete(self, key: str) -> FileDeleteResponse:
path = f"/store/file/{key}"
path = f"/store/file/read/{key}"
resp = Request(
config=self.config,
path=path,
Expand All @@ -141,7 +119,6 @@ def delete(self, key: str) -> FileDeleteResponse:
return resp


class AsyncKV(ClientConfig):

config: AsyncRequestConfig

Expand Down Expand Up @@ -188,7 +165,6 @@ async def delete(self, key: str) -> KVGetResponse:

class AsyncStore(ClientConfig):
config: AsyncRequestConfig
kv: AsyncKV

def __init__(
self,
Expand All @@ -202,7 +178,7 @@ def __init__(
api_key=api_key,
disable_request_logging=disable_request_logging,
)
self.kv = AsyncKV(api_key, api_url, disable_request_logging)


async def upload(self, file: bytes, options=FileUploadParams) -> Any:
overwrite = options.get("overwrite")
Expand All @@ -225,7 +201,7 @@ async def upload(self, file: bytes, options=FileUploadParams) -> Any:
return resp

async def get(self, key: str) -> Any:
path = f"/store/file/{key}"
path = f"/store/file/read/{key}"
resp = await AsyncRequest(
config=self.config,
path=path,
Expand All @@ -235,7 +211,7 @@ async def get(self, key: str) -> Any:
return resp

async def delete(self, key: str) -> FileDeleteResponse:
path = f"/store/file/{key}"
path = f"/store/file/read/{key}"
resp = AsyncRequest(
config=self.config,
path=path,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name="jigsawstack",
version="0.1.29",
version="0.1.30",
description="JigsawStack Python SDK",
long_description=open("README.md", encoding="utf8").read(),
long_description_content_type="text/markdown",
Expand Down
Loading