opengradient 0.3.12__tar.gz → 0.3.14__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.14/.gitignore +162 -0
- {opengradient-0.3.12/src/opengradient.egg-info → opengradient-0.3.14}/PKG-INFO +16 -17
- {opengradient-0.3.12 → opengradient-0.3.14}/pyproject.toml +15 -4
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/__init__.py +22 -1
- opengradient-0.3.14/src/opengradient/abi/inference.abi +1 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/cli.py +38 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/client.py +135 -1
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/defaults.py +3 -2
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/llm/chat.py +23 -8
- opengradient-0.3.14/src/opengradient/proto/__init__.py +2 -0
- opengradient-0.3.14/src/opengradient/proto/infer.proto +50 -0
- opengradient-0.3.14/src/opengradient/proto/infer_pb2.py +50 -0
- opengradient-0.3.14/src/opengradient/proto/infer_pb2_grpc.py +186 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/utils.py +14 -1
- opengradient-0.3.12/PKG-INFO +0 -231
- opengradient-0.3.12/setup.cfg +0 -4
- opengradient-0.3.12/src/opengradient/abi/inference.abi +0 -1
- opengradient-0.3.12/src/opengradient.egg-info/SOURCES.txt +0 -20
- opengradient-0.3.12/src/opengradient.egg-info/dependency_links.txt +0 -1
- opengradient-0.3.12/src/opengradient.egg-info/entry_points.txt +0 -2
- opengradient-0.3.12/src/opengradient.egg-info/requires.txt +0 -95
- opengradient-0.3.12/src/opengradient.egg-info/top_level.txt +0 -1
- {opengradient-0.3.12 → opengradient-0.3.14}/LICENSE +0 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/README.md +0 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/account.py +0 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/exceptions.py +0 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/llm/__init__.py +0 -0
- {opengradient-0.3.12 → opengradient-0.3.14}/src/opengradient/types.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.14
|
|
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,11 +74,11 @@ 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
|
|
87
84
|
Requires-Dist: langchain==0.3.7
|
|
@@ -98,23 +95,24 @@ Requires-Dist: pkginfo==1.11.1
|
|
|
98
95
|
Requires-Dist: platformdirs==4.3.6
|
|
99
96
|
Requires-Dist: proto-plus==1.24.0
|
|
100
97
|
Requires-Dist: protobuf==5.28.2
|
|
98
|
+
Requires-Dist: protobuf>=4.24.0
|
|
101
99
|
Requires-Dist: ptyprocess==0.7.0
|
|
102
100
|
Requires-Dist: pyarrow==17.0.0
|
|
101
|
+
Requires-Dist: pyasn1-modules==0.4.1
|
|
103
102
|
Requires-Dist: pyasn1==0.6.1
|
|
104
|
-
Requires-Dist: pyasn1_modules==0.4.1
|
|
105
103
|
Requires-Dist: pycparser==2.22
|
|
106
104
|
Requires-Dist: pycryptodome==3.21.0
|
|
105
|
+
Requires-Dist: pydantic-core==2.23.4
|
|
107
106
|
Requires-Dist: pydantic==2.9.2
|
|
108
|
-
Requires-Dist:
|
|
109
|
-
Requires-Dist: pyproject_hooks==1.2.0
|
|
107
|
+
Requires-Dist: pyproject-hooks==1.2.0
|
|
110
108
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
111
109
|
Requires-Dist: python-jwt==4.1.0
|
|
112
110
|
Requires-Dist: pytz==2024.2
|
|
113
111
|
Requires-Dist: pyunormalize==16.0.0
|
|
114
|
-
Requires-Dist:
|
|
112
|
+
Requires-Dist: rapidfuzz==3.10.0
|
|
115
113
|
Requires-Dist: regex==2024.9.11
|
|
116
|
-
Requires-Dist: requests==2.32.3
|
|
117
114
|
Requires-Dist: requests-toolbelt==1.0.0
|
|
115
|
+
Requires-Dist: requests==2.32.3
|
|
118
116
|
Requires-Dist: rlp==4.0.1
|
|
119
117
|
Requires-Dist: rsa==4.9
|
|
120
118
|
Requires-Dist: shellingham==1.5.4
|
|
@@ -123,13 +121,14 @@ Requires-Dist: tomlkit==0.13.2
|
|
|
123
121
|
Requires-Dist: toolz==0.12.1
|
|
124
122
|
Requires-Dist: trove-classifiers==2024.9.12
|
|
125
123
|
Requires-Dist: types-requests==2.32.0.20240914
|
|
126
|
-
Requires-Dist:
|
|
124
|
+
Requires-Dist: typing-extensions==4.12.2
|
|
127
125
|
Requires-Dist: tzdata==2024.2
|
|
128
126
|
Requires-Dist: urllib3==2.2.3
|
|
129
127
|
Requires-Dist: web3==7.3.0
|
|
130
128
|
Requires-Dist: websockets==13.1
|
|
131
129
|
Requires-Dist: xattr==1.1.0
|
|
132
130
|
Requires-Dist: yarl==1.13.1
|
|
131
|
+
Description-Content-Type: text/markdown
|
|
133
132
|
|
|
134
133
|
# OpenGradient Python SDK
|
|
135
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.
|
|
@@ -228,4 +227,4 @@ opengradient infer QmbUqS93oc4JTLMHwpVxsE39mhNxy6hpf6Py3r9oANr8aZ VANILLA --inpu
|
|
|
228
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
|
|
229
228
|
```
|
|
230
229
|
|
|
231
|
-
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.14"
|
|
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,7 +62,8 @@ 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",
|
|
@@ -145,3 +146,13 @@ ignore = []
|
|
|
145
146
|
|
|
146
147
|
[tool.ruff.mccabe]
|
|
147
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.14"
|
|
9
9
|
|
|
10
10
|
_client = None
|
|
11
11
|
|
|
@@ -74,3 +74,24 @@ 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
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
|
|
@@ -10,6 +10,9 @@ from langchain.schema import (
|
|
|
10
10
|
ChatResult,
|
|
11
11
|
ChatGeneration,
|
|
12
12
|
)
|
|
13
|
+
from langchain_core.messages.tool import (
|
|
14
|
+
ToolMessage
|
|
15
|
+
)
|
|
13
16
|
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
|
|
14
17
|
from langchain_core.tools import BaseTool
|
|
15
18
|
from langchain_core.messages import ToolCall
|
|
@@ -70,24 +73,36 @@ class OpenGradientChatModel(BaseChatModel):
|
|
|
70
73
|
run_manager: Optional[CallbackManagerForLLMRun] = None,
|
|
71
74
|
**kwargs: Any,
|
|
72
75
|
) -> ChatResult:
|
|
73
|
-
|
|
76
|
+
|
|
77
|
+
sdk_messages = []
|
|
74
78
|
for message in messages:
|
|
75
79
|
if isinstance(message, SystemMessage):
|
|
76
|
-
|
|
80
|
+
sdk_messages.append({"role": "system", "content": message.content})
|
|
77
81
|
elif isinstance(message, HumanMessage):
|
|
78
|
-
|
|
82
|
+
sdk_messages.append({"role": "user", "content": message.content})
|
|
79
83
|
elif isinstance(message, AIMessage):
|
|
80
|
-
|
|
84
|
+
sdk_messages.append({
|
|
85
|
+
"role": "assistant",
|
|
86
|
+
"content": message.content,
|
|
87
|
+
"tool_calls": [{
|
|
88
|
+
"id": call["id"],
|
|
89
|
+
"name": call["name"],
|
|
90
|
+
"arguments": json.dumps(call["args"])
|
|
91
|
+
} for call in message.tool_calls]})
|
|
92
|
+
elif isinstance(message, ToolMessage):
|
|
93
|
+
sdk_messages.append({"role": "tool", "content": message.content, "tool_call_id": message.tool_call_id})
|
|
94
|
+
else:
|
|
95
|
+
raise ValueError(f"Unexpected message type: {message}")
|
|
81
96
|
|
|
82
|
-
|
|
97
|
+
_, finish_reason, chat_response = self.client.llm_chat(
|
|
83
98
|
model_cid=self.model_cid,
|
|
84
|
-
messages=
|
|
99
|
+
messages=sdk_messages,
|
|
85
100
|
stop_sequence=stop,
|
|
86
101
|
max_tokens=self.max_tokens,
|
|
87
102
|
tools=self.tools
|
|
88
103
|
)
|
|
89
104
|
|
|
90
|
-
if "tool_calls" in chat_response:
|
|
105
|
+
if "tool_calls" in chat_response and chat_response["tool_calls"]:
|
|
91
106
|
tool_calls = []
|
|
92
107
|
for tool_call in chat_response["tool_calls"]:
|
|
93
108
|
tool_calls.append(
|
|
@@ -104,7 +119,7 @@ class OpenGradientChatModel(BaseChatModel):
|
|
|
104
119
|
)
|
|
105
120
|
else:
|
|
106
121
|
message = AIMessage(content=chat_response["content"])
|
|
107
|
-
|
|
122
|
+
|
|
108
123
|
return ChatResult(
|
|
109
124
|
generations=[ChatGeneration(
|
|
110
125
|
message=message,
|