fxn 0.0.21__py3-none-any.whl → 0.0.23__py3-none-any.whl

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/__init__.py CHANGED
@@ -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/graph")
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
fxn/api/api.py CHANGED
@@ -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) -> dict:
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.raise_for_status()
31
- response = response.json()
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 response:
34
- raise RuntimeError(response["errors"][0]["message"])
36
+ if "errors" in payload:
37
+ raise RuntimeError(payload["errors"][0]["message"])
35
38
  # Return
36
- result = response["data"]
39
+ result = payload["data"]
37
40
  return result
fxn/api/prediction.py CHANGED
@@ -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
- # Collect inputs
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
- # Check
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):
fxn/api/predictor.py CHANGED
@@ -417,6 +417,7 @@ class AccessMode (str, Enum):
417
417
  """
418
418
  Public = "PUBLIC"
419
419
  Private = "PRIVATE"
420
+ Protected = "PROTECTED"
420
421
 
421
422
  class PredictorType (str, Enum):
422
423
  """
fxn/version.py CHANGED
@@ -3,4 +3,4 @@
3
3
  # Copyright © 2023 NatML Inc. All Rights Reserved.
4
4
  #
5
5
 
6
- __version__ = "0.0.21"
6
+ __version__ = "0.0.23"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fxn
3
- Version: 0.0.21
3
+ Version: 0.0.23
4
4
  Summary: Run on-device and cloud AI prediction functions in Python. Register at https://fxn.ai.
5
5
  Home-page: https://fxn.ai
6
6
  Author: NatML Inc.
@@ -17,9 +17,11 @@ Classifier: Topic :: Software Development :: Libraries
17
17
  Requires-Python: >=3.7
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: aiohttp
20
21
  Requires-Dist: filetype
21
22
  Requires-Dist: numpy
22
23
  Requires-Dist: pillow
24
+ Requires-Dist: pydantic
23
25
  Requires-Dist: requests
24
26
  Requires-Dist: rich
25
27
  Requires-Dist: typer
@@ -1,12 +1,12 @@
1
- fxn/__init__.py,sha256=0NzZl5hRQ0MPNN4Wp9-ghqak2NJzhfHvVyBGX-IntKs,320
1
+ fxn/__init__.py,sha256=S_HfYZK-ppKazPThGnm3Ei9NG51fq_2dJVLnYiZH20U,314
2
2
  fxn/magic.py,sha256=TRgE68OAo1djmeQRiqxnSJqa72td6zxnwo0s0bkdUKM,1041
3
- fxn/version.py,sha256=pS0q_JGq_GGDrxYMd6x6dFCVcxH7u2LZZZT1h2PnK4g,95
3
+ fxn/version.py,sha256=3ETsrDYC7I_z2qdkmyQKAUISJj_eLlE6C7S-GZ8bisA,95
4
4
  fxn/api/__init__.py,sha256=UcCERjadfSbqnt7urXYbrdRRFwA0QwpC9uBQYPJC5rE,460
5
- fxn/api/api.py,sha256=X2LRjer0s7ifecYsZmdqv5txEwPjA2ekdSCGUaQJ5So,927
5
+ fxn/api/api.py,sha256=rvrj7L37F1YQBnfJJT4rkGWIp1Q-XACFThu3D0kyiFA,1046
6
6
  fxn/api/dtype.py,sha256=z9zjjsOk8X8LTCEpwLuWOTUys6nP_3L6VmZXLt0ilAY,617
7
7
  fxn/api/environment.py,sha256=qZObVWl2UneTy9iYm4b1KRHiapW1qafvVp4P6s5KBCc,3874
8
- fxn/api/prediction.py,sha256=IKyFZ593FvlVVF0sljPR8S3m7JSX0TSOAK_9s24I5eU,4140
9
- fxn/api/predictor.py,sha256=kPoHL50dr7RvDmznkBLy9KgUWSy7PPBYkn8FRWk9jv8,13133
8
+ fxn/api/prediction.py,sha256=EU-k68BNnY-56yHj3yikJRh2FFjf32LDl44vWipOSFw,6663
9
+ fxn/api/predictor.py,sha256=nzrcYArtCFXOt_FD-EoF-2rmVI4Rw0CztvdbNAelwtM,13161
10
10
  fxn/api/profile.py,sha256=76RVnP0wF9eT5kefqbRVj2T7e-6yZbK4bzggDS1CYjY,876
11
11
  fxn/api/storage.py,sha256=GxSwYN5xOWovVJh1WfkVkwkWdCoBkeNP9OHTX8KgEiQ,4560
12
12
  fxn/api/tag.py,sha256=g7HuRv5ZCYYDy4iV8P0hR1tEQ1pZjv-HeqbE0-Li1Bs,832
@@ -18,9 +18,9 @@ fxn/cli/env.py,sha256=mnyaL27n59pCU-p2Jm1fo03se7btMV2zdoJWWVshF_M,1658
18
18
  fxn/cli/misc.py,sha256=gLEGGWyawUQaLOuy8bfS2wrJuS-tN-bleOrv5A07xck,690
19
19
  fxn/cli/predict.py,sha256=YP7BiqnT39AeeA3A9EXfHmw-6t5vCxOu27_kjinWdGE,3178
20
20
  fxn/cli/predictors.py,sha256=vAL1FioQSseEiu7jbXY0DRiHnnMmThK2csJLThizS7A,3481
21
- fxn-0.0.21.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
22
- fxn-0.0.21.dist-info/METADATA,sha256=1TAftjeYqJAaSUEgkUioXFghSBPyEK0P_NdPaeDNjSk,2887
23
- fxn-0.0.21.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
24
- fxn-0.0.21.dist-info/entry_points.txt,sha256=QBwKIRed76CRY98VYQYrQDVEBZtJugxJJmBpilxuios,46
25
- fxn-0.0.21.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
26
- fxn-0.0.21.dist-info/RECORD,,
21
+ fxn-0.0.23.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
22
+ fxn-0.0.23.dist-info/METADATA,sha256=AOo1jp5RVouQOm6Q68lhVgA4w0Bo3wGoknRkyB38kUY,2934
23
+ fxn-0.0.23.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
24
+ fxn-0.0.23.dist-info/entry_points.txt,sha256=QBwKIRed76CRY98VYQYrQDVEBZtJugxJJmBpilxuios,46
25
+ fxn-0.0.23.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
26
+ fxn-0.0.23.dist-info/RECORD,,
File without changes
File without changes