opengradient 0.4.12b1__tar.gz → 0.4.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.
Files changed (40) hide show
  1. {opengradient-0.4.12b1/src/opengradient.egg-info → opengradient-0.4.14}/PKG-INFO +3 -5
  2. {opengradient-0.4.12b1 → opengradient-0.4.14}/pyproject.toml +3 -5
  3. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/__init__.py +7 -5
  4. opengradient-0.4.14/src/opengradient/abi/InferencePrecompile.abi +1 -0
  5. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/cli.py +2 -0
  6. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/client.py +100 -3
  7. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/defaults.py +2 -1
  8. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/llm/og_langchain.py +2 -2
  9. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/utils.py +5 -14
  10. {opengradient-0.4.12b1 → opengradient-0.4.14/src/opengradient.egg-info}/PKG-INFO +3 -5
  11. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient.egg-info/SOURCES.txt +1 -0
  12. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient.egg-info/requires.txt +2 -4
  13. {opengradient-0.4.12b1 → opengradient-0.4.14}/LICENSE +0 -0
  14. {opengradient-0.4.12b1 → opengradient-0.4.14}/README.md +0 -0
  15. {opengradient-0.4.12b1 → opengradient-0.4.14}/setup.cfg +0 -0
  16. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/abi/PriceHistoryInference.abi +0 -0
  17. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/abi/WorkflowScheduler.abi +0 -0
  18. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/abi/inference.abi +0 -0
  19. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/account.py +0 -0
  20. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/alphasense/__init__.py +0 -0
  21. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/alphasense/read_workflow_tool.py +0 -0
  22. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/alphasense/run_model_tool.py +0 -0
  23. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/alphasense/types.py +0 -0
  24. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/bin/PriceHistoryInference.bin +0 -0
  25. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/exceptions.py +0 -0
  26. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/llm/__init__.py +0 -0
  27. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/llm/og_openai.py +0 -0
  28. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/proto/__init__.py +0 -0
  29. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/proto/infer.proto +0 -0
  30. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/proto/infer_pb2.py +0 -0
  31. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/proto/infer_pb2_grpc.py +0 -0
  32. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/types.py +0 -0
  33. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/workflow_models/__init__.py +0 -0
  34. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/workflow_models/constants.py +0 -0
  35. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/workflow_models/types.py +0 -0
  36. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/workflow_models/utils.py +0 -0
  37. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient/workflow_models/workflow_models.py +0 -0
  38. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient.egg-info/dependency_links.txt +0 -0
  39. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient.egg-info/entry_points.txt +0 -0
  40. {opengradient-0.4.12b1 → opengradient-0.4.14}/src/opengradient.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengradient
3
- Version: 0.4.12b1
3
+ Version: 0.4.14
4
4
  Summary: Python SDK for OpenGradient decentralized model management & inference services
5
5
  Author-email: OpenGradient <oliver@opengradient.ai>
6
6
  License: MIT License
@@ -35,10 +35,8 @@ Classifier: Programming Language :: Python :: 3.12
35
35
  Requires-Python: >=3.10
36
36
  Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
- Requires-Dist: eth-utils==2.2.2
39
- Requires-Dist: eth-account>=0.13.0
40
- Requires-Dist: web3>=6.11
41
- Requires-Dist: websockets>=14.1
38
+ Requires-Dist: eth-account>=0.13.4
39
+ Requires-Dist: web3>=7.3.0
42
40
  Requires-Dist: click>=8.1.7
43
41
  Requires-Dist: firebase-rest-api>=1.11.0
44
42
  Requires-Dist: grpcio>=1.66.2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opengradient"
7
- version = "0.4.12.beta1"
7
+ version = "0.4.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"}
@@ -20,10 +20,8 @@ classifiers = [
20
20
  ]
21
21
 
