naeural-client 2.6.15__py3-none-any.whl → 2.6.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- naeural_client/_ver.py +1 -1
- naeural_client/const/base.py +3 -0
- naeural_client-2.6.16.dist-info/METADATA +279 -0
- {naeural_client-2.6.15.dist-info → naeural_client-2.6.16.dist-info}/RECORD +7 -7
- naeural_client-2.6.15.dist-info/METADATA +0 -358
- {naeural_client-2.6.15.dist-info → naeural_client-2.6.16.dist-info}/WHEEL +0 -0
- {naeural_client-2.6.15.dist-info → naeural_client-2.6.16.dist-info}/entry_points.txt +0 -0
- {naeural_client-2.6.15.dist-info → naeural_client-2.6.16.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
naeural_client/const/base.py
CHANGED
@@ -18,6 +18,9 @@ DAUTH_VARS = [DAUTH_NONCE, BCctbase.SIGN, BCctbase.SENDER, BCctbase.HASH]
|
|
18
18
|
|
19
19
|
ETH_ENABLED_ENV_KEY = 'EE_ETH_ENABLED'
|
20
20
|
|
21
|
+
EE_EPOCH_INTERVALS_KEY = 'EE_EPOCH_INTERVALS'
|
22
|
+
EE_EPOCH_INTERVAL_SECONDS_KEY = 'EE_EPOCH_INTERVAL_SECONDS'
|
23
|
+
|
21
24
|
|
22
25
|
class LocalInfo:
|
23
26
|
LOCAL_INFO_FILE = 'local_info.json'
|
@@ -0,0 +1,279 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: naeural_client
|
3
|
+
Version: 2.6.16
|
4
|
+
Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
|
5
|
+
Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
|
6
|
+
Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
|
7
|
+
Author-email: Andrei Ionut Damian <andrei.damian@me.com>, Cristan Bleotiu <cristibleotiu@gmail.com>, Stefan Saraev <saraevstefan@gmail.com>
|
8
|
+
License-File: LICENSE
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Requires-Python: >=3.8
|
13
|
+
Requires-Dist: cryptography>=39.0.0
|
14
|
+
Requires-Dist: numpy
|
15
|
+
Requires-Dist: paho-mqtt
|
16
|
+
Requires-Dist: pandas
|
17
|
+
Requires-Dist: pika
|
18
|
+
Requires-Dist: pyaml
|
19
|
+
Requires-Dist: pyopenssl>=23.0.0
|
20
|
+
Requires-Dist: python-dateutil
|
21
|
+
Requires-Dist: web3
|
22
|
+
Description-Content-Type: text/markdown
|
23
|
+
|
24
|
+
# Ratio1 SDK
|
25
|
+
|
26
|
+
Welcome to the **Ratio1 SDK** repository, formerly known as the **naeural_client SDK**. The Ratio1 SDK is a crucial component of the Ratio1 ecosystem, designed to facilitate interactions, development, and deployment of jobs within the Ratio1 network. By enabling low-code development, the SDK allows developers to build and deploy end-to-end AI (and beyond) cooperative application pipelines seamlessly within the Ratio1 Edge Nodes ecosystem.
|
27
|
+
|
28
|
+
## Overview
|
29
|
+
|
30
|
+
The **Ratio1 SDK** is engineered to enhance the Ratio1 protocol and ecosystem, aiming to improve the functionality and performance of the Ratio1 Edge Node through dedicated research and community contributions. This SDK serves as an essential tool for developers looking to integrate their applications with the Ratio1 network, enabling them to leverage the decentralized, secure, and privacy-preserving capabilities of Ratio1 Edge Nodes.
|
31
|
+
|
32
|
+
Key functionalities of the Ratio1 SDK include:
|
33
|
+
|
34
|
+
- **Job Interactions**: Facilitate the development and management of computation tasks within the Ratio1 network.
|
35
|
+
- **Development Tools**: Provide low-code solutions for creating and deploying AI-driven application pipelines.
|
36
|
+
- **Ecosystem Integration**: Seamlessly integrate with Ratio1 Edge Nodes to utilize their computational resources effectively.
|
37
|
+
- **Collaboration and Deployment**: Enable cooperative application development and deployment across multiple edge nodes within the Ratio1 ecosystem.
|
38
|
+
|
39
|
+
Unlike the Ratio1 Core Packages, which are intended solely for protocol and ecosystem enhancements and are not meant for standalone installation, the Ratio1 SDK is designed for both client-side development and sending workloads to Ratio1 Edge Nodes, making it an indispensable tool for developers within the ecosystem.
|
40
|
+
|
41
|
+
## Dependencies
|
42
|
+
|
43
|
+
The Ratio1 SDK relies on several key packages to function effectively. These dependencies are automatically managed when installing the SDK via pip:
|
44
|
+
|
45
|
+
- `pika`
|
46
|
+
- `paho-mqtt`
|
47
|
+
- `numpy`
|
48
|
+
- `pyopenssl>=23.0.0`
|
49
|
+
- `cryptography>=39.0.0`
|
50
|
+
- `python-dateutil`
|
51
|
+
- `pyaml`
|
52
|
+
|
53
|
+
## Installation
|
54
|
+
|
55
|
+
Installing the Ratio1 SDK is straightforward and is intended for development and integration into your projects. Use the following pip commands to install the SDK:
|
56
|
+
|
57
|
+
### Standard Installation
|
58
|
+
|
59
|
+
To install the Ratio1 SDK, run:
|
60
|
+
|
61
|
+
```shell
|
62
|
+
pip install ratio1_sdk --upgrade
|
63
|
+
```
|
64
|
+
|
65
|
+
### Development Installation
|
66
|
+
|
67
|
+
For development purposes, you can clone the repository and set up the SDK in an editable mode:
|
68
|
+
|
69
|
+
```shell
|
70
|
+
git clone https://github.com/Ratio1/ratio1_sdk
|
71
|
+
cd ratio1_sdk
|
72
|
+
pip install -e .
|
73
|
+
```
|
74
|
+
|
75
|
+
This allows you to make modifications to the SDK and have them reflected immediately without reinstalling.
|
76
|
+
|
77
|
+
## Documentation
|
78
|
+
|
79
|
+
Comprehensive documentation for the Ratio1 SDK is currently a work in progress. Minimal documentation is available here, with detailed code examples located in the `tutorials` folder within the project's repository. We encourage developers to explore these examples to understand the SDK's capabilities and integration methods.
|
80
|
+
|
81
|
+
## Quick Start Guides
|
82
|
+
|
83
|
+
Starting with version 2.6+, the Ratio1 SDK automatically performs self-configuration using **dAuth**—the Ratio1 decentralized self-authentication system. To begin integrating with the Ratio1 network, follow these steps:
|
84
|
+
|
85
|
+
### 1. Start a Local Edge Node
|
86
|
+
|
87
|
+
Launch a local Ratio1 Edge Node using Docker:
|
88
|
+
|
89
|
+
```bash
|
90
|
+
docker run -d --name=local_node ratio1/edge_node:develop
|
91
|
+
```
|
92
|
+
|
93
|
+
After a few seconds, the node will be online. Retrieve the node's address by running:
|
94
|
+
|
95
|
+
```bash
|
96
|
+
docker exec local_node get_node_info
|
97
|
+
```
|
98
|
+
|
99
|
+
The output will resemble:
|
100
|
+
|
101
|
+
```json
|
102
|
+
{
|
103
|
+
"address": "0xai_AtMvIwaEPi5M8cnkdbaZ3tbUhCzKbGKEYuZ1xFtCjT_6",
|
104
|
+
"alias": "6dd74472642e",
|
105
|
+
"eth_address": "0x98FE7c0d8CeC2E97B932D2bDC1bb73B395C9Dfd7"
|
106
|
+
}
|
107
|
+
```
|
108
|
+
|
109
|
+
### 2. Develop and Deploy Jobs
|
110
|
+
|
111
|
+
Use the SDK to develop and send workloads to the Edge Nodes. Below are examples of both local and remote execution.
|
112
|
+
|
113
|
+
## Examples
|
114
|
+
|
115
|
+
### Local Execution
|
116
|
+
|
117
|
+
This example demonstrates how to find all 168 prime numbers in the interval 1 - 1000 using local execution. The code leverages multiple threads to perform prime number generation efficiently.
|
118
|
+
|
119
|
+
```python
|
120
|
+
import numpy as np
|
121
|
+
from concurrent.futures import ThreadPoolExecutor
|
122
|
+
|
123
|
+
def local_brute_force_prime_number_generator():
|
124
|
+
def is_prime(n):
|
125
|
+
if n <= 1:
|
126
|
+
return False
|
127
|
+
for i in range(2, int(np.sqrt(n)) + 1):
|
128
|
+
if n % i == 0:
|
129
|
+
return False
|
130
|
+
return True
|
131
|
+
|
132
|
+
random_numbers = np.random.randint(1, 1000, 20)
|
133
|
+
|
134
|
+
thread_pool = ThreadPoolExecutor(max_workers=4)
|
135
|
+
are_primes = list(thread_pool.map(is_prime, random_numbers))
|
136
|
+
|
137
|
+
prime_numbers = []
|
138
|
+
for i in range(len(random_numbers)):
|
139
|
+
if are_primes[i]:
|
140
|
+
prime_numbers.append(random_numbers[i])
|
141
|
+
|
142
|
+
return prime_numbers
|
143
|
+
|
144
|
+
if __name__ == "__main__":
|
145
|
+
found_so_far = []
|
146
|
+
print_step = 0
|
147
|
+
|
148
|
+
while len(found_so_far) < 168:
|
149
|
+
# Compute a batch of prime numbers
|
150
|
+
prime_numbers = local_brute_force_prime_number_generator()
|
151
|
+
|
152
|
+
# Keep only the new prime numbers
|
153
|
+
for prime_number in prime_numbers:
|
154
|
+
if prime_number not in found_so_far:
|
155
|
+
found_so_far.append(prime_number)
|
156
|
+
|
157
|
+
# Show progress
|
158
|
+
if print_step % 50 == 0:
|
159
|
+
print("Found so far: {}: {}\n".format(len(found_so_far), sorted(found_so_far)))
|
160
|
+
|
161
|
+
print_step += 1
|
162
|
+
|
163
|
+
# Show final result
|
164
|
+
print("Found so far: {}: {}\n".format(len(found_so_far), sorted(found_so_far)))
|
165
|
+
```
|
166
|
+
|
167
|
+
### Remote Execution
|
168
|
+
|
169
|
+
To accelerate prime number discovery, this example demonstrates deploying the task across multiple edge nodes within the Ratio1 network. Minimal code changes are required to transition from local to remote execution.
|
170
|
+
|
171
|
+
#### 1. Modify the Prime Number Generator
|
172
|
+
|
173
|
+
```python
|
174
|
+
from ratio1_sdk import CustomPluginTemplate
|
175
|
+
|
176
|
+
def remote_brute_force_prime_number_generator(plugin: CustomPluginTemplate):
|
177
|
+
def is_prime(n):
|
178
|
+
if n <= 1:
|
179
|
+
return False
|
180
|
+
for i in range(2, int(plugin.np.sqrt(n)) + 1):
|
181
|
+
if n % i == 0:
|
182
|
+
return False
|
183
|
+
return True
|
184
|
+
|
185
|
+
random_numbers = plugin.np.random.randint(1, 1000, 20)
|
186
|
+
are_primes = plugin.threadapi_map(is_prime, random_numbers, n_threads=4)
|
187
|
+
|
188
|
+
prime_numbers = []
|
189
|
+
for i in range(len(random_numbers)):
|
190
|
+
if are_primes[i]:
|
191
|
+
prime_numbers.append(random_numbers[i])
|
192
|
+
|
193
|
+
return prime_numbers
|
194
|
+
```
|
195
|
+
|
196
|
+
#### 2. Connect to the Network and Select a Node
|
197
|
+
|
198
|
+
```python
|
199
|
+
from ratio1_sdk import Session
|
200
|
+
from time import sleep
|
201
|
+
|
202
|
+
def on_heartbeat(session: Session, node: str, heartbeat: dict):
|
203
|
+
session.P("{} is online".format(node))
|
204
|
+
return
|
205
|
+
|
206
|
+
if __name__ == '__main__':
|
207
|
+
session = Session(
|
208
|
+
on_heartbeat=on_heartbeat
|
209
|
+
)
|
210
|
+
|
211
|
+
# Run the program for 15 seconds to detect online nodes
|
212
|
+
sleep(15)
|
213
|
+
|
214
|
+
# Retrieve and select an online node
|
215
|
+
node = "0xai_A8SY7lEqBtf5XaGyB6ipdk5C30vSf3HK4xELp3iplwLe" # naeural-1
|
216
|
+
```
|
217
|
+
|
218
|
+
#### 3. Deploy the Distributed Job
|
219
|
+
|
220
|
+
```python
|
221
|
+
from ratio1_sdk import DistributedCustomCodePresets as Presets
|
222
|
+
|
223
|
+
_, _ = session.create_chain_dist_custom_job(
|
224
|
+
node=node,
|
225
|
+
main_node_process_real_time_collected_data=Presets.PROCESS_REAL_TIME_COLLECTED_DATA__KEEP_UNIQUES_IN_AGGREGATED_COLLECTED_DATA,
|
226
|
+
main_node_finish_condition=Presets.FINISH_CONDITION___AGGREGATED_DATA_MORE_THAN_X,
|
227
|
+
main_node_finish_condition_kwargs={"X": 167},
|
228
|
+
main_node_aggregate_collected_data=Presets.AGGREGATE_COLLECTED_DATA___AGGREGATE_COLLECTED_DATA,
|
229
|
+
nr_remote_worker_nodes=2,
|
230
|
+
worker_node_code=remote_brute_force_prime_number_generator,
|
231
|
+
on_data=locally_process_partial_results,
|
232
|
+
deploy=True
|
233
|
+
)
|
234
|
+
```
|
235
|
+
|
236
|
+
#### 4. Close the Session Upon Completion
|
237
|
+
|
238
|
+
```python
|
239
|
+
# Wait until the finished flag is set to True
|
240
|
+
session.run(wait=lambda: not finished, close_pipelines=True)
|
241
|
+
```
|
242
|
+
|
243
|
+
## Project Financing Disclaimer
|
244
|
+
|
245
|
+
This project incorporates open-source components developed with the support of financing grants **SMIS 143488** and **SMIS 156084**, provided by the Romanian Competitiveness Operational Programme. We extend our sincere gratitude for this support, which has been instrumental in advancing our work and enabling us to share these resources with the community.
|
246
|
+
|
247
|
+
The content and information within this repository are solely the responsibility of the authors and do not necessarily reflect the views of the funding agencies. The grants have specifically supported certain aspects of this open-source project, facilitating broader dissemination and collaborative development.
|
248
|
+
|
249
|
+
For any inquiries regarding the funding and its impact on this project, please contact the authors directly.
|
250
|
+
|
251
|
+
## License
|
252
|
+
|
253
|
+
This project is licensed under the **Apache 2.0 License**. For more details, please refer to the [LICENSE](LICENSE) file.
|
254
|
+
|
255
|
+
## Contact
|
256
|
+
|
257
|
+
For more information, visit our website at [https://ratio1.ai](https://ratio1.ai) or reach out to us via email at [support@ratio1.ai](mailto:support@ratio1.ai).
|
258
|
+
|
259
|
+
## Citation
|
260
|
+
|
261
|
+
If you use the Ratio1 SDK in your research or projects, please cite it as follows:
|
262
|
+
|
263
|
+
```bibtex
|
264
|
+
@misc{Ratio1SDK,
|
265
|
+
author = {Ratio1.AI},
|
266
|
+
title = {Ratio1 SDK},
|
267
|
+
year = {2024-2025},
|
268
|
+
howpublished = {\url{https://github.com/NaeuralEdgeProtocol/naeural_client}},
|
269
|
+
}
|
270
|
+
```
|
271
|
+
|
272
|
+
```bibtex
|
273
|
+
@misc{Ratio1EdgeNode,
|
274
|
+
author = {Ratio1.AI},
|
275
|
+
title = {Ratio1: Edge Node},
|
276
|
+
year = {2024-2025},
|
277
|
+
howpublished = {\url{https://github.com/NaeuralEdgeProtocol/edge_node}},
|
278
|
+
}
|
279
|
+
```
|
@@ -1,5 +1,5 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=eM7t0xRbVJaaGjrh0O9tmQF7K_usWv_3wk3hVZ27_Qs,331
|
3
3
|
naeural_client/base_decentra_object.py,sha256=C4iwZTkhKNBS4VHlJs5DfElRYLo4Q9l1V1DNVSk1fyQ,4412
|
4
4
|
naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
|
5
5
|
naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
|
@@ -32,7 +32,7 @@ naeural_client/comm/mqtt_wrapper.py,sha256=Ig3bFZkCbWd4y_Whn2PPa91Z3aLgNbNPau6Tn
|
|
32
32
|
naeural_client/const/README.md,sha256=6OHesr-f5NBuuJGryEoi_TCu2XdlhfQYlDKx_IJoXeg,177
|
33
33
|
naeural_client/const/__init__.py,sha256=MM6Zib6i7M2qWcMkLtLx14zqU-lE-u2uPHjNvbh2jAM,478
|
34
34
|
naeural_client/const/apps.py,sha256=ePBiJXLuPfFOKuw-LJrT9OWbaodU7QApfDurIPNDoB4,655
|
35
|
-
naeural_client/const/base.py,sha256=
|
35
|
+
naeural_client/const/base.py,sha256=1ScfnfNd5xeWo7tkkDgQR95vliTpcax025Naj0Lqw38,4574
|
36
36
|
naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
|
37
37
|
naeural_client/const/environment.py,sha256=iytmTDgbOjvORPwHQmc0K0r-xJx7dnnzNnqAJJiFCDA,870
|
38
38
|
naeural_client/const/formatter.py,sha256=AW3bWlqf39uaqV4BBUuW95qKYfF2OkkU4f9hy3kSVhM,200
|
@@ -81,8 +81,8 @@ naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uw
|
|
81
81
|
naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
|
82
82
|
naeural_client/utils/config.py,sha256=v7xHikr6Z5Sbvf3opYeMhYzGWD2pe0HlRwa-aGJzUh8,6323
|
83
83
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
84
|
-
naeural_client-2.6.
|
85
|
-
naeural_client-2.6.
|
86
|
-
naeural_client-2.6.
|
87
|
-
naeural_client-2.6.
|
88
|
-
naeural_client-2.6.
|
84
|
+
naeural_client-2.6.16.dist-info/METADATA,sha256=PaCUsM0cAtvH9ZUTzfwNxZTumPu4np7e3inODMj9WLA,10362
|
85
|
+
naeural_client-2.6.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
86
|
+
naeural_client-2.6.16.dist-info/entry_points.txt,sha256=PNdyotDaQBAslZREx5luVyj0kqpQnwNACwkFNTPIHU4,55
|
87
|
+
naeural_client-2.6.16.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
88
|
+
naeural_client-2.6.16.dist-info/RECORD,,
|
@@ -1,358 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: naeural_client
|
3
|
-
Version: 2.6.15
|
4
|
-
Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
|
5
|
-
Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
|
6
|
-
Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
|
7
|
-
Author-email: Andrei Ionut Damian <andrei.damian@me.com>, Cristan Bleotiu <cristibleotiu@gmail.com>, Stefan Saraev <saraevstefan@gmail.com>
|
8
|
-
License-File: LICENSE
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
10
|
-
Classifier: Operating System :: OS Independent
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
12
|
-
Requires-Python: >=3.8
|
13
|
-
Requires-Dist: cryptography>=39.0.0
|
14
|
-
Requires-Dist: numpy
|
15
|
-
Requires-Dist: paho-mqtt
|
16
|
-
Requires-Dist: pandas
|
17
|
-
Requires-Dist: pika
|
18
|
-
Requires-Dist: pyaml
|
19
|
-
Requires-Dist: pyopenssl>=23.0.0
|
20
|
-
Requires-Dist: python-dateutil
|
21
|
-
Requires-Dist: web3
|
22
|
-
Description-Content-Type: text/markdown
|
23
|
-
|
24
|
-
# Ratio1 SDK (naeural_client SDK)
|
25
|
-
|
26
|
-
This is the Python SDK package that allows interactions, development and deployment of jobs in Ratio1 ecosystem formely known as Naeural Edge Protocol network. The SDK enables low-code development and deployment of end-to-end AI (and not only) cooperative application pipelines within the Ratio1 Edge Nodes ecosystem.
|
27
|
-
|
28
|
-
## Dependencies
|
29
|
-
|
30
|
-
This packet depends and will automatically install the following packets: `pika`, `paho-mqtt`, `numpy`, `pyopenssl>=23.0.0`, `cryptography>=39.0.0`, `python-dateutil`, `pyaml`.
|
31
|
-
|
32
|
-
## Installation
|
33
|
-
|
34
|
-
```shell
|
35
|
-
pip install naeural_client --upgrade
|
36
|
-
```
|
37
|
-
|
38
|
-
### Development installation
|
39
|
-
|
40
|
-
```shell
|
41
|
-
git clone https://github.com/NaeuralEdgeProtocol/naeural_client
|
42
|
-
pip install -e .
|
43
|
-
```
|
44
|
-
|
45
|
-
## Documentation
|
46
|
-
|
47
|
-
Minimal documentation will be presented here. The complete documentation is
|
48
|
-
Work in Progress.
|
49
|
-
|
50
|
-
Code examples are located in the `tutorials` folder in the project's repository.
|
51
|
-
|
52
|
-
## Quick start guides
|
53
|
-
|
54
|
-
Starting with version 2.6+ the SDK will automatically perform self-configuration using the dAuth - the Ratio1 decentralized self-authentication system.
|
55
|
-
|
56
|
-
In order to start a local edge node you just need to run:
|
57
|
-
|
58
|
-
```bash
|
59
|
-
docker run -d --name=local_node naeural/edge_node:develop
|
60
|
-
```
|
61
|
-
after a few seconds the node will be online and you can get the node's address by running:
|
62
|
-
|
63
|
-
```bash
|
64
|
-
docker exec local_node get_node_info
|
65
|
-
```
|
66
|
-
|
67
|
-
The output will be similar to:
|
68
|
-
|
69
|
-
```json
|
70
|
-
{
|
71
|
-
"address": "0xai_AtMvIwaEPi5M8cnkdbaZ3tbUhCzKbGKEYuZ1xFtCjT_6",
|
72
|
-
"alias": "6dd74472642e",
|
73
|
-
"eth_address": "0x98FE7c0d8CeC2E97B932D2bDC1bb73B395C9Dfd7"
|
74
|
-
}
|
75
|
-
```
|
76
|
-
|
77
|
-
|
78
|
-
## Some Examples
|
79
|
-
|
80
|
-
### Local Execution
|
81
|
-
|
82
|
-
We want to find all $168$ prime numbers in the interval $1$ - $1000$. For this we can run the following code on our local machine.
|
83
|
-
|
84
|
-
This code has segments running on multiple threads using a ThreadPool.
|
85
|
-
|
86
|
-
```python
|
87
|
-
import numpy as np
|
88
|
-
from concurrent.futures import ThreadPoolExecutor
|
89
|
-
|
90
|
-
|
91
|
-
def local_brute_force_prime_number_generator():
|
92
|
-
def is_prime(n):
|
93
|
-
if n <= 1:
|
94
|
-
return False
|
95
|
-
for i in range(2, int(np.sqrt(n)) + 1):
|
96
|
-
if n % i == 0:
|
97
|
-
return False
|
98
|
-
return True
|
99
|
-
|
100
|
-
random_numbers = np.random.randint(1, 1000, 20)
|
101
|
-
|
102
|
-
thread_pool = ThreadPoolExecutor(max_workers=4)
|
103
|
-
are_primes = list(thread_pool.map(is_prime, random_numbers))
|
104
|
-
|
105
|
-
prime_numbers = []
|
106
|
-
for i in range(len(random_numbers)):
|
107
|
-
if are_primes[i]:
|
108
|
-
prime_numbers.append(random_numbers[i])
|
109
|
-
|
110
|
-
return prime_numbers
|
111
|
-
|
112
|
-
|
113
|
-
if __name__ == "__main__":
|
114
|
-
found_so_far = []
|
115
|
-
|
116
|
-
print_step = 0
|
117
|
-
|
118
|
-
while len(found_so_far) < 168:
|
119
|
-
# compute a batch of prime numbers
|
120
|
-
prime_numbers = local_brute_force_prime_number_generator()
|
121
|
-
|
122
|
-
# keep only the new prime numbers
|
123
|
-
for prime_number in prime_numbers:
|
124
|
-
if prime_number not in found_so_far:
|
125
|
-
found_so_far.append(prime_number)
|
126
|
-
# end for
|
127
|
-
|
128
|
-
# show progress
|
129
|
-
if print_step % 50 == 0:
|
130
|
-
print("Found so far: {}: {}\n".format(len(found_so_far), sorted(found_so_far)))
|
131
|
-
|
132
|
-
print_step += 1
|
133
|
-
# end while
|
134
|
-
|
135
|
-
# show final result
|
136
|
-
print("Found so far: {}: {}\n".format(len(found_so_far), sorted(found_so_far)))
|
137
|
-
```
|
138
|
-
|
139
|
-
We can see that we have a `local_brute_force_prime_number_generator` method which will generate a random sample of $20$ numbers that will be checked if they are prime or not.
|
140
|
-
|
141
|
-
The rest of the code handles how the numbers generated with this method are kept.
|
142
|
-
Because we want to find $168$ unique numbers, we append to the list of found primes only the numbers that are not present yet.
|
143
|
-
|
144
|
-
At the end, we want to show a list of all the numbers found.
|
145
|
-
|
146
|
-
### Remote Execution
|
147
|
-
|
148
|
-
For this example we would like to use multiple edge nodes to find the prime numbers faster.
|
149
|
-
|
150
|
-
To execute this code on our network, a series of changes must be made to the `local_brute_force_prime_number_generator` method.
|
151
|
-
These changes are the only ones a developer has to do to deploy his own custom code on the network.
|
152
|
-
|
153
|
-
For this, we will create a new method, `remote_brute_force_prime_number_generator`, which will use the exposed edge node API methods.
|
154
|
-
|
155
|
-
```python
|
156
|
-
from naeural_client import CustomPluginTemplate
|
157
|
-
|
158
|
-
# through the `plugin` object we get access to the edge node API
|
159
|
-
# the CustomPluginTemplate class acts as a documentation for all the available methods and attributes
|
160
|
-
# since we do not allow imports in the custom code due to security reasons, the `plugin` object
|
161
|
-
# exposes common modules to the user
|
162
|
-
def remote_brute_force_prime_number_generator(plugin: CustomPluginTemplate):
|
163
|
-
def is_prime(n):
|
164
|
-
if n <= 1:
|
165
|
-
return False
|
166
|
-
# we use the `plugin.np` instead of the `np` module
|
167
|
-
for i in range(2, int(plugin.np.sqrt(n)) + 1):
|
168
|
-
if n % i == 0:
|
169
|
-
return False
|
170
|
-
return True
|
171
|
-
|
172
|
-
# we use the `plugin.np` instead of the `np` module
|
173
|
-
random_numbers = plugin.np.random.randint(1, 1000, 20)
|
174
|
-
|
175
|
-
# we use the `plugin.threadapi_map` instead of the `ThreadPoolExecutor.map`
|
176
|
-
are_primes = plugin.threadapi_map(is_prime, random_numbers, n_threads=4)
|
177
|
-
|
178
|
-
prime_numbers = []
|
179
|
-
for i in range(len(random_numbers)):
|
180
|
-
if are_primes[i]:
|
181
|
-
prime_numbers.append(random_numbers[i])
|
182
|
-
|
183
|
-
return prime_numbers
|
184
|
-
```
|
185
|
-
|
186
|
-
This are all the changes we have to do to deploy this code in the network.
|
187
|
-
|
188
|
-
Now lets connect to the network and see what nodes are online.
|
189
|
-
We will use the `on_heartbeat` callback to print the nodes.
|
190
|
-
|
191
|
-
```python
|
192
|
-
from naeural_client import Session
|
193
|
-
from time import sleep
|
194
|
-
|
195
|
-
def on_heartbeat(session: Session, node: str, heartbeat: dict):
|
196
|
-
# the `.P` method is used to print messages in the console and store them in the log file
|
197
|
-
session.P("{} is online".format(node))
|
198
|
-
return
|
199
|
-
|
200
|
-
|
201
|
-
if __name__ == '__main__':
|
202
|
-
# create a session
|
203
|
-
# the network credentials are read from the .env file automatically
|
204
|
-
session = Session(
|
205
|
-
on_heartbeat=on_heartbeat
|
206
|
-
)
|
207
|
-
|
208
|
-
# run the program for 15 seconds to show all the nodes that are online
|
209
|
-
sleep(15)
|
210
|
-
|
211
|
-
```
|
212
|
-
|
213
|
-
Next we will select an online node. This node will be our entrypoint in the network.
|
214
|
-
|
215
|
-
The available nodes in our test net are:
|
216
|
-
|
217
|
-
```
|
218
|
-
0xai_A8SY7lEqBtf5XaGyB6ipdk5C30vSf3HK4xELp3iplwLe naeural-1
|
219
|
-
0xai_Amfnbt3N-qg2-qGtywZIPQBTVlAnoADVRmSAsdDhlQ-6 naeural-2
|
220
|
-
0xai_ApltAljEgWk3g8x2QcSa0sS3hT1P4dyCchd04zFSMy5e naeural-3
|
221
|
-
```
|
222
|
-
|
223
|
-
We will send a task to this node. Since we want to distribute the task of finding prime numbers to multiple nodes, this selected node will handle distribution of tasks and collection of the results.
|
224
|
-
|
225
|
-
```python
|
226
|
-
node = "0xai_A8SY7lEqBtf5XaGyB6ipdk5C30vSf3HK4xELp3iplwLe" # naeural-1
|
227
|
-
|
228
|
-
# we usually wait for the node to be online before sending the task
|
229
|
-
# but in this case we are sure that the node is online because we
|
230
|
-
# have received heartbeats from it during the sleep period
|
231
|
-
|
232
|
-
# session.wait_for_node(node)
|
233
|
-
```
|
234
|
-
|
235
|
-
Our selected node will periodically output partial results with the prime numbers found so far by the worker nodes. We want to consume these results.
|
236
|
-
|
237
|
-
Thus, we need to implement a callback method that will handle this.
|
238
|
-
|
239
|
-
```python
|
240
|
-
from naeural_client import Pipeline
|
241
|
-
|
242
|
-
# a flag used to close the session when the task is finished
|
243
|
-
finished = False
|
244
|
-
|
245
|
-
def locally_process_partial_results(pipeline: Pipeline, full_payload):
|
246
|
-
global finished
|
247
|
-
found_so_far = full_payload.get("DATA")
|
248
|
-
|
249
|
-
if found_so_far:
|
250
|
-
pipeline.P("Found so far: {}: {}\n\n".format(len(found_so_far), sorted(found_so_far)))
|
251
|
-
|
252
|
-
progress = full_payload.get("PROGRESS")
|
253
|
-
if progress == 100:
|
254
|
-
pipeline.P("FINISHED\n\n")
|
255
|
-
finished = True
|
256
|
-
|
257
|
-
return
|
258
|
-
```
|
259
|
-
|
260
|
-
Now we are ready to deploy our job to the network.
|
261
|
-
|
262
|
-
```python
|
263
|
-
from naeural_client import DistributedCustomCodePresets as Presets
|
264
|
-
|
265
|
-
_, _ = session.create_chain_dist_custom_job(
|
266
|
-
# this is the main node, our entrypoint
|
267
|
-
node=node,
|
268
|
-
|
269
|
-
# this function is executed on the main node
|
270
|
-
# this handles what we want to do with primes found by a worker node after an iteration
|
271
|
-
# we want to store only the unique prime numbers
|
272
|
-
# we cam either write a custom code to pass here or we can use a preset
|
273
|
-
main_node_process_real_time_collected_data=Presets.PROCESS_REAL_TIME_COLLECTED_DATA__KEEP_UNIQUES_IN_AGGREGATED_COLLECTED_DATA,
|
274
|
-
|
275
|
-
# this function is executed on the main node
|
276
|
-
# this handles the finish condition of our distributed job
|
277
|
-
# we want to finish when we have found 168 prime numbers
|
278
|
-
# so more than 167 prime numbers
|
279
|
-
# we cam either write a custom code to pass here or we can use a preset
|
280
|
-
main_node_finish_condition=Presets.FINISH_CONDITION___AGGREGATED_DATA_MORE_THAN_X,
|
281
|
-
main_node_finish_condition_kwargs={
|
282
|
-
"X": 167
|
283
|
-
},
|
284
|
-
|
285
|
-
# this function is executed on the main node
|
286
|
-
# this handles the final processing of the results
|
287
|
-
# this function prepares data for the final result of the distributed job
|
288
|
-
# we want to aggregate all the prime numbers found by the worker nodes in a single list
|
289
|
-
# we cam either write a custom code to pass here or we can use a preset
|
290
|
-
main_node_aggregate_collected_data=Presets.AGGREGATE_COLLECTED_DATA___AGGREGATE_COLLECTED_DATA,
|
291
|
-
|
292
|
-
# how many worker nodes we want to use for this task
|
293
|
-
nr_remote_worker_nodes=2,
|
294
|
-
|
295
|
-
# this is the function that will be executed on the worker nodes
|
296
|
-
# this function generates prime numbers using brute force
|
297
|
-
# we simply pass the function reference
|
298
|
-
worker_node_code=remote_brute_force_prime_number_generator,
|
299
|
-
|
300
|
-
# this is the function that will be executed on the client
|
301
|
-
# this is the callback function that processes the partial results
|
302
|
-
# in our case we want to print the partial results
|
303
|
-
on_data=locally_process_partial_results,
|
304
|
-
|
305
|
-
# we want to deploy the job immediately
|
306
|
-
deploy=True
|
307
|
-
)
|
308
|
-
```
|
309
|
-
|
310
|
-
Last but not least, we want to close the session when the distributed job finished.
|
311
|
-
|
312
|
-
```python
|
313
|
-
# we wait until the finished flag is set to True
|
314
|
-
# we want to release the resources allocated on the selected node when the job is finished
|
315
|
-
session.run(wait=lambda: not finished, close_pipelines=True)
|
316
|
-
```
|
317
|
-
|
318
|
-
|
319
|
-
# Project Financing Disclaimer
|
320
|
-
|
321
|
-
This project includes open-source components that have been developed with the support of financing grants SMIS 143488 and SMIS 156084, provided by the Romanian Competitiveness Operational Programme. We are grateful for this support, which has enabled us to advance our work and share these resources with the community.
|
322
|
-
|
323
|
-
The content and information provided within this repository are solely the responsibility of the authors and do not necessarily reflect the views of the funding agencies. The funding received under these grants has been instrumental in supporting specific parts of this open source project, allowing for broader dissemination and collaborative development.
|
324
|
-
|
325
|
-
For any inquiries related to the funding and its impact on this project, please contact the authors directly.
|
326
|
-
|
327
|
-
|
328
|
-
# Citation
|
329
|
-
|
330
|
-
```bibtex
|
331
|
-
@misc{naeural_client,
|
332
|
-
author = {Stefan Saraev, Andrei Damian},
|
333
|
-
title = {naeural_client: Python SDK for Naeural Edge Protocol Edge Protocol},
|
334
|
-
year = {2024},
|
335
|
-
howpublished = {\url{https://github.com/Naeural Edge ProtocolEdgeProtocol/naeural_client}},
|
336
|
-
}
|
337
|
-
```
|
338
|
-
|
339
|
-
```bibtex
|
340
|
-
@misc{project_funding_acknowledgment1,
|
341
|
-
author = {Damian, Bleotiu, Saraev, Constantinescu},
|
342
|
-
title = {SOLIS – Sistem Omogen multi-Locație cu funcționalități Inteligente și Sustenabile”
|
343
|
-
SMIS 143488},
|
344
|
-
howpublished = {\url{https://github.com/Naeural Edge ProtocolEdgeProtocol/}},
|
345
|
-
note = {This project includes open-source components developed with support from the Romanian Competitiveness Operational Programme under grants SMIS 143488. The content is solely the responsibility of the authors and does not necessarily reflect the views of the funding agencies.},
|
346
|
-
year = {2021-2022}
|
347
|
-
}
|
348
|
-
```
|
349
|
-
|
350
|
-
```bibtex
|
351
|
-
@misc{project_funding_acknowledgment2,
|
352
|
-
author = {Damian, Bleotiu, Saraev, Constantinescu, Milik, Lupaescu},
|
353
|
-
title = {ReDeN – Rețea Descentralizată Neurală SMIS 156084},
|
354
|
-
howpublished = {\url{https://github.com/Naeural Edge ProtocolEdgeProtocol/}},
|
355
|
-
note = {This project includes open-source components developed with support from the Romanian Competitiveness Operational Programme under grants SMIS 143488. The content is solely the responsibility of the authors and does not necessarily reflect the views of the funding agencies.},
|
356
|
-
year = {2023-2024}
|
357
|
-
}
|
358
|
-
```
|
File without changes
|
File without changes
|
File without changes
|