Skip to content

Commit 8333e4e

Browse files
committed
clean up
1 parent aab4584 commit 8333e4e

File tree

6 files changed

+113
-20
lines changed

6 files changed

+113
-20
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: 16 additions & 3 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,13 @@ 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]]
2019

2120

2221
class PromptEngineExecuteParams(TypedDict):
2322
id: str
2423
input_values: object
24+
stream: Union[bool, None] = False
2525

2626

2727
class PromptEngineRunResponse(TypedDict):
@@ -138,9 +138,22 @@ def run_prompt_direct(
138138
).perform_with_content()
139139
return resp
140140

141-
def run(self, params: PromptEngineExecuteParams) -> PromptEngineRunResponse:
141+
def run(
142+
self, params: PromptEngineExecuteParams
143+
) -> Union[PromptEngineRunResponse, Generator[Any, None, None]]:
142144
id = params.get("id")
143145
path = f"/prompt_engine/{id}"
146+
stream = params.get("stream")
147+
148+
if stream:
149+
resp = Request(
150+
config=self.config,
151+
path=path,
152+
params=cast(Dict[Any, Any], params),
153+
verb="post",
154+
).perform_with_content_streaming()
155+
return resp
156+
144157
resp = Request(
145158
config=self.config,
146159
path=path,

jigsawstack/request.py

Lines changed: 74 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,75 @@ 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+
# this is a safety net, if we get here it means the JigsawStack API is having issues
176+
# and most likely the gateway is returning htmls
177+
if "application/json" not in resp.headers["content-type"]:
178+
raise_for_code_and_type(
179+
code=500,
180+
message="Failed to parse JigsawStack API response. Please try again.",
181+
)
182+
183+
if resp.status_code != 200:
184+
error = resp.json()
185+
raise_for_code_and_type(
186+
code=resp.status_code,
187+
message=error.get("message"),
188+
err=error.get("error"),
189+
)
190+
191+
def try_parse_data(chunk: bytes) -> Union[T, str]:
192+
if not chunk:
193+
return chunk
194+
# Decode bytes to text
195+
text = chunk.decode("utf-8")
196+
197+
try:
198+
# Try to parse as JSON
199+
return json.loads(text)
200+
except json.JSONDecodeError:
201+
# Return as text if not valid JSON
202+
return text
203+
204+
# Yield content in chunks
205+
def chunk_generator():
206+
for chunk in resp.iter_content(chunk_size=1024): # 1KB chunks
207+
if chunk: # Filter out keep-alive new chunks
208+
yield try_parse_data(chunk)
209+
210+
return chunk_generator()
211+
212+
def perform_with_content_streaming(self) -> T:
213+
"""
214+
Perform an HTTP request and return the response content as a streaming response.
215+
216+
Returns:
217+
T: The content of the response
218+
219+
Raises:
220+
NoContentError: If the response content is `None`.
221+
"""
222+
resp = self.perform_streaming()
223+
if resp is None:
224+
raise NoContentError()
225+
return resp
226+
155227
def make_request(self, url: str) -> requests.Response:
156228
"""make_request is a helper function that makes the actual
157229
HTTP request to the JigsawStack API.
@@ -183,6 +255,7 @@ def make_request(self, url: str) -> requests.Response:
183255
json=params,
184256
headers=headers,
185257
data=data,
258+
stream=self.stream,
186259
)
187260
except requests.HTTPError as e:
188261
raise e

tests/test_prompt_engine.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,20 @@
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

1315
def test_get_prompt_engine_response_success(self) -> None:
1416
try:
15-
result = jigsaw.prompt_engine.get("b08921b8-0b30-409e-8257-06fa1620c7e6")
17+
result = jigsaw.prompt_engine.run(
18+
{"id": "b08921b8-0b30-409e-8257-06fa1620c7e6", "stream": True}
19+
)
1620
assert result["success"] == True
1721
except JigsawStackError as e:
18-
assert e.message == "Failed to parse API response. Please try again."
22+
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)