Skip to content

Commit 593ad06

Browse files
authored
Merge pull request #24 from JigsawStack/update
Update
2 parents 39cc942 + ec238a7 commit 593ad06

File tree

7 files changed

+118
-22
lines changed

7 files changed

+118
-22
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ jigsawstack.egg-info/
66
.env
77
build/
88
dist/
9-
/demo
9+
/demo
10+
11+
test.py
12+
test_web.py

jigsawstack/prompt_engine.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Dict, List, Union, cast
1+
from typing import Any, Dict, List, Union, cast, Generator
22
from typing_extensions import NotRequired, TypedDict
33
from .request import Request, RequestConfig
44
from typing import List, Union
@@ -15,13 +15,15 @@ class PromptEngineRunParams(TypedDict):
1515
prompt: str
1616
inputs: NotRequired[List[object]]
1717
return_prompt: Union[str, List[object], Dict[str, str]]
18-
# grok_key: NotRequired[str]
1918
input_values: NotRequired[Dict[str, str]]
19+
stream: Union[bool, None] = False
20+
use_internet: Union[bool, None] = False
2021

2122

2223
class PromptEngineExecuteParams(TypedDict):
2324
id: str
2425
input_values: object
26+
stream: Union[bool, None] = False
2527

2628

2729
class PromptEngineRunResponse(TypedDict):
@@ -31,9 +33,10 @@ class PromptEngineRunResponse(TypedDict):
3133

3234
class PromptEngineCreateParams(TypedDict):
3335
prompt: str
34-
# grok_key: NotRequired[str]
3536
inputs: NotRequired[List[object]]
3637
return_prompt: Union[str, List[object], Dict[str, str]]
38+
use_internet: Union[bool, None] = False
39+
optimize_prompt: Union[bool, None] = False
3740

3841

3942
class PromptEngineCreateResponse(TypedDict):
@@ -128,8 +131,18 @@ def delete(self, id: str) -> PromptEngineDeleteResponse:
128131

