add search bar

This commit is contained in:
Darren Zal 2023-02-13 13:43:00 -08:00
parent 0765b7a7c7
commit 6fe346c9a6
12 changed files with 1066 additions and 87 deletions

View File

@ -1,5 +1,5 @@
{
"database": "playground3",
"database": "play",
"endpoint": "https://cloud.terminusdb.com/Myseelia/",
"team": "Myseelia",
"use JWT token": true

View File

@ -6,15 +6,23 @@ from datetime import datetime
import pytz
import re
import emoji
import json
import meilisearch
import ast
import hashlib
# we keep all the information in dictionaries with Employee id as keys
orgs = {}
orgsjson = []
client = WOQLClient("https://cloud.terminusdb.com/Myseelia/")
client.connect(db="playground3", team="Myseelia", use_token=True)
client.connect(db="play", team="Myseelia", use_token=True)
import re
client1 = meilisearch.Client(
'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io', '117c691a34b21a6651798479ebffd181eb276958')
index = client1.index('orgs')
def get_emoji_regexp():
# Sort emoji by length to make sure multi-character emojis are
@ -23,9 +31,44 @@ def get_emoji_regexp():
pattern = u'(' + u'|'.join(re.escape(u) for u in emojis) + u')'
return re.compile(pattern)
def remove_emojis(string):
return get_emoji_regexp().sub(r'', string)
def hash_string(string):
sha256 = hashlib.sha256()
sha256.update(string.encode('utf-8'))
return sha256.hexdigest()
def to_json(obj):
obj_dict = obj.__dict__
if obj_dict['blockchainecosystem']:
print(obj_dict['blockchainecosystem'])
obj_dict['blockchainecosystem'] = [
bc.name for bc in obj_dict['blockchainecosystem']]
else:
obj_dict['web3'] = None
if obj_dict['impactarea']:
print(obj_dict['impactarea'])
obj_dict['impactarea'] = [ia.name for ia in obj_dict['impactarea']]
else:
obj_dict['web3'] = None
if obj_dict['topic']:
print(obj_dict['topic'])
obj_dict['topic'] = [t.name for t in obj_dict['topic']]
else:
obj_dict['web3'] = None
if obj_dict['web3']:
print(obj_dict['web3'])
obj_dict['web3'] = [w.name for w in obj_dict['web3']]
else:
obj_dict['web3'] = None
print(obj_dict['datecreated'])
obj_dict['datecreated'] = obj_dict['datecreated'].isoformat()
print("here")
print("here" + json.dumps(obj_dict))
return json.dumps(obj_dict)
with open("Organizations.csv") as file:
csv_file = csv.reader(file)
@ -47,7 +90,7 @@ with open("Organizations.csv") as file:
value = value.strip().strip('"')
if value == "Social justice":
impact_area_set.add(ImpactArea.SocialJustice)
elif value in ("Food & Agriculture","Food & Ag."):
elif value in ("Food & Agriculture", "Food & Ag."):
impact_area_set.add(ImpactArea.FoodAg)
elif value == "Invest":
impact_area_set.add(ImpactArea.Politicsactivism)
@ -55,7 +98,8 @@ with open("Organizations.csv") as file:
impact_area_set.add(ImpactArea.Investing)
elif value == "Innovate":
impact_area_set.add(ImpactArea.Innovation)
else: impact_area_set.add(ImpactArea[value])
else:
impact_area_set.add(ImpactArea[value])
blockchainEcosystem = row[1].strip("{}").split(",")
blockchainEcosystem_set = set()
for value in blockchainEcosystem:
@ -70,11 +114,11 @@ with open("Organizations.csv") as file:
elif blockchain == "Hyperledger Fabric":
blockchain = Blockchain.HyperledgerFabric
elif blockchain == "Zero Carbon":
blockchain = Blockchain.ZeroCarbon
blockchain = Blockchain.ZeroCarbon
elif blockchain == "IXO":
blockchain = Blockchain.ixo
elif blockchain in ("Not found","Not sure / still deciding"):
blockchain = Blockchain.Other
blockchain = Blockchain.ixo
elif blockchain in ("Not found", "Not sure / still deciding"):
blockchain = Blockchain.Other
elif blockchain == "Not applicable":
break
else:
@ -85,8 +129,8 @@ with open("Organizations.csv") as file:
for value in re.split(",(?![^(]*\))", web3):
if value:
web3 = value.strip().strip('"')
#someone put "Blockchain (L1,DAO" which will match to "Blockchain (L1" since we strip the '"'
if web3 in ("Blockchain (L1, L2)","Blockchain (L1,L2)","Blockchain (L1"):
# someone put "Blockchain (L1,DAO" which will match to "Blockchain (L1" since we strip the '"'
if web3 in ("Blockchain (L1, L2)", "Blockchain (L1,L2)", "Blockchain (L1"):
web3 = Web3.Blockchain
else:
web3 = Web3[web3]
@ -114,7 +158,8 @@ with open("Organizations.csv") as file:
topic = Topic.FoodForests
elif topic == "Eco-Living":
topic = Topic.EcoLiving
else: topic = Topic[topic]
else:
topic = Topic[topic]
topic_set.add(topic)
date_string = row[2]
utc_date = datetime.min
@ -132,25 +177,43 @@ with open("Organizations.csv") as file:
if upvotesstr.isdigit():
upvotesint = int(upvotesstr)
orgs[counter] = Organization(
assignee = row[0] if row[0] not in [None, ''] else None,
blockchainecosystem = blockchainEcosystem_set if len(blockchainEcosystem_set) > 0 else None,
description = row[3] if row[3] not in [None, ''] else None,
logo = row[5] if row[5] not in [None, ''] else None,
#name is the only mandatory field, so default it to "" if blank
name = row[6] if row[6] not in [None, ''] else "",
preJan20thUpvotes = preJan20thUpvotesint if preJan20thUpvotesint not in [0] else None,
reviewed = row[8] if row[3] not in [None, ''] else None,
submittedbyemail = row[9] if row[9] not in [None, ''] else None,
submittedbyname = row[10] if row[10] not in [None, ''] else None,
submittedbyowner = row[11] if row[11] not in [None, ''] else None,
subscribed = row[12] if row[12] not in [None, ''] else None,
topic = topic_set if len(topic_set) > 0 else None,
upvotes = upvotesint if upvotesint not in [0] else None,
web3 = web3_set if len(web3_set) > 0 else None,
impactarea = impact_area_set if len(impact_area_set) > 0 else None,
datecreated = utc_date if impact_area_set not in [datetime.min] else None,
org = Organization(
assignee=row[0] if row[0] not in [None, ''] else None,
blockchainecosystem=blockchainEcosystem_set if len(
blockchainEcosystem_set) > 0 else None,
description=row[3] if row[3] not in [None, ''] else None,
logo=row[5] if row[5] not in [None, ''] else None,
# name is the only mandatory field, so default it to "" if blank
name=row[6] if row[6] not in [None, ''] else "",
preJan20thUpvotes=preJan20thUpvotesint if preJan20thUpvotesint not in [
0] else None,
reviewed=row[8] if row[3] not in [None, ''] else None,
submittedbyemail=row[9] if row[9] not in [None, ''] else None,
submittedbyname=row[10] if row[10] not in [None, ''] else None,
submittedbyowner=row[11] if row[11] not in [
None, ''] else None,
subscribed=row[12] if row[12] not in [None, ''] else None,
topic=topic_set if len(topic_set) > 0 else None,
upvotes=upvotesint if upvotesint not in [0] else None,
web3=web3_set if len(web3_set) > 0 else None,
impactarea=impact_area_set if len(
impact_area_set) > 0 else None,
datecreated=utc_date if impact_area_set not in [
datetime.min] else None,
)
counter += 1
client.insert_document(list(orgs.values()), commit_msg="Adding orgs")
orgs[counter] = org
# print(to_json(org))
# orgsjson.append(to_json(org))
counter += 1
inserted = client.insert_document(
list(orgs.values()), commit_msg="Adding orgs")
documents = []
for id in inserted:
document = client.get_document(id)
real_id = document['@id']
num_id = real_id.split("/")[-1]
document = {k: json.dumps(v) for k, v in document.items() if k != '@id'}
document.update({'id': num_id})
documents.append(document)
index.add_documents(documents)

View File

@ -1,3 +1,4 @@
import json
####
# This is the script for storing the schema of your TerminusDB
# database for your project.
@ -56,6 +57,7 @@ class Blockchain(EnumTemplate):
ZeroCarbon = ()
Topl = ()
HBAR = ()
class Organization(DocumentTemplate):
"""
@ -208,3 +210,4 @@ class Topic(EnumTemplate):
Other = ()
IoT = ()
EcoLiving = ()

100
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": {
"clipboard-copy": "^4.0.1",
"cytoscape": "^3.23.0",
"meilisearch": "^0.31.1",
"qrcode-svg": "^1.1.0",
"uint8arrays": "^3.1.0",
"webnative": "^0.34.1"
@ -3142,6 +3143,33 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/cross-fetch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
"dependencies": {
"node-fetch": "2.6.7"
}
},
"node_modules/cross-fetch/node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
@ -6375,6 +6403,14 @@
"node": ">=8"
}
},
"node_modules/meilisearch": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.31.1.tgz",
"integrity": "sha512-ajMieU0e25lLkT+05J0snX0Ycow1UofxIy5sag03flERUbjXq8ouVwkrJkW27JsKftIeDeffRRRr89LasU9+0w==",
"dependencies": {
"cross-fetch": "^3.1.5"
}
},
"node_modules/mem": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz",
@ -8502,6 +8538,11 @@
"node": ">=6"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-node": {
"version": "10.9.1",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
@ -8799,6 +8840,11 @@
"node": ">= 8"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/webnative": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.34.1.tgz",
@ -8839,6 +8885,15 @@
"node": ">=6"
}
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
@ -11292,6 +11347,24 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"cross-fetch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
"integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
"requires": {
"node-fetch": "2.6.7"
},
"dependencies": {
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
}
}
},
"cross-spawn": {
"version": "7.0.3",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
@ -13610,6 +13683,14 @@
"blueimp-md5": "^2.10.0"
}
},
"meilisearch": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.31.1.tgz",
"integrity": "sha512-ajMieU0e25lLkT+05J0snX0Ycow1UofxIy5sag03flERUbjXq8ouVwkrJkW27JsKftIeDeffRRRr89LasU9+0w==",
"requires": {
"cross-fetch": "^3.1.5"
}
},
"mem": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz",
@ -15043,6 +15124,11 @@
"integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==",
"dev": true
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"ts-node": {
"version": "10.9.1",
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
@ -15242,6 +15328,11 @@
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"webnative": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/webnative/-/webnative-0.34.1.tgz",
@ -15276,6 +15367,15 @@
"integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==",
"dev": true
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"which": {
"version": "2.0.2",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",

View File

@ -57,6 +57,7 @@
"dependencies": {
"clipboard-copy": "^4.0.1",
"cytoscape": "^3.23.0",
"meilisearch": "^0.31.1",
"qrcode-svg": "^1.1.0",
"uint8arrays": "^3.1.0",
"webnative": "^0.34.1"

33
search/import.py Normal file
View File

@ -0,0 +1,33 @@
import meilisearch
client = meilisearch.Client('https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io', '117c691a34b21a6651798479ebffd181eb276958')
# An index is where the documents are stored.
index = client.index('movies')
documents = [
{ 'id': 1, 'title': 'Carol', 'genres': ['Romance', 'Drama'] },
{ 'id': 2, 'title': 'Wonder Woman', 'genres': ['Action', 'Adventure'] },
{ 'id': 3, 'title': 'Life of Pi', 'genres': ['Adventure', 'Drama'] },
{ 'id': 4, 'title': 'Mad Max: Fury Road', 'genres': ['Adventure', 'Science Fiction'] },
{ 'id': 5, 'title': 'Moana', 'genres': ['Fantasy', 'Action']},
{ 'id': 6, 'title': 'Philadelphia', 'genres': ['Drama'] },
]
# If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
index.add_documents(documents) # => { "uid": 0 }', 'masterKey')
# An index is where the documents are stored.
index = client.index('movies')
documents = [
{ 'id': 1, 'title': 'Carol', 'genres': ['Romance', 'Drama'] },
{ 'id': 2, 'title': 'Wonder Woman', 'genres': ['Action', 'Adventure'] },
{ 'id': 3, 'title': 'Life of Pi', 'genres': ['Adventure', 'Drama'] },
{ 'id': 4, 'title': 'Mad Max: Fury Road', 'genres': ['Adventure', 'Science Fiction'] },
{ 'id': 5, 'title': 'Moana', 'genres': ['Fantasy', 'Action']},
{ 'id': 6, 'title': 'Philadelphia', 'genres': ['Drama'] },
]
# If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
index.add_documents(documents) # => { "uid": 0 }

7
search/search.py Normal file
View File

@ -0,0 +1,7 @@
import meilisearch
client = meilisearch.Client('https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io', '117c691a34b21a6651798479ebffd181eb276958')
result = index.search('caorl')
print(result)

View File

@ -0,0 +1,334 @@
<script lang="ts">
import cytoscape from 'cytoscape'
import { onMount } from 'svelte'
import { bubble } from 'svelte/internal'
import TerminusClient from '@terminusdb/terminusdb-client'
import { MeiliSearch } from 'meilisearch'
let cy
interface INodeData {
id: string
}
interface INode {
data: INodeData
}
interface IEdgeData {
id: string
source: string
target: string
label: string
}
interface IEdge {
data: IEdgeData
}
import json_graph from './knowledge_graph.json'
let knowledgeGraphJson: any = json_graph
// knowledgeGraphJson = await response.json()
// } else {
// alert(`HTTP-Error: ${response.status}`)
// }
// }
let nodes: INode[] = []
let edges: IEdge[] = []
onMount(async () => {
//await fetchData();
nodes = knowledgeGraphJson.entities.map((entity: any) => ({
data: { id: entity.id, label: entity.label }
}))
edges = knowledgeGraphJson.relations.map(
(relation: any, index: string) => ({
data: {
id: index,
source: relation.source,
target: relation.target,
label: relation.type
}
})
)
cy = cytoscape({
container: document.getElementById('cy'),
elements: {
nodes,
edges
},
style: [
{
selector: 'node',
style: {
'text-valign': 'center',
'text-halign': 'center',
'text-wrap': 'wrap',
'text-max-width': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 30
},
'font-size': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 6
},
'background-color': '#75f6df',
'border-color': '#223152',
'border-width': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2))
},
label: 'data(label)',
width: function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
},
height: function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
}
}
},
{
selector: 'edge',
style: {
'font-size': 20,
width: 5,
'line-color': '#223152',
'target-arrow-color': '#223152',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier',
'text-rotation': 'autorotate',
'text-offset': { x: 20, y: -20 },
'text-background-opacity': 1,
'text-background-color': '#fafafa',
'text-background-shape': 'roundrectangle',
label: 'data(label)'
}
}
],
layout: {
name: 'cose'
// infinite: true,
}
})
cy.nodes().forEach(function (node) {
node.data({
degree: node.connectedEdges().length
})
})
var nodes = cy.nodes()
nodes = nodes.sort(function (a, b) {
return b.data('degree') - a.data('degree')
})
var top100 = nodes.slice(0, 1000)
console.log(top100);
cy.nodes().forEach(function (node) {
if (!top100.includes(node)) {
node.hide()
}
})
let toggle = true
// cy.off('tap', 'node', event => {
// const node = event.target;
// const nodeId = node.data('id');
// alert('unDisplay info for ' + nodeId);
// });
cy.on('tap', 'node', function (evt) {
var node = evt.target
var connectedEdges = node.connectedEdges()
var connectedNodes = node.neighborhood().nodes()
var allElements = cy.elements()
var allNodes = cy.nodes()
var allEdges = cy.edges()
if (node.style('display') == 'element') {
// hide all nodes and edges except the selected node and its neighbors
allNodes.style('display', 'none')
allEdges.style('display', 'none')
connectedNodes.style('display', 'element')
node.style('display', 'element')
connectedEdges.style('display', 'element')
} else {
// show all nodes and edges
allNodes.style('display', 'element')
allEdges.style('display', 'element')
}
})
// Reset the state when clicking away from the node
cy.on('tap', function (e) {
if (e.target === cy) {
cy.nodes().style('display', 'element')
cy.edges().style('display', 'element')
cy.nodes().data('highlighted', false)
}
})
cy.on('tap', 'edge', event => {
const edge = event.target
const edgeId = edge.data('id')
alert('Display info for ' + edgeId)
})
// cy.on('tap', 'node', function(){
// alert("put code here"));
// });
// cy.layout({
// name: 'cola'
// }).run();
})
var searchTerm = ''
function updateSearchTerm(e) {
searchTerm = e.target.value
// Perform search in real timebased on searchTerm here
}
async function entered(e) {
alert(e.target.value.toString())
const searchclient = new MeiliSearch({
host: 'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io',
apiKey: '117c691a34b21a6651798479ebffd181eb276958'
})
const index = searchclient.index('orgs')
// this will search both keys and values
// const search = await index.search(e.target.value.toString(), { q: '*' });
// const searchResult = await index.search('orgs', {
// attributesToRetrieve: ['id']
// })
const searchResult = await index.search(e.target.value.toString());
console.log(searchResult)
// var node = cy.nodes().filter(function (ele) {
// return ele.data('id') == "Organization/" + searchResult.hits[0].id
// })
// console.log(node);
// var connectedEdges = node.connectedEdges()
// var connectedNodes = node.neighborhood().nodes()
// var allElements = cy.elements()
// var allNodes = cy.nodes()
// var allEdges = cy.edges()
// if (node.style('display') == 'element') {
// console.log("a");
// // hide all nodes and edges except the selected node and its neighbors
// allNodes.style('display', 'none')
// allEdges.style('display', 'none')
// connectedNodes.style('display', 'element')
// node.style('display', 'element')
// connectedEdges.style('display', 'element')
// } else {
// console.log("b");
// // show all nodes and edges
// allNodes.style('display', 'element')
// allEdges.style('display', 'element')
// }
// Perform search in real time based on searchTerm here
const client = new TerminusClient.WOQLClient(
'https://cloud.terminusdb.com/Myseelia/',
{
user: 'zaldarren@gmail.com',
organization: 'Myseelia',
db: 'playground3',
token:
'dGVybWludXNkYjovLy9kYXRhL2tleXNfYXBpLzJkMDU4N2IwYjgzMzhmODdjMjc0ZDdiNmM1MzgwNjFmYTYyMmZkOTcyZTc3NjI1NzIyYjY3MTllYTE3NmQxYjE=_bd6f9c37d87abcaf0c16b7a68335b31010c8dd04aac0b07bf0f31676af131888666200aac080e72cdc746197334eac4f52d821c90652b5611784878afabe1267535cbd896a00a396'
}
)
try {
await client.connect()
//console.log(schema);
// console.log("result");
// const result = await client.getDocument({as_list:true,type:"Person",query: { userName: "tester" }})
// console.log(result);
} catch (err) {
console.error('this is it' + err.message)
}
// let v = WOQL.vars('person_id', 'impactarea', '@schema:checked');
const WOQL = TerminusClient.WOQL
const query = WOQL.triple(
'v:OrganizationID',
'name',
WOQL.string('Sustainable Impact Token')
)
const query3 = WOQL.and(
WOQL.triple('v:NodeID', 'property_name', WOQL.like(`%${keyword}%`)),
WOQL.triple('v:NodeID', 'property_name', 'v:Value')
)
const result = await client.getDocument({
as_list: true,
type: 'Organization',
query: { name: 'Sustainable Impact Token' }
})
console.log('result ', result)
const results = await client.query(query)
console.log('Query Documents using WOQL: ', results.bindings)
}
</script>
<div class="pt-8 p-6 md:p-8 mx-auto">
<input
id="search"
type="text"
placeholder="Search..."
on:input={updateSearchTerm}
on:keydown={event => {
if (event.keyCode === 13) {
entered(event)
}
}}
/>
</div>
<section class="overflow-hidden text-gray-700">
<div class="cyDiv" />
<div id="cy" />
</section>
<style>
#search {
position: absolute;
top: 10px;
z-index: 100;
background-color: white;
width: 50%;
height: 40px;
border-radius: 20px;
padding: 10px 20px 10px 40px;
}
#search input[type='text'] {
position: absolute;
top: 0px;
left: 50px;
width: 80%;
height: 100%;
border: none;
background-color: transparent;
font-size: 18px;
}
#cy-div {
z-index: 99;
}
#cy {
width: 100%;
height: 95%;
position: absolute;
top: 55px;
left: 0px;
}
</style>

View File

@ -2,9 +2,11 @@
import cytoscape from 'cytoscape'
import { onMount } from 'svelte'
import { bubble } from 'svelte/internal'
import TerminusClient from '@terminusdb/terminusdb-client'
import { MeiliSearch } from 'meilisearch'
import { generateKnowledgeGraph } from './cytoscape.ts'
let cy
let cyDiv
interface INodeData {
id: string
@ -24,14 +26,12 @@
interface IEdge {
data: IEdgeData
}
import json_graph from './knowledge_graph.json';
import json_graph from './knowledge_graph.json'
let knowledgeGraphJson: any = json_graph;
let knowledgeGraphJson: any = json_graph
// knowledgeGraphJson = await response.json()
// knowledgeGraphJson = await response.json()
// } else {
// alert(`HTTP-Error: ${response.status}`)
// }
@ -41,7 +41,6 @@
let edges: IEdge[] = []
onMount(async () => {
//await fetchData();
nodes = knowledgeGraphJson.entities.map((entity: any) => ({
data: { id: entity.id, label: entity.label }
}))
@ -57,7 +56,7 @@
})
)
let cy = cytoscape({
cy = cytoscape({
container: document.getElementById('cy'),
elements: {
nodes,
@ -70,26 +69,36 @@
'text-valign': 'center',
'text-halign': 'center',
'text-wrap': 'wrap',
"text-max-width": function(ele){ return Math.max(1, Math.ceil(ele.degree()/2)) * 30; },
"font-size": function(ele){ return Math.max(1, Math.ceil(ele.degree()/2)) * 6; },
'background-color': "#75f6df",
'border-color': "#223152",
'border-width': function(ele){ return Math.max(1, Math.ceil(ele.degree()/2)); },
'text-max-width': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 30
},
'font-size': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 6
},
'background-color': '#75f6df',
'border-color': '#223152',
'border-width': function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2))
},
label: 'data(label)',
width: function(ele){ return Math.max(1, Math.ceil(ele.degree()/2)) * 40; },
height: function(ele){ return Math.max(1, Math.ceil(ele.degree()/2)) * 40; }
width: function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
},
height: function (ele) {
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
}
}
},
{
selector: 'edge',
style: {
"font-size": 20,
'font-size': 20,
width: 5,
'line-color': "#223152",
'target-arrow-color': "#223152",
'line-color': '#223152',
'target-arrow-color': '#223152',
'target-arrow-shape': 'triangle',
'curve-style': 'bezier',
"text-rotation": "autorotate",
'text-rotation': 'autorotate',
'text-offset': { x: 20, y: -20 },
'text-background-opacity': 1,
'text-background-color': '#fafafa',
@ -104,50 +113,65 @@
}
})
let toggle = true;
cy.nodes().forEach(function (node) {
node.data({
degree: node.connectedEdges().length
})
})
var nodes = cy.nodes()
nodes = nodes.sort(function (a, b) {
return b.data('degree') - a.data('degree')
})
var top100 = nodes.slice(0, 1000)
//console.log(top100)
cy.nodes().forEach(function (node) {
if (!top100.includes(node)) {
node.hide()
}
})
let toggle = true
// cy.off('tap', 'node', event => {
// const node = event.target;
// const nodeId = node.data('id');
// alert('unDisplay info for ' + nodeId);
// });
cy.on('tap', 'node', function (evt) {
var node = evt.target
var connectedEdges = node.connectedEdges()
var connectedNodes = node.neighborhood().nodes()
var allElements = cy.elements()
var allNodes = cy.nodes()
var allEdges = cy.edges()
cy.on('tap', 'node', function(evt){
var node = evt.target;
var connectedEdges = node.connectedEdges();
var connectedNodes = node.neighborhood().nodes();
var allElements = cy.elements();
var allNodes = cy.nodes();
var allEdges = cy.edges();
if (node.style("display") == "element") {
// hide all nodes and edges except the selected node and its neighbors
allNodes.style("display", "none");
allEdges.style("display", "none");
connectedNodes.style("display", "element");
node.style("display", "element");
connectedEdges.style("display", "element");
} else {
// show all nodes and edges
allNodes.style("display", "element");
allEdges.style("display", "element");
}
});
// Reset the state when clicking away from the node
cy.on('tap', function(e){
if (e.target === cy) {
cy.nodes().style('display', 'element');
cy.edges().style('display', 'element');
cy.nodes().data('highlighted', false);
}
});
if (node.style('display') == 'element') {
// hide all nodes and edges except the selected node and its neighbors
allNodes.style('display', 'none')
allEdges.style('display', 'none')
connectedNodes.style('display', 'element')
node.style('display', 'element')
connectedEdges.style('display', 'element')
} else {
// show all nodes and edges
allNodes.style('display', 'element')
allEdges.style('display', 'element')
}
})
// Reset the state when clicking away from the node
cy.on('tap', function (e) {
if (e.target === cy) {
cy.nodes().style('display', 'element')
cy.edges().style('display', 'element')
cy.nodes().data('highlighted', false)
}
})
cy.on('tap', 'edge', event => {
const edge = event.target
@ -163,15 +187,169 @@ cy.on('tap', function(e){
// name: 'cola'
// }).run();
})
var searchTerm = ''
function updateSearchTerm(e) {
searchTerm = e.target.value
// Perform search in real timebased on searchTerm here
}
async function entered(e) {
const searchclient = new MeiliSearch({
host: 'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io',
apiKey: '117c691a34b21a6651798479ebffd181eb276958'
})
const index = searchclient.index('orgs')
// this will search both keys and values
// const search = await index.search(e.target.value.toString(), { q: '*' });
// const searchResult = await index.search('orgs', {
// attributesToRetrieve: ['id']
// })
const searchResult = await index.search(e.target.value.toString(), {
attributesToRetrieve: ['id']
})
// need to turn the search results into an array of ids which can be used to query the knowledge graph
const resultsgraph = await generateKnowledgeGraph(searchResult.hits).then(
resultsgraph => {
const allNodes = resultsgraph.entities.map((entity: any) => ({
data: { id: entity.id, label: entity.label }
}))
const allEdges = resultsgraph.relations.map(
(relation: any, index: string) => ({
data: {
id: index,
source: relation.source,
target: relation.target,
label: relation.type
}
})
)
cy.remove(cy.elements())
cy.add(allNodes)
cy.add(allEdges)
cy.layout({
name: 'cose',
// other layout options here
}).run();
}
)
// var node = cy.nodes().filter(function (ele) {
// return ele.data('id') == "Organization/" + searchResult.hits[0].id
// })
// console.log(node);
// var connectedEdges = node.connectedEdges()
// var connectedNodes = node.neighborhood().nodes()
// var allElements = cy.elements()
// var allNodes = cy.nodes()
// var allEdges = cy.edges()
// if (node.style('display') == 'element') {
// console.log("a");
// // hide all nodes and edges except the selected node and its neighbors
// allNodes.style('display', 'none')
// allEdges.style('display', 'none')
// connectedNodes.style('display', 'element')
// node.style('display', 'element')
// connectedEdges.style('display', 'element')
// } else {
// console.log("b");
// // show all nodes and edges
// allNodes.style('display', 'element')
// allEdges.style('display', 'element')
// }
// Perform search in real time based on searchTerm here
const client = new TerminusClient.WOQLClient(
'https://cloud.terminusdb.com/Myseelia/',
{
user: 'zaldarren@gmail.com',
organization: 'Myseelia',
db: 'playground3',
token:
'dGVybWludXNkYjovLy9kYXRhL2tleXNfYXBpLzJkMDU4N2IwYjgzMzhmODdjMjc0ZDdiNmM1MzgwNjFmYTYyMmZkOTcyZTc3NjI1NzIyYjY3MTllYTE3NmQxYjE=_bd6f9c37d87abcaf0c16b7a68335b31010c8dd04aac0b07bf0f31676af131888666200aac080e72cdc746197334eac4f52d821c90652b5611784878afabe1267535cbd896a00a396'
}
)
try {
await client.connect()
//console.log(schema);
// console.log("result");
// const result = await client.getDocument({as_list:true,type:"Person",query: { userName: "tester" }})
// console.log(result);
} catch (err) {
console.error('this is it' + err.message)
}
// let v = WOQL.vars('person_id', 'impactarea', '@schema:checked');
// const WOQL = TerminusClient.WOQL
// const query = WOQL.triple(
// 'v:OrganizationID',
// 'name',
// WOQL.string('Sustainable Impact Token')
// )
// const query3 = WOQL.and(
// WOQL.triple('v:NodeID', 'property_name', WOQL.like(`%${keyword}%`)),
// WOQL.triple('v:NodeID', 'property_name', 'v:Value')
// )
// const result = await client.getDocument({
// as_list: true,
// type: 'Organization',
// query: { name: 'Sustainable Impact Token' }
// })
// console.log('result ', result)
// const results = await client.query(query)
// console.log('Query Documents using WOQL: ', results.bindings)
}
</script>
<div class="pt-8 p-6 md:p-8 mx-auto">
<input
id="search"
type="text"
placeholder="Search..."
on:input={updateSearchTerm}
on:keydown={event => {
if (event.keyCode === 13) {
entered(event)
}
}}
/>
</div>
<section class="overflow-hidden text-gray-700">
<div class="pt-8 p-6 md:p-8 mx-auto" />
<div class="cyDiv" />
<div id="cy" />
</section>
<style>
#search {
position: absolute;
top: 10px;
z-index: 100;
background-color: white;
width: 50%;
height: 40px;
border-radius: 20px;
padding: 10px 20px 10px 40px;
}
#search input[type='text'] {
position: absolute;
top: 0px;
left: 50px;
width: 80%;
height: 100%;
border: none;
background-color: transparent;
font-size: 18px;
}
#cy-div {
z-index: 99;
}
#cy {
width: 100%;
height: 95%;

View File

@ -0,0 +1,96 @@
import { isNullOrUndefined } from 'util';
import { WOQLClient } from 'terminusdb-client';
import { resultToDF } from 'terminusdb-client/woqldataframe';
import { DataFrame } from 'pandas';
import * as fs from 'fs';
const client = new WOQLClient("https://cloud.terminusdb.com/Myseelia/");
client.connect(db="playground3", team="Myseelia", use_token=true);
export async function generateKnowledgeGraph(ids: string[]) {
const orgsRaw = client.query_document({ "@type": "Organization", "Document id": { "@in": ids } });
const df = resultToDF(orgsRaw);
const entities: {id: string, label: string, type: string}[] = [];
const relations: {source: string, target: string, type: string}[] = [];
for (let i = 0; i < df.length; i++) {
const row = df[i];
entities.push({'id': row['Document id'], 'label': row['name'], 'type': 'organization'});
if (!isNullOrUndefined(row['assignee'])) {
const assigneeId = row['assignee'];
if (!isNullOrUndefined(assigneeId) && assigneeId !== '' && !isNaN(assigneeId)) {
entities.push({'id': assigneeId, 'label': row['assignee'], 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': assigneeId, 'type': 'assignee'});
}
}
if (Array.isArray(row['blockchainecosystem'])) {
for (const ecosystem of row['blockchainecosystem']) {
const ecosystemId = ecosystem;
if (!isNullOrUndefined(ecosystemId) && ecosystemId !== '' && !isNaN(ecosystemId)) {
entities.push({'id': ecosystemId, 'label': ecosystem, 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': ecosystemId, 'type': 'blockchain ecosystem'});
}
}
} else {
const ecosystemId = row['blockchainecosystem'];
if (!isNullOrUndefined(ecosystemId) && ecosystemId !== '' && !isNaN(ecosystemId)) {
entities.push({'id': ecosystemId, 'label': row['blockchainecosystem'], 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': ecosystemId, 'type': 'blockchain ecosystem'});
}
}
if (Array.isArray(row['topic'])) {
for (const topic of row['topic']) {
const topicId = topic;
if (!isNullOrUndefined(topicId) && topicId !== '' && !isNaN(topicId)) {
entities.push({'id': topicId, 'label': topic, 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': topicId, 'type': 'topic'});
}
}
} else {
const topicId = row['topic'];
if (!isNullOrUndefined(topicId) && topicId !== '' && !isNaN(topicId)) {
entities.push({'id': topicId, 'label': row['topic'], 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': topicId, 'type': 'topic'});
}
}
if (Array.isArray(row['web3'])) {
for (const web3 of row['web3']) {
const web3Id = web3;
if (!isNullOrUndefined(web3Id) && web3Id !== '' && !isNaN(web3Id)) {
entities.push({'id': web3Id, 'label': web3, 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': web3Id, 'type': 'web3'});
}
}
} else {
const web3Id = row['web3'];
if (!isNullOrUndefined(web3Id) && web3Id !== '' && !isNaN(web3Id)) {
entities.push({'id': web3Id, 'label': row['web3'], 'type': 'attribute'});
relations.push({'source': row['Document id'], 'target': web3Id, 'type': 'web3'});
}
}
}
const knowledgeGraphJson = {
'entities': entities,
'relations': relations
};
fs.writeFileSync("knowledge_graph.json", JSON.stringify(knowledgeGraphJson), 'utf-8');
export function getData(client: WOQLClient, ids: string[]): DataFrame {
const query = {
"@type": "Organization",
"Document id": {
"$in": ids
}
};
const orgsRaw = client.query_document(query);
return resultToDF(orgsRaw);
}

View File

@ -0,0 +1,164 @@
// import { isNullOrUndefined } from 'util'
import TerminusClient from '@terminusdb/terminusdb-client'
import * as fs from 'fs'
const client = new TerminusClient.WOQLClient(
'https://cloud.terminusdb.com/Myseelia/',
{
user: 'zaldarren@gmail.com',
organization: 'Myseelia',
db: 'play',
token:
'dGVybWludXNkYjovLy9kYXRhL2tleXNfYXBpLzJkMDU4N2IwYjgzMzhmODdjMjc0ZDdiNmM1MzgwNjFmYTYyMmZkOTcyZTc3NjI1NzIyYjY3MTllYTE3NmQxYjE=_bd6f9c37d87abcaf0c16b7a68335b31010c8dd04aac0b07bf0f31676af131888666200aac080e72cdc746197334eac4f52d821c90652b5611784878afabe1267535cbd896a00a396'
}
)
try {
await client.connect()
//console.log(schema);
// console.log("result");
// const result = await client.getDocument({as_list:true,type:"Person",query: { userName: "tester" }})
// console.log(result);
} catch (err) {
console.error('this is it' + err.message)
}
const WOQL = TerminusClient.WOQL
export async function generateKnowledgeGraph(ids: unknown[]): Promise<object> {
const results: unknown[] = []
const entities: { id: string; label: string; type: string }[] = []
const relations: { source: string; target: string; type: string }[] = []
for (const id of ids) {
const orgid = 'Organization/' + id['id'].toString()
const result = await client.getDocument({ as_list: true, type: 'Organization', id: orgid })
for (const document of result) {
let orgEntity = entities.find(entity => entity.id === orgid)
if (!orgEntity) {
entities.push({ 'id': orgid, 'label': document['name'], 'type': 'organization' })
orgEntity = entities[entities.length - 1]
}
if (document['assignee'] !== undefined) {
const assigneeId = document['assignee']
if (assigneeId !== undefined && assigneeId !== '') {
let assigneeEntity = entities.find(entity => entity.id === assigneeId)
if (!assigneeEntity) {
entities.push({ 'id': assigneeId, 'label': document['name'] + ' assignee', 'type': 'attribute' })
assigneeEntity = entities[entities.length - 1]
}
let assigneeRelation = relations.find(relation => relation.source === orgid && relation.target === assigneeId)
if (!assigneeRelation) {
relations.push({ 'source': orgid, 'target': assigneeId, 'type': 'assignee' })
}
}
}
if (Array.isArray(document['blockchainecosystem'])) {
for (const ecosystem of document['blockchainecosystem']) {
const ecosystemId = ecosystem
if (ecosystemId !== undefined && ecosystemId !== '') {
let ecosystemEntity = entities.find(entity => entity.id === ecosystemId)
if (!ecosystemEntity) {
entities.push({ 'id': ecosystemId, 'label': ecosystem, 'type': 'attribute' })
ecosystemEntity = entities[entities.length - 1]
}
let ecosystemRelation = relations.find(relation => relation.source === orgid && relation.target === ecosystemId)
if (!ecosystemRelation) {
relations.push({ 'source': orgid, 'target': ecosystemId, 'type': 'blockchain ecosystem' })
}
}
}
} else {
const ecosystemId = document['blockchainecosystem']
if (ecosystemId !== undefined && ecosystemId !== '') {
let ecosystemEntity = entities.find(entity => entity.id === ecosystemId)
if (!ecosystemEntity) {
entities.push({ 'id': ecosystemId, 'label': document['blockchainecosystem'], 'type': 'attribute' })
ecosystemEntity = entities[entities.length - 1]
}
let ecosystemRelation = relations.find(relation => relation.source === orgid && relation.target === ecosystemId)
if (!ecosystemRelation) {
relations.push({ 'source': orgid, 'target': ecosystemId, 'type': 'blockchain ecosystem' })
}
}
}
if (Array.isArray(document['topic'])) {
for (const topic of document['topic']) {
const topicId = topic
if (topicId !== undefined && topicId !== '') {
let topicEntity = entities.find(entity => entity.id === topicId)
if (!topicEntity) {
entities.push({ 'id': topicId, 'label': topic, 'type': 'attribute' })
topicEntity = entities[entities.length - 1]
}
let topicRelation = relations.find(relation => relation.source === orgid && relation.target === topicId)
if (!topicRelation) {
relations.push({ 'source': orgid, 'target': topicId, 'type': 'topic' })
}
}
}
} else {
const topicId = document['topic']
if (topicId !== undefined && topicId !== '') {
let topicEntity = entities.find(entity => entity.id === topicId)
if (!topicEntity) {
entities.push({ 'id': topicId, 'label': document['topic'], 'type': 'attribute' })
topicEntity = entities[entities.length - 1]
}
let topicRelation = relations.find(relation => relation.source === orgid && relation.target === topicId)
if (!topicRelation) {
relations.push({ 'source': orgid, 'target': topicId, 'type': 'topic' })
}
}
}
if (Array.isArray(document['web3'])) {
for (const web3 of document['web3']) {
const web3Id = web3
if (web3Id !== undefined && web3Id !== '') {
let web3Entity = entities.find(entity => entity.id === web3Id)
if (!web3Entity) {
entities.push({ 'id': web3Id, 'label': web3, 'type': 'attribute' })
web3Entity = entities[entities.length - 1]
}
let web3Relation = relations.find(relation => relation.source === orgid && relation.target === web3Id)
if (!web3Relation) {
relations.push({ 'source': orgid, 'target': web3Id, 'type': 'web3' })
}
}
}
} else {
const web3Id = document['web3']
if (web3Id !== undefined && web3Id !== '') {
let web3Entity = entities.find(entity => entity.id === web3Id)
if (!web3Entity) {
entities.push({ 'id': web3Id, 'label': document['web3'], 'type': 'attribute' })
web3Entity = entities[entities.length - 1]
}
let web3Relation = relations.find(relation => relation.source === orgid && relation.target === web3Id)
if (!web3Relation) {
relations.push({ 'source': orgid, 'target': web3Id, 'type': 'web3' })
}
}
}
}
}
return {
'entities': entities,
'relations': relations
}
}
export default generateKnowledgeGraph