neuronum 6.0.1__tar.gz → 7.0.1__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.
Potentially problematic release.
This version of neuronum might be problematic. Click here for more details.
- {neuronum-6.0.1/neuronum.egg-info → neuronum-7.0.1}/PKG-INFO +15 -90
- {neuronum-6.0.1 → neuronum-7.0.1}/README.md +13 -89
- {neuronum-6.0.1 → neuronum-7.0.1}/cli/main.py +289 -213
- {neuronum-6.0.1 → neuronum-7.0.1/neuronum.egg-info}/PKG-INFO +15 -90
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum.egg-info/requires.txt +1 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/setup.py +2 -1
- {neuronum-6.0.1 → neuronum-7.0.1}/LICENSE.md +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/cli/__init__.py +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum/__init__.py +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum/neuronum.py +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum.egg-info/SOURCES.txt +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum.egg-info/dependency_links.txt +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum.egg-info/entry_points.txt +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/neuronum.egg-info/top_level.txt +0 -0
- {neuronum-6.0.1 → neuronum-7.0.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.1
|
|
4
4
|
Summary: Official client library to interact with the Neuronum Network
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -19,6 +19,7 @@ Requires-Dist: questionary
|
|
|
19
19
|
Requires-Dist: python-dotenv
|
|
20
20
|
Requires-Dist: requests
|
|
21
21
|
Requires-Dist: psutil
|
|
22
|
+
Requires-Dist: jinja2
|
|
22
23
|
Dynamic: author
|
|
23
24
|
Dynamic: author-email
|
|
24
25
|
Dynamic: classifier
|
|
@@ -78,7 +79,6 @@ Neuronum is the real-time data engine designed for developers to build event-dri
|
|
|
78
79
|
|
|
79
80
|
### Requirements
|
|
80
81
|
- Python >= 3.8
|
|
81
|
-
- neuronum >= 5.5.0
|
|
82
82
|
|
|
83
83
|
------------------
|
|
84
84
|
|
|
@@ -104,102 +104,27 @@ neuronum connect-cell # connect Cell
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
### **Build On Neuronum**
|
|
107
|
-
|
|
107
|
+
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
To get started, initialize a new Node with the command below.
|
|
110
110
|
```sh
|
|
111
|
-
neuronum init-node
|
|
111
|
+
neuronum init-node
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
This command
|
|
114
|
+
This command will prompt you for a description (e.g., Test App) and will create
|
|
115
115
|
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
NODE=your_node_id
|
|
119
|
-
HOST=your_cell_id
|
|
120
|
-
PASSWORD=your_password
|
|
121
|
-
NETWORK=neuronum.net
|
|
122
|
-
SYNAPSE=your_synapse # auth token
|
|
123
|
-
```
|
|
116
|
+
1. A Stream (STX) so your App can receive requests, and a Transmitter (TX) to match those requests
|
|
117
|
+
2. A new directory named "Test App_<your_node_id>" with the following files
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
```python
|
|
127
|
-
import asyncio
|
|
128
|
-
import neuronum
|
|
129
|
-
import os
|
|
130
|
-
from dotenv import load_dotenv
|
|
131
|
-
|
|
132
|
-
load_dotenv()
|
|
133
|
-
host = os.getenv("HOST")
|
|
134
|
-
password = os.getenv("PASSWORD")
|
|
135
|
-
network = os.getenv("NETWORK")
|
|
136
|
-
synapse = os.getenv("SYNAPSE")
|
|
137
|
-
|
|
138
|
-
cell = neuronum.Cell(
|
|
139
|
-
host=host,
|
|
140
|
-
password=password,
|
|
141
|
-
network=network,
|
|
142
|
-
synapse=synapse
|
|
143
|
-
)
|
|
119
|
+
.env: Stores your Node's credentials for connecting to the network.
|
|
144
120
|
|
|
145
|
-
|
|
146
|
-
STX = "id::stx"
|
|
147
|
-
async for operation in cell.sync(STX):
|
|
148
|
-
txID = operation.get("txID")
|
|
149
|
-
client = operation.get("operator")
|
|
150
|
-
|
|
151
|
-
if txID == "id::tx":
|
|
152
|
-
data = {
|
|
153
|
-
"json": f"Hello {client}",
|
|
154
|
-
"html": f"""
|
|
155
|
-
<!DOCTYPE html>
|
|
156
|
-
<html>
|
|
157
|
-
<head>
|
|
158
|
-
<meta charset="UTF-8">
|
|
159
|
-
<title>Greeting Node</title>
|
|
160
|
-
</head>
|
|
161
|
-
<body>
|
|
162
|
-
<div class="card">
|
|
163
|
-
<h1>Hello, {client}</h1>
|
|
164
|
-
</div>
|
|
165
|
-
</body>
|
|
166
|
-
</html>
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
await cell.tx_response(txID, client, data)
|
|
121
|
+
app.py: The main Python script that contains your Node's core logic.
|
|
171
122
|
|
|
172
|
-
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
config.json (required if you want to make your app accessible to Cellai (currently in testing))
|
|
176
|
-
```json
|
|
177
|
-
{
|
|
178
|
-
"data_gateways": [
|
|
179
|
-
{
|
|
180
|
-
"type": "stream",
|
|
181
|
-
"id": "id::stx",
|
|
182
|
-
"info": "provide a detailed description about the stream"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"type": "transmitter",
|
|
186
|
-
"id": "id::tx",
|
|
187
|
-
"info": "provide a detailed description about the transmitter"
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"type": "circuit",
|
|
191
|
-
"id": "id::ctx",
|
|
192
|
-
"info": "provide a detailed description about the circuit"
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
```
|
|
123
|
+
NODE.md: Public documentation that provides instructions for interacting with your Node.
|
|
197
124
|
|
|
198
|
-
|
|
199
|
-
```
|
|
200
|
-
### NODE.md: Create a detailed Markdown File on how to interact with this Node
|
|
201
|
-
```
|
|
125
|
+
config.json: A configuration file that stores metadata about your app and enables Cellai to interact with your Node's data gateways.
|
|
202
126
|
|
|
127
|
+
ping.html: A static HTML file used to render web-based responses.
|
|
203
128
|
|
|
204
129
|
Change into Node folder
|
|
205
130
|
```sh
|
|
@@ -247,6 +172,6 @@ asyncio.run(main())
|
|
|
247
172
|
neuronum activate --tx id::tx 'say:hello'
|
|
248
173
|
```
|
|
249
174
|
|
|
250
|
-
#### **Cellai**
|
|
251
|
-
Cellai is
|
|
175
|
+
#### **Cellai (in Testing)**
|
|
176
|
+
Cellai is an AI tool for developers to test their apps built on Neuronum and will soon be published to the Google Play Store.
|
|
252
177
|
|
|
@@ -45,7 +45,6 @@ Neuronum is the real-time data engine designed for developers to build event-dri
|
|
|
45
45
|
|
|
46
46
|
### Requirements
|
|
47
47
|
- Python >= 3.8
|
|
48
|
-
- neuronum >= 5.5.0
|
|
49
48
|
|
|
50
49
|
------------------
|
|
51
50
|
|
|
@@ -71,102 +70,27 @@ neuronum connect-cell # connect Cell
|
|
|
71
70
|
|
|
72
71
|
|
|
73
72
|
### **Build On Neuronum**
|
|
74
|
-
|
|
73
|
+
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
To get started, initialize a new Node with the command below.
|
|
77
76
|
```sh
|
|
78
|
-
neuronum init-node
|
|
77
|
+
neuronum init-node
|
|
79
78
|
```
|
|
80
79
|
|
|
81
|
-
This command
|
|
80
|
+
This command will prompt you for a description (e.g., Test App) and will create
|
|
82
81
|
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
NODE=your_node_id
|
|
86
|
-
HOST=your_cell_id
|
|
87
|
-
PASSWORD=your_password
|
|
88
|
-
NETWORK=neuronum.net
|
|
89
|
-
SYNAPSE=your_synapse # auth token
|
|
90
|
-
```
|
|
82
|
+
1. A Stream (STX) so your App can receive requests, and a Transmitter (TX) to match those requests
|
|
83
|
+
2. A new directory named "Test App_<your_node_id>" with the following files
|
|
91
84
|
|
|
92
|
-
|
|
93
|
-
```python
|
|
94
|
-
import asyncio
|
|
95
|
-
import neuronum
|
|
96
|
-
import os
|
|
97
|
-
from dotenv import load_dotenv
|
|
98
|
-
|
|
99
|
-
load_dotenv()
|
|
100
|
-
host = os.getenv("HOST")
|
|
101
|
-
password = os.getenv("PASSWORD")
|
|
102
|
-
network = os.getenv("NETWORK")
|
|
103
|
-
synapse = os.getenv("SYNAPSE")
|
|
104
|
-
|
|
105
|
-
cell = neuronum.Cell(
|
|
106
|
-
host=host,
|
|
107
|
-
password=password,
|
|
108
|
-
network=network,
|
|
109
|
-
synapse=synapse
|
|
110
|
-
)
|
|
85
|
+
.env: Stores your Node's credentials for connecting to the network.
|
|
111
86
|
|
|
112
|
-
|
|
113
|
-
STX = "id::stx"
|
|
114
|
-
async for operation in cell.sync(STX):
|
|
115
|
-
txID = operation.get("txID")
|
|
116
|
-
client = operation.get("operator")
|
|
117
|
-
|
|
118
|
-
if txID == "id::tx":
|
|
119
|
-
data = {
|
|
120
|
-
"json": f"Hello {client}",
|
|
121
|
-
"html": f"""
|
|
122
|
-
<!DOCTYPE html>
|
|
123
|
-
<html>
|
|
124
|
-
<head>
|
|
125
|
-
<meta charset="UTF-8">
|
|
126
|
-
<title>Greeting Node</title>
|
|
127
|
-
</head>
|
|
128
|
-
<body>
|
|
129
|
-
<div class="card">
|
|
130
|
-
<h1>Hello, {client}</h1>
|
|
131
|
-
</div>
|
|
132
|
-
</body>
|
|
133
|
-
</html>
|
|
134
|
-
"""
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
await cell.tx_response(txID, client, data)
|
|
87
|
+
app.py: The main Python script that contains your Node's core logic.
|
|
138
88
|
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
config.json (required if you want to make your app accessible to Cellai (currently in testing))
|
|
143
|
-
```json
|
|
144
|
-
{
|
|
145
|
-
"data_gateways": [
|
|
146
|
-
{
|
|
147
|
-
"type": "stream",
|
|
148
|
-
"id": "id::stx",
|
|
149
|
-
"info": "provide a detailed description about the stream"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"type": "transmitter",
|
|
153
|
-
"id": "id::tx",
|
|
154
|
-
"info": "provide a detailed description about the transmitter"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"type": "circuit",
|
|
158
|
-
"id": "id::ctx",
|
|
159
|
-
"info": "provide a detailed description about the circuit"
|
|
160
|
-
}
|
|
161
|
-
]
|
|
162
|
-
}
|
|
163
|
-
```
|
|
89
|
+
NODE.md: Public documentation that provides instructions for interacting with your Node.
|
|
164
90
|
|
|
165
|
-
|
|
166
|
-
```
|
|
167
|
-
### NODE.md: Create a detailed Markdown File on how to interact with this Node
|
|
168
|
-
```
|
|
91
|
+
config.json: A configuration file that stores metadata about your app and enables Cellai to interact with your Node's data gateways.
|
|
169
92
|
|
|
93
|
+
ping.html: A static HTML file used to render web-based responses.
|
|
170
94
|
|
|
171
95
|
Change into Node folder
|
|
172
96
|
```sh
|
|
@@ -214,6 +138,6 @@ asyncio.run(main())
|
|
|
214
138
|
neuronum activate --tx id::tx 'say:hello'
|
|
215
139
|
```
|
|
216
140
|
|
|
217
|
-
#### **Cellai**
|
|
218
|
-
Cellai is
|
|
141
|
+
#### **Cellai (in Testing)**
|
|
142
|
+
Cellai is an AI tool for developers to test their apps built on Neuronum and will soon be published to the Google Play Store.
|
|
219
143
|
|
|
@@ -249,17 +249,14 @@ def delete_cell():
|
|
|
249
249
|
|
|
250
250
|
|
|
251
251
|
@click.command()
|
|
252
|
-
|
|
253
|
-
@click.option('--stream', multiple=True, default=None, help="Optional stream ID for stream.")
|
|
254
|
-
@click.option('--app', is_flag=True, help="Generate a Node with app template")
|
|
255
|
-
def init_node(sync, stream, app):
|
|
252
|
+
def init_node():
|
|
256
253
|
descr = click.prompt("Node description: Type up to 25 characters").strip()
|
|
257
254
|
if descr and len(descr) > 25:
|
|
258
255
|
click.echo("Description too long. Max 25 characters allowed.")
|
|
259
256
|
return
|
|
260
|
-
asyncio.run(async_init_node(
|
|
257
|
+
asyncio.run(async_init_node(descr))
|
|
261
258
|
|
|
262
|
-
async def async_init_node(
|
|
259
|
+
async def async_init_node(descr):
|
|
263
260
|
credentials_folder_path = Path.home() / ".neuronum"
|
|
264
261
|
env_path = credentials_folder_path / ".env"
|
|
265
262
|
|
|
@@ -308,51 +305,37 @@ async def async_init_node(sync, stream, app, descr):
|
|
|
308
305
|
click.echo(f"Error sending request: {e}")
|
|
309
306
|
return
|
|
310
307
|
|
|
311
|
-
node_filename = "
|
|
308
|
+
node_filename = descr + "_" + nodeID.replace("::node", "")
|
|
312
309
|
project_path = Path(node_filename)
|
|
313
310
|
project_path.mkdir(exist_ok=True)
|
|
314
311
|
|
|
315
312
|
env_path = project_path / ".env"
|
|
316
313
|
await asyncio.to_thread(env_path.write_text, f"NODE={nodeID}\nHOST={host}\nPASSWORD={password}\nNETWORK={network}\nSYNAPSE={synapse}\n")
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
config_path = project_path / "config.json"
|
|
320
|
-
await asyncio.to_thread(config_path.write_text, """{
|
|
321
|
-
"data_gateways": [
|
|
322
|
-
{
|
|
323
|
-
"type": "stream",
|
|
324
|
-
"id": "id::stx",
|
|
325
|
-
"info": "provide a detailed description about the stream"
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
"type": "transmitter",
|
|
329
|
-
"id": "id::tx",
|
|
330
|
-
"info": "provide a detailed description about the transmitter"
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
"type": "circuit",
|
|
334
|
-
"id": "id::ctx",
|
|
335
|
-
"info": "provide a detailed description about the circuit"
|
|
336
|
-
}
|
|
337
|
-
]
|
|
338
|
-
}
|
|
339
|
-
"""
|
|
340
|
-
)
|
|
341
314
|
|
|
342
|
-
|
|
343
|
-
|
|
315
|
+
stx_descr = f"{nodeID} App"
|
|
316
|
+
partners = ["private"]
|
|
317
|
+
stxID = await cell.create_stx(stx_descr, partners)
|
|
344
318
|
|
|
345
|
-
|
|
319
|
+
tx_descr = f"Greet {nodeID}"
|
|
320
|
+
key_values = {
|
|
321
|
+
"ping": "pong",
|
|
322
|
+
}
|
|
323
|
+
STX = stxID
|
|
324
|
+
label = "ping:pong"
|
|
325
|
+
partners = ["private"]
|
|
326
|
+
txID = await cell.create_tx(tx_descr, key_values, STX, label, partners)
|
|
346
327
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
sync_path = project_path / f"sync_{stx.replace('::stx', '')}.py"
|
|
350
|
-
sync_path.write_text(f"""\
|
|
328
|
+
app_path = project_path / "app.py"
|
|
329
|
+
app_path.write_text(f"""\
|
|
351
330
|
import asyncio
|
|
352
331
|
import neuronum
|
|
353
332
|
import os
|
|
354
333
|
from dotenv import load_dotenv
|
|
334
|
+
from jinja2 import Environment, FileSystemLoader
|
|
355
335
|
|
|
336
|
+
env = Environment(loader=FileSystemLoader('.'))
|
|
337
|
+
template = env.get_template('ping.html')
|
|
338
|
+
|
|
356
339
|
load_dotenv()
|
|
357
340
|
host = os.getenv("HOST")
|
|
358
341
|
password = os.getenv("PASSWORD")
|
|
@@ -366,188 +349,293 @@ cell = neuronum.Cell(
|
|
|
366
349
|
synapse=synapse
|
|
367
350
|
)
|
|
368
351
|
|
|
369
|
-
async def main():
|
|
370
|
-
STX = "{
|
|
371
|
-
async for operation in cell.sync(STX):
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
ts = operation.get("time")
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
352
|
+
async def main():
|
|
353
|
+
STX = "{stxID}"
|
|
354
|
+
async for operation in cell.sync(STX):
|
|
355
|
+
txID = operation.get("txID")
|
|
356
|
+
client = operation.get("operator")
|
|
357
|
+
ts = operation.get("time")
|
|
358
|
+
data = operation.get("data")
|
|
359
|
+
operation_id = operation.get("operationID")
|
|
360
|
+
|
|
361
|
+
if txID == "{txID}":
|
|
362
|
+
|
|
363
|
+
def render_html_template(client, ts, data, operation_id):
|
|
364
|
+
return template.render(client=client, ts=ts, data=data, operation_id=operation_id)
|
|
381
365
|
|
|
366
|
+
html_content = render_html_template(client, ts, data, operation_id)
|
|
382
367
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
import asyncio
|
|
388
|
-
import neuronum
|
|
389
|
-
import os
|
|
390
|
-
from dotenv import load_dotenv
|
|
391
|
-
import time
|
|
368
|
+
data = {{
|
|
369
|
+
"json": f"{{operation_id}} - Reply from {nodeID}: Pinged by {{client}} at {{ts}} with data: {{data}}",
|
|
370
|
+
"html": html_content
|
|
371
|
+
}}
|
|
392
372
|
|
|
393
|
-
|
|
394
|
-
host = os.getenv("HOST")
|
|
395
|
-
password = os.getenv("PASSWORD")
|
|
396
|
-
network = os.getenv("NETWORK")
|
|
397
|
-
synapse = os.getenv("SYNAPSE")
|
|
373
|
+
await cell.notify(f"{{client}}", "{nodeID} Ping","Pinged successfully")
|
|
398
374
|
|
|
399
|
-
cell
|
|
400
|
-
host=host,
|
|
401
|
-
password=password,
|
|
402
|
-
network=network,
|
|
403
|
-
synapse=synapse
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
async def main():
|
|
407
|
-
STX = "{stx}"
|
|
408
|
-
label = "your_label"
|
|
409
|
-
|
|
410
|
-
while True:
|
|
411
|
-
data = {{
|
|
412
|
-
"key1": "value1",
|
|
413
|
-
"key2": "value2",
|
|
414
|
-
"key3": "value3",
|
|
415
|
-
}}
|
|
416
|
-
await cell.stream(label, data, STX)
|
|
417
|
-
time.sleep(5)
|
|
375
|
+
await cell.tx_response(txID, client, data)
|
|
418
376
|
|
|
419
377
|
asyncio.run(main())
|
|
420
378
|
""")
|
|
421
379
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
380
|
+
html_path = project_path / "ping.html"
|
|
381
|
+
html_content = f"""\
|
|
382
|
+
<!DOCTYPE html>
|
|
383
|
+
<html>
|
|
384
|
+
<head>
|
|
385
|
+
<style>
|
|
386
|
+
body {{
|
|
387
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
388
|
+
background-color: #121212;
|
|
389
|
+
color: #e0e0e0;
|
|
390
|
+
margin: 0;
|
|
391
|
+
padding: 0;
|
|
392
|
+
display: flex;
|
|
393
|
+
justify-content: center;
|
|
394
|
+
align-items: center;
|
|
395
|
+
min-height: 100vh;
|
|
396
|
+
}}
|
|
397
|
+
|
|
398
|
+
.container {{
|
|
399
|
+
background-color: #1e1e1e;
|
|
400
|
+
border-radius: 12px;
|
|
401
|
+
padding: 40px;
|
|
402
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
|
403
|
+
width: 100%;
|
|
404
|
+
max-width: 500px;
|
|
405
|
+
text-align: center;
|
|
406
|
+
box-sizing: border-box;
|
|
407
|
+
}}
|
|
408
|
+
|
|
409
|
+
.logo {{
|
|
410
|
+
width: 80px;
|
|
411
|
+
margin-bottom: 25px;
|
|
412
|
+
filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.1));
|
|
413
|
+
}}
|
|
414
|
+
|
|
415
|
+
h1 {{
|
|
416
|
+
font-size: 1.5em;
|
|
417
|
+
font-weight: 600;
|
|
418
|
+
margin-bottom: 5px;
|
|
419
|
+
color: #f5f5f5;
|
|
420
|
+
}}
|
|
421
|
+
|
|
422
|
+
.subtitle {{
|
|
423
|
+
font-size: 0.9em;
|
|
424
|
+
color: #a0a0a0;
|
|
425
|
+
margin-bottom: 30px;
|
|
426
|
+
}}
|
|
427
|
+
|
|
428
|
+
.data-row {{
|
|
429
|
+
background-color: #2a2a2a;
|
|
430
|
+
padding: 12px 15px;
|
|
431
|
+
border-radius: 8px;
|
|
432
|
+
margin-bottom: 10px;
|
|
433
|
+
display: flex;
|
|
434
|
+
justify-content: space-between;
|
|
435
|
+
align-items: center;
|
|
436
|
+
}}
|
|
437
|
+
|
|
438
|
+
.data-label {{
|
|
439
|
+
font-weight: 400;
|
|
440
|
+
color: #a0a0a0;
|
|
441
|
+
margin: 0;
|
|
442
|
+
}}
|
|
443
|
+
|
|
444
|
+
.data-value {{
|
|
445
|
+
font-weight: 500;
|
|
446
|
+
color: #e0e0e0;
|
|
447
|
+
margin: 0;
|
|
448
|
+
}}
|
|
449
|
+
|
|
450
|
+
.data-value.truncated {{
|
|
451
|
+
white-space: nowrap;
|
|
452
|
+
overflow: hidden;
|
|
453
|
+
text-overflow: ellipsis;
|
|
454
|
+
max-width: 60%;
|
|
455
|
+
}}
|
|
456
|
+
|
|
457
|
+
.data-value.client {{
|
|
458
|
+
color: #8cafff;
|
|
459
|
+
}}
|
|
460
|
+
.data-value.timestamp {{
|
|
461
|
+
color: #a1e8a1;
|
|
462
|
+
}}
|
|
463
|
+
.data-value.operation-id {{
|
|
464
|
+
color: #f7a2a2;
|
|
465
|
+
}}
|
|
466
|
+
.api-button {{
|
|
467
|
+
background: #01c07d 100%;
|
|
468
|
+
color: white;
|
|
469
|
+
border: none;
|
|
470
|
+
border-radius: 8px;
|
|
471
|
+
padding: 12px 24px;
|
|
472
|
+
font-size: 16px;
|
|
473
|
+
font-weight: bold;
|
|
474
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
475
|
+
cursor: pointer;
|
|
476
|
+
margin-top: 10px;
|
|
477
|
+
}}
|
|
478
|
+
</style>
|
|
479
|
+
</head>
|
|
480
|
+
<body>
|
|
481
|
+
<div class="container">
|
|
482
|
+
<img class="logo" src="https://neuronum.net/static/logo.png" alt="Neuronum Logo">
|
|
483
|
+
|
|
484
|
+
<h1>Reply from {nodeID}</h1>
|
|
485
|
+
<p class="subtitle">Pinged successfully.</p>
|
|
486
|
+
|
|
487
|
+
<div class="data-row">
|
|
488
|
+
<p class="data-label">Client</p>
|
|
489
|
+
<p class="data-value client">{{{{client}}}}</p>
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
<div class="data-row">
|
|
493
|
+
<p class="data-label">Timestamp</p>
|
|
494
|
+
<p class="data-value timestamp">{{{{ts}}}}</p>
|
|
495
|
+
</div>
|
|
496
|
+
|
|
497
|
+
<div class="data-row">
|
|
498
|
+
<p class="data-label">Data</p>
|
|
499
|
+
<p class="data-value">{{{{data}}}}</p>
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
<div class="data-row">
|
|
503
|
+
<p class="data-label">Operation ID</p>
|
|
504
|
+
<p class="data-value operation-id truncated">{{{{operation_id}}}}</p>
|
|
505
|
+
</div>
|
|
506
|
+
|
|
507
|
+
<button id="send-request-btn" class="api-button">Ping again</button>
|
|
508
|
+
</div>
|
|
429
509
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
network = os.getenv("NETWORK")
|
|
434
|
-
synapse = os.getenv("SYNAPSE")
|
|
510
|
+
<script>
|
|
511
|
+
document.getElementById('send-request-btn').addEventListener('click', () => {{
|
|
512
|
+
const apiEndpoint = 'https://neuronum.net/api/activate/{txID}';
|
|
435
513
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
514
|
+
const dataToSend = {{
|
|
515
|
+
"data": {{"ping": "node"}},
|
|
516
|
+
"cell": {{
|
|
517
|
+
"host": CLIENT_CELL,
|
|
518
|
+
"session": CLIENT_SESSION,
|
|
519
|
+
}}
|
|
520
|
+
}};
|
|
521
|
+
|
|
522
|
+
fetch(apiEndpoint, {{
|
|
523
|
+
method: 'POST',
|
|
524
|
+
headers: {{
|
|
525
|
+
'Content-Type': 'application/json',
|
|
526
|
+
'Accept': 'application/json'
|
|
527
|
+
}},
|
|
528
|
+
body: JSON.stringify(dataToSend)
|
|
529
|
+
}})
|
|
530
|
+
.then(response => {{
|
|
531
|
+
if (!response.ok) {{
|
|
532
|
+
throw new Error(`HTTP error! status: ${{response.status}}`);
|
|
533
|
+
}}
|
|
534
|
+
return response.json();
|
|
535
|
+
}})
|
|
536
|
+
.then(data => {{
|
|
537
|
+
if (data.success && data.response && data.response.html) {{
|
|
538
|
+
document.open();
|
|
539
|
+
document.write(data.response.html);
|
|
540
|
+
document.close();
|
|
541
|
+
console.log('API Response: Page replaced with new HTML.');
|
|
542
|
+
}} else {{
|
|
543
|
+
console.error('API Response does not contain HTML to replace the page:', data);
|
|
544
|
+
alert('API response error: Expected HTML content to replace the page.');
|
|
545
|
+
}}
|
|
546
|
+
}})
|
|
547
|
+
.catch(error => {{
|
|
548
|
+
console.error('API request failed:', error);
|
|
549
|
+
alert('API request failed. See the console for details.');
|
|
550
|
+
}});
|
|
551
|
+
}});
|
|
552
|
+
</script>
|
|
553
|
+
</body>
|
|
554
|
+
</html>
|
|
555
|
+
"""
|
|
556
|
+
html_path.write_text(html_content)
|
|
557
|
+
|
|
558
|
+
config_path = project_path / "config.json"
|
|
559
|
+
await asyncio.to_thread(
|
|
560
|
+
config_path.write_text,
|
|
561
|
+
f"""{{
|
|
562
|
+
"app_metadata": {{
|
|
563
|
+
"name": "{descr}",
|
|
564
|
+
"version": "1.0.0",
|
|
565
|
+
"author": "{host}"
|
|
566
|
+
}},
|
|
567
|
+
"data_gateways": [
|
|
568
|
+
{{
|
|
569
|
+
"type": "transmitter",
|
|
570
|
+
"id": "{txID}",
|
|
571
|
+
"info": "Ping Your Node"
|
|
572
|
+
}}
|
|
573
|
+
],
|
|
574
|
+
"legals": {{
|
|
575
|
+
"terms_and_conditions": "https://neuronum.net/legals",
|
|
576
|
+
"data_privacy": "https://neuronum.net/legals"
|
|
577
|
+
}}
|
|
578
|
+
}}"""
|
|
441
579
|
)
|
|
442
580
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
message = operation.get("data").get("message")
|
|
446
|
-
print(message)
|
|
581
|
+
nodemd_path = project_path / "NODE.md"
|
|
582
|
+
await asyncio.to_thread(nodemd_path.write_text, f"""### NODE.md of {nodeID}
|
|
447
583
|
|
|
448
|
-
|
|
449
|
-
""")
|
|
450
|
-
|
|
451
|
-
stream_path = project_path / f"stream_{stx.replace('::stx', '')}.py"
|
|
452
|
-
stream_path.write_text(f"""\
|
|
453
|
-
import asyncio
|
|
454
|
-
import neuronum
|
|
455
|
-
import os
|
|
456
|
-
from dotenv import load_dotenv
|
|
457
|
-
import time
|
|
584
|
+
Welcome to your Node's documentation! This guide provides several ways for users to interact with your application.
|
|
458
585
|
|
|
459
|
-
|
|
460
|
-
host = os.getenv("HOST")
|
|
461
|
-
password = os.getenv("PASSWORD")
|
|
462
|
-
network = os.getenv("NETWORK")
|
|
463
|
-
synapse = os.getenv("SYNAPSE")
|
|
586
|
+
***
|
|
464
587
|
|
|
465
|
-
|
|
466
|
-
host=host,
|
|
467
|
-
password=password,
|
|
468
|
-
network=network,
|
|
469
|
-
synapse=synapse
|
|
470
|
-
)
|
|
588
|
+
### 💻 Using the CLI
|
|
471
589
|
|
|
472
|
-
|
|
473
|
-
label = "Welcome to Neuronum"
|
|
474
|
-
|
|
475
|
-
while True:
|
|
476
|
-
data = {{
|
|
477
|
-
"message": "Hello, Neuronum!"
|
|
478
|
-
}}
|
|
479
|
-
await cell.stream(label, data)
|
|
480
|
-
time.sleep(5)
|
|
590
|
+
To ping this Node via the command-line interface, use the following command:
|
|
481
591
|
|
|
482
|
-
|
|
483
|
-
""")
|
|
484
|
-
|
|
485
|
-
if app and nodeID:
|
|
592
|
+
`neuronum activate --tx {txID} 'ping:node'`
|
|
486
593
|
|
|
487
|
-
|
|
488
|
-
partners = ["private"]
|
|
489
|
-
stxID = await cell.create_stx(descr, partners)
|
|
594
|
+
***
|
|
490
595
|
|
|
596
|
+
### 🌐 Via the Web
|
|
491
597
|
|
|
492
|
-
|
|
493
|
-
key_values = {
|
|
494
|
-
"say": "hello",
|
|
495
|
-
}
|
|
496
|
-
STX = stxID
|
|
497
|
-
label = "say:hello"
|
|
498
|
-
partners = ["private"]
|
|
499
|
-
txID = await cell.create_tx(descr, key_values, STX, label, partners)
|
|
598
|
+
You can also interact with this Node by simply visiting this URL in your web browser:
|
|
500
599
|
|
|
600
|
+
[https://neuronum.net/tx/{txID}](https://neuronum.net/tx/{txID})
|
|
501
601
|
|
|
502
|
-
|
|
503
|
-
|
|
602
|
+
***
|
|
603
|
+
|
|
604
|
+
### 🐍 With Python
|
|
605
|
+
|
|
606
|
+
For programmatic access, use the following Python code snippet. This script utilizes the `neuronum` library to activate the transaction and receive a response.
|
|
607
|
+
|
|
608
|
+
```python
|
|
504
609
|
import asyncio
|
|
505
610
|
import neuronum
|
|
506
|
-
import os
|
|
507
|
-
from dotenv import load_dotenv
|
|
508
|
-
|
|
509
|
-
load_dotenv()
|
|
510
|
-
host = os.getenv("HOST")
|
|
511
|
-
password = os.getenv("PASSWORD")
|
|
512
|
-
network = os.getenv("NETWORK")
|
|
513
|
-
synapse = os.getenv("SYNAPSE")
|
|
514
611
|
|
|
612
|
+
# Set up Cell connection parameters
|
|
515
613
|
cell = neuronum.Cell(
|
|
516
|
-
host=host,
|
|
517
|
-
password=password,
|
|
518
|
-
network=network
|
|
519
|
-
synapse=synapse
|
|
614
|
+
host="host", # Cell host
|
|
615
|
+
password="password", # Cell password
|
|
616
|
+
network="neuronum.net", # Cell network
|
|
617
|
+
synapse="synapse" # Cell synapse
|
|
520
618
|
)
|
|
521
619
|
|
|
522
|
-
async def main():
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
</head>
|
|
538
|
-
<body>
|
|
539
|
-
<div class="card">
|
|
540
|
-
<h1>Hello, {{client}}</h1>
|
|
541
|
-
<p>Greetings from <span class="node">{nodeID}</span></p>
|
|
542
|
-
</div>
|
|
543
|
-
</body>
|
|
544
|
-
</html>
|
|
545
|
-
\"\"\"
|
|
546
|
-
|
|
547
|
-
}}
|
|
548
|
-
await cell.tx_response(txID, client, data)
|
|
620
|
+
async def main():
|
|
621
|
+
# Define the transaction ID and data payload
|
|
622
|
+
TX = "{txID}"
|
|
623
|
+
data = {{"ping": "node"}}
|
|
624
|
+
|
|
625
|
+
# Activate the transaction and get the response
|
|
626
|
+
tx_response = await cell.activate_tx(TX, data)
|
|
627
|
+
|
|
628
|
+
# Print the response from the Node
|
|
629
|
+
print(tx_response)
|
|
630
|
+
|
|
631
|
+
# Run the main asynchronous function
|
|
632
|
+
if __name__ == "__main__":
|
|
633
|
+
asyncio.run(main())
|
|
634
|
+
```
|
|
549
635
|
|
|
550
|
-
|
|
636
|
+
🤖 Via Cellai (Android App - Currently in Testing)
|
|
637
|
+
Download the app from the Google Play Store.
|
|
638
|
+
Send the command "Ping Node" to Cellai
|
|
551
639
|
""")
|
|
552
640
|
|
|
553
641
|
click.echo(f"Neuronum Node '{nodeID}' initialized!")
|
|
@@ -556,6 +644,7 @@ asyncio.run(main())
|
|
|
556
644
|
@click.command()
|
|
557
645
|
@click.option('--d', is_flag=True, help="Start node in detached mode")
|
|
558
646
|
def start_node(d):
|
|
647
|
+
update_node()
|
|
559
648
|
pid_file = Path.cwd() / "status.txt"
|
|
560
649
|
system_name = platform.system()
|
|
561
650
|
active_pids = []
|
|
@@ -586,27 +675,24 @@ def start_node(d):
|
|
|
586
675
|
click.echo("Starting Node...")
|
|
587
676
|
|
|
588
677
|
project_path = Path.cwd()
|
|
589
|
-
script_files = glob.glob("
|
|
678
|
+
script_files = glob.glob("stream.py") + glob.glob("app.py")
|
|
590
679
|
processes = []
|
|
591
680
|
|
|
592
681
|
for script in script_files:
|
|
593
682
|
script_path = project_path / script
|
|
594
683
|
if script_path.exists():
|
|
595
|
-
python_cmd = "pythonw" if system_name == "Windows" else "python"
|
|
596
684
|
|
|
597
685
|
if d:
|
|
598
686
|
process = subprocess.Popen(
|
|
599
|
-
["nohup",
|
|
600
|
-
else [
|
|
687
|
+
["nohup", sys.executable, str(script_path), "&"] if system_name != "Windows"
|
|
688
|
+
else ["pythonw", str(script_path)],
|
|
601
689
|
stdout=subprocess.DEVNULL,
|
|
602
690
|
stderr=subprocess.DEVNULL,
|
|
603
691
|
start_new_session=True
|
|
604
692
|
)
|
|
605
693
|
else:
|
|
606
694
|
process = subprocess.Popen(
|
|
607
|
-
[sys.executable, str(script_path)]
|
|
608
|
-
stdout=None,
|
|
609
|
-
stderr=None
|
|
695
|
+
[sys.executable, str(script_path)]
|
|
610
696
|
)
|
|
611
697
|
|
|
612
698
|
processes.append(process.pid)
|
|
@@ -678,11 +764,6 @@ def check_node():
|
|
|
678
764
|
continue
|
|
679
765
|
|
|
680
766
|
if running_pids:
|
|
681
|
-
for pid in running_pids:
|
|
682
|
-
proc = psutil.Process(pid)
|
|
683
|
-
mem = proc.memory_info().rss / (1024 * 1024) # in MB
|
|
684
|
-
cpu = proc.cpu_percent(interval=0.1)
|
|
685
|
-
click.echo(f"PID {pid} → Memory: {mem:.2f} MB | CPU: {cpu:.1f}%")
|
|
686
767
|
click.echo(f"Node {nodeID} is running. Active PIDs: {', '.join(map(str, running_pids))}")
|
|
687
768
|
else:
|
|
688
769
|
click.echo(f"Node {nodeID} is not running.")
|
|
@@ -691,6 +772,7 @@ def check_node():
|
|
|
691
772
|
@click.command()
|
|
692
773
|
@click.option('--d', is_flag=True, help="Restart node in detached mode")
|
|
693
774
|
def restart_node(d):
|
|
775
|
+
update_node()
|
|
694
776
|
pid_file = Path.cwd() / "status.txt"
|
|
695
777
|
system_name = platform.system()
|
|
696
778
|
|
|
@@ -740,27 +822,23 @@ def restart_node(d):
|
|
|
740
822
|
|
|
741
823
|
click.echo(f"Starting Node {nodeID}...")
|
|
742
824
|
project_path = Path.cwd()
|
|
743
|
-
script_files = glob.glob("
|
|
825
|
+
script_files = glob.glob("stream.py") + glob.glob("app.py")
|
|
744
826
|
processes = []
|
|
745
827
|
|
|
746
|
-
python_cmd = "pythonw" if system_name == "Windows" else "python"
|
|
747
|
-
|
|
748
828
|
for script in script_files:
|
|
749
829
|
script_path = project_path / script
|
|
750
830
|
if script_path.exists():
|
|
751
831
|
if d:
|
|
752
832
|
process = subprocess.Popen(
|
|
753
|
-
["nohup",
|
|
754
|
-
else [
|
|
833
|
+
["nohup", sys.executable, str(script_path), "&"] if system_name != "Windows"
|
|
834
|
+
else ["pythonw", str(script_path)],
|
|
755
835
|
stdout=subprocess.DEVNULL,
|
|
756
836
|
stderr=subprocess.DEVNULL,
|
|
757
837
|
start_new_session=True
|
|
758
838
|
)
|
|
759
839
|
else:
|
|
760
840
|
process = subprocess.Popen(
|
|
761
|
-
[sys.executable, str(script_path)]
|
|
762
|
-
stdout=None,
|
|
763
|
-
stderr=None
|
|
841
|
+
[sys.executable, str(script_path)]
|
|
764
842
|
)
|
|
765
843
|
|
|
766
844
|
processes.append(process.pid)
|
|
@@ -825,7 +903,6 @@ async def async_stop_node():
|
|
|
825
903
|
click.echo("Error: Unable to stop some node processes.")
|
|
826
904
|
|
|
827
905
|
|
|
828
|
-
@click.command()
|
|
829
906
|
def update_node():
|
|
830
907
|
click.echo("Update your Node")
|
|
831
908
|
env_data = {}
|
|
@@ -1126,7 +1203,6 @@ cli.add_command(start_node)
|
|
|
1126
1203
|
cli.add_command(restart_node)
|
|
1127
1204
|
cli.add_command(stop_node)
|
|
1128
1205
|
cli.add_command(check_node)
|
|
1129
|
-
cli.add_command(update_node)
|
|
1130
1206
|
cli.add_command(delete_node)
|
|
1131
1207
|
cli.add_command(activate)
|
|
1132
1208
|
cli.add_command(load)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.1
|
|
4
4
|
Summary: Official client library to interact with the Neuronum Network
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -19,6 +19,7 @@ Requires-Dist: questionary
|
|
|
19
19
|
Requires-Dist: python-dotenv
|
|
20
20
|
Requires-Dist: requests
|
|
21
21
|
Requires-Dist: psutil
|
|
22
|
+
Requires-Dist: jinja2
|
|
22
23
|
Dynamic: author
|
|
23
24
|
Dynamic: author-email
|
|
24
25
|
Dynamic: classifier
|
|
@@ -78,7 +79,6 @@ Neuronum is the real-time data engine designed for developers to build event-dri
|
|
|
78
79
|
|
|
79
80
|
### Requirements
|
|
80
81
|
- Python >= 3.8
|
|
81
|
-
- neuronum >= 5.5.0
|
|
82
82
|
|
|
83
83
|
------------------
|
|
84
84
|
|
|
@@ -104,102 +104,27 @@ neuronum connect-cell # connect Cell
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
### **Build On Neuronum**
|
|
107
|
-
|
|
107
|
+
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
To get started, initialize a new Node with the command below.
|
|
110
110
|
```sh
|
|
111
|
-
neuronum init-node
|
|
111
|
+
neuronum init-node
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
This command
|
|
114
|
+
This command will prompt you for a description (e.g., Test App) and will create
|
|
115
115
|
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
NODE=your_node_id
|
|
119
|
-
HOST=your_cell_id
|
|
120
|
-
PASSWORD=your_password
|
|
121
|
-
NETWORK=neuronum.net
|
|
122
|
-
SYNAPSE=your_synapse # auth token
|
|
123
|
-
```
|
|
116
|
+
1. A Stream (STX) so your App can receive requests, and a Transmitter (TX) to match those requests
|
|
117
|
+
2. A new directory named "Test App_<your_node_id>" with the following files
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
```python
|
|
127
|
-
import asyncio
|
|
128
|
-
import neuronum
|
|
129
|
-
import os
|
|
130
|
-
from dotenv import load_dotenv
|
|
131
|
-
|
|
132
|
-
load_dotenv()
|
|
133
|
-
host = os.getenv("HOST")
|
|
134
|
-
password = os.getenv("PASSWORD")
|
|
135
|
-
network = os.getenv("NETWORK")
|
|
136
|
-
synapse = os.getenv("SYNAPSE")
|
|
137
|
-
|
|
138
|
-
cell = neuronum.Cell(
|
|
139
|
-
host=host,
|
|
140
|
-
password=password,
|
|
141
|
-
network=network,
|
|
142
|
-
synapse=synapse
|
|
143
|
-
)
|
|
119
|
+
.env: Stores your Node's credentials for connecting to the network.
|
|
144
120
|
|
|
145
|
-
|
|
146
|
-
STX = "id::stx"
|
|
147
|
-
async for operation in cell.sync(STX):
|
|
148
|
-
txID = operation.get("txID")
|
|
149
|
-
client = operation.get("operator")
|
|
150
|
-
|
|
151
|
-
if txID == "id::tx":
|
|
152
|
-
data = {
|
|
153
|
-
"json": f"Hello {client}",
|
|
154
|
-
"html": f"""
|
|
155
|
-
<!DOCTYPE html>
|
|
156
|
-
<html>
|
|
157
|
-
<head>
|
|
158
|
-
<meta charset="UTF-8">
|
|
159
|
-
<title>Greeting Node</title>
|
|
160
|
-
</head>
|
|
161
|
-
<body>
|
|
162
|
-
<div class="card">
|
|
163
|
-
<h1>Hello, {client}</h1>
|
|
164
|
-
</div>
|
|
165
|
-
</body>
|
|
166
|
-
</html>
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
await cell.tx_response(txID, client, data)
|
|
121
|
+
app.py: The main Python script that contains your Node's core logic.
|
|
171
122
|
|
|
172
|
-
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
config.json (required if you want to make your app accessible to Cellai (currently in testing))
|
|
176
|
-
```json
|
|
177
|
-
{
|
|
178
|
-
"data_gateways": [
|
|
179
|
-
{
|
|
180
|
-
"type": "stream",
|
|
181
|
-
"id": "id::stx",
|
|
182
|
-
"info": "provide a detailed description about the stream"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"type": "transmitter",
|
|
186
|
-
"id": "id::tx",
|
|
187
|
-
"info": "provide a detailed description about the transmitter"
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"type": "circuit",
|
|
191
|
-
"id": "id::ctx",
|
|
192
|
-
"info": "provide a detailed description about the circuit"
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
}
|
|
196
|
-
```
|
|
123
|
+
NODE.md: Public documentation that provides instructions for interacting with your Node.
|
|
197
124
|
|
|
198
|
-
|
|
199
|
-
```
|
|
200
|
-
### NODE.md: Create a detailed Markdown File on how to interact with this Node
|
|
201
|
-
```
|
|
125
|
+
config.json: A configuration file that stores metadata about your app and enables Cellai to interact with your Node's data gateways.
|
|
202
126
|
|
|
127
|
+
ping.html: A static HTML file used to render web-based responses.
|
|
203
128
|
|
|
204
129
|
Change into Node folder
|
|
205
130
|
```sh
|
|
@@ -247,6 +172,6 @@ asyncio.run(main())
|
|
|
247
172
|
neuronum activate --tx id::tx 'say:hello'
|
|
248
173
|
```
|
|
249
174
|
|
|
250
|
-
#### **Cellai**
|
|
251
|
-
Cellai is
|
|
175
|
+
#### **Cellai (in Testing)**
|
|
176
|
+
Cellai is an AI tool for developers to test their apps built on Neuronum and will soon be published to the Google Play Store.
|
|
252
177
|
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='neuronum',
|
|
5
|
-
version='
|
|
5
|
+
version='7.0.1',
|
|
6
6
|
author='Neuronum Cybernetics',
|
|
7
7
|
author_email='welcome@neuronum.net',
|
|
8
8
|
description='Official client library to interact with the Neuronum Network',
|
|
@@ -27,6 +27,7 @@ setup(
|
|
|
27
27
|
'python-dotenv',
|
|
28
28
|
'requests',
|
|
29
29
|
'psutil',
|
|
30
|
+
'jinja2',
|
|
30
31
|
],
|
|
31
32
|
entry_points={
|
|
32
33
|
"console_scripts": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|