22
22
  dependencies = [
23
- "eth-utils==2.2.2",
24
- "eth-account>=0.13.0",
25
- "web3>=6.11",
26
- "websockets>=14.1",
23
+ "eth-account>=0.13.4",
24
+ "web3>=7.3.0",
27
25
  "click>=8.1.7",
28
26
  "firebase-rest-api>=1.11.0",
29
27
  "grpcio>=1.66.2",
@@ -5,7 +5,7 @@ OpenGradient Python SDK for interacting with AI models and infrastructure.
5
5
  from typing import Any, Dict, List, Optional, Tuple, Union
6
6
 
7
7
  from .client import Client
8
- from .defaults import DEFAULT_INFERENCE_CONTRACT_ADDRESS, DEFAULT_RPC_URL
8
+ from .defaults import DEFAULT_INFERENCE_CONTRACT_ADDRESS, DEFAULT_RPC_URL, DEFAULT_API_URL
9
9
  from .types import (
10
10
  LLM,
11
11
  TEE_LLM,
@@ -32,6 +32,7 @@ def new_client(
32
32
  password: Optional[str],
33
33
  private_key: str,
34
34
  rpc_url=DEFAULT_RPC_URL,
35
+ api_url=DEFAULT_API_URL,
35
36
  contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS,
36
37
  ) -> Client:
37
38
  """
@@ -45,10 +46,10 @@ def new_client(
45
46
  contract_address: Optional inference contract address
46
47
  """
47
48
 
48
- return Client(email=email, password=password, private_key=private_key, rpc_url=rpc_url, contract_address=contract_address)
49
+ return Client(email=email, password=password, private_key=private_key, rpc_url=rpc_url, api_url=api_url, contract_address=contract_address)
49
50
 
50
51
 
51
- def init(email: str, password: str, private_key: str, rpc_url=DEFAULT_RPC_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS):
52
+ def init(email: str, password: str, private_key: str, rpc_url=DEFAULT_RPC_URL, api_url=DEFAULT_API_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS):
52
53
  """Initialize the OpenGradient SDK with authentication and network settings.
53
54
 
54
55
  Args:
@@ -56,11 +57,12 @@ def init(email: str, password: str, private_key: str, rpc_url=DEFAULT_RPC_URL, c
56
57
  password: User's password for authentication
57
58
  private_key: Ethereum private key for blockchain transactions
58
59
  rpc_url: Optional RPC URL for the blockchain network, defaults to mainnet
60
+ api_url: Optional API URL for the OpenGradient API, defaults to mainnet
59
61
  contract_address: Optional inference contract address
60
62
  """
61
63
  global _client
62
-
63
- _client = Client(private_key=private_key, rpc_url=rpc_url, email=email, password=password, contract_address=contract_address)
64
+
65
+ _client = Client(private_key=private_key, rpc_url=rpc_url, api_url=api_url, email=email, password=password, contract_address=contract_address)
64
66
  return _client
65
67
 
66
68
 
@@ -0,0 +1 @@
1
+ [{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"inferenceID","type":"string"},{"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"}],"indexed":false,"internalType":"struct LLMChatRequest","name":"request","type":"tuple"},{"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":"LLMChat","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"inferenceID","type":"string"},{"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"}],"indexed":false,"internalType":"struct LLMCompletionRequest","name":"request","type":"tuple"},{"components":[{"internalType":"string","name":"answer","type":"string"}],"indexed":false,"internalType":"struct LLMCompletionResponse","name":"response","type":"tuple"}],"name":"LLMCompletionEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"inferenceID","type":"string"},{"components":[{"internalType":"enum ModelInferenceMode","name":"mode","type":"uint8"},{"internalType":"string","name":"modelCID","type":"string"},{"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":"input","type":"tuple"}],"indexed":false,"internalType":"struct ModelInferenceRequest","name":"request","type":"tuple"},{"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":"response","type":"tuple"}],"name":"ModelInferenceEvent","type":"event"},{"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"},{"inputs":[{"components":[{"internalType":"enum ModelInferenceMode","name":"mode","type":"uint8"},{"internalType":"string","name":"modelCID","type":"string"},{"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":"input","type":"tuple"}],"internalType":"struct ModelInferenceRequest","name":"request","type":"tuple"}],"name":"runModelInference","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"}]
@@ -17,6 +17,7 @@ from .defaults import (
17
17
  DEFAULT_INFERENCE_CONTRACT_ADDRESS,
18
18
  DEFAULT_OG_FAUCET_URL,
19
19
  DEFAULT_RPC_URL,
20
+ DEFAULT_API_URL,
20
21
  )
