holosphere 1.0.0 → 1.0.2

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 (2) hide show
  1. package/index.js +72 -169
  2. package/package.json +1 -2
package/index.js CHANGED
@@ -1,145 +1,58 @@
1
- import 'dotenv/config'
2
- import h3 from 'h3-js';
1
+ import * as h3 from 'h3-js';
3
2
  import OpenAI from 'openai';
4
3
  import Gun from 'gun'
5
4
  import Ajv2019 from 'ajv/dist/2019.js'
6
5
  import { createHash } from "crypto";
7
6
 
8
7
  class HoloSphere {
9
- constructor(appname) {
8
+ constructor(appname, openaikey = null) {
9
+ this.appname = appname;
10
10
  this.validator = new Ajv2019({ allErrors: false, strict: false });
11
11
  this.gun = Gun({
12
12
  peers: ['https://59.src.eco/gun'],
13
- axe: false,
14
- // uuid: (content) => { // generate a unique id for each node
15
- // console.log('uuid', content);
16
- // return content;}
13
+ axe: false
17
14
  });
18
15
 
19
- this.gun = gun.get(appname)
20
- this.openai = new OpenAI({
21
- apiKey: process.env.OPENAI,
22
- });
23
-
24
- //this.bot.command('sethex', async (ctx) => { this.setHex(ctx) }) TODO: MOVE HERE FROM SETTINGS
25
-
26
- this.bot.command('resethex', async (ctx) => {
27
- let chatID = ctx.message.chat.id;
28
- let hex = (await this.db.get('settings', chatID)).hex
29
- this.delete(hex, ctx.message.text.split(' ')[1])
30
- })
31
-
32
- this.bot.command('get', async (ctx) => {
33
- const chatID = ctx.message.chat.id;
34
- const lense = ctx.message.text.split(' ')[1];
35
- if (!lense) {
36
- return ctx.reply('Please specify a tag.');
37
- }
38
- let hex = (await this.db.get('settings', chatID)).hex
39
- //let hex = settings.hex
40
- console.log('hex', hex)
41
-
42
- let data = await this.get(ctx, hex, lense)
43
-
44
- })
45
-
46
- this.bot.command('gethex', async (ctx) => {
47
- let settings = await this.db.get('settings', chatID)
48
- let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
49
- ctx.reply(id)
50
- })
51
-
52
- this.bot.command('compute', async (ctx) => {
53
- const chatID = ctx.message.chat.id;
54
- let operation = ctx.message.text.split(' ')[1];
55
- if (operation != 'sum') {
56
- ctx.reply('Operation not implemented')
57
- return
58
- }
59
- let lense = ctx.message.text.split(' ')[2]
60
- if (!lense) {
61
- ctx.reply('Please specify a lense where to perform the operation ')
62
- return
63
- }
64
- let hex = (await this.db.get('settings', chatID)).hex
65
- await this.compute(hex, lense, operation)
66
-
67
- // let parentInfo = await this.getCellInfo(parent)
68
- // parentInfo.wisdom[id] = report
69
- // //update summary
70
- // let summary = await this.summarize(Object.values(parentInfo.wisdom).join('\n'))
71
- // parentInfo.summary = summary
72
-
73
- // await this.db.put('cell', parentInfo)
74
- // return parentInfo
75
-
76
- // let content = await this.db.getAll(hex+'/tags')
77
- })
78
-
79
-
80
-
81
-
82
- this.bot.command('cast', async (ctx) => {
83
- if (!ctx.message.reply_to_message) {
84
- return ctx.reply('Please reply to a message you want to tag.');
85
- }
86
- const tags = ctx.message.text.split(' ').slice(1);
87
- if (tags.length === 0) {
88
- return ctx.reply('Please provide at least one tag.');
89
- }
90
-
91
- const messageID = ctx.message.reply_to_message.message_id;
92
- const chatID = ctx.message.chat.id;
93
- const messageContent = ctx.message.reply_to_message.text;
94
- let settings = await this.db.get('settings', chatID)
95
- let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
96
- //create root node for the item
97
- let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
98
- for (let tag of tags) {
99
- await this.gun.get(id).get(tag).set(node)
100
- this.upcast(id, tag, node)
101
- }
102
- })
103
-
104
- this.bot.command('publish', async (ctx) => {
105
- console.log(ctx.message)
106
- if (!ctx.message.reply_to_message) {
107
- return ctx.reply('Please reply to a message you want to tag.');
108
- }
109
- const tags = ctx.message.text.split(' ').slice(1);
110
- if (tags.length === 0) {
111
- return ctx.reply('Please provide at least one tag.');
112
- }
113
-
114
- const messageID = ctx.message.reply_to_message.message_id;
115
- const chatID = ctx.message.chat.id;
116
- const messageContent = ctx.message.reply_to_message.text;
117
- let settings = await this.db.get('settings', chatID)
118
- let hex = settings.hex
119
-
120
- for (let tag of tags) {
121
- let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
122
- await this.put(hex, tag, node)
123
- }
124
-
125
- ctx.reply('Tag published.');
126
- });
16
+ if (openaikey != null) {
17
+ this.openai = new OpenAI({
18
+ apiKey: openaikey,
19
+ });
20
+ }
127
21
 
128
22
  }
129
23
 
130
24
  async setSchema(lense, schema) {
131
25
  return new Promise((resolve, reject) => {
132
- this.db.gun.get(lense).get('schema').put(JSON.stringify(schema), ack => {
26
+ this.gun.get(this.appname).get(lense).get('schema').put(JSON.stringify(schema), ack => {
133
27
  if (ack.err) {
134
28
  resolve(new Error('Failed to add schema: ' + ack.err));
135
29
  } else {
136
- console.log('Schema added successfully under tag:', lense);
30
+ console.log('Schema added successfully under lense:', lense);
137
31
  resolve(ack);
138
32
  }
139
33
  })
140
34
  })
141
35
  }
142
36
 
37
+ async getSchema(lense) {
38
+ return new Promise((resolve) => {
39
+ this.gun.get(this.appname).get(lense).get('schema').once(data => {
40
+ if (data) {
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(data);
44
+ }
45
+ catch (e) {
46
+ resolve(null)
47
+ }
48
+ resolve(parsed);
49
+ } else {
50
+ resolve(null);
51
+ }
52
+ })
53
+ })
54
+ }
55
+
143
56
  async setHex(ctx) {
144
57
  const chatID = ctx.message.chat.id;
145
58
  const hex = ctx.message.text.split(' ')[1];
@@ -158,32 +71,20 @@ class HoloSphere {
158
71
  }
159
72
 
160
73
  async delete(id, tag) {
161
- await this.gun.get(id).get(tag).put(null)
74
+ await this.gun.get(this.appname).get(id).get(tag).put(null)
162
75
  }
163
76
 
164
77
  async put(hex, lense, content) {
165
78
  // Retrieve the schema for the lense
166
- let schemaData;
167
- try {
168
- schemaData = await new Promise((resolve, reject) => {
169
- this.gun.get(lense).get('schema').once(data => {
170
- if (data) {
171
- resolve(JSON.parse(data));
172
- } else {
173
- reject(new Error('No schema data found'));
174
- }
175
- });
176
- });
177
- } catch (error) {
178
- console.error(`Error fetching schema for "${lense}": ${error}`);
179
- return null;
180
- }
181
-
182
- // Validate the content against the schema
183
- const valid = this.validator.validate(schemaData, content);
184
- if (!valid) {
185
- console.error('Invalid content:', this.validator.errors);
186
- return null;
79
+ console.log('HoloSphere: Putting content in lense:', lense, 'at hex:', hex, 'content:', content)
80
+ let schema = await this.getSchema(lense)
81
+ if (schema) {
82
+ // Validate the content against the schema
83
+ const valid = this.validator.validate(schema, content);
84
+ if (!valid) {
85
+ console.error('Not committing invalid content:', this.validator.errors);
86
+ return null;
87
+ }
187
88
  }
188
89
 
189
90
  // Create a node for the content
@@ -192,16 +93,16 @@ class HoloSphere {
192
93
  let noderef;
193
94
 
194
95
  if (content.id) { //use the user-defined id. Important to be able to send updates using put
195
- noderef = this.gun.get(lense).get(content.id).put(payload)
196
- this.gun.get(hex.toString()).get(lense).get(content.id).put(payload)
96
+ noderef = this.gun.get(this.appname).get(lense).get(content.id).put(payload)
97
+ this.gun.get(this.appname).get(hex.toString()).get(lense).get(content.id).put(payload)
197
98
  } else { // create a content-addressable reference like IPFS. Note: no updates possible using put
198
99
  const hash = createHash("sha256").update(payload).digest("hex");
199
- noderef = this.gun.get(lense).get(hash).put(payload)
200
- this.gun.get(hex.toString()).get(lense).get(hash).put(payload)
100
+ noderef = this.gun.get(this.appname).get(lense).get(hash).put(payload)
101
+ this.gun.get(this.appname).get(hex.toString()).get(lense).get(hash).put(payload)
201
102
  }
202
103
 
203
104
  // return new Promise((resolve, reject) => {
204
- // this.gun.get(hex.toString()).get(lense).set(noderef, ack => {
105
+ // this.gun.get(this.appname).get(hex.toString()).get(lense).set(noderef, ack => {
205
106
  // if (ack.err) {
206
107
  // reject(new Error('Failed to add content: ' + ack.err));
207
108
  // } else {
@@ -216,36 +117,26 @@ class HoloSphere {
216
117
  async get(hex, lense) {
217
118
  // Wrap the GunDB operation in a promise
218
119
  //retrieve lense schema
219
- const schemaData = JSON.parse(await new Promise((resolve, reject) => {
220
- this.gun.get(lense).get('schema').once(data => {
221
- if (data) {
222
- resolve(data);
223
- } else {
224
- resolve(null);
225
- }
226
- });
227
- })
228
- )
120
+ const schema = await this.getSchema(lense);
229
121
 
230
- if (!schemaData) {
122
+ if (!schema) {
231
123
  console.log('The schema for "' + lense + '" is not defined');
232
- return null;
124
+ // return null; // No schema found, return null if strict about it
233
125
  }
234
126
 
235
127
  return new Promise(async (resolve, reject) => {
236
128
  let output = []
237
129
  let counter = 0
238
- this.gun.get(hex.toString()).get(lense).once((data, key) => {
130
+ this.gun.get(this.appname).get(hex.toString()).get(lense).once((data, key) => {
239
131
  if (data) {
240
132
  const maplenght = Object.keys(data).length - 1
241
- this.gun.get(hex.toString()).get(lense).map().once(async (itemdata, key) => {
133
+ console.log('Map length:', maplenght)
134
+ this.gun.get(this.appname).get(hex.toString()).get(lense).map().once(async (itemdata, key) => {
242
135
  counter += 1
243
136
  if (itemdata) {
244
-
245
-
246
137
  // if (itemdata._["#"]) {
247
138
  // // If the data is a reference, fetch the actual content
248
- // itemdata = await this.gun.get(itemdata._['#']).then();
139
+ // itemdata = await this.gun.get(this.appname).get(itemdata._['#']).then();
249
140
  // console.log("Data :",itemdata)
250
141
  // }
251
142
  var parsed = {}
@@ -253,14 +144,20 @@ class HoloSphere {
253
144
  parsed = JSON.parse(itemdata);
254
145
  } catch (e) {
255
146
  console.log('Invalid JSON:', itemdata);
147
+ parsed = itemdata //return the raw data
256
148
  }
257
149
 
258
- let valid = this.validator.validate(schemaData, parsed);
259
- if (!valid || parsed == null || parsed == undefined) {
260
- console.log('Removing Invalid content:', this.validator.errors);
261
- this.gun.get(hex).get(lense).get(key).put(null);
150
+ if (schema) {
151
+ let valid = this.validator.validate(schema, parsed);
152
+ if (!valid || parsed == null || parsed == undefined) {
153
+ console.log('Removing Invalid content:', this.validator.errors);
154
+ this.gun.get(this.appname).get(hex).get(lense).get(key).put(null);
262
155
 
263
- } else {
156
+ } else {
157
+ output.push(parsed);
158
+ }
159
+ }
160
+ else {
264
161
  output.push(parsed);
265
162
  }
266
163
  }
@@ -311,7 +208,7 @@ class HoloSphere {
311
208
  console.log('Content:', content);
312
209
  let computed = await this.summarize(content.join('\n'))
313
210
  console.log('Computed:', computed)
314
- let node = await this.gun.get(parent + '_summary').put({ id: parent + '_summary', content: computed })
211
+ let node = await this.gun.get(this.appname).get(parent + '_summary').put({ id: parent + '_summary', content: computed })
315
212
 
316
213
  this.put(parent, lense, node);
317
214
  this.compute(parent, lense, operation)
@@ -321,15 +218,18 @@ class HoloSphere {
321
218
  let entities = {};
322
219
 
323
220
  // Get list out of Gun
324
- this.gun.get(hex).get(lense).map().once((data, key) => {
221
+ this.gun.get(this.appname).get(hex).get(lense).map().once((data, key) => {
325
222
  //entities = data;
326
223
  //const id = Object.keys(entities)[0] // since this would be in object form, you can manipulate it as you would like.
327
- this.gun.get(hex).get(lense).put({ [key]: null })
224
+ this.gun.get(this.appname).get(hex).get(lense).put({ [key]: null })
328
225
  })
329
226
  }
330
227
 
331
228
 
332
229
  async summarize(history) {
230
+ if (!this.openai) {
231
+ return 'OpenAI not initialized, please specify the API key in the constructor.'
232
+ }
333
233
  //const run = await this.openai.beta.threads.runs.retrieve(thread.id,run.id)
334
234
  const assistant = await this.openai.beta.assistants.retrieve("asst_qhk79F8wV9BDNuwfOI80TqzC")
335
235
  const thread = await this.openai.beta.threads.create()
@@ -360,15 +260,18 @@ class HoloSphere {
360
260
 
361
261
  async upcast(hex, lense, content) {
362
262
  let res = h3.getResolution(hex)
263
+
363
264
  if (res == 0)
364
265
  return content
365
266
 
366
267
  console.log('Upcasting ', hex, lense, content)
367
268
  let parent = h3.cellToParent(hex, res - 1)
368
269
  await this.put(parent, lense, content)
270
+
369
271
  return this.upcast(parent, lense, content)
370
272
  }
371
273
 
274
+
372
275
  // send information upwards, triggers the parent to update its summary
373
276
  async updateParent(id, report) {
374
277
  let cellinfo = await this.getCellInfo(id)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holosphere",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Holonic Geospatial Communication Infrastructure based on h3.js and gun.js",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -11,7 +11,6 @@
11
11
  "license": "GPL-3.0-or-later",
12
12
  "dependencies": {
13
13
  "ajv": "^8.12.0",
14
- "dotenv": "^16.4.5",
15
14
  "gun": "^0.2020.1239",
16
15
  "h3-js": "^4.1.0",
17
16
  "openai": "^4.29.2"