opengradient 0.3.11__tar.gz → 0.3.13__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.3.13/.gitignore +162 -0
- {opengradient-0.3.11/src/opengradient.egg-info → opengradient-0.3.13}/PKG-INFO +17 -17
- {opengradient-0.3.11 → opengradient-0.3.13}/pyproject.toml +17 -5
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/__init__.py +23 -2
- opengradient-0.3.13/src/opengradient/abi/inference.abi +1 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/cli.py +38 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/client.py +135 -1
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/defaults.py +3 -2
- opengradient-0.3.13/src/opengradient/proto/__init__.py +2 -0
- opengradient-0.3.13/src/opengradient/proto/infer.proto +50 -0
- opengradient-0.3.13/src/opengradient/proto/infer_pb2.py +50 -0
- opengradient-0.3.13/src/opengradient/proto/infer_pb2_grpc.py +186 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/types.py +3 -2
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/utils.py +14 -1
- opengradient-0.3.11/PKG-INFO +0 -230
- opengradient-0.3.11/setup.cfg +0 -4
- opengradient-0.3.11/src/opengradient/abi/inference.abi +0 -1
- opengradient-0.3.11/src/opengradient.egg-info/SOURCES.txt +0 -20
- opengradient-0.3.11/src/opengradient.egg-info/dependency_links.txt +0 -1
- opengradient-0.3.11/src/opengradient.egg-info/entry_points.txt +0 -2
- opengradient-0.3.11/src/opengradient.egg-info/requires.txt +0 -94
- opengradient-0.3.11/src/opengradient.egg-info/top_level.txt +0 -1
- {opengradient-0.3.11 → opengradient-0.3.13}/LICENSE +0 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/README.md +0 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/account.py +0 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/exceptions.py +0 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/llm/__init__.py +0 -0
- {opengradient-0.3.11 → opengradient-0.3.13}/src/opengradient/llm/chat.py +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
102
|
+
#poetry.lock
|
|
103
|
+
|
|
104
|
+
# pdm
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
106
|
+
#pdm.lock
|
|
107
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
108
|
+
# in version control.
|
|
109
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
110
|
+
.pdm.toml
|
|
111
|
+
.pdm-python
|
|
112
|
+
.pdm-build/
|
|
113
|
+
|
|
114
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
115
|
+
__pypackages__/
|
|
116
|
+
|
|
117
|
+
# Celery stuff
|
|
118
|
+
celerybeat-schedule
|
|
119
|
+
celerybeat.pid
|
|
120
|
+
|
|
121
|
+
# SageMath parsed files
|
|
122
|
+
*.sage.py
|
|
123
|
+
|
|
124
|
+
# Environments
|
|
125
|
+
.env
|
|
126
|
+
.venv
|
|
127
|
+
env/
|
|
128
|
+
venv/
|
|
129
|
+
ENV/
|
|
130
|
+
env.bak/
|
|
131
|
+
venv.bak/
|
|
132
|
+
|
|
133
|
+
# Spyder project settings
|
|
134
|
+
.spyderproject
|
|
135
|
+
.spyproject
|
|
136
|
+
|
|
137
|
+
# Rope project settings
|
|
138
|
+
.ropeproject
|
|
139
|
+
|
|
140
|
+
# mkdocs documentation
|
|
141
|
+
/site
|
|
142
|
+
|
|
143
|
+
# mypy
|
|
144
|
+
.mypy_cache/
|
|
145
|
+
.dmypy.json
|
|
146
|
+
dmypy.json
|
|
147
|
+
|
|
148
|
+
# Pyre type checker
|
|
149
|
+
.pyre/
|
|
150
|
+
|
|
151
|
+
# pytype static type analyzer
|
|
152
|
+
.pytype/
|
|
153
|
+
|
|
154
|
+
# Cython debug symbols
|
|
155
|
+
cython_debug/
|
|
156
|
+
|
|
157
|
+
# PyCharm
|
|
158
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
159
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
160
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
161
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
162
|
+
#.idea/
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: opengradient
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.13
|
|
4
4
|
Summary: Python SDK for OpenGradient decentralized model management & inference services
|
|
5
|
+
Project-URL: Homepage, https://opengradient.ai
|
|
5
6
|
Author-email: OpenGradient <oliver@opengradient.ai>
|
|
6
7
|
License: MIT License
|
|
7
8
|
|
|
@@ -24,8 +25,6 @@ License: MIT License
|
|
|
24
25
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
26
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
27
|
SOFTWARE.
|
|
27
|
-
|
|
28
|
-
Project-URL: Homepage, https://opengradient.ai
|
|
29
28
|
Classifier: Development Status :: 3 - Alpha
|
|
30
29
|
Classifier: Intended Audience :: Developers
|
|
31
30
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -33,15 +32,13 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
33
32
|
Classifier: Programming Language :: Python :: 3.11
|
|
34
33
|
Classifier: Programming Language :: Python :: 3.12
|
|
35
34
|
Requires-Python: >=3.10
|
|
36
|
-
Description-Content-Type: text/markdown
|
|
37
|
-
License-File: LICENSE
|
|
38
35
|
Requires-Dist: aiohappyeyeballs==2.4.3
|
|
39
36
|
Requires-Dist: aiohttp==3.10.8
|
|
40
37
|
Requires-Dist: aiosignal==1.3.1
|
|
41
38
|
Requires-Dist: annotated-types==0.7.0
|
|
42
39
|
Requires-Dist: attrs==24.2.0
|
|
43
40
|
Requires-Dist: bitarray==2.9.2
|
|
44
|
-
Requires-Dist:
|
|
41
|
+
Requires-Dist: cachecontrol==0.14.0
|
|
45
42
|
Requires-Dist: cachetools==5.5.0
|
|
46
43
|
Requires-Dist: certifi==2024.8.30
|
|
47
44
|
Requires-Dist: cffi==1.17.1
|
|
@@ -55,6 +52,7 @@ Requires-Dist: cryptography==43.0.1
|
|
|
55
52
|
Requires-Dist: cytoolz==0.12.3
|
|
56
53
|
Requires-Dist: distlib==0.3.8
|
|
57
54
|
Requires-Dist: dulwich==0.21.7
|
|
55
|
+
Requires-Dist: eth-abi==5.1.0
|
|
58
56
|
Requires-Dist: eth-account==0.13.4
|
|
59
57
|
Requires-Dist: eth-hash==0.7.0
|
|
60
58
|
Requires-Dist: eth-keyfile==0.8.1
|
|
@@ -62,7 +60,6 @@ Requires-Dist: eth-keys==0.5.1
|
|
|
62
60
|
Requires-Dist: eth-rlp==2.1.0
|
|
63
61
|
Requires-Dist: eth-typing==5.0.0
|
|
64
62
|
Requires-Dist: eth-utils==5.0.0
|
|
65
|
-
Requires-Dist: eth_abi==5.1.0
|
|
66
63
|
Requires-Dist: fastjsonschema==2.20.0
|
|
67
64
|
Requires-Dist: fastparquet==2024.5.0
|
|
68
65
|
Requires-Dist: filelock==3.16.1
|
|
@@ -77,13 +74,14 @@ Requires-Dist: google-cloud-storage==2.18.2
|
|
|
77
74
|
Requires-Dist: google-crc32c==1.6.0
|
|
78
75
|
Requires-Dist: google-resumable-media==2.7.2
|
|
79
76
|
Requires-Dist: googleapis-common-protos==1.65.0
|
|
77
|
+
Requires-Dist: grpcio-tools==1.66.2
|
|
80
78
|
Requires-Dist: grpcio==1.66.2
|
|
81
|
-
Requires-Dist: grpcio-status==1.66.2
|
|
82
79
|
Requires-Dist: hexbytes==1.2.1
|
|
83
80
|
Requires-Dist: idna==3.10
|
|
84
|
-
Requires-Dist: jaraco
|
|
81
|
+
Requires-Dist: jaraco-classes==3.4.0
|
|
85
82
|
Requires-Dist: jwcrypto==1.5.6
|
|
86
83
|
Requires-Dist: keyring==24.3.1
|
|
84
|
+
Requires-Dist: langchain==0.3.7
|
|
87
85
|
Requires-Dist: more-itertools==10.5.0
|
|
88
86
|
Requires-Dist: msgpack==1.1.0
|
|
89
87
|
Requires-Dist: multidict==6.1.0
|
|
@@ -97,23 +95,24 @@ Requires-Dist: pkginfo==1.11.1
|
|
|
97
95
|
Requires-Dist: platformdirs==4.3.6
|
|
98
96
|
Requires-Dist: proto-plus==1.24.0
|
|
99
97
|
Requires-Dist: protobuf==5.28.2
|
|
98
|
+
Requires-Dist: protobuf>=4.24.0
|
|
100
99
|
Requires-Dist: ptyprocess==0.7.0
|
|
101
100
|
Requires-Dist: pyarrow==17.0.0
|
|
101
|
+
Requires-Dist: pyasn1-modules==0.4.1
|
|
102
102
|
Requires-Dist: pyasn1==0.6.1
|
|
103
|
-
Requires-Dist: pyasn1_modules==0.4.1
|
|
104
103
|
Requires-Dist: pycparser==2.22
|
|
105
104
|
Requires-Dist: pycryptodome==3.21.0
|
|
105
|
+
Requires-Dist: pydantic-core==2.23.4
|
|
106
106
|
Requires-Dist: pydantic==2.9.2
|
|
107
|
-
Requires-Dist:
|
|
108
|
-
Requires-Dist: pyproject_hooks==1.2.0
|
|
107
|
+
Requires-Dist: pyproject-hooks==1.2.0
|
|
109
108
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
110
109
|
Requires-Dist: python-jwt==4.1.0
|
|
111
110
|
Requires-Dist: pytz==2024.2
|
|
112
111
|
Requires-Dist: pyunormalize==16.0.0
|
|
113
|
-
Requires-Dist:
|
|
112
|
+
Requires-Dist: rapidfuzz==3.10.0
|
|
114
113
|
Requires-Dist: regex==2024.9.11
|
|
115
|
-
Requires-Dist: requests==2.32.3
|
|
116
114
|
Requires-Dist: requests-toolbelt==1.0.0
|
|
115
|
+
Requires-Dist: requests==2.32.3
|
|
117
116
|
Requires-Dist: rlp==4.0.1
|
|
118
117
|
Requires-Dist: rsa==4.9
|
|
119
118
|
Requires-Dist: shellingham==1.5.4
|
|
@@ -122,13 +121,14 @@ Requires-Dist: tomlkit==0.13.2
|
|
|
122
121
|
Requires-Dist: toolz==0.12.1
|
|
123
122
|
Requires-Dist: trove-classifiers==2024.9.12
|
|
124
123
|
Requires-Dist: types-requests==2.32.0.20240914
|
|
125
|
-
Requires-Dist:
|
|
124
|
+
Requires-Dist: typing-extensions==4.12.2
|
|
126
125
|
Requires-Dist: tzdata==2024.2
|
|
127
126
|
Requires-Dist: urllib3==2.2.3
|
|
128
127
|
Requires-Dist: web3==7.3.0
|
|
129
128
|
Requires-Dist: websockets==13.1
|
|
130
129
|
Requires-Dist: xattr==1.1.0
|
|
131
130
|
Requires-Dist: yarl==1.13.1
|
|
131
|
+
Description-Content-Type: text/markdown
|
|
132
132
|
|
|
133
133
|
# OpenGradient Python SDK
|
|
134
134
|
Python SDK for the OpenGradient platform provides decentralized model management & inference services. Python SDK allows programmatic access to our model repository and decentralized AI infrastructure.
|
|
@@ -227,4 +227,4 @@ opengradient infer QmbUqS93oc4JTLMHwpVxsE39mhNxy6hpf6Py3r9oANr8aZ VANILLA --inpu
|
|
|
227
227
|
opengradient llm --model "meta-llama/Meta-Llama-3-8B-Instruct" --prompt "Translate to French: Hello, how are you?" --max-tokens 50 --temperature 0.7
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
-
For more information read the OpenGradient [documentation](https://docs.opengradient.ai/).
|
|
230
|
+
For more information read the OpenGradient [documentation](https://docs.opengradient.ai/).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "opengradient"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.13"
|
|
8
8
|
description = "Python SDK for OpenGradient decentralized model management & inference services"
|
|
9
9
|
authors = [{name = "OpenGradient", email = "oliver@opengradient.ai"}]
|
|
10
10
|
license = {file = "LICENSE"}
|
|
@@ -62,12 +62,14 @@ dependencies = [
|
|
|
62
62
|
"google-resumable-media==2.7.2",
|
|
63
63
|
"googleapis-common-protos==1.65.0",
|
|
64
64
|
"grpcio==1.66.2",
|
|
65
|
-
"grpcio-
|
|
65
|
+
"grpcio-tools==1.66.2",
|
|
66
|
+
"protobuf>=4.24.0",
|
|
66
67
|
"hexbytes==1.2.1",
|
|
67
68
|
"idna==3.10",
|
|
68
69
|
"jaraco.classes==3.4.0",
|
|
69
70
|
"jwcrypto==1.5.6",
|
|
70
71
|
"keyring==24.3.1",
|
|
72
|
+
"langchain==0.3.7",
|
|
71
73
|
"more-itertools==10.5.0",
|
|
72
74
|
"msgpack==1.1.0",
|
|
73
75
|
"multidict==6.1.0",
|
|
@@ -143,4 +145,14 @@ select = ["E", "F", "I", "N"]
|
|
|
143
145
|
ignore = []
|
|
144
146
|
|
|
145
147
|
[tool.ruff.mccabe]
|
|
146
|
-
max-complexity = 10
|
|
148
|
+
max-complexity = 10
|
|
149
|
+
|
|
150
|
+
[tool.hatch.build]
|
|
151
|
+
include = [
|
|
152
|
+
"src/opengradient/**/*.py",
|
|
153
|
+
"src/opengradient/proto/*.proto",
|
|
154
|
+
"src/opengradient/abi/*.abi"
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
[tool.hatch.build.targets.wheel]
|
|
158
|
+
packages = ["src/opengradient"]
|
|
@@ -5,7 +5,7 @@ from .defaults import DEFAULT_INFERENCE_CONTRACT_ADDRESS, DEFAULT_RPC_URL
|
|
|
5
5
|
from .types import InferenceMode, LLM
|
|
6
6
|
from . import llm
|
|
7
7
|
|
|
8
|
-
__version__ = "0.3.
|
|
8
|
+
__version__ = "0.3.13"
|
|
9
9
|
|
|
10
10
|
_client = None
|
|
11
11
|
|
|
@@ -73,4 +73,25 @@ def login(email: str, password: str):
|
|
|
73
73
|
def list_files(model_name: str, version: str) -> List[Dict]:
|
|
74
74
|
if _client is None:
|
|
75
75
|
raise RuntimeError("OpenGradient client not initialized. Call og.init() first.")
|
|
76
|
-
return _client.list_files(model_name, version)
|
|
76
|
+
return _client.list_files(model_name, version)
|
|
77
|
+
|
|
78
|
+
def generate_image(model: str, prompt: str, height: Optional[int] = None, width: Optional[int] = None) -> bytes:
|
|
79
|
+
"""
|
|
80
|
+
Generate an image using the specified model and prompt.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
model (str): The model identifier (e.g. "stabilityai/stable-diffusion-xl-base-1.0")
|
|
84
|
+
prompt (str): The text prompt to generate the image from
|
|
85
|
+
height (Optional[int]): Height of the generated image. Default is None.
|
|
86
|
+
width (Optional[int]): Width of the generated image. Default is None.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
bytes: The raw image data bytes
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
RuntimeError: If the client is not initialized
|
|
93
|
+
OpenGradientError: If the image generation fails
|
|
94
|
+
"""
|
|
95
|
+
if _client is None:
|
|
96
|
+
raise RuntimeError("OpenGradient client not initialized. Call og.init() first.")
|
|
97
|
+
return _client.generate_image(model, prompt, height=height, width=width)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"anonymous":false,"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"int128","name":"value","type":"int128"},{"internalType":"int128","name":"decimals","type":"int128"}],"internalType":"struct TensorLib.Number[]","name":"values","type":"tuple[]"},{"internalType":"uint32[]","name":"shape","type":"uint32[]"}],"internalType":"struct TensorLib.MultiDimensionalNumberTensor[]","name":"numbers","type":"tuple[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string[]","name":"values","type":"string[]"}],"internalType":"struct TensorLib.StringTensor[]","name":"strings","type":"tuple[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"}],"internalType":"struct TensorLib.JsonScalar[]","name":"jsons","type":"tuple[]"},{"internalType":"bool","name":"is_simulation_result","type":"bool"}],"indexed":false,"internalType":"struct ModelOutput","name":"output","type":"tuple"}],"name":"InferenceResult","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"string","name":"finish_reason","type":"string"},{"components":[{"internalType":"string","name":"role","type":"string"},{"internalType":"string","name":"content","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"tool_call_id","type":"string"},{"components":[{"internalType":"string","name":"id","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"arguments","type":"string"}],"internalType":"struct ToolCall[]","name":"tool_calls","type":"tuple[]"}],"internalType":"struct ChatMessage","name":"message","type":"tuple"}],"indexed":false,"internalType":"struct LLMChatResponse","name":"response","type":"tuple"}],"name":"LLMChatResult","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"string","name":"answer","type":"string"}],"indexed":false,"internalType":"struct LLMCompletionResponse","name":"response","type":"tuple"}],"name":"LLMCompletionResult","type":"event"},{"inputs":[{"internalType":"string","name":"modelId","type":"string"},{"internalType":"enum ModelInferenceMode","name":"inferenceMode","type":"uint8"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"int128","name":"value","type":"int128"},{"internalType":"int128","name":"decimals","type":"int128"}],"internalType":"struct TensorLib.Number[]","name":"values","type":"tuple[]"},{"internalType":"uint32[]","name":"shape","type":"uint32[]"}],"internalType":"struct TensorLib.MultiDimensionalNumberTensor[]","name":"numbers","type":"tuple[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string[]","name":"values","type":"string[]"}],"internalType":"struct TensorLib.StringTensor[]","name":"strings","type":"tuple[]"}],"internalType":"struct ModelInput","name":"modelInput","type":"tuple"}],"name":"run","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"int128","name":"value","type":"int128"},{"internalType":"int128","name":"decimals","type":"int128"}],"internalType":"struct TensorLib.Number[]","name":"values","type":"tuple[]"},{"internalType":"uint32[]","name":"shape","type":"uint32[]"}],"internalType":"struct TensorLib.MultiDimensionalNumberTensor[]","name":"numbers","type":"tuple[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string[]","name":"values","type":"string[]"}],"internalType":"struct TensorLib.StringTensor[]","name":"strings","type":"tuple[]"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"value","type":"string"}],"internalType":"struct TensorLib.JsonScalar[]","name":"jsons","type":"tuple[]"},{"internalType":"bool","name":"is_simulation_result","type":"bool"}],"internalType":"struct ModelOutput","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum LLMInferenceMode","name":"mode","type":"uint8"},{"internalType":"string","name":"modelCID","type":"string"},{"components":[{"internalType":"string","name":"role","type":"string"},{"internalType":"string","name":"content","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"tool_call_id","type":"string"},{"components":[{"internalType":"string","name":"id","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"arguments","type":"string"}],"internalType":"struct ToolCall[]","name":"tool_calls","type":"tuple[]"}],"internalType":"struct ChatMessage[]","name":"messages","type":"tuple[]"},{"components":[{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"parameters","type":"string"}],"internalType":"struct ToolDefinition[]","name":"tools","type":"tuple[]"},{"internalType":"string","name":"tool_choice","type":"string"},{"internalType":"uint32","name":"max_tokens","type":"uint32"},{"internalType":"string[]","name":"stop_sequence","type":"string[]"},{"internalType":"uint32","name":"temperature","type":"uint32"}],"internalType":"struct LLMChatRequest","name":"request","type":"tuple"}],"name":"runLLMChat","outputs":[{"components":[{"internalType":"string","name":"finish_reason","type":"string"},{"components":[{"internalType":"string","name":"role","type":"string"},{"internalType":"string","name":"content","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"tool_call_id","type":"string"},{"components":[{"internalType":"string","name":"id","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"arguments","type":"string"}],"internalType":"struct ToolCall[]","name":"tool_calls","type":"tuple[]"}],"internalType":"struct ChatMessage","name":"message","type":"tuple"}],"internalType":"struct LLMChatResponse","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum LLMInferenceMode","name":"mode","type":"uint8"},{"internalType":"string","name":"modelCID","type":"string"},{"internalType":"string","name":"prompt","type":"string"},{"internalType":"uint32","name":"max_tokens","type":"uint32"},{"internalType":"string[]","name":"stop_sequence","type":"string[]"},{"internalType":"uint32","name":"temperature","type":"uint32"}],"internalType":"struct LLMCompletionRequest","name":"request","type":"tuple"}],"name":"runLLMCompletion","outputs":[{"components":[{"internalType":"string","name":"answer","type":"string"}],"internalType":"struct LLMCompletionResponse","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]
|
|
@@ -604,6 +604,44 @@ def list_files(client: Client, repo_name: str, version: str):
|
|
|
604
604
|
click.echo(f"Error listing files: {str(e)}")
|
|
605
605
|
|
|
606
606
|
|
|
607
|
+
@cli.command()
|
|
608
|
+
@click.option('--model', '-m', required=True, help='Model identifier for image generation')
|
|
609
|
+
@click.option('--prompt', '-p', required=True, help='Text prompt for generating the image')
|
|
610
|
+
@click.option('--output-path', '-o', required=True, type=click.Path(path_type=Path),
|
|
611
|
+
help='Output file path for the generated image')
|
|
612
|
+
@click.option('--width', type=int, default=1024, help='Output image width')
|
|
613
|
+
@click.option('--height', type=int, default=1024, help='Output image height')
|
|
614
|
+
@click.pass_context
|
|
615
|
+
def generate_image(ctx, model: str, prompt: str, output_path: Path, width: int, height: int):
|
|
616
|
+
"""
|
|
617
|
+
Generate an image using a diffusion model.
|
|
618
|
+
|
|
619
|
+
Example usage:
|
|
620
|
+
opengradient generate-image --model stabilityai/stable-diffusion-xl-base-1.0
|
|
621
|
+
--prompt "A beautiful sunset over mountains" --output-path sunset.png
|
|
622
|
+
"""
|
|
623
|
+
client: Client = ctx.obj['client']
|
|
624
|
+
try:
|
|
625
|
+
click.echo(f"Generating image with model \"{model}\"")
|
|
626
|
+
image_data = client.generate_image(
|
|
627
|
+
model_cid=model,
|
|
628
|
+
prompt=prompt,
|
|
629
|
+
width=width,
|
|
630
|
+
height=height
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
# Save the image
|
|
634
|
+
with open(output_path, 'wb') as f:
|
|
635
|
+
f.write(image_data)
|
|
636
|
+
|
|
637
|
+
click.echo() # Add a newline for better spacing
|
|
638
|
+
click.secho("✅ Image generation successful", fg="green", bold=True)
|
|
639
|
+
click.echo(f"Image saved to: {output_path}")
|
|
640
|
+
|
|
641
|
+
except Exception as e:
|
|
642
|
+
click.echo(f"Error generating image: {str(e)}")
|
|
643
|
+
|
|
644
|
+
|
|
607
645
|
if __name__ == '__main__':
|
|
608
646
|
logging.getLogger().setLevel(logging.WARN)
|
|
609
647
|
cli()
|
|
@@ -14,6 +14,14 @@ from opengradient import utils
|
|
|
14
14
|
from opengradient.exceptions import OpenGradientError
|
|
15
15
|
from opengradient.types import InferenceMode, LLM
|
|
16
16
|
|
|
17
|
+
import grpc
|
|
18
|
+
import time
|
|
19
|
+
import uuid
|
|
20
|
+
from google.protobuf import timestamp_pb2
|
|
21
|
+
|
|
22
|
+
from opengradient.proto import infer_pb2
|
|
23
|
+
from opengradient.proto import infer_pb2_grpc
|
|
24
|
+
from .defaults import DEFAULT_IMAGE_GEN_HOST, DEFAULT_IMAGE_GEN_PORT
|
|
17
25
|
|
|
18
26
|
class Client:
|
|
19
27
|
FIREBASE_CONFIG = {
|
|
@@ -319,6 +327,7 @@ class Client:
|
|
|
319
327
|
Raises:
|
|
320
328
|
OpenGradientError: If the inference fails.
|
|
321
329
|
"""
|
|
330
|
+
# TODO (Kyle): Add input support for JSON tensors
|
|
322
331
|
try:
|
|
323
332
|
logging.debug("Entering infer method")
|
|
324
333
|
self._initialize_web3()
|
|
@@ -705,4 +714,129 @@ class Client:
|
|
|
705
714
|
status_code=e.response.status_code if hasattr(e, 'response') else None)
|
|
706
715
|
except Exception as e:
|
|
707
716
|
logging.error(f"Unexpected error during file listing: {str(e)}", exc_info=True)
|
|
708
|
-
raise OpenGradientError(f"Unexpected error during file listing: {str(e)}")
|
|
717
|
+
raise OpenGradientError(f"Unexpected error during file listing: {str(e)}")
|
|
718
|
+
|
|
719
|
+
def generate_image(
|
|
720
|
+
self,
|
|
721
|
+
model_cid: str,
|
|
722
|
+
prompt: str,
|
|
723
|
+
host: str = DEFAULT_IMAGE_GEN_HOST,
|
|
724
|
+
port: int = DEFAULT_IMAGE_GEN_PORT,
|
|
725
|
+
width: int = 1024,
|
|
726
|
+
height: int = 1024,
|
|
727
|
+
timeout: int = 300, # 5 minute timeout
|
|
728
|
+
max_retries: int = 3
|
|
729
|
+
) -> bytes:
|
|
730
|
+
"""
|
|
731
|
+
Generate an image using a diffusion model through gRPC.
|
|
732
|
+
|
|
733
|
+
Args:
|
|
734
|
+
model_cid (str): The model identifier (e.g. "stabilityai/stable-diffusion-xl-base-1.0")
|
|
735
|
+
prompt (str): The text prompt to generate the image from
|
|
736
|
+
host (str, optional): gRPC host address. Defaults to DEFAULT_IMAGE_GEN_HOST.
|
|
737
|
+
port (int, optional): gRPC port number. Defaults to DEFAULT_IMAGE_GEN_PORT.
|
|
738
|
+
width (int, optional): Output image width. Defaults to 1024.
|
|
739
|
+
height (int, optional): Output image height. Defaults to 1024.
|
|
740
|
+
timeout (int, optional): Maximum time to wait for generation in seconds. Defaults to 300.
|
|
741
|
+
max_retries (int, optional): Maximum number of retry attempts. Defaults to 3.
|
|
742
|
+
|
|
743
|
+
Returns:
|
|
744
|
+
bytes: The raw image data bytes
|
|
745
|
+
|
|
746
|
+
Raises:
|
|
747
|
+
OpenGradientError: If the image generation fails
|
|
748
|
+
TimeoutError: If the generation exceeds the timeout period
|
|
749
|
+
"""
|
|
750
|
+
def exponential_backoff(attempt: int, max_delay: float = 30.0) -> None:
|
|
751
|
+
"""Calculate and sleep for exponential backoff duration"""
|
|
752
|
+
delay = min(0.1 * (2 ** attempt), max_delay)
|
|
753
|
+
time.sleep(delay)
|
|
754
|
+
|
|
755
|
+
channel = None
|
|
756
|
+
start_time = time.time()
|
|
757
|
+
retry_count = 0
|
|
758
|
+
|
|
759
|
+
try:
|
|
760
|
+
while retry_count < max_retries:
|
|
761
|
+
try:
|
|
762
|
+
# Initialize gRPC channel and stub
|
|
763
|
+
channel = grpc.insecure_channel(f'{host}:{port}')
|
|
764
|
+
stub = infer_pb2_grpc.InferenceServiceStub(channel)
|
|
765
|
+
|
|
766
|
+
# Create image generation request
|
|
767
|
+
image_request = infer_pb2.ImageGenerationRequest(
|
|
768
|
+
model=model_cid,
|
|
769
|
+
prompt=prompt,
|
|
770
|
+
height=height,
|
|
771
|
+
width=width
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
# Create inference request with random transaction ID
|
|
775
|
+
tx_id = str(uuid.uuid4())
|
|
776
|
+
request = infer_pb2.InferenceRequest(
|
|
777
|
+
tx=tx_id,
|
|
778
|
+
image_generation=image_request
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
# Send request with timeout
|
|
782
|
+
response_id = stub.RunInferenceAsync(
|
|
783
|
+
request,
|
|
784
|
+
timeout=min(30, timeout) # Initial request timeout
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
# Poll for completion
|
|
788
|
+
attempt = 0
|
|
789
|
+
while True:
|
|
790
|
+
# Check timeout
|
|
791
|
+
if time.time() - start_time > timeout:
|
|
792
|
+
raise TimeoutError(f"Image generation timed out after {timeout} seconds")
|
|
793
|
+
|
|
794
|
+
status_request = infer_pb2.InferenceTxId(id=response_id.id)
|
|
795
|
+
try:
|
|
796
|
+
status = stub.GetInferenceStatus(
|
|
797
|
+
status_request,
|
|
798
|
+
timeout=min(5, timeout) # Status check timeout
|
|
799
|
+
).status
|
|
800
|
+
except grpc.RpcError as e:
|
|
801
|
+
logging.warning(f"Status check failed (attempt {attempt}): {str(e)}")
|
|
802
|
+
exponential_backoff(attempt)
|
|
803
|
+
attempt += 1
|
|
804
|
+
continue
|
|
805
|
+
|
|
806
|
+
if status == infer_pb2.InferenceStatus.STATUS_COMPLETED:
|
|
807
|
+
break
|
|
808
|
+
elif status == infer_pb2.InferenceStatus.STATUS_ERROR:
|
|
809
|
+
raise OpenGradientError("Image generation failed on server")
|
|
810
|
+
elif status != infer_pb2.InferenceStatus.STATUS_IN_PROGRESS:
|
|
811
|
+
raise OpenGradientError(f"Unexpected status: {status}")
|
|
812
|
+
|
|
813
|
+
exponential_backoff(attempt)
|
|
814
|
+
attempt += 1
|
|
815
|
+
|
|
816
|
+
# Get result
|
|
817
|
+
result = stub.GetInferenceResult(
|
|
818
|
+
response_id,
|
|
819
|
+
timeout=min(30, timeout) # Result fetch timeout
|
|
820
|
+
)
|
|
821
|
+
return result.image_generation_result.image_data
|
|
822
|
+
|
|
823
|
+
except (grpc.RpcError, TimeoutError) as e:
|
|
824
|
+
retry_count += 1
|
|
825
|
+
if retry_count >= max_retries:
|
|
826
|
+
raise OpenGradientError(f"Image generation failed after {max_retries} retries: {str(e)}")
|
|
827
|
+
|
|
828
|
+
logging.warning(f"Attempt {retry_count} failed: {str(e)}. Retrying...")
|
|
829
|
+
exponential_backoff(retry_count)
|
|
830
|
+
|
|
831
|
+
except grpc.RpcError as e:
|
|
832
|
+
logging.error(f"gRPC error: {str(e)}")
|
|
833
|
+
raise OpenGradientError(f"Image generation failed: {str(e)}")
|
|
834
|
+
except TimeoutError as e:
|
|
835
|
+
logging.error(f"Timeout error: {str(e)}")
|
|
836
|
+
raise
|
|
837
|
+
except Exception as e:
|
|
838
|
+
logging.error(f"Error in generate image method: {str(e)}", exc_info=True)
|
|
839
|
+
raise OpenGradientError(f"Image generation failed: {str(e)}")
|
|
840
|
+
finally:
|
|
841
|
+
if channel:
|
|
842
|
+
channel.close()
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
1
|
# Default variables
|
|
3
2
|
DEFAULT_RPC_URL="http://18.218.115.248:8545"
|
|
4
3
|
DEFAULT_OG_FAUCET_URL="http://18.218.115.248:8080/?address="
|
|
5
4
|
DEFAULT_HUB_SIGNUP_URL="https://hub.opengradient.ai/signup"
|
|
6
|
-
DEFAULT_INFERENCE_CONTRACT_ADDRESS="
|
|
5
|
+
DEFAULT_INFERENCE_CONTRACT_ADDRESS="0x3fDCb0394CF4919ff4361f4EbA0750cEc2e3bBc7"
|
|
7
6
|
DEFAULT_BLOCKCHAIN_EXPLORER="http://3.145.62.2/tx/"
|
|
7
|
+
DEFAULT_IMAGE_GEN_HOST="18.217.25.69"
|
|
8
|
+
DEFAULT_IMAGE_GEN_PORT=5125
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
package inference;
|
|
4
|
+
|
|
5
|
+
// The inference service definition
|
|
6
|
+
service InferenceService {
|
|
7
|
+
rpc RunInferenceAsync(InferenceRequest) returns (InferenceTxId);
|
|
8
|
+
rpc GetInferenceStatus(InferenceTxId) returns (InferenceStatus);
|
|
9
|
+
rpc GetInferenceResult(InferenceTxId) returns (InferenceResult);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Request messages
|
|
13
|
+
message InferenceRequest {
|
|
14
|
+
string tx = 1;
|
|
15
|
+
ImageGenerationRequest image_generation = 6; // Field number 6 matches original proto
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
message ImageGenerationRequest {
|
|
19
|
+
string model = 1;
|
|
20
|
+
string prompt = 2;
|
|
21
|
+
optional int32 height = 3;
|
|
22
|
+
optional int32 width = 4;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
message InferenceTxId {
|
|
26
|
+
string id = 1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Status messages
|
|
30
|
+
message InferenceStatus {
|
|
31
|
+
enum Status {
|
|
32
|
+
STATUS_UNSPECIFIED = 0;
|
|
33
|
+
STATUS_IN_PROGRESS = 1;
|
|
34
|
+
STATUS_COMPLETED = 2;
|
|
35
|
+
STATUS_ERROR = 3;
|
|
36
|
+
}
|
|
37
|
+
Status status = 1;
|
|
38
|
+
optional string error_message = 2; // For error handling
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Result messages
|
|
42
|
+
message InferenceResult {
|
|
43
|
+
ImageGenerationResponse image_generation_result = 5; // Field number 5 matches original proto
|
|
44
|
+
optional string public_key = 7;
|
|
45
|
+
optional string signature = 8;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
message ImageGenerationResponse {
|
|
49
|
+
bytes image_data = 1;
|
|
50
|
+
}
|