fxn 0.0.21__tar.gz → 0.0.23__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fxn-0.0.21 → fxn-0.0.23}/PKG-INFO +1 -1
- {fxn-0.0.21 → fxn-0.0.23}/fxn/__init__.py +1 -1
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/api.py +12 -9
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/prediction.py +70 -13
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/predictor.py +1 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/version.py +1 -1
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/PKG-INFO +1 -1
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/requires.txt +2 -0
- {fxn-0.0.21 → fxn-0.0.23}/setup.py +2 -0
- {fxn-0.0.21 → fxn-0.0.23}/LICENSE +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/README.md +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/__init__.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/dtype.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/environment.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/profile.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/storage.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/tag.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/user.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/api/value.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/__init__.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/auth.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/env.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/misc.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/predict.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/cli/predictors.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn/magic.py +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/SOURCES.txt +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/dependency_links.txt +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/entry_points.txt +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/fxn.egg-info/top_level.txt +0 -0
- {fxn-0.0.21 → fxn-0.0.23}/setup.cfg +0 -0
@@ -6,7 +6,7 @@
|
|
6
6
|
from os import environ
|
7
7
|
|
8
8
|
# Define API URL and access key
|
9
|
-
api_url = environ.get("FXN_API_URL", "https://api.fxn.ai
|
9
|
+
api_url = environ.get("FXN_API_URL", "https://api.fxn.ai")
|
10
10
|
access_key: str = environ.get("FXN_ACCESS_KEY", None)
|
11
11
|
|
12
12
|
# Import everything
|
@@ -3,11 +3,11 @@
|
|
3
3
|
# Copyright © 2023 NatML Inc. All Rights Reserved.
|
4
4
|
#
|
5
5
|
|
6
|
-
from requests import post
|
7
|
-
|
8
6
|
import fxn
|
7
|
+
from requests import post
|
8
|
+
from typing import Any, Dict
|
9
9
|
|
10
|
-
def query (query: str, variables: dict=None, access_key: str=None) ->
|
10
|
+
def query (query: str, variables: dict=None, access_key: str=None) -> Dict[str, Any]:
|
11
11
|
"""
|
12
12
|
Query the Function graph API.
|
13
13
|
|
@@ -22,16 +22,19 @@ def query (query: str, variables: dict=None, access_key: str=None) -> dict:
|
|
22
22
|
access_key = access_key or fxn.access_key
|
23
23
|
headers = { "Authorization": f"Bearer {access_key}" } if access_key else { }
|
24
24
|
response = post(
|
25
|
-
fxn.api_url,
|
25
|
+
f"{fxn.api_url}/graph",
|
26
26
|
json={ "query": query, "variables": variables },
|
27
27
|
headers=headers
|
28
28
|
)
|
29
29
|
# Check
|
30
|
-
response.
|
31
|
-
|
30
|
+
payload = response.json()
|
31
|
+
try:
|
32
|
+
response.raise_for_status()
|
33
|
+
except:
|
34
|
+
raise RuntimeError(payload.get("error"))
|
32
35
|
# Check error
|
33
|
-
if "errors" in
|
34
|
-
raise RuntimeError(
|
36
|
+
if "errors" in payload:
|
37
|
+
raise RuntimeError(payload["errors"][0]["message"])
|
35
38
|
# Return
|
36
|
-
result =
|
39
|
+
result = payload["data"]
|
37
40
|
return result
|
@@ -4,12 +4,15 @@
|
|
4
4
|
#
|
5
5
|
|
6
6
|
from __future__ import annotations
|
7
|
+
from aiohttp import ClientSession
|
7
8
|
from dataclasses import asdict, dataclass
|
9
|
+
import fxn
|
10
|
+
from json import dumps, loads
|
8
11
|
from numpy import ndarray
|
9
12
|
from pathlib import Path
|
10
13
|
from PIL import Image
|
11
14
|
from platform import system
|
12
|
-
from typing import Any, Dict, List, Union
|
15
|
+
from typing import Any, AsyncIterator, Dict, List, Union
|
13
16
|
from uuid import uuid4
|
14
17
|
|
15
18
|
from .api import query
|
@@ -72,7 +75,7 @@ class Prediction:
|
|
72
75
|
Returns:
|
73
76
|
CloudPrediction | EdgePrediction: Created prediction.
|
74
77
|
"""
|
75
|
-
#
|
78
|
+
# Serialize inputs
|
76
79
|
key = uuid4().hex
|
77
80
|
inputs = { name: Value.from_value(value, name, key=key) for name, value in inputs.items() }
|
78
81
|
inputs = [{ "name": name, **asdict(value) } for name, value in inputs.items()]
|
@@ -86,19 +89,57 @@ class Prediction:
|
|
86
89
|
{ "input": { "tag": tag, "client": cls.__get_client(), "inputs": inputs, "dataUrlLimit": data_url_limit } },
|
87
90
|
access_key=access_key
|
88
91
|
)
|
89
|
-
#
|
90
|
-
prediction = response["createPrediction"]
|
91
|
-
if not prediction:
|
92
|
-
return None
|
93
|
-
# Parse results
|
94
|
-
if "results" in prediction and prediction["results"] is not None:
|
95
|
-
prediction["results"] = [Value(**value) for value in prediction["results"]]
|
96
|
-
if not raw_outputs:
|
97
|
-
prediction["results"] = [value.to_value(return_binary_path=return_binary_path) for value in prediction["results"]]
|
98
|
-
# Create
|
99
|
-
prediction = CloudPrediction(**prediction) if prediction["type"] == PredictorType.Cloud else EdgePrediction(**prediction)
|
92
|
+
# Parse
|
93
|
+
prediction = cls.__parse_prediction(response["createPrediction"])
|
100
94
|
# Return
|
101
95
|
return prediction
|
96
|
+
|
97
|
+
@classmethod
|
98
|
+
async def stream (
|
99
|
+
cls,
|
100
|
+
tag: str,
|
101
|
+
raw_outputs: bool=False,
|
102
|
+
return_binary_path: bool=True,
|
103
|
+
data_url_limit: int=None,
|
104
|
+
access_key: str=None,
|
105
|
+
**inputs: Dict[str, Union[ndarray, str, float, int, bool, List, Dict[str, Any], Path, Image.Image, Value]],
|
106
|
+
) -> AsyncIterator[Union[CloudPrediction, EdgePrediction]]:
|
107
|
+
"""
|
108
|
+
Create a streaming prediction.
|
109
|
+
|
110
|
+
NOTE: This feature is currently experimental.
|
111
|
+
|
112
|
+
Parameters:
|
113
|
+
tag (str): Predictor tag.
|
114
|
+
raw_outputs (bool): Skip converting output values into Pythonic types.
|
115
|
+
return_binary_path (bool): Write binary values to file and return a `Path` instead of returning `BytesIO` instance.
|
116
|
+
data_url_limit (int): Return a data URL if a given output value is smaller than this size in bytes. Only applies to `CLOUD` predictions.
|
117
|
+
access_key (str): Function access key.
|
118
|
+
inputs (dict): Input values. Only applies to `CLOUD` predictions.
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
CloudPrediction | EdgePrediction: Created prediction.
|
122
|
+
"""
|
123
|
+
# Serialize inputs
|
124
|
+
key = uuid4().hex
|
125
|
+
inputs = { name: asdict(Value.from_value(value, name, key=key)) for name, value in inputs.items() }
|
126
|
+
# Request
|
127
|
+
url = f"{fxn.api_url}/predict/{tag}?stream=true&rawOutputs=true&dataUrlLimit={data_url_limit}"
|
128
|
+
headers = {
|
129
|
+
"Content-Type": "application/json",
|
130
|
+
"Authorization": f"Bearer {access_key or fxn.access_key}",
|
131
|
+
"fxn-client": cls.__get_client()
|
132
|
+
}
|
133
|
+
async with ClientSession(headers=headers) as session:
|
134
|
+
async with session.post(url, data=dumps(inputs)) as response:
|
135
|
+
async for chunk in response.content.iter_any():
|
136
|
+
payload = loads(chunk)
|
137
|
+
# Check status
|
138
|
+
if response.status >= 400:
|
139
|
+
raise RuntimeError(payload.get("error"))
|
140
|
+
# Yield
|
141
|
+
prediction = cls.__parse_prediction(payload, raw_outputs=raw_outputs, return_binary_path=return_binary_path)
|
142
|
+
yield prediction
|
102
143
|
|
103
144
|
@classmethod
|
104
145
|
def __get_client (cls) -> str:
|
@@ -110,6 +151,22 @@ class Prediction:
|
|
110
151
|
if id == "Windows":
|
111
152
|
return "windows"
|
112
153
|
raise RuntimeError(f"Function cannot make predictions on the {id} platform")
|
154
|
+
|
155
|
+
@classmethod
|
156
|
+
def __parse_prediction (
|
157
|
+
cls,
|
158
|
+
prediction: Dict[str, Any],
|
159
|
+
raw_outputs: bool=False,
|
160
|
+
return_binary_path: bool=True
|
161
|
+
) -> Union[CloudPrediction, EdgePrediction]:
|
162
|
+
if not prediction:
|
163
|
+
return None
|
164
|
+
if "results" in prediction and prediction["results"] is not None:
|
165
|
+
prediction["results"] = [Value(**value) for value in prediction["results"]]
|
166
|
+
if not raw_outputs:
|
167
|
+
prediction["results"] = [value.to_value(return_binary_path=return_binary_path) for value in prediction["results"]]
|
168
|
+
prediction = CloudPrediction(**prediction) if prediction["type"] == PredictorType.Cloud else EdgePrediction(**prediction)
|
169
|
+
return prediction
|
113
170
|
|
114
171
|
@dataclass(frozen=True)
|
115
172
|
class CloudPrediction (Prediction):
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|