opengradient 0.1.8__tar.gz → 0.2.0__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.
- {opengradient-0.1.8/src/opengradient.egg-info → opengradient-0.2.0}/PKG-INFO +2 -1
- {opengradient-0.1.8 → opengradient-0.2.0}/pyproject.toml +5 -1
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/__init__.py +1 -1
- opengradient-0.2.0/src/opengradient/cli.py +184 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/client.py +1 -1
- {opengradient-0.1.8 → opengradient-0.2.0/src/opengradient.egg-info}/PKG-INFO +2 -1
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient.egg-info/SOURCES.txt +2 -0
- opengradient-0.2.0/src/opengradient.egg-info/entry_points.txt +2 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient.egg-info/requires.txt +1 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/LICENSE +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/README.md +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/setup.cfg +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/abi/inference.abi +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/exceptions.py +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/types.py +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient/utils.py +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient.egg-info/dependency_links.txt +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/src/opengradient.egg-info/top_level.txt +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/tests/test_api.py +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/tests/test_exceptions.py +0 -0
- {opengradient-0.1.8 → opengradient-0.2.0}/tests/test_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: opengradient
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Python SDK for OpenGradient inference services
|
|
5
5
|
Author-email: OpenGradient <oliver@opengradient.ai>
|
|
6
6
|
License: MIT License
|
|
@@ -45,6 +45,7 @@ Requires-Dist: web3
|
|
|
45
45
|
Requires-Dist: pyarrow
|
|
46
46
|
Requires-Dist: firebase-rest-api
|
|
47
47
|
Requires-Dist: fastparquet
|
|
48
|
+
Requires-Dist: pathlib
|
|
48
49
|
|
|
49
50
|
# OpenGradient Python SDK
|
|
50
51
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "opengradient"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "A Python SDK for OpenGradient inference services"
|
|
9
9
|
authors = [{name = "OpenGradient", email = "oliver@opengradient.ai"}]
|
|
10
10
|
license = {file = "LICENSE"}
|
|
@@ -29,8 +29,12 @@ dependencies = [
|
|
|
29
29
|
"pyarrow",
|
|
30
30
|
"firebase-rest-api",
|
|
31
31
|
"fastparquet",
|
|
32
|
+
"pathlib",
|
|
32
33
|
]
|
|
33
34
|
|
|
35
|
+
[project.scripts]
|
|
36
|
+
opengradient = "opengradient.cli:cli"
|
|
37
|
+
|
|
34
38
|
[project.urls]
|
|
35
39
|
Homepage = "https://opengradient.ai"
|
|
36
40
|
|
|
@@ -2,7 +2,7 @@ from .client import Client
|
|
|
2
2
|
from .exceptions import OpenGradientError, FileNotFoundError, UploadError, InferenceError, ResultRetrievalError
|
|
3
3
|
from .types import ModelInput, InferenceMode, Number, NumberTensor, StringTensor, ModelOutput
|
|
4
4
|
|
|
5
|
-
__version__ = "0.
|
|
5
|
+
__version__ = "0.2.0"
|
|
6
6
|
|
|
7
7
|
_client = None
|
|
8
8
|
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import os
|
|
3
|
+
import opengradient
|
|
4
|
+
import json
|
|
5
|
+
import ast
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from .client import Client
|
|
8
|
+
from opengradient.types import InferenceMode, ModelInput
|
|
9
|
+
|
|
10
|
+
# Environment variable names
|
|
11
|
+
API_KEY_ENV = 'OPENGRADIENT_API_KEY'
|
|
12
|
+
RPC_URL_ENV = 'OPENGRADIENT_RPC_URL'
|
|
13
|
+
CONTRACT_ADDRESS_ENV = 'OPENGRADIENT_CONTRACT_ADDRESS'
|
|
14
|
+
EMAIL_ENV = 'OPENGRADIENT_EMAIL'
|
|
15
|
+
PASSWORD_ENV = 'OPENGRADIENT_PASSWORD'
|
|
16
|
+
|
|
17
|
+
# Convert string to dictionary click parameter typing
|
|
18
|
+
class DictParamType(click.ParamType):
|
|
19
|
+
name = "dictionary"
|
|
20
|
+
|
|
21
|
+
def convert(self, value, param, ctx):
|
|
22
|
+
if isinstance(value, dict):
|
|
23
|
+
return value
|
|
24
|
+
try:
|
|
25
|
+
# First, try to parse as JSON
|
|
26
|
+
return json.loads(value)
|
|
27
|
+
except json.JSONDecodeError:
|
|
28
|
+
# If JSON parsing fails, try to evaluate as a Python literal
|
|
29
|
+
try:
|
|
30
|
+
# ast.literal_eval is safer than eval as it only parses Python literals
|
|
31
|
+
result = ast.literal_eval(value)
|
|
32
|
+
if not isinstance(result, dict):
|
|
33
|
+
self.fail(f"'{value}' is not a valid dictionary", param, ctx)
|
|
34
|
+
return result
|
|
35
|
+
except (ValueError, SyntaxError):
|
|
36
|
+
self.fail(f"'{value}' is not a valid dictionary", param, ctx)
|
|
37
|
+
|
|
38
|
+
Dict = DictParamType()
|
|
39
|
+
|
|
40
|
+
# Support inference modes
|
|
41
|
+
InferenceModes = {
|
|
42
|
+
"VANILLA": opengradient.InferenceMode.VANILLA,
|
|
43
|
+
"ZKML": opengradient.InferenceMode.PRIVATE,
|
|
44
|
+
"TEE": opengradient.InferenceMode.VERIFIED,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# TODO (Kyle): Once we're farther into development, we should remove the defaults for these options
|
|
48
|
+
@click.group()
|
|
49
|
+
@click.option('--api_key',
|
|
50
|
+
envvar=API_KEY_ENV,
|
|
51
|
+
help='Your OpenGradient private key',
|
|
52
|
+
default="cd09980ef6e280afc3900d2d6801f9e9c5d858a5deaeeab74a65643f5ff1a4c1")
|
|
53
|
+
@click.option('--rpc_url',
|
|
54
|
+
envvar=RPC_URL_ENV,
|
|
55
|
+
help='OpenGradient RPC URL address',
|
|
56
|
+
default="http://18.218.115.248:8545")
|
|
57
|
+
@click.option('--contract_address',
|
|
58
|
+
envvar=CONTRACT_ADDRESS_ENV,
|
|
59
|
+
help='OpenGradient contract address',
|
|
60
|
+
default="0x350E0A430b2B1563481833a99523Cfd17a530e4e")
|
|
61
|
+
@click.option('--email',
|
|
62
|
+
envvar=EMAIL_ENV,
|
|
63
|
+
help='Your OpenGradient hub email address -- not required for inference',
|
|
64
|
+
default="test@test.com")
|
|
65
|
+
@click.option('--password',
|
|
66
|
+
envvar=PASSWORD_ENV,
|
|
67
|
+
help='Your OpenGradient hub password -- not required for inference',
|
|
68
|
+
default="Test-123")
|
|
69
|
+
@click.pass_context
|
|
70
|
+
def cli(ctx, api_key, rpc_url, contract_address, email, password):
|
|
71
|
+
"""CLI for OpenGradient SDK"""
|
|
72
|
+
if not api_key:
|
|
73
|
+
click.echo("Please provide an API key via flag or setting environment variable OPENGRADIENT_API_KEY")
|
|
74
|
+
if not rpc_url:
|
|
75
|
+
click.echo("Please provide a RPC URL via flag or setting environment variable OPENGRADIENT_RPC_URL")
|
|
76
|
+
if not contract_address:
|
|
77
|
+
click.echo("Please provide a contract address via flag or setting environment variable OPENGRADIENT_CONTRACT_ADDRESS")
|
|
78
|
+
if not api_key or not rpc_url or not contract_address:
|
|
79
|
+
ctx.exit(1)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
ctx.obj = Client(private_key=api_key,
|
|
84
|
+
rpc_url=rpc_url,
|
|
85
|
+
contract_address=contract_address,
|
|
86
|
+
email=email,
|
|
87
|
+
password=password)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
click.echo(f"Failed to create OpenGradient client: {str(e)}")
|
|
90
|
+
|
|
91
|
+
@cli.command()
|
|
92
|
+
@click.pass_obj
|
|
93
|
+
def client_settings(client):
|
|
94
|
+
"""Display OpenGradient client settings"""
|
|
95
|
+
click.echo("Settings for OpenGradient client:")
|
|
96
|
+
click.echo(f"\tAPI key ({API_KEY_ENV}): {client.private_key}")
|
|
97
|
+
click.echo(f"\tRPC URL ({RPC_URL_ENV}): {client.rpc_url}")
|
|
98
|
+
click.echo(f"\tContract address ({CONTRACT_ADDRESS_ENV}): {client.contract_address}")
|
|
99
|
+
if client.user:
|
|
100
|
+
click.echo(f"\tEmail ({EMAIL_ENV}): {client.user["email"]}")
|
|
101
|
+
else:
|
|
102
|
+
click.echo(f"\tEmail: not set")
|
|
103
|
+
|
|
104
|
+
@cli.command()
|
|
105
|
+
@click.argument('model_path', type=Path)
|
|
106
|
+
@click.argument('model_id', type=str)
|
|
107
|
+
@click.argument('version_id', type=str)
|
|
108
|
+
@click.pass_obj
|
|
109
|
+
def upload(client, model_path, model_id, version_id):
|
|
110
|
+
"""Upload a model"""
|
|
111
|
+
try:
|
|
112
|
+
result = client.upload(model_path, model_id, version_id)
|
|
113
|
+
click.echo(f"Model uploaded successfully: {result}")
|
|
114
|
+
except Exception as e:
|
|
115
|
+
click.echo(f"Error uploading model: {str(e)}")
|
|
116
|
+
|
|
117
|
+
@cli.command()
|
|
118
|
+
@click.argument('model_name', type=str)
|
|
119
|
+
@click.argument('model_desc', type=str)
|
|
120
|
+
@click.pass_obj
|
|
121
|
+
def create_model(client, model_name, model_desc):
|
|
122
|
+
"""Create a new model"""
|
|
123
|
+
try:
|
|
124
|
+
result = client.create_model(model_name, model_desc)
|
|
125
|
+
click.echo(f"Model created successfully: {result}")
|
|
126
|
+
except Exception as e:
|
|
127
|
+
click.echo(f"Error creating model: {str(e)}")
|
|
128
|
+
|
|
129
|
+
@cli.command()
|
|
130
|
+
@click.argument('model_id', type=str)
|
|
131
|
+
@click.option('--notes', type=str, default=None, help='Version notes')
|
|
132
|
+
@click.option('--is-major', default=False, is_flag=True, help='Is this a major version')
|
|
133
|
+
@click.pass_obj
|
|
134
|
+
def create_version(client, model_id, notes, is_major):
|
|
135
|
+
"""Create a new version of a model"""
|
|
136
|
+
try:
|
|
137
|
+
result = client.create_version(model_id, notes, is_major)
|
|
138
|
+
click.echo(f"Version created successfully: {result}")
|
|
139
|
+
except Exception as e:
|
|
140
|
+
click.echo(f"Error creating version: {str(e)}")
|
|
141
|
+
|
|
142
|
+
@cli.command()
|
|
143
|
+
@click.argument('model_id', type=str)
|
|
144
|
+
@click.argument('inference_mode', type=click.Choice(InferenceModes.keys()), default="VANILLA")
|
|
145
|
+
@click.argument('input_data', type=Dict, required=False)
|
|
146
|
+
@click.option('--input_file',
|
|
147
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path),
|
|
148
|
+
help="Optional file input for model inference -- must be JSON")
|
|
149
|
+
@click.pass_context
|
|
150
|
+
def infer(ctx, model_id, inference_mode, input_data, input_file):
|
|
151
|
+
"""Run inference on a model"""
|
|
152
|
+
client = ctx.obj
|
|
153
|
+
try:
|
|
154
|
+
if not input_data and not input_file:
|
|
155
|
+
click.echo("Must specify either input_data or input_file")
|
|
156
|
+
ctx.exit(1)
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
if input_data and input_file:
|
|
160
|
+
click.echo("Cannot have both input_data and input_file")
|
|
161
|
+
ctx.exit(1)
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
if input_data:
|
|
165
|
+
model_input = input_data
|
|
166
|
+
|
|
167
|
+
if input_file:
|
|
168
|
+
with input_file.open('r') as file:
|
|
169
|
+
model_input = json.load(file)
|
|
170
|
+
|
|
171
|
+
# Parse input data from string to dict
|
|
172
|
+
click.echo(f"Running {inference_mode} inference for {model_id}...")
|
|
173
|
+
tx_hash, model_output = client.infer(model_cid=model_id, inference_mode=InferenceModes[inference_mode], model_input=model_input)
|
|
174
|
+
click.secho("Success!", fg="green")
|
|
175
|
+
click.echo(f"\nTransaction Hash: \n{tx_hash}")
|
|
176
|
+
click.echo(f"\nInference result: \n{model_output}")
|
|
177
|
+
except json.JSONDecodeError as e:
|
|
178
|
+
click.echo(f"Error decoding JSON: {e}", err=True)
|
|
179
|
+
click.echo(f"Error occurred on line {e.lineno}, column {e.colno}", err=True)
|
|
180
|
+
except Exception as e:
|
|
181
|
+
click.echo(f"Error running inference: {str(e)}")
|
|
182
|
+
|
|
183
|
+
if __name__ == '__main__':
|
|
184
|
+
cli()
|
|
@@ -32,7 +32,7 @@ class Client:
|
|
|
32
32
|
rpc_url (str): The RPC URL for the Ethereum node.
|
|
33
33
|
contract_address (str): The contract address for the smart contract.
|
|
34
34
|
email (str, optional): Email for authentication. Defaults to "test@test.com".
|
|
35
|
-
password (str, optional): Password for authentication. Defaults to "
|
|
35
|
+
password (str, optional): Password for authentication. Defaults to "Test-123".
|
|
36
36
|
"""
|
|
37
37
|
self.private_key = private_key
|
|
38
38
|
self.rpc_url = rpc_url
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: opengradient
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A Python SDK for OpenGradient inference services
|
|
5
5
|
Author-email: OpenGradient <oliver@opengradient.ai>
|
|
6
6
|
License: MIT License
|
|
@@ -45,6 +45,7 @@ Requires-Dist: web3
|
|
|
45
45
|
Requires-Dist: pyarrow
|
|
46
46
|
Requires-Dist: firebase-rest-api
|
|
47
47
|
Requires-Dist: fastparquet
|
|
48
|
+
Requires-Dist: pathlib
|
|
48
49
|
|
|
49
50
|
# OpenGradient Python SDK
|
|
50
51
|
|
|
@@ -2,6 +2,7 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/opengradient/__init__.py
|
|
5
|
+
src/opengradient/cli.py
|
|
5
6
|
src/opengradient/client.py
|
|
6
7
|
src/opengradient/exceptions.py
|
|
7
8
|
src/opengradient/types.py
|
|
@@ -9,6 +10,7 @@ src/opengradient/utils.py
|
|
|
9
10
|
src/opengradient.egg-info/PKG-INFO
|
|
10
11
|
src/opengradient.egg-info/SOURCES.txt
|
|
11
12
|
src/opengradient.egg-info/dependency_links.txt
|
|
13
|
+
src/opengradient.egg-info/entry_points.txt
|
|
12
14
|
src/opengradient.egg-info/requires.txt
|
|
13
15
|
src/opengradient.egg-info/top_level.txt
|
|
14
16
|
src/opengradient/abi/inference.abi
|
|
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
|