129132
def run_prompt_direct(
130133
self, params: PromptEngineRunParams
131-
) -> PromptEngineRunResponse:
134+
) -> Union[PromptEngineRunResponse, Generator[Any, None, None]]:
132135
path = "/prompt_engine/run"
136+
stream = params.get("stream")
137+
if stream:
138+
resp = Request(
139+
config=self.config,
140+
path=path,
141+
params=cast(Dict[Any, Any], params),
142+
verb="post",
143+
).perform_with_content_streaming()
144+
return resp
145+
133146
resp = Request(
134147
config=self.config,
135148
path=path,
@@ -138,9 +151,22 @@ def run_prompt_direct(
138151
).perform_with_content()
139152
return resp
140153

141-
def run(self, params: PromptEngineExecuteParams) -> PromptEngineRunResponse:
154+
def run(
155+
self, params: PromptEngineExecuteParams
156+
) -> Union[PromptEngineRunResponse, Generator[Any, None, None]]:
142157
id = params.get("id")
143158
path = f"/prompt_engine/{id}"
159+
stream = params.get("stream")
160+
161+
if stream:
162+
resp = Request(
163+
config=self.config,
164+
path=path,
165+
params=cast(Dict[Any, Any], params),
166+
verb="post",
167+
).perform_with_content_streaming()
168+
return resp
169+
144170
resp = Request(
145171
config=self.config,
146172
path=path,

jigsawstack/request.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from typing import Any, Dict, Generic, List, Union, cast, TypedDict
1+
from typing import Any, Dict, Generic, List, Union, cast, TypedDict, Generator
22
import requests
33
from typing_extensions import Literal, TypeVar
44
from .exceptions import NoContentError, raise_for_code_and_type
5+
import json
56

67
RequestVerb = Literal["get", "post", "put", "patch", "delete"]
78

@@ -24,6 +25,7 @@ def __init__(
2425
verb: RequestVerb,
2526
headers: Dict[str, str] = {"Content-Type": "application/json"},
2627
data: Union[bytes, None] = None,
28+
stream: Union[bool, None] = False,
2729
):
2830
self.path = path
2931
self.params = params
@@ -33,6 +35,7 @@ def __init__(
3335
self.data = data
3436
self.headers = headers
3537
self.disable_request_logging = config.get("disable_request_logging")
38+
self.stream = stream
3639

3740
def perform(self) -> Union[T, None]:
3841
"""Is the main function that makes the HTTP request
@@ -152,6 +155,67 @@ def __get_headers(self) -> Dict[Any, Any]:
152155

153156
return _headers
154157

158+
def perform_streaming(self) -> Generator[Union[T, str], None, None]:
159+
"""Is the main function that makes the HTTP request
160+
to the JigsawStack API. It uses the path, params, and verb attributes
161+
to make the request.
162+
163+
Returns:
164+
Generator[bytes, None, None]: A generator of bytes
165+
166+
Raises:
167+
requests.HTTPError: If the request fails
168+
"""
169+
resp = self.make_request(url=f"{self.api_url}{self.path}")
170+
171+
# delete calls do not return a body
172+
if resp.text == "":
173+
return None
174+
175+
if resp.status_code != 200:
176+
error = resp.json()
177+
raise_for_code_and_type(
178+
code=resp.status_code,
179+
message=error.get("message"),
180+
err=error.get("error"),
181+
)
182+
183+
def try_parse_data(chunk: bytes) -> Union[T, str]:
184+
if not chunk:
185+
return chunk
186+
# Decode bytes to text
187+
text = chunk.decode("utf-8")
188+
189+
try:
190+
# Try to parse as JSON
191+
return json.loads(text)
192+
except json.JSONDecodeError:
193+
# Return as text if not valid JSON
194+
return text
195+
196+
# Yield content in chunks
197+
def chunk_generator():
198+
for chunk in resp.iter_content(chunk_size=1024): # 1KB chunks
199+
if chunk: # Filter out keep-alive new chunks
200+
yield try_parse_data(chunk)
201+
202+
return chunk_generator()
203+
204+
def perform_with_content_streaming(self) -> Generator[Union[T, str], None, None]:
205+
"""
206+
Perform an HTTP request and return the response content as a streaming response.
207+
208+
Returns:
209+
T: The content of the response
210+
211+
Raises:
212+
NoContentError: If the response content is `None`.
213+
"""
214+
resp = self.perform_streaming()
215+
if resp is None:
216+
raise NoContentError()
217+
return resp
218+
155219
def make_request(self, url: str) -> requests.Response:
156220
"""make_request is a helper function that makes the actual
157221
HTTP request to the JigsawStack API.
@@ -183,6 +247,7 @@ def make_request(self, url: str) -> requests.Response:
183247
json=params,
184248
headers=headers,
185249
data=data,
250+
stream=self.stream,
186251
)
187252
except requests.HTTPError as e:
188253
raise e

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
setup(
88
name="jigsawstack",
9-
version="0.1.17",
9+
version="0.1.18",
1010
description="JigsawStack Python SDK",
1111
long_description=open("README.md", encoding="utf8").read(),
1212
long_description_content_type="text/markdown",

tests/test_prompt_engine.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
from jigsawstack.exceptions import JigsawStackError
44
import jigsawstack
55
import pytest
6+
67
# flake8: noq
78

89
jigsaw = jigsawstack.JigsawStack()
910

11+
1012
@pytest.mark.skip(reason="Skipping TestWebAPI class for now")
1113
class TestPromptEngine(unittest.TestCase):
1214

@@ -15,4 +17,4 @@ def test_get_prompt_engine_response_success(self) -> None:
1517
result = jigsaw.prompt_engine.get("b08921b8-0b30-409e-8257-06fa1620c7e6")
1618
assert result["success"] == True
1719
except JigsawStackError as e:
18-
assert e.message == "Failed to parse API response. Please try again."
20+
assert e.message == "Failed to parse API response. Please try again."

tests/test_search.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from jigsawstack.exceptions import JigsawStackError
44
import jigsawstack
55
import pytest
6+
67
# flake8: noq
78

89
jigsaw = jigsawstack.JigsawStack()
@@ -12,21 +13,17 @@
1213
class TestSearchAPI(unittest.TestCase):
1314

1415
def test_search_suggestion_response_success(self) -> None:
15-
params = {
16-
"query": "Time Square New Yor"
17-
}
16+
params = {"query": "Time Square New Yor"}
1817
try:
1918
result = jigsaw.search.suggestion(params)
2019
assert result["success"] == True
2120
except JigsawStackError as e:
2221
assert e.message == "Failed to parse API response. Please try again."
2322

2423
def test_ai_search_response_success(self) -> None:
25-
params = {
26-
"query": "Time Square New Yor"
27-
}
24+
params = {"query": "Time Square New Yor"}
2825
try:
2926
result = jigsaw.search.ai_search(params)
3027
assert result["success"] == True
3128
except JigsawStackError as e:
32-
assert e.message == "Failed to parse API response. Please try again."
29+
assert e.message == "Failed to parse API response. Please try again."

tests/test_web.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,28 @@
44
from jigsawstack import JigsawStack
55

66
import pytest
7+
78
# flake8: noqa
89

910
client = JigsawStack()
11+
12+
1013
@pytest.mark.skip(reason="Skipping TestWebAPI class for now")
1114
class TestWebAPI(unittest.TestCase):
1215
def test_ai_scrape_success_response(self) -> None:
1316
params = {
14-
"url": "https://supabase.com/pricing",
15-
"element_prompts": ["Plan title", "Plan price"],
17+
"url": "https://supabase.com/pricing",
18+
"element_prompts": ["Plan title", "Plan price"],
1619
}
1720
try:
18-
result =client.file.upload(params)
21+
result = client.file.upload(params)
1922
assert result["success"] == True
2023
except JigsawStackError as e:
2124
assert e.message == "Failed to parse API response. Please try again."
2225

2326
def test_scrape_success_response(self) -> None:
2427
params = {
25-
"url": "https://supabase.com/pricing",
28+
"url": "https://supabase.com/pricing",
2629
}
2730
try:
2831
result = client.web.scrape(params)
@@ -33,10 +36,10 @@ def test_scrape_success_response(self) -> None:
3336
def test_dns_success_response(self) -> None:
3437

3538
params = {
36-
"url": "https://supabase.com/pricing",
39+
"url": "https://supabase.com/pricing",
3740
}
3841
try:
3942
result = client.web.dns(params)
4043
assert result["success"] == True
4144
except JigsawStackError as e:
42-
assert e.message == "Failed to parse API response. Please try again."
45+
assert e.message == "Failed to parse API response. Please try again."

0 commit comments

Comments
 (0)