21
22
  from .types import InferenceMode, LlmInferenceMode, LLM, TEE_LLM
22
23
 
@@ -132,6 +133,7 @@ def cli(ctx):
132
133
  ctx.obj["client"] = Client(
133
134
  private_key=ctx.obj["private_key"],
134
135
  rpc_url=DEFAULT_RPC_URL,
136
+ api_url=DEFAULT_API_URL,
135
137
  contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS,
136
138
  email=ctx.obj.get("email"),
137
139
  password=ctx.obj.get("password"),
@@ -2,6 +2,7 @@ import json
2
2
  import logging
3
3
  import os
4
4
  import time
5
+ import base64
5
6
  from pathlib import Path
6
7
  from typing import Any, Dict, List, Optional, Union, Callable
7
8
 
@@ -12,6 +13,7 @@ from eth_account.account import LocalAccount
12
13
  from web3 import Web3
13
14
  from web3.exceptions import ContractLogicError
14
15
  from web3.logs import DISCARD
16
+ import urllib.parse
15
17
 
16
18
  from .exceptions import OpenGradientError
17
19
  from .proto import infer_pb2, infer_pb2_grpc
@@ -42,13 +44,14 @@ _FIREBASE_CONFIG = {
42
44
 
43
45
  # How much time we wait for txn to be included in chain
44
46
  LLM_TX_TIMEOUT = 60
45
- INFERENCE_TX_TIMEOUT = 60
47
+ INFERENCE_TX_TIMEOUT = 120
46
48
  REGULAR_TX_TIMEOUT = 30
47
49
 
48
50
  # How many times we retry a transaction because of nonce conflict
49
51
  DEFAULT_MAX_RETRY = 5
50
52
  DEFAULT_RETRY_DELAY_SEC = 1
51
53
 
54
+ PRECOMPILE_CONTRACT_ADDRESS = "0x00000000000000000000000000000000000000F4"
52
55
 
53
56
  class Client:
54
57
  _inference_hub_contract_address: str
@@ -56,9 +59,10 @@ class Client:
56
59
  _wallet_account: LocalAccount
57
60
 
58
61
  _hub_user: Optional[Dict]
62
+ _api_url: str
59
63
  _inference_abi: Dict
60
-
61
- def __init__(self, private_key: str, rpc_url: str, contract_address: str, email: Optional[str], password: Optional[str]):
64
+ _precompile_abi: Dict
65
+ def __init__(self, private_key: str, rpc_url: str, api_url: str, contract_address: str, email: Optional[str], password: Optional[str]):
62
66
  """
63
67
  Initialize the Client with private key, RPC URL, and contract address.
64
68
 
@@ -71,12 +75,17 @@ class Client:
71
75
  """
72
76
  self._inference_hub_contract_address = contract_address
73
77
  self._blockchain = Web3(Web3.HTTPProvider(rpc_url))
78
+ self._api_url = api_url
74
79
  self._wallet_account = self._blockchain.eth.account.from_key(private_key)
75
80
 
76
81
  abi_path = Path(__file__).parent / "abi" / "inference.abi"
77
82
  with open(abi_path, "r") as abi_file:
78
83
  self._inference_abi = json.load(abi_file)
79
84
 
85
+ abi_path = Path(__file__).parent / "abi" / "InferencePrecompile.abi"
86
+ with open(abi_path, "r") as abi_file:
87
+ self._precompile_abi = json.load(abi_file)
88
+
80
89
  if email is not None:
81
90
  self._hub_user = self._login_to_hub(email, password)
82
91
  else:
@@ -292,6 +301,7 @@ class Client:
292
301
 
293
302
  def execute_transaction():
294
303
  contract = self._blockchain.eth.contract(address=self._inference_hub_contract_address, abi=self._inference_abi)
304
+ precompile_contract = self._blockchain.eth.contract(address=PRECOMPILE_CONTRACT_ADDRESS, abi=self._precompile_abi)
295
305
 
296
306
  inference_mode_uint8 = inference_mode.value
297
307
  converted_model_input = convert_to_model_input(model_input)
@@ -305,6 +315,12 @@ class Client:
305
315
 
306
316
  # TODO: This should return a ModelOutput class object
307
317
  model_output = convert_to_model_output(parsed_logs[0]["args"])
318
+ if len(model_output) == 0:
319
+ # check inference directly from node
320
+ parsed_logs = precompile_contract.events.ModelInferenceEvent().process_receipt(tx_receipt, errors=DISCARD)
321
+ inference_id = parsed_logs[0]["args"]["inferenceID"]
322
+ inference_result = self._get_inference_result_from_node(inference_id, inference_mode)
323
+ model_output = convert_to_model_output(inference_result)
308
324
 
309
325
  return InferenceResult(tx_hash.hex(), model_output)
310
326
 
@@ -956,6 +972,87 @@ class Client:
956
972
  return [convert_array_to_model_output(result) for result in results]
957
973
 
958
974
 
975
+ def _get_inference_result_from_node(self, inference_id: str, inference_mode: InferenceMode) -> Dict:
976
+ """
977
+ Get the inference result from node.
978
+
979
+ Args:
980
+ inference_id (str): Inference id for a inference request
981
+
982
+ Returns:
983
+ Dict: The inference result as returned by the node
984
+
985
+ Raises:
986
+ OpenGradientError: If the request fails or returns an error
987
+ """
988
+ try:
989
+ encoded_id = urllib.parse.quote(inference_id, safe='')
990
+ url = f"{self._api_url}/artela-network/artela-rollkit/inference/tx/{encoded_id}"
991
+
992
+ response = requests.get(url)
993
+ if response.status_code == 200:
994
+ resp = response.json()
995
+ inference_result = resp.get("inference_results", {})
996
+ if inference_result:
997
+ decoded_bytes = base64.b64decode(inference_result[0])
998
+ decoded_string = decoded_bytes.decode('utf-8')
999
+ output = json.loads(decoded_string).get("InferenceResult",{})
1000
+ if output is None:
1001
+ raise OpenGradientError("Missing InferenceResult in inference output")
1002
+
1003
+ match inference_mode:
1004
+ case InferenceMode.VANILLA:
1005
+ if "VanillaResult" not in output:
1006
+ raise OpenGradientError("Missing VanillaResult in inference output")
1007
+ if "model_output" not in output["VanillaResult"]:
1008
+ raise OpenGradientError("Missing model_output in VanillaResult")
1009
+ return {
1010
+ "output": output["VanillaResult"]["model_output"]
1011
+ }
1012
+
1013
+ case InferenceMode.TEE:
1014
+ if "TeeNodeResult" not in output:
1015
+ raise OpenGradientError("Missing TeeNodeResult in inference output")
1016
+ if "Response" not in output["TeeNodeResult"]:
1017
+ raise OpenGradientError("Missing Response in TeeNodeResult")
1018
+ if "VanillaResponse" in output["TeeNodeResult"]["Response"]:
1019
+ if "model_output" not in output["TeeNodeResult"]["Response"]["VanillaResponse"]:
1020
+ raise OpenGradientError("Missing model_output in VanillaResponse")
1021
+ return {
1022
+ "output": output["TeeNodeResult"]["Response"]["VanillaResponse"]["model_output"]
1023
+ }
1024
+
1025
+ else:
1026
+ raise OpenGradientError("Missing VanillaResponse in TeeNodeResult Response")
1027
+
1028
+ case InferenceMode.ZKML:
1029
+ if "ZkmlResult" not in output:
1030
+ raise OpenGradientError("Missing ZkmlResult in inference output")
1031
+ if "model_output" not in output["ZkmlResult"]:
1032
+ raise OpenGradientError("Missing model_output in ZkmlResult")
1033
+ return {
1034
+ "output": output["ZkmlResult"]["model_output"]
1035
+ }
1036
+
1037
+ case _:
1038
+ raise OpenGradientError(f"Invalid inference mode: {inference_mode}")
1039
+ else:
1040
+ return None
1041
+
1042
+ else:
1043
+ error_message = f"Failed to get inference result: HTTP {response.status_code}"
1044
+ if response.text:
1045
+ error_message += f" - {response.text}"
1046
+ logging.error(error_message)
1047
+ raise OpenGradientError(error_message)
1048
+
1049
+ except requests.RequestException as e:
1050
+ logging.error(f"Request exception when getting inference result: {str(e)}")
1051
+ raise OpenGradientError(f"Failed to get inference result: {str(e)}")
1052
+ except Exception as e:
1053
+ logging.error(f"Unexpected error when getting inference result: {str(e)}", exc_info=True)
1054
+ raise OpenGradientError(f"Failed to get inference result: {str(e)}")
1055
+
959
1056
  def run_with_retry(txn_function: Callable, max_retries=DEFAULT_MAX_RETRY, retry_delay=DEFAULT_RETRY_DELAY_SEC):
960
1057
  """
961
1058
  Execute a blockchain transaction with retry logic.
@@ -1,9 +1,10 @@
1
1
  # Default variables
2
2
  DEFAULT_RPC_URL = "https://eth-devnet.opengradient.ai"
3
+ DEFAULT_API_URL = "https://sdk-devnet.opengradient.ai"
3
4
  DEFAULT_OG_FAUCET_URL = "https://faucet.opengradient.ai/?address="
4
5
  DEFAULT_HUB_SIGNUP_URL = "https://hub.opengradient.ai/signup"
5
6
  DEFAULT_INFERENCE_CONTRACT_ADDRESS = "0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE"
6
7
  DEFAULT_SCHEDULER_ADDRESS = "0x7179724De4e7FF9271FA40C0337c7f90C0508eF6"
7
8
  DEFAULT_BLOCKCHAIN_EXPLORER = "https://explorer.opengradient.ai/tx/"
8
9
  DEFAULT_IMAGE_GEN_HOST = "18.217.25.69"
9
- DEFAULT_IMAGE_GEN_PORT = 5125
10
+ DEFAULT_IMAGE_GEN_PORT = 5125
@@ -19,7 +19,7 @@ from langchain_core.runnables import Runnable
19
19
  from langchain_core.language_models.base import LanguageModelInput
20
20
 
21
21
  from opengradient import Client, LlmInferenceMode, LLM
22
- from opengradient.defaults import DEFAULT_INFERENCE_CONTRACT_ADDRESS, DEFAULT_RPC_URL
22
+ from opengradient.defaults import DEFAULT_INFERENCE_CONTRACT_ADDRESS, DEFAULT_RPC_URL, DEFAULT_API_URL
23
23
 
24
24
 
25
25
  class OpenGradientChatModel(BaseChatModel):
@@ -34,7 +34,7 @@ class OpenGradientChatModel(BaseChatModel):
34
34
  super().__init__()
35
35
 
36
36
  self._client = Client(
37
- private_key=private_key, rpc_url=DEFAULT_RPC_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS, email=None, password=None
37
+ private_key=private_key, rpc_url=DEFAULT_RPC_URL, api_url=DEFAULT_API_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS, email=None, password=None
38
38
  )
39
39
  self._model_cid = model_cid
40
40
  self._max_tokens = max_tokens
@@ -122,24 +122,18 @@ def convert_to_model_output(event_data: AttributeDict) -> Dict[str, np.ndarray]:
122
122
  We need to reshape each output array using the shape parameter in order to get the array
123
123
  back into its original shape.
124
124
  """
125
- logging.debug(f"Parsing event data: {event_data}")
126
-
127
125
  output_dict = {}
128
-
129
126
  output = event_data.get("output", {})
130
- logging.debug(f"Output data: {output}")
131
127
 
132
- if isinstance(output, AttributeDict):
133
- # Parse numbers
128
+ if isinstance(output, (AttributeDict, dict)):
134
129
  for tensor in output.get("numbers", []):
135
- logging.debug(f"Processing number tensor: {tensor}")
136
- if isinstance(tensor, AttributeDict):
130
+ if isinstance(tensor, (AttributeDict, dict)):
137
131
  name = tensor.get("name")
138
132
  shape = tensor.get("shape")
139
133
  values = []
140
134
  # Convert from fixed point back into np.float32
141
135
  for v in tensor.get("values", []):
142
- if isinstance(v, AttributeDict):
136
+ if isinstance(v, (AttributeDict, dict)):
143
137
  values.append(convert_to_float32(value=int(v.get("value")), decimals=int(v.get("decimals"))))
144
138
  else:
145
139
  logging.warning(f"Unexpected number type: {type(v)}")
@@ -149,8 +143,7 @@ def convert_to_model_output(event_data: AttributeDict) -> Dict[str, np.ndarray]:
149
143
 
150
144
  # Parse strings
151
145
  for tensor in output.get("strings", []):
152
- logging.debug(f"Processing string tensor: {tensor}")
153
- if isinstance(tensor, AttributeDict):
146
+ if isinstance(tensor, (AttributeDict, dict)):
154
147
  name = tensor.get("name")
155
148
  shape = tensor.get("shape")
156
149
  values = tensor.get("values", [])
@@ -160,8 +153,7 @@ def convert_to_model_output(event_data: AttributeDict) -> Dict[str, np.ndarray]:
160
153
 
161
154
  # Parse JSON dicts
162
155
  for tensor in output.get("jsons", []):
163
- logging.debug(f"Processing JSON tensor: {tensor}")
164
- if isinstance(tensor, AttributeDict):
156
+ if isinstance(tensor, (AttributeDict, dict)):
165
157
  name = tensor.get("name")
166
158
  value = tensor.get("value")
167
159
  output_dict[name] = np.array(json.loads(value))
@@ -172,7 +164,6 @@ def convert_to_model_output(event_data: AttributeDict) -> Dict[str, np.ndarray]:
172
164
  logging.warning(f"Unexpected output type: {type(output)}")
173
165
 
174
166
  logging.debug(f"Parsed output: {output_dict}")
175
-
176
167
  return output_dict
177
168
 
178
169
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengradient
3
- Version: 0.4.12b1
3
+ Version: 0.4.14
4
4
  Summary: Python SDK for OpenGradient decentralized model management & inference services
5
5
  Author-email: OpenGradient <oliver@opengradient.ai>
6
6
  License: MIT License
@@ -35,10 +35,8 @@ Classifier: Programming Language :: Python :: 3.12
35
35
  Requires-Python: >=3.10
36
36
  Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
38
- Requires-Dist: eth-utils==2.2.2
39
- Requires-Dist: eth-account>=0.13.0
40
- Requires-Dist: web3>=6.11
41
- Requires-Dist: websockets>=14.1
38
+ Requires-Dist: eth-account>=0.13.4
39
+ Requires-Dist: web3>=7.3.0
42
40
  Requires-Dist: click>=8.1.7
43
41
  Requires-Dist: firebase-rest-api>=1.11.0
44
42
  Requires-Dist: grpcio>=1.66.2
@@ -15,6 +15,7 @@ src/opengradient.egg-info/dependency_links.txt
15
15
  src/opengradient.egg-info/entry_points.txt
16
16
  src/opengradient.egg-info/requires.txt
17
17
  src/opengradient.egg-info/top_level.txt
18
+ src/opengradient/abi/InferencePrecompile.abi
18
19
  src/opengradient/abi/PriceHistoryInference.abi
19
20
  src/opengradient/abi/WorkflowScheduler.abi
20
21
  src/opengradient/abi/inference.abi
@@ -1,7 +1,5 @@
1
- eth-utils==2.2.2
2
- eth-account>=0.13.0
3
- web3>=6.11
4
- websockets>=14.1
1
+ eth-account>=0.13.4
2
+ web3>=7.3.0
5
3
  click>=8.1.7
6
4
  firebase-rest-api>=1.11.0
7
5
  grpcio>=1.66.2
File without changes
File without changes
File without changes