diff --git a/Project/backend/codebase/graph_analysis/graph_analysis.py b/Project/backend/codebase/graph_analysis/graph_analysis.py index 6097c41..c5618fd 100644 --- a/Project/backend/codebase/graph_analysis/graph_analysis.py +++ b/Project/backend/codebase/graph_analysis/graph_analysis.py @@ -2,6 +2,18 @@ import os import json +def get_top_n_central_nodes(centrality_dict, n): + """Sort nodes based on centrality measure and return top N nodes. + + Args: + centrality_dict: Dictionary of nodes with their centrality values. + n: Number of top nodes to return. + + Returns: + Sorted list of top N nodes with their centrality values. + """ + sorted_nodes = sorted(centrality_dict.items(), key=lambda item: item[1], reverse=True) + return sorted_nodes[:n] def analyze_graph_structure(G): """Analyzes the structure of a knowledge graph and provides hopefully useful information. @@ -17,15 +29,12 @@ def analyze_graph_structure(G): # Basic Graph Statistics num_nodes = G.number_of_nodes() # Total number of nodes num_edges = G.number_of_edges() # Total number of edges - density = nx.density(G) # Ratio of actual edges to possible edges (0 to 1) - average_degree = 2 * num_edges / num_nodes # Average number of edges per node - # Degree Distribution - degree_distribution = dict(G.degree()) - # Degree distribution can indicate the presence of hubs or important nodes + if num_nodes == 0 or num_edges == 0: + raise ValueError("The graph is empty or not properly constructed.") + # Degree Centrality: Measures node connectivity degree_centrality = nx.degree_centrality(G) - """ Centrality Measures - Degree Centrality: Measures node connectivity - Nodes with high degree centrality are important in the network @@ -36,8 +45,9 @@ def analyze_graph_structure(G): - Degree Centrality: node1 = 0.33(1/3), node2 = 0.66(2/3), node3 = 0.33(1/3) """ - betweenness_centrality = nx.betweenness_centrality(G) + # Betweenness Centrality: Measures node's control over information flow + betweenness_centrality = nx.betweenness_centrality(G) """ - Betweenness Centrality: Measures node's control over information flow - Nodes with high betweenness centrality are important in the network @@ -54,24 +64,8 @@ def analyze_graph_structure(G): - Betweenness Centrality show the dependency of the network on a node """ - - # - Closeness Centrality: Measures average length of the shortest path from a node to all other nodes - closeness_centrality = nx.closeness_centrality(G) - - """ - - Closeness Centrality: Measures average length of the shortest path from a node to all other nodes - - Nodes with high closeness centrality are important in the network - - Examples: 4 nodes are connected - 0 - / | \ -2--1--3 - - - Here, node 0, 1 (1.0) has the highest closeness centrality because it is connected to all other nodes (node 2, 3 = 0.75) - - Closeness Centrality show the average distance of a node to all other nodes in the network - """ - - # - Eigenvector Centrality: Measures influence of a node in a network + + # eigenvector centrality measures the influence of a node in a network eigenvector_centrality = nx.eigenvector_centrality(G) """ @@ -92,78 +86,16 @@ def analyze_graph_structure(G): """ - # Community Structure - # - Louvain Algorithm (for community detection) - communities = list(nx.community.greedy_modularity_communities(G)) - community_sizes = [len(community) for community in communities] - num_communities = len(communities) - # Communities can reveal modular structures in the graph - """ - - Community Detection: Identifying groups of nodes that are more connected to each other than to the rest of the network - - Communities can reveal modular structures in the graph - - Communities can be used to identify groups of nodes that are more connected to each other than to the rest of the network - - Examples: 7 nodes are connected - 1 - / \ -2-----3 - \ / 5 - 4-----/ \ - 6-----7 - - - Here, nodes 1, 2, 3, 4 are in one community and nodes 5, 6, 7 are in another community - """ - - # Graph Connectivity - # - Check if the graph is connected - is_connected = nx.is_connected(G) - # - Calculate diameter: Longest shortest path between any two nodes - diameter = nx.diameter(G) if is_connected else float('inf') - # - Average shortest path length: Average of all shortest paths in the graph - average_shortest_path_length = nx.average_shortest_path_length(G) if is_connected else float('inf') - - # Clustering Coefficient - # - Measures the degree to which nodes tend to cluster together - average_clustering_coefficient = nx.average_clustering(G) - - # Assortativity - # - Measures the similarity of connections in the graph with respect to node degree - assortativity = nx.degree_assortativity_coefficient(G) - - # Graph Diameter and Radius - # - Diameter: Longest shortest path in the graph - # - Radius: Minimum eccentricity of any node - radius = nx.radius(G) if is_connected else float('inf') - - # Graph Transitivity - # - Measures the overall probability for the network to have adjacent nodes interconnected - transitivity = nx.transitivity(G) - - # Return a dictionary containing the structural information graph_info = { "num_nodes": num_nodes, "num_edges": num_edges, - "density": density, - "average_degree": average_degree, - "degree_distribution": degree_distribution, - "degree_centrality": degree_centrality, - "betweenness_centrality": betweenness_centrality, - "closeness_centrality": closeness_centrality, - "eigenvector_centrality": eigenvector_centrality, - "num_communities": num_communities, - "community_sizes": community_sizes, - "is_connected": is_connected, - "diameter": diameter, - "average_shortest_path_length": average_shortest_path_length, - "average_clustering_coefficient": average_clustering_coefficient, - "assortativity": assortativity, - "radius": radius, - "transitivity": transitivity + "top_degree_centrality": get_top_n_central_nodes(degree_centrality, top_n), + "top_betweenness_centrality": get_top_n_central_nodes(betweenness_centrality, top_n), + "top_eigenvector_centrality": get_top_n_central_nodes(eigenvector_centrality, top_n) } return graph_info - def print_graph_info(graph_info): """Prints the graph information in a formatted and readable way. @@ -176,9 +108,12 @@ def print_graph_info(graph_info): graph_directory = os.fsencode("../.media/graphs/") + +top_n = int(input("Enter the number of top nodes to display: ")) + with os.scandir("./Project/backend/codebase/.media/graphs/") as it: for entry in it: - if entry.name.endswith(".gml") and entry.is_file(): + if entry.name.endswith("c.gml") and entry.is_file(): print("-----------------------") print(f"Filename: {entry.name}") graph = nx.read_gml(entry.path) diff --git a/Project/backend/codebase/graph_creator/gemini.py b/Project/backend/codebase/graph_creator/gemini.py index 5dca737..ed9a906 100644 --- a/Project/backend/codebase/graph_creator/gemini.py +++ b/Project/backend/codebase/graph_creator/gemini.py @@ -1,6 +1,8 @@ import os from datetime import datetime + import google.generativeai as genai + from graph_creator.services.json_handler import transform_llm_output_to_dict @@ -36,27 +38,29 @@ def extract_entities_and_relations(chunk, genai_client): """ SYS_PROMPT = ( "Only answer in a JSON format. \n" - "You are a network graph maker who extracts terms and their relations from a given context. " - "You are provided with a context chunk (delimited by ```) Your task is to extract the ontology " - "of terms mentioned in the given context. These terms should represent the key concepts as per the context. \n" - "Thought 1: While traversing through each sentence, Think about the key terms mentioned in it.\n" - "\tTerms may include object, entity, location, organization, person, \n" - "\tcondition, acronym, documents, service, concept, etc.\n" - "\tTerms should be as atomistic as possible\n\n" - "Thought 2: Think about how these terms can have one on one relation with other terms.\n" - "\tTerms that are mentioned in the same sentence or the same paragraph are typically related to each other.\n" - "\tTerms can be related to many other terms\n\n" - "Thought 3: Find out the relation between each such related pair of terms. \n\n" - "Format your output as a list of JSON. Each element of the list contains a pair of terms" + "You are a network graph maker who extracts the most critical terms and their relations from a given context. " + "You are provided with a context chunk (delimited by ```). Your task is to extract the ontology " + "of the few key terms that are indispensable for understanding the given context. These terms should represent the core concepts as per the context. \n" + "Thought 1: Identify the few most critical terms in the entire context.\n" + "\tTerms may include only the most significant objects, entities, locations, organizations, people, conditions, acronyms, documents, services, concepts, etc.\n" + "\tExclude all terms that are not crucial to the core message.\n" + "\tDo not extract a term from every sentence; focus only on the most important terms across the entire context.\n\n" + "Thought 2: Determine how these indispensable terms are directly related to each other.\n" + "\tTerms that are mentioned in the same sentence or paragraph are typically related to each other.\n" + "\tFocus solely on relationships that reveal the most critical interactions or dependencies, ignoring all minor details.\n\n" + "Thought 3: Identify the specific type of relationship between each related pair of terms.\n" + "\tEnsure the relationship is crucial, highly relevant, and necessary for understanding the context.\n\n" + "Format your output as a list of JSON. Each element of the list contains a pair of terms " "and the relation between them, like the following: \n" "[\n" " {\n" - ' "node_1": "A concept from extracted ontology",\n' - ' "node_2": "A related concept from extracted ontology",\n' + ' "node_1": "A core concept from extracted ontology",\n' + ' "node_2": "A related core concept from extracted ontology",\n' ' "edge": "relationship between the two concepts, node_1 and node_2"\n' " }, {...}\n" "]" ) + USER_PROMPT = f"context: ```{chunk}``` \n\n output: " chat_session = genai_client.start_chat(history=[]) @@ -74,9 +78,12 @@ def check_for_connecting_relation( """ SYS_PROMPT = ( "Only answer in JSON format. \n" - "Your task is to help create a knowledge graph by extracting one more relation between any entity of list_1 with any entity of list_2.\n" - "We want to connect the subgraphs of nodes and relations that were extracted from the given text chunk (delimited by ```)." - "For this one more relation needs to be extracted from the given text chunk between any entity of list_1 and list_2:\n" + "Your task is to help create a knowledge graph by extracting one more relation between any entity of list_1 " + "with any entity of list_2.\n " + "We want to connect the subgraphs of nodes and relations that were extracted from the given text chunk (" + "delimited by ```). " + "For this one more relation needs to be extracted from the given text chunk between any entity of list_1 and " + "list_2:\n " f"list_1: {entities_component_1}\n" f"list_2: {entities_component_2}\n" "Only use the exact entities given in the lists." @@ -110,7 +117,7 @@ def check_for_connecting_relation_( The text chunk to be proccessed entities_component_1 : list List of entities - entities_component_1 : list + entities_component_2 : list List of entities Returns diff --git a/Project/backend/codebase/graph_creator/graph_creator_main.py b/Project/backend/codebase/graph_creator/graph_creator_main.py index c61d142..2778cbd 100644 --- a/Project/backend/codebase/graph_creator/graph_creator_main.py +++ b/Project/backend/codebase/graph_creator/graph_creator_main.py @@ -1,12 +1,15 @@ +import logging import mimetypes -import pandas +from graph_creator import graph_handler +from graph_creator import pdf_handler from graph_creator.llama3 import process_chunks as groq_process_chunks from graph_creator.models.graph_job import GraphJob -from graph_creator import pdf_handler -from graph_creator import graph_handler from graph_creator.services import netx_graphdb +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + def process_file_to_graph(g_job: GraphJob): """ @@ -58,11 +61,9 @@ def process_file_to_entities_and_relations(file: str): ] # Assuming chunk has 'page_content' attribute # Generate response using LLM - # response_json = process_chunks(text_chunks, prompt_template) response_json = groq_process_chunks(text_chunks) - print(response_json) except Exception as e: - print(e) + logging.error(e) response_json = None return response_json, chunks @@ -83,6 +84,7 @@ def create_and_store_graph(uuid, entities_and_relations, chunks): # combine knowledge graph pieces # combined = graph_handler.connect_with_chunk_proximity(df_e_and_r) + # combined['chunk_id'] = '1' for i in range(len(chunks)): chunks[i] = chunks[i].dict() combined = graph_handler.connect_with_llm(df_e_and_r, chunks, 30) @@ -91,7 +93,7 @@ def create_and_store_graph(uuid, entities_and_relations, chunks): graph_db_service = netx_graphdb.NetXGraphDB() # read entities and relations - graph = graph_db_service.create_graph_from_df(combined) + graph = graph_db_service.create_graph_from_df(combined, chunks) # save graph as file graph_db_service.save_graph(uuid, graph) diff --git a/Project/backend/codebase/graph_creator/graph_handler.py b/Project/backend/codebase/graph_creator/graph_handler.py index 471606a..2c48eb5 100644 --- a/Project/backend/codebase/graph_creator/graph_handler.py +++ b/Project/backend/codebase/graph_creator/graph_handler.py @@ -1,8 +1,15 @@ -import pandas as pd -import re import json +import logging +import re import time + +import pandas as pd + from graph_creator import llama3 +from bertopic import BERTopic + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) def build_flattened_dataframe(entities_and_relations): @@ -11,7 +18,7 @@ def build_flattened_dataframe(entities_and_relations): Parameters ---------- - entity_and_relations : list + entities_and_relations : list List of Lists of dictionaries Returns @@ -47,7 +54,7 @@ def connect_with_chunk_proximity(entity_and_relation_df): pandas.dataframe A table with given relations and chunk proximity relations between the nodes """ - # seperate all nodes by chunk_id + # separate all nodes by chunk_id df_by_chunk_id = pd.melt( entity_and_relation_df, id_vars=["chunk_id"], @@ -116,7 +123,7 @@ def index_entity_relation_table(entity_and_relation_df, entities): A List containing all relations as tuples of entity indexes """ entities_dict = {} - # for reproducable results + # for reproducible results entities = sorted(entities) for i in range(len(entities)): entities_dict[entities[i]] = i @@ -178,7 +185,7 @@ def extract_components(relations_list): elif inserte["at"] >= 0: components[inserte["at"]].append(inserte["new_node"]) - # remove empty componente + # remove empty components components.pop(len(components) - 1) return components @@ -242,7 +249,6 @@ def get_shared_chunks_by_component(component1, component2, entity_chunks_list): chunk_entities = set(entity_chunks_list[keys[i]]) intersection_c1 = chunk_entities.intersection(entities_component_1) intersection_c2 = chunk_entities.intersection(entities_component_2) - # print(f"{intersection_size_c1}, {intersection_size_c2}") if len(intersection_c1) > 0 and len(intersection_c2) > 0: shared_chunks.append(keys[i]) intersections[keys[i]] = {"c1": intersection_c1, "c2": intersection_c2} @@ -333,6 +339,21 @@ def add_relations_to_data(entity_and_relation_df, new_relations): return entity_and_relation_df +def add_topic(data: pd.DataFrame) -> pd.DataFrame: + documents = list(set(data['node_1']).union(set(data['node_2']))) + + topic_model = BERTopic() + topics, probabilities = topic_model.fit_transform(documents) + topic_name_info = {row['Topic']: row['Name'] for _, row in topic_model.get_topic_info().iterrows()} + doc_topic_map = {doc: topic for doc, topic in zip(documents, topics)} + doc_topic_strings_map = {doc: topic_name_info.get(topic, "no_topic") for doc, topic in doc_topic_map.items()} + + # Add new columns to the DataFrame and populate them + data['topic_node_1'] = [doc_topic_strings_map[node] for i, node in data['node_1'].items()] + data['topic_node_2'] = [doc_topic_strings_map[node] for i, node in data['node_2'].items()] + return data + + def connect_with_llm(data, text_chunks, rate_limit): """ Connect the pieces of the knowlege graph by extracting new relations between disjoint @@ -344,6 +365,9 @@ def connect_with_llm(data, text_chunks, rate_limit): Table of nodes and relations between the nodes text_chunks : list A list of dictionaries containing the text chunks + rate_limit : int + The maximum number of requests that can be made to the LLM within a specified + timeframe. Returns ------- @@ -356,7 +380,7 @@ def connect_with_llm(data, text_chunks, rate_limit): components = extract_components(relations_list) number_components = len(components) - print("Before connecting {} components".format(number_components)) + logger.info(f"Before connecting {number_components} components") # get chunk information about contained entities entity_chunks_list = get_entities_by_chunk(data, entities_dict) @@ -408,19 +432,19 @@ def connect_with_llm(data, text_chunks, rate_limit): relation = extract_relation_from_llm_output( connecting_relation, main_chunk_entities, current_chunk_entities ) + # if relation is extracted than a valid relation containing only existing entities can be added - # print(relation) if relation is not None: relation["chunk_id"] = key_shared_chunk connecting_relations.append(relation) connections += 1 break - print( - "Made {} new connections and thereby reduced the graph to {} components".format( - connections, number_components - connections - ) + logger.info( + f"Made {connections} new connections and thereby reduced the graph " + f"to {number_components - connections} components " ) data = add_relations_to_data(data, connecting_relations) + data = add_topic(data) return data diff --git a/Project/backend/codebase/graph_creator/json_to_graphml.py b/Project/backend/codebase/graph_creator/json_to_graphml.py index 629e30f..0d23456 100644 --- a/Project/backend/codebase/graph_creator/json_to_graphml.py +++ b/Project/backend/codebase/graph_creator/json_to_graphml.py @@ -1,7 +1,8 @@ import json +import logging + import networkx as nx import pandas as pd -import logging def json_string_to_graph(json_string): diff --git a/Project/backend/codebase/graph_creator/llama3.py b/Project/backend/codebase/graph_creator/llama3.py index e82d7b7..64988c4 100644 --- a/Project/backend/codebase/graph_creator/llama3.py +++ b/Project/backend/codebase/graph_creator/llama3.py @@ -1,5 +1,6 @@ import os from datetime import datetime + from groq import Groq from graph_creator.services.json_handler import transform_llm_output_to_dict @@ -9,7 +10,7 @@ def configure_groq(): """ Ensure the API key is set in the environment """ - # load_dotenv("Project/backend/.env", override=True) + api_key = os.getenv("GROQ_API_KEY") if not api_key: raise ValueError("API key not found in environment variables") @@ -37,23 +38,24 @@ def extract_entities_and_relations(chunk, groq_client): """ SYS_PROMPT = ( "Only answer in a JSON format. \n" - "You are a network graph maker who extracts terms and their relations from a given context. " - "You are provided with a context chunk (delimited by ```) Your task is to extract the ontology " - "of terms mentioned in the given context. These terms should represent the key concepts as per the context. \n" - "Thought 1: While traversing through each sentence, Think about the key terms mentioned in it.\n" - "\tTerms may include object, entity, location, organization, person, \n" - "\tcondition, acronym, documents, service, concept, etc.\n" - "\tTerms should be as atomistic as possible\n\n" - "Thought 2: Think about how these terms can have one on one relation with other terms.\n" - "\tTerms that are mentioned in the same sentence or the same paragraph are typically related to each other.\n" - "\tTerms can be related to many other terms\n\n" - "Thought 3: Find out the relation between each such related pair of terms. \n\n" - "Format your output as a list of JSON. Each element of the list contains a pair of terms" + "You are a network graph maker who extracts the most critical terms and their relations from a given context. " + "You are provided with a context chunk (delimited by ```). Your task is to extract the ontology " + "of the few key terms that are indispensable for understanding the given context. These terms should represent the core concepts as per the context. \n" + "Thought 1: Identify the few most critical terms in the entire context.\n" + "\tTerms may include only the most significant objects, entities, locations, organizations, people, conditions, acronyms, documents, services, concepts, etc.\n" + "\tExclude all terms that are not crucial to the core message.\n" + "\tDo not extract a term from every sentence; focus only on the most important terms across the entire context.\n\n" + "Thought 2: Determine how these indispensable terms are directly related to each other.\n" + "\tTerms that are mentioned in the same sentence or paragraph are typically related to each other.\n" + "\tFocus solely on relationships that reveal the most critical interactions or dependencies, ignoring all minor details.\n\n" + "Thought 3: Identify the specific type of relationship between each related pair of terms.\n" + "\tEnsure the relationship is crucial, highly relevant, and necessary for understanding the context.\n\n" + "Format your output as a list of JSON. Each element of the list contains a pair of terms " "and the relation between them, like the following: \n" "[\n" " {\n" - ' "node_1": "A concept from extracted ontology",\n' - ' "node_2": "A related concept from extracted ontology",\n' + ' "node_1": "A core concept from extracted ontology",\n' + ' "node_2": "A related core concept from extracted ontology",\n' ' "edge": "relationship between the two concepts, node_1 and node_2"\n' " }, {...}\n" "]" @@ -77,9 +79,12 @@ def check_for_connecting_relation( """ SYS_PROMPT = ( "Only answer in JSON format. \n" - "Your task is to help create a knowledge graph by extracting one more relation between any entity of list_1 with any entity of list_2.\n" - "We want to connect the subgraphs of nodes and relations that were extracted from the given text chunk (delimited by ```)." - "For this one more relation needs to be extracted from the given text chunk between any entity of list_1 and list_2:\n" + "Your task is to help create a knowledge graph by extracting one more relation between any entity of list_1 " + "with any entity of list_2.\n " + "We want to connect the subgraphs of nodes and relations that were extracted from the given text chunk (" + "delimited by ```). " + "For this one more relation needs to be extracted from the given text chunk between any entity of list_1 and " + "list_2:\n " f"list_1: {entities_component_1}\n" f"list_2: {entities_component_2}\n" "Only use the exact entities given in the lists." @@ -115,7 +120,7 @@ def check_for_connecting_relation_( The text chunk to be proccessed entities_component_1 : list List of entities - entities_component_1 : list + entities_component_2 : list List of entities Returns diff --git a/Project/backend/codebase/graph_creator/pdf_handler.py b/Project/backend/codebase/graph_creator/pdf_handler.py index 6299554..7d4e9ef 100644 --- a/Project/backend/codebase/graph_creator/pdf_handler.py +++ b/Project/backend/codebase/graph_creator/pdf_handler.py @@ -1,6 +1,7 @@ import os -from langchain_text_splitters import RecursiveCharacterTextSplitter + from langchain_community.document_loaders import PyPDFLoader +from langchain_text_splitters import RecursiveCharacterTextSplitter def process_pdf_into_chunks(filename): @@ -10,7 +11,7 @@ def process_pdf_into_chunks(filename): Parameters ---------- filename : str - The name of the pdf file to be proccessed + The name of the pdf file to be processed Returns ------- diff --git a/Project/backend/codebase/graph_creator/router.py b/Project/backend/codebase/graph_creator/router.py index e36fa4e..d357f37 100644 --- a/Project/backend/codebase/graph_creator/router.py +++ b/Project/backend/codebase/graph_creator/router.py @@ -1,25 +1,26 @@ import logging +import mimetypes import os -import uuid - +import shutil import tempfile +import uuid from typing import Optional - from fastapi import APIRouter, Depends from fastapi import UploadFile, File, HTTPException from starlette.responses import JSONResponse +import graph_creator.graph_creator_main as graph_creator_main from graph_creator.dao.graph_job_dao import GraphJobDAO -from graph_creator.schemas.graph_job import GraphJobCreate -from graph_creator.pdf_handler import process_pdf_into_chunks from graph_creator.gemini import process_chunks -import shutil -import mimetypes -from graph_creator.schemas.graph_vis import GraphVisData, QueryInputData, GraphQueryOutput +from graph_creator.pdf_handler import process_pdf_into_chunks +from graph_creator.schemas.graph_job import GraphJobCreate +from graph_creator.schemas.graph_vis import ( + GraphVisData, + QueryInputData, + GraphQueryOutput, +) from graph_creator.services.netx_graphdb import NetXGraphDB - -import graph_creator.graph_creator_main as graph_creator_main from graph_creator.services.query_graph import GraphQuery from graph_creator.utils.const import GraphStatus @@ -102,7 +103,6 @@ async def upload_pdf( ) if not os.path.exists(documents_directory): os.makedirs(documents_directory) - logger.info(documents_directory) # Define file path file_path = os.path.join(documents_directory, file.filename) @@ -117,7 +117,7 @@ async def upload_pdf( # Save file with open(file_path, "wb") as f: f.write(file.file.read()) - logger.info(file_path) + logger.info(f" Uploaded file is saved here {file_path}") graph_job = GraphJobCreate( name=file.filename, location=file_path, status=GraphStatus.DOC_UPLOADED @@ -216,16 +216,17 @@ async def read_graph_job_by_name( @router.delete("/graph_jobs/{graph_job_id}") async def delete_graph_job( - graph_job_id: uuid.UUID, - graph_job_dao: GraphJobDAO = Depends(), - netx_services: NetXGraphDB = Depends(), + graph_job_id: uuid.UUID, + graph_job_dao: GraphJobDAO = Depends(), + netx_services: NetXGraphDB = Depends(), ): """ Delete a graph job with the given name Args: - graph_job_name (str): Name + graph_job_id (uuid.UUID): ID of the graph job graph_job_dao (GraphJobDAO): + netx_services (NetXGraphDB): Raises: HTTPException: If there is no graph job with the given name. @@ -254,7 +255,6 @@ async def create_graph( ) # trigger graph creation - # background_tasks.add_task(graph_creator_main.process_file_to_graph, graph_job) graph_creator_main.process_file_to_graph(g_job) g_job.status = GraphStatus.GRAPH_READY @@ -282,8 +282,8 @@ async def get_graph_data_for_visualization( raise HTTPException( status_code=400, detail="A graph needs to be created for this job first!" ) - return netx_services.graph_data_for_visualization( - g_job.id, node=node, adj_depth=adj_depth + return await netx_services.graph_data_for_visualization( + graph_job=g_job, node=node, adj_depth=adj_depth ) @@ -302,7 +302,7 @@ async def query_graph( if g_job.status != GraphStatus.GRAPH_READY: raise HTTPException( status_code=400, - detail=f"No graph created for this job!", + detail="No graph created for this job!", ) graph = netx_services.load_graph(graph_job_id=graph_job_id) data = graph_query_services.query_graph(graph=graph, query=input_data.text) diff --git a/Project/backend/codebase/graph_creator/schemas/graph_vis.py b/Project/backend/codebase/graph_creator/schemas/graph_vis.py index e57eeff..27628da 100644 --- a/Project/backend/codebase/graph_creator/schemas/graph_vis.py +++ b/Project/backend/codebase/graph_creator/schemas/graph_vis.py @@ -1,3 +1,5 @@ +from datetime import datetime + from pydantic import BaseModel, Field @@ -6,6 +8,8 @@ class GraphNode(BaseModel): label: str size: int = Field(default=1) color: str = Field(default="#7FFFD4", description="Color aquamarine") + topic: str + pages: str class GraphEdge(BaseModel): @@ -19,6 +23,8 @@ class GraphEdge(BaseModel): class GraphVisData(BaseModel): + document_name: str + graph_created_at: datetime nodes: list[GraphNode] edges: list[GraphEdge] diff --git a/Project/backend/codebase/graph_creator/services/json_handler.py b/Project/backend/codebase/graph_creator/services/json_handler.py index 5f83d44..933d9f8 100644 --- a/Project/backend/codebase/graph_creator/services/json_handler.py +++ b/Project/backend/codebase/graph_creator/services/json_handler.py @@ -29,4 +29,4 @@ def transform_llm_output_to_dict(llm_output) -> dict: except json.JSONDecodeError: return {} - return relation \ No newline at end of file + return relation diff --git a/Project/backend/codebase/graph_creator/services/netx_graphdb.py b/Project/backend/codebase/graph_creator/services/netx_graphdb.py index 09b83a5..a88fde4 100644 --- a/Project/backend/codebase/graph_creator/services/netx_graphdb.py +++ b/Project/backend/codebase/graph_creator/services/netx_graphdb.py @@ -1,13 +1,17 @@ import os import uuid + import networkx as nx import numpy as np import pandas as pd + +from graph_creator.models.graph_job import GraphJob from graph_creator.schemas.graph_vis import GraphVisData, GraphNode, GraphEdge # Scale range for min-max scaling the node sizes scale_range = [15, 35] + class NetXGraphDB: """ This class serves as a service to create, read, save and work with graphs @@ -16,15 +20,42 @@ class NetXGraphDB: All the graphs operations will happen in memory. """ - def create_graph_from_df(self, data: pd.DataFrame = None) -> nx.Graph: + def create_graph_from_df(self, data: pd.DataFrame, chunks: dict) -> nx.Graph: df = pd.DataFrame(data) graph = nx.Graph() + chunk_to_page = {} + for i, chunk in enumerate(chunks): + chunk_id = i + page_number = chunk["metadata"]["page"] + chunk_to_page[chunk_id] = page_number + # Iterate over each row in the DataFrame for _, edge in df.iterrows(): + # Get the page number using the chunk id + + chunk_id = edge["chunk_id"] + page_number = chunk_to_page[int(chunk_id)] + + # Add nodes with page attribute + if edge["node_1"] not in graph: + graph.add_node(edge["node_1"], pages=set([]), topic=edge["topic_node_1"]) + if edge["node_2"] not in graph: + graph.add_node(edge["node_2"], pages=set([]), topic=edge["topic_node_2"]) + # Add edge with attributes to the graph graph.add_edge(edge["node_1"], edge["node_2"], relation=edge["edge"]) + # Add page numbers to each node + graph.nodes[edge["node_1"]]["pages"].add(page_number) + graph.nodes[edge["node_2"]]["pages"].add(page_number) + + # Sort pages and save as a string + for node in graph.nodes: + graph.nodes[node]["pages"] = ",".join( + map(str, sorted(graph.nodes[node]["pages"])) + ) + # Add min max log scaled sizes to nodes based on degree log_sizes = [np.log(graph.degree(node)) for node in graph.nodes()] min_log_size = min(log_sizes) @@ -42,7 +73,7 @@ def create_graph_from_df(self, data: pd.DataFrame = None) -> nx.Graph: for i, node in enumerate(graph.nodes): graph.nodes[node]["size"] = scaled_sizes[i] - graph.nodes[node]["degree"] = graph.degree(node) # Add node degree as an attribute + graph.nodes[node]["degree"] = graph.degree(node) return graph @@ -66,19 +97,20 @@ def delete_graph(self, graph_job_id: uuid.UUID): if os.path.exists(file_location): os.remove(file_location) - def graph_data_for_visualization( - self, graph_job_id: uuid.UUID, node: str | None, adj_depth: int + async def graph_data_for_visualization( + self, graph_job: GraphJob, node: str = None, adj_depth: int = 1 ) -> GraphVisData: """ Given a graph travers it and return a json format of all the nodes and edges they have ready for visualization to FE """ - graph = self.load_graph(graph_job_id) + + graph = self.load_graph(graph_job.id) if node: - return self._graph_bfs_edges(graph, node, adj_depth) + return self._graph_bfs_edges(graph, graph_job, node, adj_depth) - return self._all_graph_data_for_visualization(graph) + return self._all_graph_data_for_visualization(graph, graph_job) @staticmethod def _get_graph_file_path_local_storage(graph_job_id: uuid.UUID) -> str: @@ -95,7 +127,9 @@ def _get_graph_file_path_local_storage(graph_job_id: uuid.UUID) -> str: return os.path.join(graphs_directory, f"{graph_job_id}.gml") @staticmethod - def _graph_bfs_edges(graph: nx.Graph, node: str, adj_depth: int) -> GraphVisData: + def _graph_bfs_edges( + graph: nx.Graph, graph_job: GraphJob, node: str, adj_depth: int + ) -> GraphVisData: nodes_data = [] edges_data = [] visited = set() @@ -108,7 +142,9 @@ def _graph_bfs_edges(graph: nx.Graph, node: str, adj_depth: int) -> GraphVisData id=str(source), label=str(source), size=graph.nodes[source].get("size", 1), - degree=graph.nodes[source].get("degree", 0) + degree=graph.nodes[source].get("degree", 0), + pages=graph.nodes[source].get("pages", "pages not found"), + topic=graph.nodes[source].get("topic", "topic not found"), ) ) @@ -119,7 +155,9 @@ def _graph_bfs_edges(graph: nx.Graph, node: str, adj_depth: int) -> GraphVisData id=str(target), label=str(target), size=graph.nodes[target].get("size", 1), - degree=graph.nodes[target].get("degree", 0) + degree=graph.nodes[target].get("degree", 0), + pages=graph.nodes[source].get("pages", "pages not found"), + topic=graph.nodes[source].get("topic", "topic not found"), ) ) edge_properties = graph[source][target] @@ -132,10 +170,15 @@ def _graph_bfs_edges(graph: nx.Graph, node: str, adj_depth: int) -> GraphVisData ) ) - return GraphVisData(nodes=nodes_data, edges=edges_data) + return GraphVisData(document_name=graph_job.name, + graph_created_at=graph_job.updated_at, + nodes=nodes_data, + edges=edges_data) @staticmethod - def _all_graph_data_for_visualization(graph: nx.Graph) -> GraphVisData: + def _all_graph_data_for_visualization( + graph: nx.Graph, graph_job: GraphJob + ) -> GraphVisData: nodes_data = [] edges_data = [] @@ -147,7 +190,9 @@ def _all_graph_data_for_visualization(graph: nx.Graph) -> GraphVisData: id=str(node_id), label=str(node_id), size=node_attrs.get("size", 1), - degree=node_attrs.get("degree", 0) + degree=node_attrs.get("degree", 0), + pages=node_attrs.get("pages", "pages not found"), + topic=node_attrs.get("topic", "topic not found"), ) ) @@ -163,4 +208,7 @@ def _all_graph_data_for_visualization(graph: nx.Graph) -> GraphVisData: ) ) - return GraphVisData(nodes=nodes_data, edges=edges_data) + return GraphVisData(document_name=graph_job.name, + graph_created_at=graph_job.updated_at, + nodes=nodes_data, + edges=edges_data) diff --git a/Project/backend/codebase/graph_creator/services/query_graph.py b/Project/backend/codebase/graph_creator/services/query_graph.py index 620bc8a..4ecc4ef 100644 --- a/Project/backend/codebase/graph_creator/services/query_graph.py +++ b/Project/backend/codebase/graph_creator/services/query_graph.py @@ -27,7 +27,7 @@ def query_graph(self, graph: nx.Graph, query: str) -> GraphQueryOutput: try: for neighbor in graph.neighbors(node): edge_data = graph.get_edge_data(node, neighbor) - relationship = edge_data.get('relation', 'is connected to') + relationship = edge_data.get("relation", "is connected to") edges_info.append((relationship, neighbor)) entities_relationships[node] = edges_info except NetworkXError: @@ -61,7 +61,7 @@ def retrieve_entities_from_llm(query: str): @staticmethod def retrieve_entities_from_spacy(query: str): - nlp = spacy.load('en_core_web_sm') + nlp = spacy.load("en_core_web_sm") doc = nlp(query) entities = [(ent.text, ent.label_) for ent in doc.ents] @@ -71,10 +71,10 @@ def query_graph_via_langchain(self, query: str, graph_path: str): graph1 = NetworkxEntityGraph.from_gml(graph_path) chain = GraphQAChain.from_llm( ChatGroq( - temperature=0, - model="llama3-8b-8192", - api_key=os.getenv("GROQ_API_KEY") - ), graph=graph1, verbose=True + temperature=0, model="llama3-8b-8192", api_key=os.getenv("GROQ_API_KEY") + ), + graph=graph1, + verbose=True, ) response = chain.invoke(query) - return response \ No newline at end of file + return response diff --git a/Project/backend/codebase/requirements.txt b/Project/backend/codebase/requirements.txt index 4162780..789226c 100644 --- a/Project/backend/codebase/requirements.txt +++ b/Project/backend/codebase/requirements.txt @@ -85,4 +85,5 @@ urllib3==2.2.1 google-generativeai==0.5.4 groq==0.8.0 spacy -langchain-groq \ No newline at end of file +langchain-groq +bertopic \ No newline at end of file diff --git a/Project/backend/codebase/settings/defaults.py b/Project/backend/codebase/settings/defaults.py index f2f3803..436543c 100644 --- a/Project/backend/codebase/settings/defaults.py +++ b/Project/backend/codebase/settings/defaults.py @@ -10,4 +10,3 @@ POSTGRES_HOST = os.getenv("POSTGRES_HOST", "amos-db") DB_URL = f"postgresql+asyncpg://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}" - diff --git a/Project/backend/codebase/tests/test_json_handler.py b/Project/backend/codebase/tests/test_json_handler.py index d98a0d0..68c5ec5 100644 --- a/Project/backend/codebase/tests/test_json_handler.py +++ b/Project/backend/codebase/tests/test_json_handler.py @@ -1,10 +1,12 @@ from graph_creator.services.json_handler import transform_llm_output_to_dict + def test_valid_json(): llm_output = '[{"key1": "value1", "key2": "value2"}]' expected_output = [{"key1": "value1", "key2": "value2"}] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_leading_comments_and_text(): llm_output = """ Here is the requested json: @@ -16,16 +18,19 @@ def test_leading_comments_and_text(): expected_output = [{"key1": "value1", "key2": "value2"}] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_trailing_text(): llm_output = '[{"key1": "value1", "key2": "value2"}] Some trailing text.' expected_output = [{"key1": "value1", "key2": "value2"}] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_double_commas(): llm_output = '[{"key1": "value1", "key2": "value2",, "key3": "value3"}]' expected_output = [{"key1": "value1", "key2": "value2", "key3": "value3"}] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_comments_within_json(): llm_output = """ [ @@ -36,60 +41,541 @@ def test_comments_within_json(): """ expected_output = [ {"key1": "value1", "key2": "value2", "key3": "value3"}, - {"key1": "value4", "key2": "value5", "key3": "value6"} + {"key1": "value4", "key2": "value5", "key3": "value6"}, ] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_extra_commas_before_closing_brackets(): llm_output = '[{"key1": "value1", "key2": "value2",}]' expected_output = [{"key1": "value1", "key2": "value2"}] assert transform_llm_output_to_dict(llm_output) == expected_output + def test_incorrect_json_structure(): - llm_output = 'Here is the requested json: [key1: value1, key2: value2]' + llm_output = "Here is the requested json: [key1: value1, key2: value2]" expected_output = {} assert transform_llm_output_to_dict(llm_output) == expected_output + def test_empty_input(): - llm_output = '' + llm_output = "" expected_output = {} assert transform_llm_output_to_dict(llm_output) == expected_output + def test_no_json_found(): - llm_output = 'Here is the requested json: no json here.' + llm_output = "Here is the requested json: no json here." expected_output = {} assert transform_llm_output_to_dict(llm_output) == expected_output + def test_florian_examples(): list_of_examples = [ - "[\n {\n \"node_1\": \"IOP\",\n \"node_2\": \"Conference\",\n \"edge\": \"part of\"\n },\n {\n \"node_1\": \"Materials\",\n \"node_2\": \"Science\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Engineering\",\n \"node_2\": \"Autonomous\",\n \"edge\": \"research focus\"\n },\n {\n \"node_1\": \"cars\",\n \"node_2\": \"Recent\",\n \"edge\": \"development\"\n },\n {\n \"node_1\": \"Solutions\",\n \"node_2\": \"Possible\",\n \"edge\": \"type of\"\n },\n {\n \"node_1\": \"Sehajbir\",\n \"node_2\": \"Singh\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Baljit\",\n \"node_2\": \"Saini\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Autonomous\",\n \"node_2\": \"vehicles\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Wissam\",\n \"node_2\": \"Kontar\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Soyoung\",\n \"node_2\": \"Ahn\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Andrea\",\n \"node_2\": \"Hicks\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Modeling\",\n \"node_2\": \"heterogeneous\",\n \"edge\": \"method\"\n },\n {\n \"node_1\": \"traffic\",\n \"node_2\": \"flow\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"self-stabilizing\",\n \"node_2\": \"autonomous\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"vehicles\",\n \"node_2\": \"impact\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Residents'\",\n \"node_2\": \"Choice\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Network\",\n \"node_2\": \"Questionnaire\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Nanchang\",\n \"node_2\": \"China\",\n \"edge\": \"location\"\n },\n {\n \"node_1\": \"Yating\",\n \"node_2\": \"Huang\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Lixin\",\n \"node_2\": \"Yan\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Article\",\n \"node_2\": \"online\",\n \"edge\": \"platform\"\n },\n {\n \"node_1\": \"IP\",\n \"node_2\": \"address\",\n \"edge\": \"location\"\n },\n {\n \"node_1\": \"updates\",\n \"node_2\": \"enhancements\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"environ\",\n \"node_2\": \"implications\",\n \"edge\": \"related\"\n }\n]", - "[\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Developments\",\n \"edge\": \"Related\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Challenges\",\n \"edge\": \"Related\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Solutions\",\n \"edge\": \"Related\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Technology\",\n \"edge\": \"TypeOf\"\n },\n {\n \"node_1\": \"Electric vehicles\",\n \"node_2\": \"Cars\",\n \"edge\": \"TypeOf\"\n },\n {\n \"node_1\": \"Internal combustion engines\",\n \"node_2\": \"Technology\",\n \"edge\": \"TypeOf\"\n },\n {\n \"node_1\": \"University\",\n \"node_2\": \"Lovely Professional University\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"School\",\n \"node_2\": \"School of Computer Science and Engineering\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Person\",\n \"node_2\": \"Sehajbir Singh\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Person\",\n \"node_2\": \"Baljit Singh Saini\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Journal\",\n \"node_2\": \"IOP Conf. Series: Materials Science and Engineering\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Year\",\n \"node_2\": \"2021\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Year\",\n \"node_2\": \"2020\",\n \"edge\": \"InstanceOf\"\n },\n {\n \"node_1\": \"Domain\",\n \"node_2\": \"Autonomous vehicle technology\",\n \"edge\": \"InstanceOf\"\n }\n]", - "[\n {\n \"node_1\": \"Technology\",\n \"node_2\": \"Challenges\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"History of the automobile\",\n \"node_2\": \"1885\",\n \"edge\": \"dates to\"\n },\n {\n \"node_1\": \"Karl Benz\",\n \"node_2\": \"Benz Patent-Motorwagen\",\n \"edge\": \"developed\"\n },\n {\n \"node_1\": \"Ford Motor Company\",\n \"node_2\": \"Ford Model T\",\n \"edge\": \"produced\"\n },\n {\n \"node_1\": \"Ford's Piquette Avenue Assembly Plant\",\n \"node_2\": \"Ford Model T\",\n \"edge\": \"assembled\"\n },\n {\n \"node_1\": \"Model T\",\n \"node_2\": \"Ford Motor Company\",\n \"edge\": \"by\"\n },\n {\n \"node_1\": \"Detroit, Michigan\",\n \"node_2\": \"Ford's Piquette Avenue Assembly Plant\",\n \"edge\": \"located\"\n },\n {\n \"node_1\": \"Assembly line\",\n \"node_2\": \"Ford Motor Company\",\n \"edge\": \"used\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Computer science\",\n \"edge\": \"combine\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Electrical engineering\",\n \"edge\": \"combine\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Mechanical engineering\",\n \"edge\": \"combine\"\n },\n {\n \"node_1\": \"Linriccan Wonder\",\n \"node_2\": \"1920s\",\n \"edge\": \"introduced\"\n },\n {\n \"node_1\": \"Embedded-circuits\",\n \"node_2\": \"Electric cars\",\n \"edge\": \"powered\"\n },\n {\n \"node_1\": \"Mercedes-Benz\",\n \"node_2\": \"Robotic van\",\n \"edge\": \"developed\"\n },\n {\n \"node_1\": \"Vision-guided systems\",\n \"node_2\": \"Robotic van\",\n \"edge\": \"used\"\n },\n {\n \"node_1\": \"Modern vehicles\",\n \"node_2\": \"Technologies\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Lane keep assist\",\n \"node_2\": \"Modern vehicles\",\n \"edge\": \"include\"\n },\n {\n \"node_1\": \"Lane departure warning\",\n \"node_2\": \"Modern vehicles\",\n \"edge\": \"include\"\n },\n {\n \"node_1\": \"Adaptive cruise control\",\n \"node_2\": \"Modern vehicles\",\n \"edge\": \"include\"\n },\n {\n \"node_1\": \"World Health Organization\",\n \"node_2\": \"Road traffic injuries\",\n \"edge\": \"report\"\n },\n {\n \"node_1\": \"February 2020\",\n \"node_2\": \"Road traffic injuries\",\n \"edge\": \"report\"\n }\n]", - "[\n {\n \"node_1\": \"World Health Organization\",\n \"node_2\": \"report\",\n \"edge\": \"mentioned\"\n },\n {\n \"node_1\": \"road traffic injuries\",\n \"node_2\": \"deaths\",\n \"edge\": \"caused by\"\n },\n {\n \"node_1\": \"human error\",\n \"node_2\": \"road crashes\",\n \"edge\": \"attributed to\"\n },\n {\n \"node_1\": \"over-speeding\",\n \"node_2\": \"errors\",\n \"edge\": \"caused by\"\n },\n {\n \"node_1\": \"alcohol\",\n \"node_2\": \"errors\",\n \"edge\": \"caused by\"\n },\n {\n \"node_1\": \"distractions\",\n \"node_2\": \"errors\",\n \"edge\": \"caused by\"\n },\n {\n \"node_1\": \"non-usage of seatbelts\",\n \"node_2\": \"errors\",\n \"edge\": \"caused by\"\n },\n {\n \"node_1\": \"seatbelts\",\n \"node_2\": \"safety equipment\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"helmets\",\n \"node_2\": \"safety equipment\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"autonomous vehicle technology\",\n \"node_2\": \"transportation injuries\",\n \"edge\": \"reduces\"\n },\n {\n \"node_1\": \"autonomous vehicle technology\",\n \"node_2\": \"deaths\",\n \"edge\": \"reduces\"\n },\n {\n \"node_1\": \"broad adoption\",\n \"node_2\": \"autonomous vehicle technology\",\n \"edge\": \"advocates\"\n },\n {\n \"node_1\": \"increase\",\n \"node_2\": \"transportation injuries and deaths\",\n \"edge\": \"expected\"\n },\n {\n \"node_1\": \"drastic reduction\",\n \"node_2\": \"transportation injuries and deaths\",\n \"edge\": \"expected\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA\",\n \"node_2\": \"2020\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"ICCRDA\",\n \"node_2\": \"IOP Conf. Series: Materials Science and Engineering\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"traffic congestion\",\n \"node_2\": \"reliability of traffic flow\",\n \"edge\": \"has impact on\"\n },\n {\n \"node_1\": \"RAC foundation\",\n \"node_2\": \"report\",\n \"edge\": \"produced by\"\n },\n {\n \"node_1\": \"average car\",\n \"node_2\": \"parking time\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"ride-sharing\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"Cruise\",\n \"node_2\": \"Origin\",\n \"edge\": \"produces\"\n },\n {\n \"node_1\": \"Autonomous vehicles\",\n \"node_2\": \"delivery of goods\",\n \"edge\": \"can be used for\"\n },\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"challenges in development\",\n \"edge\": \"associated with\"\n },\n {\n \"node_1\": \"leg al framework\",\n \"node_2\": \"regulations for autonomous cars\",\n \"edge\": \"required for\"\n },\n {\n \"node_1\": \"autonomous system\",\n \"node_2\": \"quick decision making\",\n \"edge\": \"may face challenge\"\n }\n]", - "[\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"autonomous vehicle\",\n \"edge\": \"synonym\"\n },\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"self-driving car\",\n \"edge\": \"synonym\"\n },\n {\n \"node_1\": \"driverless car\",\n \"node_2\": \"autonomous vehicle\",\n \"edge\": \"synonym\"\n },\n {\n \"node_1\": \"challenges\",\n \"node_2\": \"liability\",\n \"edge\": \"related_to\"\n },\n {\n \"node_1\": \"challenges\",\n \"node_2\": \"cyber-attacks\",\n \"edge\": \"type_of\"\n },\n {\n \"node_1\": \"challenges\",\n \"node_2\": \"consumer concerns\",\n \"edge\": \"related_to\"\n },\n {\n \"node_1\": \"autonomous vehicle\",\n \"node_2\": \"sensors\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"autonomous vehicle\",\n \"node_2\": \"machine learning\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"autonomous vehicle\",\n \"node_2\": \"actuators\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"study\",\n \"node_2\": \"autonomous cars\",\n \"edge\": \"subject_of\"\n },\n {\n \"node_1\": \"industry\",\n \"node_2\": \"Waymo\",\n \"edge\": \"related_to\"\n },\n {\n \"node_1\": \"industry\",\n \"node_2\": \"Cruise\",\n \"edge\": \"related_to\"\n },\n {\n \"node_1\": \"industry\",\n \"node_2\": \"Argo AI\",\n \"edge\": \"related_to\"\n },\n {\n \"node_1\": \"technical challenges\",\n \"node_2\": \"solutions\",\n \"edge\": \"related_to\"\n }\n]", - "[\n {\n \"node_1\": \"Combination of sensors, actuators, machine learning systems and complex algorithms\",\n \"node_2\": \"Software\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Sensors\",\n \"node_2\": \"Real-time data\",\n \"edge\": \"gather\"\n },\n {\n \"node_1\": \"Surrounding environment\",\n \"node_2\": \"Geographical coordinates\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Surrounding environment\",\n \"node_2\": \"Speed and direction of the car\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Surrounding environment\",\n \"node_2\": \"Obstacles which the vehicle can encounter\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Car navigation system\",\n \"node_2\": \"GPS\",\n \"edge\": \"equipped with\"\n },\n {\n \"node_1\": \"Car navigation system\",\n \"node_2\": \"Geographic information system\",\n \"edge\": \"equipped with\"\n },\n {\n \"node_1\": \"Location system\",\n \"node_2\": \"INS\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Electronic map (EM)\",\n \"node_2\": \"Traffic and road facilities\",\n \"edge\": \"stores information about\"\n },\n {\n \"node_1\": \"HD map\",\n \"node_2\": \"Self-driving cars\",\n \"edge\": \"applicable to\"\n },\n {\n \"node_1\": \"Path planning\",\n \"node_2\": \"Map matching\",\n \"edge\": \"is primarily achieved by\"\n },\n {\n \"node_1\": \"Path planning\",\n \"node_2\": \"Car location\",\n \"edge\": \"calculates\"\n },\n {\n \"node_1\": \"Environment perception\",\n \"node_2\": \"Laser perception\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Environment perception\",\n \"node_2\": \"Visual perception\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Environment perception\",\n \"node_2\": \"Radar perception\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Laser perception\",\n \"node_2\": \"Reflection time\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Laser perception\",\n \"node_2\": \"Reflection signal strength\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Laser perception\",\n \"node_2\": \"Cloud data of target point\",\n \"edge\": \"generates\"\n },\n {\n \"node_1\": \"LIDAR\",\n \"node_2\": \"Laser pulses\",\n \"edge\": \"emits\"\n },\n {\n \"node_1\": \"LIDAR\",\n \"node_2\": \"Collisions\",\n \"edge\": \"uses for avoidance\"\n },\n {\n \"node_1\": \"LIDAR\",\n \"node_2\": \"Emergency braking\",\n \"edge\": \"uses for\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"Conference\",\n \"edge\": \"paper\"\n },\n {\n \"node_1\": \"IOP Conf. Series: Materials Science and Engineering\",\n \"node_2\": \"Journal\",\n \"edge\": \"published in\"\n },\n {\n \"node_1\": \"IOP Publishing\",\n \"node_2\": \"Publisher\",\n \"edge\": \"published by\"\n },\n {\n \"node_1\": \"Radar\",\n \"node_2\": \"Sensor\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Radar perception\",\n \"node_2\": \"Distance measurement\",\n \"edge\": \"method\"\n },\n {\n \"node_1\": \"Self-driving cars\",\n \"node_2\": \"Vehicles\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Vehicular ad-hoc networks (VANETs)\",\n \"node_2\": \"Mobile ad-hoc networks (MANETs)\",\n \"edge\": \"derived from\"\n },\n {\n \"node_1\": \"Vehicular ad-hoc networks (VANETs)\",\n \"node_2\": \"Connected cars\",\n \"edge\": \"used by\"\n },\n {\n \"node_1\": \"Autonomous car\",\n \"node_2\": \"Connected car technology\",\n \"edge\": \"uses same communication standard\"\n },\n {\n \"node_1\": \"Vehicle Automation\",\n \"node_2\": \"Classification\",\n \"edge\": \"based on\"\n },\n {\n \"node_1\": \"Level 3 - 4 Autonomy\",\n \"node_2\": \"Autonomous car\",\n \"edge\": \"corresponds to\"\n },\n {\n \"node_1\": \"Advanced Infotainment\",\n \"node_2\": \"Uncompressed ADAS\",\n \"edge\": \"requires\"\n },\n {\n \"node_1\": \"Network bandwidth\",\n \"node_2\": \"Advanced Infotainment\",\n \"edge\": \"requires\"\n },\n {\n \"node_1\": \"Mobile ad-hoc networks (MANETs)\",\n \"node_2\": \"Wireless network\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Autonomous car\",\n \"node_2\": \"Human integration\",\n \"edge\": \"level of involvement\"\n },\n {\n \"node_1\": \"Ad-hoc networks\",\n \"node_2\": \"Network architecture\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Real-time\",\n \"node_2\": \"Communication\",\n \"edge\": \"requirement\"\n },\n {\n \"node_1\": \"Redundant architecture\",\n \"node_2\": \"Self-driving cars\",\n \"edge\": \"requirement\"\n },\n {\n \"node_1\": \"Level 3 - 4 Autonomy\",\n \"node_2\": \"Autonomous car\",\n \"edge\": \"corresponds to\"\n }\n]", - "[\n {\n \"node_1\": \"National Highway Traffic Safety Admin\",\n \"node_2\": \"NHTSA\",\n \"edge\": \"organization\"\n },\n {\n \"node_1\": \"Electronic Stability Program\",\n \"node_2\": \"ESP\",\n \"edge\": \"acronym\"\n },\n {\n \"node_1\": \"Automatic Braking\",\n \"node_2\": \"Automatic Braking\",\n \"edge\": \"technology\"\n },\n {\n \"node_1\": \"Lane-keeping\",\n \"node_2\": \"Adaptive Cruise Control\",\n \"edge\": \"related_feature\"\n },\n {\n \"node_1\": \"Conditional Automation\",\n \"node_2\": \"Full Control\",\n \"edge\": \"conditional_dependency\"\n },\n {\n \"node_1\": \"Level 3\",\n \"node_2\": \"Driver\",\n \"edge\": \"human_dependency\"\n },\n {\n \"node_1\": \"Full Automation\",\n \"node_2\": \"Vehicle\",\n \"edge\": \"autonomous_function\"\n },\n {\n \"node_1\": \"VANET\",\n \"node_2\": \"Vehicular Ad hoc NETwork\",\n \"edge\": \"acronym\"\n },\n {\n \"node_1\": \"Notifications about crash\",\n \"node_2\": \"Prior warnings about accidents\",\n \"edge\": \"service\"\n },\n {\n \"node_1\": \"Recent developments\",\n \"node_2\": \"Applications and services\",\n \"edge\": \"related_development\"\n }\n]", - "[\n {\n \"node_1\": \"Network technology\",\n \"node_2\": \"Notifications\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Crash\",\n \"node_2\": \"Notifications\",\n \"edge\": \"provides\"\n },\n {\n \"node_1\": \"Prior warnings\",\n \"node_2\": \"Accidents\",\n \"edge\": \"provides\"\n },\n {\n \"node_1\": \"Construction\",\n \"node_2\": \"Roads\",\n \"edge\": \"on\"\n },\n {\n \"node_1\": \"Over-speed\",\n \"node_2\": \"Traffic signals\",\n \"edge\": \"implies\"\n },\n {\n \"node_1\": \"Warnings\",\n \"node_2\": \"Fog\",\n \"edge\": \"provides\"\n },\n {\n \"node_1\": \"Existence\",\n \"node_2\": \"Black-ice\",\n \"edge\": \"implies\"\n },\n {\n \"node_1\": \"Services\",\n \"node_2\": \"Location\",\n \"edge\": \"based on\"\n },\n {\n \"node_1\": \"Google\",\n \"node_2\": \"Connected car technology\",\n \"edge\": \"developed\"\n },\n {\n \"node_1\": \"Tesla\",\n \"node_2\": \"Autonomous car technology\",\n \"edge\": \"developed\"\n },\n {\n \"node_1\": \"Audi\",\n \"node_2\": \"Autonomous car technology\",\n \"edge\": \"developed\"\n },\n {\n \"node_1\": \"Ford\",\n \"node_2\": \"Smart parking\",\n \"edge\": \"offers\"\n },\n {\n \"node_1\": \"Ford\",\n \"node_2\": \"Emergency braking\",\n \"edge\": \"offers\"\n },\n {\n \"node_1\": \"Ford\",\n \"node_2\": \"Accident warning\",\n \"edge\": \"offers\"\n },\n {\n \"node_1\": \"Ford\",\n \"node_2\": \"Semi-automatic pilot driving\",\n \"edge\": \"offers\"\n },\n {\n \"node_1\": \"Microsoft\",\n \"node_2\": \"Autonomous cars\",\n \"edge\": \"partnered for\"\n },\n {\n \"node_1\": \"Toyota\",\n \"node_2\": \"Autonomous cars\",\n \"edge\": \"partnered for\"\n },\n {\n \"node_1\": \"Volvo\",\n \"node_2\": \"Autonomous cars\",\n \"edge\": \"partnered for\"\n },\n {\n \"node_1\": \"Apple\",\n \"node_2\": \"Autonomous car project\",\n \"edge\": \"partnered for\"\n },\n {\n \"node_1\": \"Uber\",\n \"node_2\": \"Autonomous car project\",\n \"edge\": \"partnered for\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"IOP Conf. Series: Materials Science and Engineering 1022 (2021) 012028\",\n \"edge\": \"cite\"\n },\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"Mercedes \u2013Benz\",\n \"edge\": \"collaborates with\"\n },\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"BMW\",\n \"edge\": \"collaborates with\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Alphabet Inc.\",\n \"edge\": \"subsiidiary of\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"driverless car technology company\",\n \"edge\": \"is a\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Level 5 of autonomy\",\n \"edge\": \"closest to\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Mountain View\",\n \"edge\": \"test location\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"San Francisco\",\n \"edge\": \"test location\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Palo Alto\",\n \"edge\": \"test location\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Phoenix\",\n \"edge\": \"test location\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Detroit\",\n \"edge\": \"test location\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Level 4 automated driving system\",\n \"edge\": \"develops\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"SAE International\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Jaguar I \u2013 Pace\",\n \"edge\": \"equips with\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"sensors\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Jaguar I \u2013 Pace\",\n \"node_2\": \"Waymo\",\n \"edge\": \"equipped by\"\n }\n]", - "[\n {\n \"node_1\": \"objects\",\n \"node_2\": \"vehicles\",\n \"edge\": \"containing\"\n },\n {\n \"node_1\": \"objects\",\n \"node_2\": \"construction equipment\",\n \"edge\": \"including\"\n },\n {\n \"node_1\": \"LIDAR system\",\n \"node_2\": \"vehicles\",\n \"edge\": \"equipped with\"\n },\n {\n \"node_1\": \"LIDAR system\",\n \"node_2\": \"millions of laser pulses\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"LIDAR system\",\n \"node_2\": \"360 degrees\",\n \"edge\": \"measuring\"\n },\n {\n \"node_1\": \"high-resolution vision system\",\n \"node_2\": \"cameras\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"high-resolution vision system\",\n \"node_2\": \"world\",\n \"edge\": \"seeing\"\n },\n {\n \"node_1\": \"radar system\",\n \"node_2\": \"objects\",\n \"edge\": \"tracking\"\n },\n {\n \"node_1\": \"radar system\",\n \"node_2\": \"wavelength\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"Waymo vehicles\",\n \"node_2\": \"sensors\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"Waymo vehicles\",\n \"node_2\": \"GPS\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"Waymo vehicles\",\n \"node_2\": \"audio detection system\",\n \"edge\": \"using\"\n },\n {\n \"node_1\": \"Waymo vehicles\",\n \"node_2\": \"Jaguar I - Pace\",\n \"edge\": \"modified\"\n },\n {\n \"node_1\": \"Jaguar I - Pace\",\n \"node_2\": \"29 cameras\",\n \"edge\": \"located\"\n }\n]", - "[\n {\n \"node_1\": \"Cruise\",\n \"node_2\": \"General Motors\",\n \"edge\": \"acquired by\"\n },\n {\n \"node_1\": \"Cruise\",\n \"node_2\": \"Chevrolet Bolt\",\n \"edge\": \"developing software for\"\n },\n {\n \"node_1\": \"Cruise\",\n \"node_2\": \"LIDAR sensors\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Cruise\",\n \"node_2\": \"Origin\",\n \"edge\": \"unveiled\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"allows for\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"steering wheel\",\n \"edge\": \"does not have\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"pedals\",\n \"edge\": \"does not have\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"level 5 autonomous driving\",\n \"edge\": \"able to achieve\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"1 million miles\",\n \"edge\": \"has a lifespan of\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"ride sharing service\",\n \"edge\": \"will be used as\"\n },\n {\n \"node_1\": \"Origin\",\n \"node_2\": \"owl\",\n \"edge\": \"is fitted with\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"fully integrated self-driving system\",\n \"edge\": \"developing\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"ride-sharing\",\n \"edge\": \"intended for\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Ford and Volkswagen\",\n \"edge\": \"working with\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"technology\",\n \"edge\": \"developing\"\n }\n]", - "[\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Ford\",\n \"edge\": \"collaboration\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Carnegie Mellon University\",\n \"edge\": \"partnership\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Ford Fusion Hybrid\",\n \"edge\": \"testing equipment\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Level-4 automation\",\n \"edge\": \"development focus\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"LIDAR\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"radar\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"cameras\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"softw are platform\",\n \"edge\": \"development\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Autonomous Vehicle Platform\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"machine learning algorithms\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"deep networks\",\n \"edge\": \"use\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"Carnegie Mellon University Argo AI Center for Autonomous Vehicle Research\",\n \"edge\": \"funding\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"redundant systems\",\n \"edge\": \"development\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"backup electrical power sources\",\n \"edge\": \"development\"\n },\n {\n \"node_1\": \"Argo AI\",\n \"node_2\": \"12-volt power system\",\n \"edge\": \"consideration\"\n },\n {\n \"node_1\": \"Ford\",\n \"node_2\": \"Volkswagen\",\n \"edge\": \"competition\"\n }\n]", - "[\n {\n \"node_1\": \"brake\",\n \"node_2\": \"pedal\",\n \"edge\": \"part_of\"\n },\n {\n \"node_1\": \"vehicle\",\n \"node_2\": \"brake\",\n \"edge\": \"equipped_with\"\n },\n {\n \"node_1\": \"vehicle\",\n \"node_2\": \"pedal\",\n \"edge\": \"has\"\n },\n {\n \"node_1\": \"vehicle\",\n \"node_2\": \"backup electrical power sources\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"sensor systems\",\n \"node_2\": \"vehicle\",\n \"edge\": \"used_on\"\n },\n {\n \"node_1\": \"Figure 2\",\n \"node_2\": \"sensor systems\",\n \"edge\": \"represents\"\n },\n {\n \"node_1\": \"sensor systems\",\n \"node_2\": \"Waymo\",\n \"edge\": \"provided_by\"\n },\n {\n \"node_1\": \"image\",\n \"node_2\": \"Figure 2\",\n \"edge\": \"is\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"IOP Conf. Series: Materials Science and Engineering 1022 (2021)\",\n \"edge\": \"Publication\"\n },\n {\n \"node_1\": \"IOP Conf. Series: Materials Science and Engineering 1022 (2021)\",\n \"node_2\": \"doi:10.1088/1757-899X/1022/1/012028\",\n \"edge\": \"Reference\"\n },\n {\n \"node_1\": \"Computers\",\n \"node_2\": \"Sensors\",\n \"edge\": \"Component of\"\n },\n {\n \"node_1\": \"Computers\",\n \"node_2\": \"Braking systems\",\n \"edge\": \"Component of\"\n },\n {\n \"node_1\": \"Computers\",\n \"node_2\": \"Steering systems\",\n \"edge\": \"Component of\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Reliability\",\n \"edge\": \"Requires\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Safety\",\n \"edge\": \"Requires\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Technical challenges\",\n \"edge\": \"Faces\"\n },\n {\n \"node_1\": \"Technical challenges\",\n \"node_2\": \"Full commercialization\",\n \"edge\": \"Barrier to\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Miles\",\n \"edge\": \"Relates to\"\n },\n {\n \"node_1\": \"Autonomous cars\",\n \"node_2\": \"Human driver\",\n \"edge\": \"Compared to\"\n },\n {\n \"node_1\": \"Safety report\",\n \"node_2\": \"General Motors\",\n \"edge\": \"Published by\"\n },\n {\n \"node_1\": \"Challenging / difficult miles\",\n \"node_2\": \"On-road situations\",\n \"edge\": \"Type of\"\n },\n {\n \"node_1\": \"Phoenix, AZ\",\n \"node_2\": \"San Francisco, CA\",\n \"edge\": \"Comparison\"\n }\n]", - "[\n {\n \"node_1\": \"California\",\n \"node_2\": \"law\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"California\",\n \"node_2\": \"state\",\n \"edge\": \"part of\"\n },\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"testing\",\n \"edge\": \"related to\"\n },\n {\n \"node_1\": \"Uber\",\n \"node_2\": \"fatal crash\",\n \"edge\": \"involved in\"\n },\n {\n \"node_1\": \"pedestrian\",\n \"node_2\": \"crash\",\n \"edge\": \"affected by\"\n },\n {\n \"node_1\": \"NTSB\",\n \"node_2\": \"report\",\n \"edge\": \"produced\"\n },\n {\n \"node_1\": \"automated emergency braking system\",\n \"node_2\": \"crash\",\n \"edge\": \"failed to prevent\"\n },\n {\n \"node_1\": \"pedestrian\",\n \"node_2\": \"identification\",\n \"edge\": \"failed\"\n },\n {\n \"node_1\": \"University of Michigan\",\n \"node_2\": \"Mcity\",\n \"edge\": \"runs\"\n },\n {\n \"node_1\": \"Mcity\",\n \"node_2\": \"autonomous car testing facility\",\n \"edge\": \"is\"\n },\n {\n \"node_1\": \"Mcity\",\n \"node_2\": \"ABC Test\",\n \"edge\": \"hosts\"\n },\n {\n \"node_1\": \"Mcity ABC Test\",\n \"node_2\": \"safety test\",\n \"edge\": \"is\"\n },\n {\n \"node_1\": \"Mcity ABC Test\",\n \"node_2\": \"automated vehicles\",\n \"edge\": \"evaluates\"\n },\n {\n \"node_1\": \"Accelerated evaluation\",\n \"node_2\": \"scenarios\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Accelerated evaluation\",\n \"node_2\": \"naturalistic driving data\",\n \"edge\": \"collects\"\n }\n]", - "[\n {\n \"node_1\": \"vehicles\",\n \"node_2\": \"public roads\",\n \"edge\": \"located on\"\n },\n {\n \"node_1\": \"driver behavior\",\n \"node_2\": \"challenging miles\",\n \"edge\": \"increased\"\n },\n {\n \"node_1\": \"be behavior competence\",\n \"node_2\": \"safety\",\n \"edge\": \"tests\"\n },\n {\n \"node_1\": \"scenarios\",\n \"node_2\": \"weather\",\n \"edge\": \"considered\"\n },\n {\n \"node_1\": \"lighting conditions\",\n \"node_2\": \"daytime\",\n \"edge\": \"tested\"\n },\n {\n \"node_1\": \"lighting conditions\",\n \"node_2\": \"night -time\",\n \"edge\": \"tested\"\n },\n {\n \"node_1\": \"radars\",\n \"node_2\": \"LIDARs\",\n \"edge\": \"tested\"\n },\n {\n \"node_1\": \"cameras\",\n \"node_2\": \"rain\",\n \"edge\": \"tested\"\n },\n {\n \"node_1\": \"cameras\",\n \"node_2\": \"snow\",\n \"edge\": \"tested\"\n },\n {\n \"node_1\": \"testing\",\n \"node_2\": \"scenarios\",\n \"edge\": \"selected\"\n },\n {\n \"node_1\": \"corner cases\",\n \"node_2\": \"extremities\",\n \"edge\": \"involves\"\n },\n {\n \"node_1\": \"corner cases\",\n \"node_2\": \"dark surroundings\",\n \"edge\": \"detect\"\n },\n {\n \"node_1\": \"cars\",\n \"node_2\": \"dark surroundings\",\n \"edge\": \"detect\"\n },\n {\n \"node_1\": \"joggers\",\n \"node_2\": \"street\",\n \"edge\": \"move\"\n },\n {\n \"node_1\": \"cyclists\",\n \"node_2\": \"busy traffic\",\n \"edge\": \"move\"\n },\n {\n \"node_1\": \"Autonomous systems\",\n \"node_2\": \"testing\",\n \"edge\": \"require\"\n },\n {\n \"node_1\": \"ISO 26262 standard\",\n \"node_2\": \"vehicle -guidance systems\",\n \"edge\": \"provides\"\n }\n]", - "[\n {\n \"node_1\": \"ISO 26262\",\n \"node_2\": \"Standard\",\n \"edge\": \"standard\"\n },\n {\n \"node_1\": \"Automotive industry\",\n \"node_2\": \"Industry\",\n \"edge\": \"industry\"\n },\n {\n \"node_1\": \"Complex set of requirements\",\n \"node_2\": \"Uncertainty\",\n \"edge\": \"causes\"\n },\n {\n \"node_1\": \"Machine learning\",\n \"node_2\": \"Technology\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Supervised learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Unsupervised learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Deep learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Semi-supervised learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Active learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Inductive learning\",\n \"node_2\": \"Machine learning\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Classifiers\",\n \"node_2\": \"Machine learning algorithms\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Large amount of data\",\n \"node_2\": \"Data\",\n \"edge\": \"amount\"\n },\n {\n \"node_1\": \"Testing process\",\n \"node_2\": \"Process\",\n \"edge\": \"part\"\n },\n {\n \"node_1\": \"Fail-operational system\",\n \"node_2\": \"System\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Redundant subsystems\",\n \"node_2\": \"Subsystems\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Fault injection techniques\",\n \"node_2\": \"Techniques\",\n \"edge\": \"type\"\n },\n {\n \"node_1\": \"Exposure to magnetic field\",\n \"node_2\": \"Fault injection\",\n \"edge\": \"causes\"\n },\n {\n \"node_1\": \"Trigger bit flips\",\n \"node_2\": \"Hardware faults\",\n \"edge\": \"triggers\"\n },\n {\n \"node_1\": \"Devices\",\n \"node_2\": \"Hardware\",\n \"edge\": \"includes\"\n },\n {\n \"node_1\": \"Defects\",\n \"node_2\": \"Hardware\",\n \"edge\": \"includes\"\n }\n]", - "[\n {\n \"node_1\": \"Autonomous vehicles\",\n \"node_2\": \"Orientation challenges\",\n \"edge\": \"causes\"\n },\n {\n \"node_1\": \"Dynamic situations on roads\",\n \"node_2\": \"Orientation challenges\",\n \"edge\": \"cause\"\n },\n {\n \"node_1\": \"Road diversions\",\n \"node_2\": \"Orientation challenges\",\n \"edge\": \"cause\"\n },\n {\n \"node_1\": \"Construction sites\",\n \"node_2\": \"Orientation challenges\",\n \"edge\": \"cause\"\n },\n {\n \"node_1\": \"Missing road signs and markings\",\n \"node_2\": \"Orientation challenges\",\n \"edge\": \"cause\"\n },\n {\n \"node_1\": \"Real-time image processing\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Machine learning approach\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Tesla vehicles\",\n \"node_2\": \"Real-time image processing\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"General Motors\",\n \"node_2\": \"L IDAR\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"Mercedes Benz\",\n \"node_2\": \"L IDAR\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"L IDAR\",\n \"node_2\": \"3-dimensional map\",\n \"edge\": \"creates\"\n },\n {\n \"node_1\": \"Vehicle-to-everything (V2X) suite\",\n \"node_2\": \"Smarter environments\",\n \"edge\": \"component\"\n },\n {\n \"node_1\": \"Volkswagen\",\n \"node_2\": \"Vehicle-to-everything (V2X) suite\",\n \"edge\": \"uses\"\n }\n]", - "[\n {\n \"node_1\": \"Volkswagen\",\n \"node_2\": \"vehicles\",\n \"edge\": \"owns\"\n },\n {\n \"node_1\": \"Vehicle-to-Infrastructure (V2I)\",\n \"node_2\": \"smart traffic lights\",\n \"edge\": \"uses\"\n },\n {\n \"node_1\": \"autonomous vehicles\",\n \"node_2\": \"complexity of autonomous vehicle systems\",\n \"edge\": \"reduces\"\n },\n {\n \"node_1\": \"liability\",\n \"node_2\": \"companies that design and develop these vehicles\",\n \"edge\": \"falls on\"\n },\n {\n \"node_1\": \"laws\",\n \"node_2\": \"autonomous vehicles on public roads\",\n \"edge\": \"addresses\"\n },\n {\n \"node_1\": \"concerns of a potential consumer\",\n \"node_2\": \"clear and concise policy\",\n \"edge\": \"requires\"\n },\n {\n \"node_1\": \"passengers\",\n \"node_2\": \"autonomous cars\",\n \"edge\": \"may impact the lives of\"\n },\n {\n \"node_1\": \"pedestrian\",\n \"node_2\": \"autonomous cars\",\n \"edge\": \"may put the life of\"\n },\n {\n \"node_1\": \"autonomous cars\",\n \"node_2\": \"passengers\",\n \"edge\": \"may put the lives of\"\n },\n {\n \"node_1\": \"decision-making\",\n \"node_2\": \"emergency situations\",\n \"edge\": \"involves\"\n }\n]\n", - "[\n {\n \"node_1\": \"Germany\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"is related to\"\n },\n {\n \"node_1\": \"German Ethics Commission\",\n \"node_2\": \"Autonomous and Connected Driving\",\n \"edge\": \"produced\"\n },\n {\n \"node_1\": \"Moral Machine Experiment\",\n \"node_2\": \"Moral attitudes\",\n \"edge\": \"influences\"\n },\n {\n \"node_1\": \"Stakeholders\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"are associated with\"\n },\n {\n \"node_1\": \"Financial challenges\",\n \"node_2\": \"Autonomous vehicle development\",\n \"edge\": \"is a challenge\"\n },\n {\n \"node_1\": \"Premium tier production vehicles\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"has\"\n },\n {\n \"node_1\": \"Autonomous vehicles\",\n \"node_2\": \"End-consumers\",\n \"edge\": \"has affordability issue\"\n },\n {\n \"node_1\": \"Sensors\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"are used in\"\n },\n {\n \"node_1\": \"Communication devices\",\n \"node_2\": \"Autonomous vehicles\",\n \"edge\": \"are used in\"\n }\n]", - "[\n{\n\"node_1\": \"autonomous vehicles\",\n\"node_2\": \"technology\",\n\"edge\": \"associated with\"\n},\n{\n\"node_1\": \"ride-sharing\",\n\"node_2\": \"model\",\n\"edge\": \"based on\"\n},\n{\n\"node_1\": \"robo-taxis\",\n\"node_2\": \"ride-sharing\",\n\"edge\": \"operate by\"\n},\n{\n\"node_1\": \"utilization rate\",\n\"node_2\": \"robo-taxis\",\n\"edge\": \"associated with\"\n},\n{\n\"node_1\": \"time spent\",\n\"node_2\": \"robo-taxis\",\n\"edge\": \"associated with\"\n},\n{\n\"node_1\": \"autonomous vehicles\",\n\"node_2\": \"affordability\",\n\"edge\": \"related to\"\n},\n{\n\"node_1\": \"future\",\n\"node_2\": \"autonomous vehicles\",\n\"edge\": \"dependent on\"\n},\n{\n\"node_1\": \"predictions\",\n\"node_2\": \"fully autonomous cars\",\n\"edge\": \"related to\"\n},\n{\n\"node_1\": \"utilize\",\n\"node_2\": \"autonomous technology\",\n\"edge\": \"required to\"\n},\n{\n\"node_1\": \"challenges\",\n\"node_2\": \"autonomous vehicle technology\",\n\"edge\": \"associated with\"\n},\n{\n\"node_1\": \"paper\",\n\"node_2\": \"autonomous vehicle technology\",\n\"edge\": \"provides insight into\"\n},\n{\n\"node_1\": \"references\",\n\"node_2\": \"autonomous vehicle technology\",\n\"edge\": \"related to\"\n}\n]", - "[\n {\n \"node_1\": \"Technology\",\n \"node_2\": \"Road Safety\",\n \"edge\": \"About\"\n },\n {\n \"node_1\": \"Road Safety\",\n \"node_2\": \"India\",\n \"edge\": \"Topic of\"\n },\n {\n \"node_1\": \"World Health Organization\",\n \"node_2\": \"Road Traffic Injuries\",\n \"edge\": \"Study\"\n },\n {\n \"node_1\": \"RAC Foundation\",\n \"node_2\": \"Parking Policy\",\n \"edge\": \"Research\"\n },\n {\n \"node_1\": \"Urooj S\",\n \"node_2\": \"Autonomous Cars\",\n \"edge\": \"Research\"\n },\n {\n \"node_1\": \"Farrell J\",\n \"node_2\": \"Global Positioning System\",\n \"edge\": \"Research\"\n },\n {\n \"node_1\": \"Zhao J\",\n \"node_2\": \"Self-Driving Car\",\n \"edge\": \"Research\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA\",\n \"node_2\": \"2020\",\n \"edge\": \"date\"\n },\n {\n \"node_1\": \"ICCRDA\",\n \"node_2\": \"IOP Conf. Series: Materials Science and Engineering 1022\",\n \"edge\": \"related work\"\n },\n {\n \"node_1\": \"IOP Conf. Series: Materials Science and Engineering 1022\",\n \"node_2\": \"doi:10.1088/1757-899X/1022/1/012028\",\n \"edge\": \"related work\"\n },\n {\n \"node_1\": \"IOP Publishing\",\n \"node_2\": \"doi:10.1088/1757-899X/1022/1/012028\",\n \"edge\": \"publisher\"\n },\n {\n \"node_1\": \"IEEE Spectrum\",\n \"node_2\": \"6 Key Connectivity Requirements of Autonomous Driving\",\n \"edge\": \"article\"\n },\n {\n \"node_1\": \"6 Key Connectivity Requirements of Autonomous Driving\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"key concept\"\n },\n {\n \"node_1\": \"IEEE Spectrum\",\n \"node_2\": \"transportation\",\n \"edge\": \"related field\"\n },\n {\n \"node_1\": \"transportation\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"field of study\"\n },\n {\n \"node_1\": \"Wikipedia\",\n \"node_2\": \"Vehicular ad-hoc network\",\n \"edge\": \"article\"\n },\n {\n \"node_1\": \"Vehicular ad-hoc network\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"related concept\"\n },\n {\n \"node_1\": \"Zeadally S\",\n \"node_2\": \"2018 Autonomous Cars: Research Results, Issues, and Future Challenges\",\n \"edge\": \"research work\"\n },\n {\n \"node_1\": \"Zeadally S\",\n \"node_2\": \"IEEE Communications Surveys & Tutorials\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"National Highway Traffic Safety Administration NHTSA\",\n \"node_2\": \"Automated Vehicles for Safety\",\n \"edge\": \"resource\"\n },\n {\n \"node_1\": \"Automated Vehicles for Safety\",\n \"node_2\": \"safety\",\n \"edge\": \"topic\"\n },\n {\n \"node_1\": \"National Highway Traffic Safety Administration NHTSA\",\n \"node_2\": \"technology\",\n \"edge\": \"related field\"\n },\n {\n \"node_1\": \"Guerrero-Ibanez J A\",\n \"node_2\": \"2015 Integration challenges of intelligent transportation systems with connected vehicle, cloud computing, and Internet of Things technologies\",\n \"edge\": \"research work\"\n },\n {\n \"node_1\": \"Contreras-Castillo J\",\n \"node_2\": \"2017 A seven-layered model architecture for Internet of Vehicles\",\n \"edge\": \"research work\"\n },\n {\n \"node_1\": \"Contreras-Castillo J\",\n \"node_2\": \"J. Inf. Telecommun.\",\n \"edge\": \"author\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"Waymo Safety Report\",\n \"edge\": \"resource\"\n },\n {\n \"node_1\": \"Waymo Safety Report\",\n \"node_2\": \"safety\",\n \"edge\": \"topic\"\n },\n {\n \"node_1\": \"Waymo\",\n \"node_2\": \"self-driving car\",\n \"edge\": \"related concept\"\n },\n {\n \"node_1\": \"Waymo Safety Report\",\n \"node_2\": \"safety\",\n \"edge\": \"related concept\"\n },\n {\n \"node_1\": \"Internet of Things\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"related concept\"\n },\n {\n \"node_1\": \"cloud computing\",\n \"node_2\": \"autonomous driving\",\n \"edge\": \"related concept\"\n }\n]", - "[\n {\n \"node_1\": \"Safety Report\",\n \"node_2\": \"Waymo\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Jaguar I-Pace\",\n \"node_2\": \"Waymo\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Autonomous Vehicle\",\n \"node_2\": \"Jaguar I-Pace\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"GM's Cruise Origin\",\n \"node_2\": \"Autonomous Vehicle\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Carnegie Mellon\",\n \"node_2\": \"Argo AI\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Center for Autonomous Vehicle Research\",\n \"node_2\": \"Carnegie Mellon\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Argo AI Safety Report\",\n \"node_2\": \"Argo AI\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Self-Driving Car\",\n \"node_2\": \"Autonomous Vehicle\",\n \"edge\": \"synonym\"\n },\n {\n \"node_1\": \"Mcity ABC Test\",\n \"node_2\": \"MCity\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Scenarios for Development, Test and Validation\",\n \"node_2\": \"Menzel\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Safety\",\n \"node_2\": \"Autonomous Vehicle\",\n \"edge\": \"related\"\n },\n {\n \"node_1\": \"Autonomous Vehicle Research\",\n \"node_2\": \"Carnegie Mellon\",\n \"edge\": \"related\"\n }\n]", - "[\n {\n \"node_1\": \"Automation\",\n \"node_2\": \"Vehicle\",\n \"edge\": \"part-of\"\n },\n {\n \"node_1\": \"Autonomous\",\n \"node_2\": \"Vehicle\",\n \"edge\": \"type-of\"\n },\n {\n \"node_1\": \"Test\",\n \"node_2\": \"Validation\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Scenarios\",\n \"node_2\": \"Development\",\n \"edge\": \"used-for\"\n },\n {\n \"node_1\": \"IEEE\",\n \"node_2\": \"Intelligent\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Symposium\",\n \"node_2\": \"Automated\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Challenges\",\n \"node_2\": \"Testing\",\n \"edge\": \"form-of\"\n },\n {\n \"node_1\": \"Validation\",\n \"node_2\": \"Systems\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Software\",\n \"node_2\": \"Validation\",\n \"edge\": \"used-in\"\n },\n {\n \"node_1\": \"Connected\",\n \"node_2\": \"IO\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Orientation\",\n \"node_2\": \"Problem\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Federal\",\n \"node_2\": \"Ministry\",\n \"edge\": \"part-of\"\n },\n {\n \"node_1\": \"Transport\",\n \"node_2\": \"Infrastrucuture\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Report\",\n \"node_2\": \"Driving\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Experiment\",\n \"node_2\": \"Machine\",\n \"edge\": \"related-to\"\n },\n {\n \"node_1\": \"Cost\",\n \"node_2\": \"Cars\",\n \"edge\": \"associated-with\"\n },\n {\n \"node_1\": \"Barrier\",\n \"node_2\": \"Implementation\",\n \"edge\": \"block-to\"\n }\n]", - "[\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"conference\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"ICCRDA 2020\",\n \"node_2\": \"conference proceedings\",\n \"edge\": \"is relation to\"\n },\n {\n \"node_1\": \"IOP Conf. Series: Materials Science and Engineering 1022\",\n \"node_2\": \"publisher\",\n \"edge\": \"is publisher of\"\n },\n {\n \"node_1\": \"IOP Conf. Series: Materials Science and Engineering 1022\",\n \"node_2\": \"journal\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"doi:10.1088/1757-899X/1022/1/012028\",\n \"node_2\": \"digital object identifier\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"Harvard Business Review\",\n \"node_2\": \"academic journal\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"Harvard Business Review\",\n \"node_2\": \"publication\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"the cost of self-driving cars\",\n \"node_2\": \"concept\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"the cost of self-driving cars\",\n \"node_2\": \"barrier\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"self-driving cars\",\n \"node_2\": \"technology\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"barrier\",\n \"node_2\": \"hurdle\",\n \"edge\": \"is synonym of\"\n },\n {\n \"node_1\": \"adoption\",\n \"node_2\": \"process\",\n \"edge\": \"is instance of\"\n },\n {\n \"node_1\": \"hbr.org\",\n \"node_2\": \"website\",\n \"edge\": \"is instance of\"\n }\n]"] + '[\n {\n "node_1": "IOP",\n "node_2": "Conference",\n "edge": "part of"\n ' + '},\n {\n "node_1": "Materials",\n "node_2": "Science",\n "edge": "related"\n ' + ' },\n {\n "node_1": "Engineering",\n "node_2": "Autonomous",\n "edge": ' + '"research focus"\n },\n {\n "node_1": "cars",\n "node_2": "Recent",' + '\n "edge": "development"\n },\n {\n "node_1": "Solutions",\n "node_2": ' + '"Possible",\n "edge": "type of"\n },\n {\n "node_1": "Sehajbir",' + '\n "node_2": "Singh",\n "edge": "author"\n },\n {\n "node_1": "Baljit",' + '\n "node_2": "Saini",\n "edge": "author"\n },\n {\n "node_1": ' + '"Autonomous",\n "node_2": "vehicles",\n "edge": "related"\n },\n {\n ' + '"node_1": "Wissam",\n "node_2": "Kontar",\n "edge": "author"\n },\n {\n ' + '"node_1": "Soyoung",\n "node_2": "Ahn",\n "edge": "author"\n },\n {\n ' + '"node_1": "Andrea",\n "node_2": "Hicks",\n "edge": "author"\n },\n {\n ' + '"node_1": "Modeling",\n "node_2": "heterogeneous",\n "edge": "method"\n },' + '\n {\n "node_1": "traffic",\n "node_2": "flow",\n "edge": "related"\n },' + '\n {\n "node_1": "self-stabilizing",\n "node_2": "autonomous",\n "edge": ' + '"type"\n },\n {\n "node_1": "vehicles",\n "node_2": "impact",\n "edge": ' + '"related"\n },\n {\n "node_1": "Residents\'",\n "node_2": "Choice",' + '\n "edge": "related"\n },\n {\n "node_1": "Network",\n "node_2": ' + '"Questionnaire",\n "edge": "type"\n },\n {\n "node_1": "Nanchang",' + '\n "node_2": "China",\n "edge": "location"\n },\n {\n "node_1": "Yating",' + '\n "node_2": "Huang",\n "edge": "author"\n },\n {\n "node_1": "Lixin",' + '\n "node_2": "Yan",\n "edge": "author"\n },\n {\n "node_1": "Article",' + '\n "node_2": "online",\n "edge": "platform"\n },\n {\n "node_1": "IP",' + '\n "node_2": "address",\n "edge": "location"\n },\n {\n "node_1": ' + '"updates",\n "node_2": "enhancements",\n "edge": "type"\n },\n {\n ' + '"node_1": "environ",\n "node_2": "implications",\n "edge": "related"\n }\n]', + '[\n {\n "node_1": "Autonomous cars",\n "node_2": "Developments",\n "edge": ' + '"Related"\n },\n {\n "node_1": "Autonomous cars",\n "node_2": "Challenges",' + '\n "edge": "Related"\n },\n {\n "node_1": "Autonomous cars",\n ' + '"node_2": "Solutions",\n "edge": "Related"\n },\n {\n "node_1": "Autonomous ' + 'cars",\n "node_2": "Technology",\n "edge": "TypeOf"\n },\n {\n ' + '"node_1": "Electric vehicles",\n "node_2": "Cars",\n "edge": "TypeOf"\n },' + '\n {\n "node_1": "Internal combustion engines",\n "node_2": "Technology",' + '\n "edge": "TypeOf"\n },\n {\n "node_1": "University",\n "node_2": ' + '"Lovely Professional University",\n "edge": "InstanceOf"\n },\n {\n "node_1": ' + '"School",\n "node_2": "School of Computer Science and Engineering",\n "edge": ' + '"InstanceOf"\n },\n {\n "node_1": "Person",\n "node_2": "Sehajbir Singh",' + '\n "edge": "InstanceOf"\n },\n {\n "node_1": "Person",\n "node_2": ' + '"Baljit Singh Saini",\n "edge": "InstanceOf"\n },\n {\n "node_1": "Journal",' + '\n "node_2": "IOP Conf. Series: Materials Science and Engineering",\n "edge": ' + '"InstanceOf"\n },\n {\n "node_1": "Year",\n "node_2": "2021",\n ' + '"edge": "InstanceOf"\n },\n {\n "node_1": "Year",\n "node_2": "2020",' + '\n "edge": "InstanceOf"\n },\n {\n "node_1": "Domain",\n "node_2": ' + '"Autonomous vehicle technology",\n "edge": "InstanceOf"\n }\n]', + '[\n {\n "node_1": "Technology",\n "node_2": "Challenges",\n "edge": ' + '"includes"\n },\n {\n "node_1": "History of the automobile",\n "node_2": "1885",' + '\n "edge": "dates to"\n },\n {\n "node_1": "Karl Benz",\n "node_2": "Benz ' + 'Patent-Motorwagen",\n "edge": "developed"\n },\n {\n "node_1": "Ford Motor ' + 'Company",\n "node_2": "Ford Model T",\n "edge": "produced"\n },\n {\n ' + '"node_1": "Ford\'s Piquette Avenue Assembly Plant",\n "node_2": "Ford Model T",' + '\n "edge": "assembled"\n },\n {\n "node_1": "Model T",\n "node_2": "Ford ' + 'Motor Company",\n "edge": "by"\n },\n {\n "node_1": "Detroit, Michigan",' + '\n "node_2": "Ford\'s Piquette Avenue Assembly Plant",\n "edge": "located"\n },' + '\n {\n "node_1": "Assembly line",\n "node_2": "Ford Motor Company",\n "edge": ' + '"used"\n },\n {\n "node_1": "Autonomous cars",\n "node_2": "Computer science",' + '\n "edge": "combine"\n },\n {\n "node_1": "Autonomous cars",\n "node_2": ' + '"Electrical engineering",\n "edge": "combine"\n },\n {\n "node_1": "Autonomous ' + 'cars",\n "node_2": "Mechanical engineering",\n "edge": "combine"\n },\n {\n ' + '"node_1": "Linriccan Wonder",\n "node_2": "1920s",\n "edge": "introduced"\n },' + '\n {\n "node_1": "Embedded-circuits",\n "node_2": "Electric cars",\n "edge": ' + '"powered"\n },\n {\n "node_1": "Mercedes-Benz",\n "node_2": "Robotic van",' + '\n "edge": "developed"\n },\n {\n "node_1": "Vision-guided systems",' + '\n "node_2": "Robotic van",\n "edge": "used"\n },\n {\n "node_1": "Modern ' + 'vehicles",\n "node_2": "Technologies",\n "edge": "use"\n },\n {\n "node_1": ' + '"Lane keep assist",\n "node_2": "Modern vehicles",\n "edge": "include"\n },' + '\n {\n "node_1": "Lane departure warning",\n "node_2": "Modern vehicles",' + '\n "edge": "include"\n },\n {\n "node_1": "Adaptive cruise control",' + '\n "node_2": "Modern vehicles",\n "edge": "include"\n },\n {\n "node_1": ' + '"World Health Organization",\n "node_2": "Road traffic injuries",\n "edge": "report"\n ' + ' },\n {\n "node_1": "February 2020",\n "node_2": "Road traffic injuries",' + '\n "edge": "report"\n }\n]', + '[\n {\n "node_1": "World Health Organization",\n "node_2": "report",\n "edge": ' + '"mentioned"\n },\n {\n "node_1": "road traffic injuries",\n "node_2": "deaths",' + '\n "edge": "caused by"\n },\n {\n "node_1": "human error",\n "node_2": "road ' + 'crashes",\n "edge": "attributed to"\n },\n {\n "node_1": "over-speeding",\n "node_2": ' + '"errors",\n "edge": "caused by"\n },\n {\n "node_1": "alcohol",\n "node_2": ' + '"errors",\n "edge": "caused by"\n },\n {\n "node_1": "distractions",\n "node_2": ' + '"errors",\n "edge": "caused by"\n },\n {\n "node_1": "non-usage of seatbelts",' + '\n "node_2": "errors",\n "edge": "caused by"\n },\n {\n "node_1": "seatbelts",' + '\n "node_2": "safety equipment",\n "edge": "includes"\n },\n {\n "node_1": "helmets",' + '\n "node_2": "safety equipment",\n "edge": "includes"\n },\n {\n "node_1": "autonomous ' + 'vehicle technology",\n "node_2": "transportation injuries",\n "edge": "reduces"\n },' + '\n {\n "node_1": "autonomous vehicle technology",\n "node_2": "deaths",\n "edge": ' + '"reduces"\n },\n {\n "node_1": "broad adoption",\n "node_2": "autonomous vehicle ' + 'technology",\n "edge": "advocates"\n },\n {\n "node_1": "increase",\n "node_2": ' + '"transportation injuries and deaths",\n "edge": "expected"\n },\n {\n "node_1": "drastic ' + 'reduction",\n "node_2": "transportation injuries and deaths",\n "edge": "expected"\n }\n]', + '[\n {\n "node_1": "ICCRDA",\n "node_2": "2020",\n "edge": "related to"\n },\n {\n ' + '"node_1": "ICCRDA",\n "node_2": "IOP Conf. Series: Materials Science and Engineering",' + '\n "edge": "related to"\n },\n {\n "node_1": "traffic congestion",\n "node_2": ' + '"reliability of traffic flow",\n "edge": "has impact on"\n },\n {\n "node_1": "RAC ' + 'foundation",\n "node_2": "report",\n "edge": "produced by"\n },\n {\n "node_1": ' + '"average car",\n "node_2": "parking time",\n "edge": "related to"\n },\n {\n ' + '"node_1": "autonomous cars",\n "node_2": "ride-sharing",\n "edge": "related to"\n },' + '\n {\n "node_1": "Cruise",\n "node_2": "Origin",\n "edge": "produces"\n },\n {\n ' + '"node_1": "Autonomous vehicles",\n "node_2": "delivery of goods",\n "edge": "can be used ' + 'for"\n },\n {\n "node_1": "autonomous cars",\n "node_2": "challenges in development",' + '\n "edge": "associated with"\n },\n {\n "node_1": "leg al framework",\n "node_2": ' + '"regulations for autonomous cars",\n "edge": "required for"\n },\n {\n "node_1": ' + '"autonomous system",\n "node_2": "quick decision making",\n "edge": "may face challenge"\n ' + "}\n]", + '[\n {\n "node_1": "autonomous cars",\n "node_2": "autonomous vehicle",\n "edge": ' + '"synonym"\n },\n {\n "node_1": "autonomous cars",\n "node_2": "self-driving car",' + '\n "edge": "synonym"\n },\n {\n "node_1": "driverless car",\n "node_2": "autonomous ' + 'vehicle",\n "edge": "synonym"\n },\n {\n "node_1": "challenges",\n "node_2": ' + '"liability",\n "edge": "related_to"\n },\n {\n "node_1": "challenges",\n "node_2": ' + '"cyber-attacks",\n "edge": "type_of"\n },\n {\n "node_1": "challenges",\n "node_2": ' + '"consumer concerns",\n "edge": "related_to"\n },\n {\n "node_1": "autonomous vehicle",' + '\n "node_2": "sensors",\n "edge": "uses"\n },\n {\n "node_1": "autonomous vehicle",' + '\n "node_2": "machine learning",\n "edge": "uses"\n },\n {\n "node_1": "autonomous ' + 'vehicle",\n "node_2": "actuators",\n "edge": "uses"\n },\n {\n "node_1": "study",' + '\n "node_2": "autonomous cars",\n "edge": "subject_of"\n },\n {\n "node_1": ' + '"industry",\n "node_2": "Waymo",\n "edge": "related_to"\n },\n {\n "node_1": ' + '"industry",\n "node_2": "Cruise",\n "edge": "related_to"\n },\n {\n "node_1": ' + '"industry",\n "node_2": "Argo AI",\n "edge": "related_to"\n },\n {\n "node_1": ' + '"technical challenges",\n "node_2": "solutions",\n "edge": "related_to"\n }\n]', + '[\n {\n "node_1": "Combination of sensors, actuators, machine learning systems and complex ' + 'algorithms",\n "node_2": "Software",\n "edge": "uses"\n },\n {\n "node_1": ' + '"Sensors",\n "node_2": "Real-time data",\n "edge": "gather"\n },\n {\n "node_1": ' + '"Surrounding environment",\n "node_2": "Geographical coordinates",\n "edge": "includes"\n ' + '},\n {\n "node_1": "Surrounding environment",\n "node_2": "Speed and direction of the car",' + '\n "edge": "includes"\n },\n {\n "node_1": "Surrounding environment",\n "node_2": ' + '"Obstacles which the vehicle can encounter",\n "edge": "includes"\n },\n {\n "node_1": "Car ' + 'navigation system",\n "node_2": "GPS",\n "edge": "equipped with"\n },\n {\n "node_1": ' + '"Car navigation system",\n "node_2": "Geographic information system",\n "edge": "equipped ' + 'with"\n },\n {\n "node_1": "Location system",\n "node_2": "INS",\n "edge": "uses"\n ' + '},\n {\n "node_1": "Electronic map (EM)",\n "node_2": "Traffic and road facilities",' + '\n "edge": "stores information about"\n },\n {\n "node_1": "HD map",\n "node_2": ' + '"Self-driving cars",\n "edge": "applicable to"\n },\n {\n "node_1": "Path planning",' + '\n "node_2": "Map matching",\n "edge": "is primarily achieved by"\n },\n {\n "node_1": ' + '"Path planning",\n "node_2": "Car location",\n "edge": "calculates"\n },\n {\n ' + '"node_1": "Environment perception",\n "node_2": "Laser perception",\n "edge": "uses"\n },' + '\n {\n "node_1": "Environment perception",\n "node_2": "Visual perception",\n "edge": ' + '"uses"\n },\n {\n "node_1": "Environment perception",\n "node_2": "Radar perception",' + '\n "edge": "uses"\n },\n {\n "node_1": "Laser perception",\n "node_2": "Reflection ' + 'time",\n "edge": "uses"\n },\n {\n "node_1": "Laser perception",\n "node_2": ' + '"Reflection signal strength",\n "edge": "uses"\n },\n {\n "node_1": "Laser perception",' + '\n "node_2": "Cloud data of target point",\n "edge": "generates"\n },\n {\n "node_1": ' + '"LIDAR",\n "node_2": "Laser pulses",\n "edge": "emits"\n },\n {\n "node_1": ' + '"LIDAR",\n "node_2": "Collisions",\n "edge": "uses for avoidance"\n },\n {\n ' + '"node_1": "LIDAR",\n "node_2": "Emergency braking",\n "edge": "uses for"\n }\n]', + '[\n {\n "node_1": "ICCRDA 2020",\n "node_2": "Conference",\n "edge": "paper"\n },' + '\n {\n "node_1": "IOP Conf. Series: Materials Science and Engineering",\n "node_2": ' + '"Journal",\n "edge": "published in"\n },\n {\n "node_1": "IOP Publishing",' + '\n "node_2": "Publisher",\n "edge": "published by"\n },\n {\n "node_1": "Radar",' + '\n "node_2": "Sensor",\n "edge": "uses"\n },\n {\n "node_1": "Radar perception",' + '\n "node_2": "Distance measurement",\n "edge": "method"\n },\n {\n "node_1": ' + '"Self-driving cars",\n "node_2": "Vehicles",\n "edge": "type"\n },\n {\n "node_1": ' + '"Vehicular ad-hoc networks (VANETs)",\n "node_2": "Mobile ad-hoc networks (MANETs)",\n "edge": ' + '"derived from"\n },\n {\n "node_1": "Vehicular ad-hoc networks (VANETs)",\n "node_2": ' + '"Connected cars",\n "edge": "used by"\n },\n {\n "node_1": "Autonomous car",' + '\n "node_2": "Connected car technology",\n "edge": "uses same communication standard"\n },' + '\n {\n "node_1": "Vehicle Automation",\n "node_2": "Classification",\n "edge": "based ' + 'on"\n },\n {\n "node_1": "Level 3 - 4 Autonomy",\n "node_2": "Autonomous car",' + '\n "edge": "corresponds to"\n },\n {\n "node_1": "Advanced Infotainment",\n "node_2": ' + '"Uncompressed ADAS",\n "edge": "requires"\n },\n {\n "node_1": "Network bandwidth",' + '\n "node_2": "Advanced Infotainment",\n "edge": "requires"\n },\n {\n "node_1": ' + '"Mobile ad-hoc networks (MANETs)",\n "node_2": "Wireless network",\n "edge": "type"\n },' + '\n {\n "node_1": "Autonomous car",\n "node_2": "Human integration",\n "edge": "level of ' + 'involvement"\n },\n {\n "node_1": "Ad-hoc networks",\n "node_2": "Network architecture",' + '\n "edge": "type"\n },\n {\n "node_1": "Real-time",\n "node_2": "Communication",' + '\n "edge": "requirement"\n },\n {\n "node_1": "Redundant architecture",\n "node_2": ' + '"Self-driving cars",\n "edge": "requirement"\n },\n {\n "node_1": "Level 3 - 4 Autonomy",' + '\n "node_2": "Autonomous car",\n "edge": "corresponds to"\n }\n]', + '[\n {\n "node_1": "National Highway Traffic Safety Admin",\n "node_2": "NHTSA",' + '\n "edge": "organization"\n },\n {\n "node_1": "Electronic Stability Program",' + '\n "node_2": "ESP",\n "edge": "acronym"\n },\n {\n "node_1": "Automatic ' + 'Braking",\n "node_2": "Automatic Braking",\n "edge": "technology"\n },\n {\n ' + '"node_1": "Lane-keeping",\n "node_2": "Adaptive Cruise Control",\n "edge": ' + '"related_feature"\n },\n {\n "node_1": "Conditional Automation",\n "node_2": "Full ' + 'Control",\n "edge": "conditional_dependency"\n },\n {\n "node_1": "Level 3",' + '\n "node_2": "Driver",\n "edge": "human_dependency"\n },\n {\n "node_1": ' + '"Full Automation",\n "node_2": "Vehicle",\n "edge": "autonomous_function"\n },' + '\n {\n "node_1": "VANET",\n "node_2": "Vehicular Ad hoc NETwork",\n "edge": ' + '"acronym"\n },\n {\n "node_1": "Notifications about crash",\n "node_2": "Prior ' + 'warnings about accidents",\n "edge": "service"\n },\n {\n "node_1": "Recent ' + 'developments",\n "node_2": "Applications and services",\n "edge": ' + '"related_development"\n }\n]', + '[\n {\n "node_1": "Network technology",\n "node_2": "Notifications",\n "edge": ' + '"includes"\n },\n {\n "node_1": "Crash",\n "node_2": "Notifications",\n "edge": ' + '"provides"\n },\n {\n "node_1": "Prior warnings",\n "node_2": "Accidents",\n "edge": ' + '"provides"\n },\n {\n "node_1": "Construction",\n "node_2": "Roads",\n "edge": ' + '"on"\n },\n {\n "node_1": "Over-speed",\n "node_2": "Traffic signals",\n "edge": ' + '"implies"\n },\n {\n "node_1": "Warnings",\n "node_2": "Fog",\n "edge": ' + '"provides"\n },\n {\n "node_1": "Existence",\n "node_2": "Black-ice",\n "edge": ' + '"implies"\n },\n {\n "node_1": "Services",\n "node_2": "Location",\n "edge": "based ' + 'on"\n },\n {\n "node_1": "Google",\n "node_2": "Connected car technology",\n "edge": ' + '"developed"\n },\n {\n "node_1": "Tesla",\n "node_2": "Autonomous car technology",' + '\n "edge": "developed"\n },\n {\n "node_1": "Audi",\n "node_2": "Autonomous car ' + 'technology",\n "edge": "developed"\n },\n {\n "node_1": "Ford",\n "node_2": "Smart ' + 'parking",\n "edge": "offers"\n },\n {\n "node_1": "Ford",\n "node_2": "Emergency ' + 'braking",\n "edge": "offers"\n },\n {\n "node_1": "Ford",\n "node_2": "Accident ' + 'warning",\n "edge": "offers"\n },\n {\n "node_1": "Ford",\n "node_2": "Semi-automatic ' + 'pilot driving",\n "edge": "offers"\n },\n {\n "node_1": "Microsoft",\n "node_2": ' + '"Autonomous cars",\n "edge": "partnered for"\n },\n {\n "node_1": "Toyota",' + '\n "node_2": "Autonomous cars",\n "edge": "partnered for"\n },\n {\n "node_1": ' + '"Volvo",\n "node_2": "Autonomous cars",\n "edge": "partnered for"\n },\n {\n ' + '"node_1": "Apple",\n "node_2": "Autonomous car project",\n "edge": "partnered for"\n },' + '\n {\n "node_1": "Uber",\n "node_2": "Autonomous car project",\n "edge": "partnered ' + 'for"\n }\n]', + '[\n {\n "node_1": "ICCRDA 2020",\n "node_2": "IOP Conf. Series: Materials Science and ' + 'Engineering 1022 (2021) 012028",\n "edge": "cite"\n },\n {\n "node_1": "ICCRDA 2020",' + '\n "node_2": "Mercedes \u2013Benz",\n "edge": "collaborates with"\n },\n {\n "node_1": ' + '"ICCRDA 2020",\n "node_2": "BMW",\n "edge": "collaborates with"\n },\n {\n "node_1": ' + '"Waymo",\n "node_2": "Alphabet Inc.",\n "edge": "subsiidiary of"\n },\n {\n "node_1": ' + '"Waymo",\n "node_2": "driverless car technology company",\n "edge": "is a"\n },\n {\n ' + '"node_1": "Waymo",\n "node_2": "Level 5 of autonomy",\n "edge": "closest to"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "Mountain View",\n "edge": "test location"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "San Francisco",\n "edge": "test location"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "Palo Alto",\n "edge": "test location"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "Phoenix",\n "edge": "test location"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "Detroit",\n "edge": "test location"\n },' + '\n {\n "node_1": "Waymo",\n "node_2": "Level 4 automated driving system",\n "edge": ' + '"develops"\n },\n {\n "node_1": "Waymo",\n "node_2": "SAE International",\n "edge": ' + '"related to"\n },\n {\n "node_1": "Waymo",\n "node_2": "Jaguar I \u2013 Pace",' + '\n "edge": "equips with"\n },\n {\n "node_1": "Waymo",\n "node_2": "sensors",' + '\n "edge": "uses"\n },\n {\n "node_1": "Jaguar I \u2013 Pace",\n "node_2": "Waymo",' + '\n "edge": "equipped by"\n }\n]', + '[\n {\n "node_1": "objects",\n "node_2": "vehicles",\n "edge": "containing"\n },' + '\n {\n "node_1": "objects",\n "node_2": "construction equipment",\n "edge": ' + '"including"\n },\n {\n "node_1": "LIDAR system",\n "node_2": "vehicles",\n "edge": ' + '"equipped with"\n },\n {\n "node_1": "LIDAR system",\n "node_2": "millions of laser ' + 'pulses",\n "edge": "using"\n },\n {\n "node_1": "LIDAR system",\n "node_2": "360 ' + 'degrees",\n "edge": "measuring"\n },\n {\n "node_1": "high-resolution vision system",' + '\n "node_2": "cameras",\n "edge": "using"\n },\n {\n "node_1": "high-resolution vision ' + 'system",\n "node_2": "world",\n "edge": "seeing"\n },\n {\n "node_1": "radar ' + 'system",\n "node_2": "objects",\n "edge": "tracking"\n },\n {\n "node_1": "radar ' + 'system",\n "node_2": "wavelength",\n "edge": "using"\n },\n {\n "node_1": "Waymo ' + 'vehicles",\n "node_2": "sensors",\n "edge": "using"\n },\n {\n "node_1": "Waymo ' + 'vehicles",\n "node_2": "GPS",\n "edge": "using"\n },\n {\n "node_1": "Waymo ' + 'vehicles",\n "node_2": "audio detection system",\n "edge": "using"\n },\n {\n ' + '"node_1": "Waymo vehicles",\n "node_2": "Jaguar I - Pace",\n "edge": "modified"\n },' + '\n {\n "node_1": "Jaguar I - Pace",\n "node_2": "29 cameras",\n "edge": "located"\n ' + "}\n]", + '[\n {\n "node_1": "Cruise",\n "node_2": "General Motors",\n "edge": "acquired by"\n ' + '},\n {\n "node_1": "Cruise",\n "node_2": "Chevrolet Bolt",\n "edge": "developing ' + 'software for"\n },\n {\n "node_1": "Cruise",\n "node_2": "LIDAR sensors",\n "edge": ' + '"uses"\n },\n {\n "node_1": "Cruise",\n "node_2": "Origin",\n "edge": "unveiled"\n ' + '},\n {\n "node_1": "Origin",\n "node_2": "autonomous driving",\n "edge": "allows ' + 'for"\n },\n {\n "node_1": "Origin",\n "node_2": "steering wheel",\n "edge": "does not ' + 'have"\n },\n {\n "node_1": "Origin",\n "node_2": "pedals",\n "edge": "does not ' + 'have"\n },\n {\n "node_1": "Origin",\n "node_2": "level 5 autonomous driving",' + '\n "edge": "able to achieve"\n },\n {\n "node_1": "Origin",\n "node_2": "1 million ' + 'miles",\n "edge": "has a lifespan of"\n },\n {\n "node_1": "Origin",\n "node_2": ' + '"ride sharing service",\n "edge": "will be used as"\n },\n {\n "node_1": "Origin",' + '\n "node_2": "owl",\n "edge": "is fitted with"\n },\n {\n "node_1": "Argo AI",' + '\n "node_2": "fully integrated self-driving system",\n "edge": "developing"\n },\n {\n ' + '"node_1": "Argo AI",\n "node_2": "ride-sharing",\n "edge": "intended for"\n },\n {\n ' + '"node_1": "Argo AI",\n "node_2": "Ford and Volkswagen",\n "edge": "working with"\n },' + '\n {\n "node_1": "Argo AI",\n "node_2": "technology",\n "edge": "developing"\n }\n]', + '[\n {\n "node_1": "Argo AI",\n "node_2": "Ford",\n "edge": ' + '"collaboration"\n },\n {\n "node_1": "Argo AI",\n "node_2": "Carnegie Mellon ' + 'University",\n "edge": "partnership"\n },\n {\n "node_1": "Argo AI",' + '\n "node_2": "Ford Fusion Hybrid",\n "edge": "testing equipment"\n },\n {\n ' + ' "node_1": "Argo AI",\n "node_2": "Level-4 automation",\n "edge": "development ' + 'focus"\n },\n {\n "node_1": "Argo AI",\n "node_2": "LIDAR",\n "edge": ' + '"use"\n },\n {\n "node_1": "Argo AI",\n "node_2": "radar",\n "edge": ' + '"use"\n },\n {\n "node_1": "Argo AI",\n "node_2": "cameras",\n ' + '"edge": "use"\n },\n {\n "node_1": "Argo AI",\n "node_2": "softw are ' + 'platform",\n "edge": "development"\n },\n {\n "node_1": "Argo AI",' + '\n "node_2": "Autonomous Vehicle Platform",\n "edge": "use"\n },\n {\n ' + '"node_1": "Argo AI",\n "node_2": "machine learning algorithms",\n "edge": "use"\n ' + ' },\n {\n "node_1": "Argo AI",\n "node_2": "deep networks",\n "edge": ' + '"use"\n },\n {\n "node_1": "Argo AI",\n "node_2": "Carnegie Mellon University ' + 'Argo AI Center for Autonomous Vehicle Research",\n "edge": "funding"\n },\n {\n ' + '"node_1": "Argo AI",\n "node_2": "redundant systems",\n "edge": "development"\n ' + '},\n {\n "node_1": "Argo AI",\n "node_2": "backup electrical power sources",' + '\n "edge": "development"\n },\n {\n "node_1": "Argo AI",\n "node_2": ' + '"12-volt power system",\n "edge": "consideration"\n },\n {\n "node_1": "Ford",' + '\n "node_2": "Volkswagen",\n "edge": "competition"\n }\n]', + '[\n {\n "node_1": "brake",\n "node_2": "pedal",\n "edge": "part_of"\n },\n {\n ' + '"node_1": "vehicle",\n "node_2": "brake",\n "edge": "equipped_with"\n },\n {\n ' + '"node_1": "vehicle",\n "node_2": "pedal",\n "edge": "has"\n },\n {\n "node_1": ' + '"vehicle",\n "node_2": "backup electrical power sources",\n "edge": "uses"\n },\n {\n ' + '"node_1": "sensor systems",\n "node_2": "vehicle",\n "edge": "used_on"\n },\n {\n ' + '"node_1": "Figure 2",\n "node_2": "sensor systems",\n "edge": "represents"\n },' + '\n {\n "node_1": "sensor systems",\n "node_2": "Waymo",\n "edge": "provided_by"\n },' + '\n {\n "node_1": "image",\n "node_2": "Figure 2",\n "edge": "is"\n }\n]', + '[\n {\n "node_1": "ICCRDA 2020",\n "node_2": "IOP Conf. Series: Materials Science ' + 'and Engineering 1022 (2021)",\n "edge": "Publication"\n },\n {\n "node_1": "IOP ' + 'Conf. Series: Materials Science and Engineering 1022 (2021)",\n "node_2": ' + '"doi:10.1088/1757-899X/1022/1/012028",\n "edge": "Reference"\n },\n {\n ' + '"node_1": "Computers",\n "node_2": "Sensors",\n "edge": "Component of"\n },' + '\n {\n "node_1": "Computers",\n "node_2": "Braking systems",\n "edge": ' + '"Component of"\n },\n {\n "node_1": "Computers",\n "node_2": "Steering ' + 'systems",\n "edge": "Component of"\n },\n {\n "node_1": "Autonomous cars",' + '\n "node_2": "Reliability",\n "edge": "Requires"\n },\n {\n "node_1": ' + '"Autonomous cars",\n "node_2": "Safety",\n "edge": "Requires"\n },\n {\n ' + ' "node_1": "Autonomous cars",\n "node_2": "Technical challenges",\n "edge": ' + '"Faces"\n },\n {\n "node_1": "Technical challenges",\n "node_2": "Full ' + 'commercialization",\n "edge": "Barrier to"\n },\n {\n "node_1": "Autonomous ' + 'cars",\n "node_2": "Miles",\n "edge": "Relates to"\n },\n {\n ' + '"node_1": "Autonomous cars",\n "node_2": "Human driver",\n "edge": "Compared to"\n ' + ' },\n {\n "node_1": "Safety report",\n "node_2": "General Motors",' + '\n "edge": "Published by"\n },\n {\n "node_1": "Challenging / difficult miles",' + '\n "node_2": "On-road situations",\n "edge": "Type of"\n },\n {\n ' + '"node_1": "Phoenix, AZ",\n "node_2": "San Francisco, CA",\n "edge": "Comparison"\n ' + " }\n]", + '[\n {\n "node_1": "California",\n "node_2": "law",\n "edge": "related to"\n },' + '\n {\n "node_1": "California",\n "node_2": "state",\n "edge": "part of"\n },' + '\n {\n "node_1": "autonomous cars",\n "node_2": "testing",\n "edge": "related to"\n ' + '},\n {\n "node_1": "Uber",\n "node_2": "fatal crash",\n "edge": "involved in"\n },' + '\n {\n "node_1": "pedestrian",\n "node_2": "crash",\n "edge": "affected by"\n },' + '\n {\n "node_1": "NTSB",\n "node_2": "report",\n "edge": "produced"\n },\n {\n ' + '"node_1": "automated emergency braking system",\n "node_2": "crash",\n "edge": "failed to ' + 'prevent"\n },\n {\n "node_1": "pedestrian",\n "node_2": "identification",\n "edge": ' + '"failed"\n },\n {\n "node_1": "University of Michigan",\n "node_2": "Mcity",' + '\n "edge": "runs"\n },\n {\n "node_1": "Mcity",\n "node_2": "autonomous car testing ' + 'facility",\n "edge": "is"\n },\n {\n "node_1": "Mcity",\n "node_2": "ABC Test",' + '\n "edge": "hosts"\n },\n {\n "node_1": "Mcity ABC Test",\n "node_2": "safety test",' + '\n "edge": "is"\n },\n {\n "node_1": "Mcity ABC Test",\n "node_2": "automated ' + 'vehicles",\n "edge": "evaluates"\n },\n {\n "node_1": "Accelerated evaluation",' + '\n "node_2": "scenarios",\n "edge": "includes"\n },\n {\n "node_1": "Accelerated ' + 'evaluation",\n "node_2": "naturalistic driving data",\n "edge": "collects"\n }\n]', + '[\n {\n "node_1": "vehicles",\n "node_2": "public roads",\n "edge": "located on"\n },' + '\n {\n "node_1": "driver behavior",\n "node_2": "challenging miles",\n "edge": ' + '"increased"\n },\n {\n "node_1": "be behavior competence",\n "node_2": "safety",' + '\n "edge": "tests"\n },\n {\n "node_1": "scenarios",\n "node_2": "weather",' + '\n "edge": "considered"\n },\n {\n "node_1": "lighting conditions",\n "node_2": ' + '"daytime",\n "edge": "tested"\n },\n {\n "node_1": "lighting conditions",\n "node_2": ' + '"night -time",\n "edge": "tested"\n },\n {\n "node_1": "radars",\n "node_2": ' + '"LIDARs",\n "edge": "tested"\n },\n {\n "node_1": "cameras",\n "node_2": "rain",' + '\n "edge": "tested"\n },\n {\n "node_1": "cameras",\n "node_2": "snow",' + '\n "edge": "tested"\n },\n {\n "node_1": "testing",\n "node_2": "scenarios",' + '\n "edge": "selected"\n },\n {\n "node_1": "corner cases",\n "node_2": "extremities",' + '\n "edge": "involves"\n },\n {\n "node_1": "corner cases",\n "node_2": "dark ' + 'surroundings",\n "edge": "detect"\n },\n {\n "node_1": "cars",\n "node_2": "dark ' + 'surroundings",\n "edge": "detect"\n },\n {\n "node_1": "joggers",\n "node_2": ' + '"street",\n "edge": "move"\n },\n {\n "node_1": "cyclists",\n "node_2": "busy ' + 'traffic",\n "edge": "move"\n },\n {\n "node_1": "Autonomous systems",\n "node_2": ' + '"testing",\n "edge": "require"\n },\n {\n "node_1": "ISO 26262 standard",\n "node_2": ' + '"vehicle -guidance systems",\n "edge": "provides"\n }\n]', + '[\n {\n "node_1": "ISO 26262",\n "node_2": "Standard",\n "edge": ' + '"standard"\n },\n {\n "node_1": "Automotive industry",\n "node_2": "Industry",' + '\n "edge": "industry"\n },\n {\n "node_1": "Complex set of requirements",' + '\n "node_2": "Uncertainty",\n "edge": "causes"\n },\n {\n "node_1": ' + '"Machine learning",\n "node_2": "Technology",\n "edge": "uses"\n },\n {\n ' + ' "node_1": "Supervised learning",\n "node_2": "Machine learning",\n "edge": ' + '"type"\n },\n {\n "node_1": "Unsupervised learning",\n "node_2": "Machine ' + 'learning",\n "edge": "type"\n },\n {\n "node_1": "Deep learning",' + '\n "node_2": "Machine learning",\n "edge": "type"\n },\n {\n "node_1": ' + '"Semi-supervised learning",\n "node_2": "Machine learning",\n "edge": "type"\n },' + '\n {\n "node_1": "Active learning",\n "node_2": "Machine learning",' + '\n "edge": "type"\n },\n {\n "node_1": "Inductive learning",\n ' + '"node_2": "Machine learning",\n "edge": "type"\n },\n {\n "node_1": ' + '"Classifiers",\n "node_2": "Machine learning algorithms",\n "edge": "uses"\n },' + '\n {\n "node_1": "Large amount of data",\n "node_2": "Data",\n "edge": ' + '"amount"\n },\n {\n "node_1": "Testing process",\n "node_2": "Process",' + '\n "edge": "part"\n },\n {\n "node_1": "Fail-operational system",' + '\n "node_2": "System",\n "edge": "type"\n },\n {\n "node_1": ' + '"Redundant subsystems",\n "node_2": "Subsystems",\n "edge": "type"\n },' + '\n {\n "node_1": "Fault injection techniques",\n "node_2": "Techniques",' + '\n "edge": "type"\n },\n {\n "node_1": "Exposure to magnetic field",' + '\n "node_2": "Fault injection",\n "edge": "causes"\n },\n {\n "node_1": ' + '"Trigger bit flips",\n "node_2": "Hardware faults",\n "edge": "triggers"\n },' + '\n {\n "node_1": "Devices",\n "node_2": "Hardware",\n "edge": ' + '"includes"\n },\n {\n "node_1": "Defects",\n "node_2": "Hardware",' + '\n "edge": "includes"\n }\n]', + '[\n {\n "node_1": "Autonomous vehicles",\n "node_2": "Orientation challenges",\n "edge": ' + '"causes"\n },\n {\n "node_1": "Dynamic situations on roads",\n "node_2": "Orientation ' + 'challenges",\n "edge": "cause"\n },\n {\n "node_1": "Road diversions",\n "node_2": ' + '"Orientation challenges",\n "edge": "cause"\n },\n {\n "node_1": "Construction sites",' + '\n "node_2": "Orientation challenges",\n "edge": "cause"\n },\n {\n "node_1": "Missing ' + 'road signs and markings",\n "node_2": "Orientation challenges",\n "edge": "cause"\n },' + '\n {\n "node_1": "Real-time image processing",\n "node_2": "Autonomous vehicles",' + '\n "edge": "uses"\n },\n {\n "node_1": "Machine learning approach",\n "node_2": ' + '"Autonomous vehicles",\n "edge": "uses"\n },\n {\n "node_1": "Tesla vehicles",' + '\n "node_2": "Real-time image processing",\n "edge": "uses"\n },\n {\n "node_1": ' + '"General Motors",\n "node_2": "L IDAR",\n "edge": "uses"\n },\n {\n "node_1": ' + '"Mercedes Benz",\n "node_2": "L IDAR",\n "edge": "uses"\n },\n {\n "node_1": "L ' + 'IDAR",\n "node_2": "3-dimensional map",\n "edge": "creates"\n },\n {\n "node_1": ' + '"Vehicle-to-everything (V2X) suite",\n "node_2": "Smarter environments",\n "edge": ' + '"component"\n },\n {\n "node_1": "Volkswagen",\n "node_2": "Vehicle-to-everything (V2X) ' + 'suite",\n "edge": "uses"\n }\n]', + '[\n {\n "node_1": "Volkswagen",\n "node_2": "vehicles",\n "edge": "owns"\n },' + '\n {\n "node_1": "Vehicle-to-Infrastructure (V2I)",\n "node_2": "smart traffic lights",' + '\n "edge": "uses"\n },\n {\n "node_1": "autonomous vehicles",\n "node_2": "complexity ' + 'of autonomous vehicle systems",\n "edge": "reduces"\n },\n {\n "node_1": "liability",' + '\n "node_2": "companies that design and develop these vehicles",\n "edge": "falls on"\n },' + '\n {\n "node_1": "laws",\n "node_2": "autonomous vehicles on public roads",\n "edge": ' + '"addresses"\n },\n {\n "node_1": "concerns of a potential consumer",\n "node_2": "clear and ' + 'concise policy",\n "edge": "requires"\n },\n {\n "node_1": "passengers",\n "node_2": ' + '"autonomous cars",\n "edge": "may impact the lives of"\n },\n {\n "node_1": "pedestrian",' + '\n "node_2": "autonomous cars",\n "edge": "may put the life of"\n },\n {\n "node_1": ' + '"autonomous cars",\n "node_2": "passengers",\n "edge": "may put the lives of"\n },' + '\n {\n "node_1": "decision-making",\n "node_2": "emergency situations",\n "edge": ' + '"involves"\n }\n]\n', + '[\n {\n "node_1": "Germany",\n "node_2": "Autonomous vehicles",\n "edge": "is related ' + 'to"\n },\n {\n "node_1": "German Ethics Commission",\n "node_2": "Autonomous and Connected ' + 'Driving",\n "edge": "produced"\n },\n {\n "node_1": "Moral Machine Experiment",' + '\n "node_2": "Moral attitudes",\n "edge": "influences"\n },\n {\n "node_1": ' + '"Stakeholders",\n "node_2": "Autonomous vehicles",\n "edge": "are associated with"\n },' + '\n {\n "node_1": "Financial challenges",\n "node_2": "Autonomous vehicle development",' + '\n "edge": "is a challenge"\n },\n {\n "node_1": "Premium tier production vehicles",' + '\n "node_2": "Autonomous vehicles",\n "edge": "has"\n },\n {\n "node_1": "Autonomous ' + 'vehicles",\n "node_2": "End-consumers",\n "edge": "has affordability issue"\n },\n {\n ' + '"node_1": "Sensors",\n "node_2": "Autonomous vehicles",\n "edge": "are used in"\n },' + '\n {\n "node_1": "Communication devices",\n "node_2": "Autonomous vehicles",\n "edge": ' + '"are used in"\n }\n]', + '[\n{\n"node_1": "autonomous vehicles",\n"node_2": "technology",\n"edge": "associated with"\n},' + '\n{\n"node_1": "ride-sharing",\n"node_2": "model",\n"edge": "based on"\n},\n{\n"node_1": ' + '"robo-taxis",\n"node_2": "ride-sharing",\n"edge": "operate by"\n},\n{\n"node_1": "utilization ' + 'rate",\n"node_2": "robo-taxis",\n"edge": "associated with"\n},\n{\n"node_1": "time spent",' + '\n"node_2": "robo-taxis",\n"edge": "associated with"\n},\n{\n"node_1": "autonomous vehicles",' + '\n"node_2": "affordability",\n"edge": "related to"\n},\n{\n"node_1": "future",\n"node_2": ' + '"autonomous vehicles",\n"edge": "dependent on"\n},\n{\n"node_1": "predictions",\n"node_2": ' + '"fully autonomous cars",\n"edge": "related to"\n},\n{\n"node_1": "utilize",\n"node_2": ' + '"autonomous technology",\n"edge": "required to"\n},\n{\n"node_1": "challenges",\n"node_2": ' + '"autonomous vehicle technology",\n"edge": "associated with"\n},\n{\n"node_1": "paper",' + '\n"node_2": "autonomous vehicle technology",\n"edge": "provides insight into"\n},\n{\n"node_1": ' + '"references",\n"node_2": "autonomous vehicle technology",\n"edge": "related to"\n}\n]', + '[\n {\n "node_1": "Technology",\n "node_2": "Road Safety",\n "edge": "About"\n },' + '\n {\n "node_1": "Road Safety",\n "node_2": "India",\n "edge": "Topic of"\n },' + '\n {\n "node_1": "World Health Organization",\n "node_2": "Road Traffic Injuries",' + '\n "edge": "Study"\n },\n {\n "node_1": "RAC Foundation",\n "node_2": "Parking ' + 'Policy",\n "edge": "Research"\n },\n {\n "node_1": "Urooj S",\n "node_2": "Autonomous ' + 'Cars",\n "edge": "Research"\n },\n {\n "node_1": "Farrell J",\n "node_2": "Global ' + 'Positioning System",\n "edge": "Research"\n },\n {\n "node_1": "Zhao J",\n "node_2": ' + '"Self-Driving Car",\n "edge": "Research"\n }\n]', + '[\n {\n "node_1": "ICCRDA",\n "node_2": "2020",\n "edge": "date"\n },' + '\n {\n "node_1": "ICCRDA",\n "node_2": "IOP Conf. Series: Materials Science and ' + 'Engineering 1022",\n "edge": "related work"\n },\n {\n "node_1": "IOP Conf. ' + 'Series: Materials Science and Engineering 1022",\n "node_2": ' + '"doi:10.1088/1757-899X/1022/1/012028",\n "edge": "related work"\n },\n {\n ' + '"node_1": "IOP Publishing",\n "node_2": "doi:10.1088/1757-899X/1022/1/012028",' + '\n "edge": "publisher"\n },\n {\n "node_1": "IEEE Spectrum",\n ' + '"node_2": "6 Key Connectivity Requirements of Autonomous Driving",\n "edge": "article"\n ' + '},\n {\n "node_1": "6 Key Connectivity Requirements of Autonomous Driving",\n ' + '"node_2": "autonomous driving",\n "edge": "key concept"\n },\n {\n "node_1": ' + '"IEEE Spectrum",\n "node_2": "transportation",\n "edge": "related field"\n },' + '\n {\n "node_1": "transportation",\n "node_2": "autonomous driving",' + '\n "edge": "field of study"\n },\n {\n "node_1": "Wikipedia",\n ' + '"node_2": "Vehicular ad-hoc network",\n "edge": "article"\n },\n {\n "node_1": ' + '"Vehicular ad-hoc network",\n "node_2": "autonomous driving",\n "edge": "related ' + 'concept"\n },\n {\n "node_1": "Zeadally S",\n "node_2": "2018 Autonomous Cars: ' + 'Research Results, Issues, and Future Challenges",\n "edge": "research work"\n },\n {\n ' + ' "node_1": "Zeadally S",\n "node_2": "IEEE Communications Surveys & Tutorials",' + '\n "edge": "author"\n },\n {\n "node_1": "National Highway Traffic Safety ' + 'Administration NHTSA",\n "node_2": "Automated Vehicles for Safety",\n "edge": ' + '"resource"\n },\n {\n "node_1": "Automated Vehicles for Safety",\n "node_2": ' + '"safety",\n "edge": "topic"\n },\n {\n "node_1": "National Highway Traffic ' + 'Safety Administration NHTSA",\n "node_2": "technology",\n "edge": "related field"\n ' + ' },\n {\n "node_1": "Guerrero-Ibanez J A",\n "node_2": "2015 Integration challenges ' + "of intelligent transportation systems with connected vehicle, cloud computing, and Internet of Things " + 'technologies",\n "edge": "research work"\n },\n {\n "node_1": ' + '"Contreras-Castillo J",\n "node_2": "2017 A seven-layered model architecture for Internet of ' + 'Vehicles",\n "edge": "research work"\n },\n {\n "node_1": "Contreras-Castillo ' + 'J",\n "node_2": "J. Inf. Telecommun.",\n "edge": "author"\n },\n {\n ' + '"node_1": "Waymo",\n "node_2": "Waymo Safety Report",\n "edge": "resource"\n },' + '\n {\n "node_1": "Waymo Safety Report",\n "node_2": "safety",\n "edge": ' + '"topic"\n },\n {\n "node_1": "Waymo",\n "node_2": "self-driving car",' + '\n "edge": "related concept"\n },\n {\n "node_1": "Waymo Safety Report",' + '\n "node_2": "safety",\n "edge": "related concept"\n },\n {\n "node_1": ' + '"Internet of Things",\n "node_2": "autonomous driving",\n "edge": "related ' + 'concept"\n },\n {\n "node_1": "cloud computing",\n "node_2": "autonomous ' + 'driving",\n "edge": "related concept"\n }\n]', + '[\n {\n "node_1": "Safety Report",\n "node_2": "Waymo",\n "edge": "related"\n },' + '\n {\n "node_1": "Jaguar I-Pace",\n "node_2": "Waymo",\n "edge": "related"\n },' + '\n {\n "node_1": "Autonomous Vehicle",\n "node_2": "Jaguar I-Pace",\n "edge": ' + '"related"\n },\n {\n "node_1": "GM\'s Cruise Origin",\n "node_2": "Autonomous Vehicle",' + '\n "edge": "related"\n },\n {\n "node_1": "Carnegie Mellon",\n "node_2": "Argo AI",' + '\n "edge": "related"\n },\n {\n "node_1": "Center for Autonomous Vehicle Research",' + '\n "node_2": "Carnegie Mellon",\n "edge": "related"\n },\n {\n "node_1": "Argo AI ' + 'Safety Report",\n "node_2": "Argo AI",\n "edge": "related"\n },\n {\n "node_1": ' + '"Self-Driving Car",\n "node_2": "Autonomous Vehicle",\n "edge": "synonym"\n },\n {\n ' + '"node_1": "Mcity ABC Test",\n "node_2": "MCity",\n "edge": "related"\n },\n {\n ' + '"node_1": "Scenarios for Development, Test and Validation",\n "node_2": "Menzel",\n "edge": ' + '"related"\n },\n {\n "node_1": "Safety",\n "node_2": "Autonomous Vehicle",\n "edge": ' + '"related"\n },\n {\n "node_1": "Autonomous Vehicle Research",\n "node_2": "Carnegie ' + 'Mellon",\n "edge": "related"\n }\n]', + '[\n {\n "node_1": "Automation",\n "node_2": "Vehicle",\n "edge": "part-of"\n },' + '\n {\n "node_1": "Autonomous",\n "node_2": "Vehicle",\n "edge": "type-of"\n },' + '\n {\n "node_1": "Test",\n "node_2": "Validation",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Scenarios",\n "node_2": "Development",\n "edge": "used-for"\n },' + '\n {\n "node_1": "IEEE",\n "node_2": "Intelligent",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Symposium",\n "node_2": "Automated",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Challenges",\n "node_2": "Testing",\n "edge": "form-of"\n },' + '\n {\n "node_1": "Validation",\n "node_2": "Systems",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Software",\n "node_2": "Validation",\n "edge": "used-in"\n },' + '\n {\n "node_1": "Connected",\n "node_2": "IO",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Orientation",\n "node_2": "Problem",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Federal",\n "node_2": "Ministry",\n "edge": "part-of"\n },' + '\n {\n "node_1": "Transport",\n "node_2": "Infrastrucuture",\n "edge": "related-to"\n ' + '},\n {\n "node_1": "Report",\n "node_2": "Driving",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Experiment",\n "node_2": "Machine",\n "edge": "related-to"\n },' + '\n {\n "node_1": "Cost",\n "node_2": "Cars",\n "edge": "associated-with"\n },' + '\n {\n "node_1": "Barrier",\n "node_2": "Implementation",\n "edge": "block-to"\n }\n]', + '[\n {\n "node_1": "ICCRDA 2020",\n "node_2": "conference",\n "edge": "is instance ' + 'of"\n },\n {\n "node_1": "ICCRDA 2020",\n "node_2": "conference proceedings",' + '\n "edge": "is relation to"\n },\n {\n "node_1": "IOP Conf. Series: Materials Science and ' + 'Engineering 1022",\n "node_2": "publisher",\n "edge": "is publisher of"\n },\n {\n ' + '"node_1": "IOP Conf. Series: Materials Science and Engineering 1022",\n "node_2": "journal",' + '\n "edge": "is instance of"\n },\n {\n "node_1": "doi:10.1088/1757-899X/1022/1/012028",' + '\n "node_2": "digital object identifier",\n "edge": "is instance of"\n },\n {\n ' + '"node_1": "Harvard Business Review",\n "node_2": "academic journal",\n "edge": "is instance ' + 'of"\n },\n {\n "node_1": "Harvard Business Review",\n "node_2": "publication",' + '\n "edge": "is instance of"\n },\n {\n "node_1": "the cost of self-driving cars",' + '\n "node_2": "concept",\n "edge": "is instance of"\n },\n {\n "node_1": "the cost of ' + 'self-driving cars",\n "node_2": "barrier",\n "edge": "is instance of"\n },\n {\n ' + '"node_1": "self-driving cars",\n "node_2": "technology",\n "edge": "is instance of"\n },' + '\n {\n "node_1": "barrier",\n "node_2": "hurdle",\n "edge": "is synonym of"\n },' + '\n {\n "node_1": "adoption",\n "node_2": "process",\n "edge": "is instance of"\n },' + '\n {\n "node_1": "hbr.org",\n "node_2": "website",\n "edge": "is instance of"\n }\n]', + ] for i, llm_output in enumerate(list_of_examples): assert transform_llm_output_to_dict(llm_output) != {} diff --git a/Project/frontend/package-lock.json b/Project/frontend/package-lock.json index cb69ed1..ad50fa9 100644 --- a/Project/frontend/package-lock.json +++ b/Project/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.15.20", "@mui/material": "^5.15.19", "@react-sigma/core": "4.0.2", "@sigma/edge-curve": "*", @@ -24,6 +25,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-filepond": "^7.1.2", + "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", "react-sigma": "*", "sigma": "3.0.0-beta.16", @@ -558,9 +560,9 @@ "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -574,9 +576,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -590,9 +592,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -606,9 +608,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -622,9 +624,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -638,9 +640,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -654,9 +656,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -670,9 +672,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -686,9 +688,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -702,9 +704,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -718,9 +720,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -734,9 +736,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -750,9 +752,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -766,9 +768,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -782,9 +784,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -798,9 +800,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -814,9 +816,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -830,9 +832,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -846,9 +848,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -862,9 +864,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -878,9 +880,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -894,9 +896,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -910,9 +912,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -1019,26 +1021,26 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", - "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.3.tgz", + "integrity": "sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==", "dependencies": { - "@floating-ui/utils": "^0.2.0" + "@floating-ui/utils": "^0.2.3" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", - "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.6.tgz", + "integrity": "sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==", "dependencies": { "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.0" + "@floating-ui/utils": "^0.2.3" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz", - "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", "dependencies": { "@floating-ui/dom": "^1.0.0" }, @@ -1048,9 +1050,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", - "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.3.tgz", + "integrity": "sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==" }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", @@ -1192,6 +1194,32 @@ "url": "https://opencollective.com/mui-org" } }, + "node_modules/@mui/icons-material": { + "version": "5.15.20", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.20.tgz", + "integrity": "sha512-oGcKmCuHaYbAAoLN67WKSXtHmEgyWcJToT1uRtmPyxMj9N5uqwc/mRtEnst4Wj/eGr+zYH2FiZQ79v9k7kSk1Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/material": { "version": "5.15.20", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.20.tgz", @@ -1439,9 +1467,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", - "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.17.0.tgz", + "integrity": "sha512-2D6XaHEVvkCn682XBnipbJjgZUU7xjLtA4dGJRBVUKpEaDYOZMENZoZjAOSb7qirxt5RupjzZxz4fK2FO+EFPw==", "engines": { "node": ">=14.0.0" } @@ -1655,9 +1683,9 @@ ] }, "node_modules/@sigma/edge-curve": { - "version": "3.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@sigma/edge-curve/-/edge-curve-3.0.0-beta.8.tgz", - "integrity": "sha512-NtHzNPdfIeK78NaVnr3MWALgVUB+zGrxgQWLG+2zcBiTRgb0sw+iybVjOrnrGpbmOQGct4PYGsS7s6MmqMWCRQ==", + "version": "3.0.0-beta.11", + "resolved": "https://registry.npmjs.org/@sigma/edge-curve/-/edge-curve-3.0.0-beta.11.tgz", + "integrity": "sha512-zE2VGfXk5Km2+yCeY+sm+tEi0Q7JBL1pVAJkDB545GRBLkzDlibWGNarrkaDroACTEdaMVyFSXDVVMrgs5qkkA==", "peerDependencies": { "sigma": ">=3.0.0-beta.10" } @@ -1716,9 +1744,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", - "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", + "version": "20.14.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz", + "integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1761,16 +1789,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", - "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz", + "integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/type-utils": "7.13.0", - "@typescript-eslint/utils": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/type-utils": "7.14.1", + "@typescript-eslint/utils": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1794,15 +1822,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", - "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", + "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4" }, "engines": { @@ -1822,13 +1850,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", - "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz", + "integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0" + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1839,13 +1867,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", - "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz", + "integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.13.0", - "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/typescript-estree": "7.14.1", + "@typescript-eslint/utils": "7.14.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1866,9 +1894,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", - "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz", + "integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1879,13 +1907,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", - "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz", + "integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/visitor-keys": "7.13.0", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/visitor-keys": "7.14.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1907,15 +1935,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", - "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", + "integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.13.0", - "@typescript-eslint/types": "7.13.0", - "@typescript-eslint/typescript-estree": "7.13.0" + "@typescript-eslint/scope-manager": "7.14.1", + "@typescript-eslint/types": "7.14.1", + "@typescript-eslint/typescript-estree": "7.14.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1929,12 +1957,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", - "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz", + "integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/types": "7.14.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1971,9 +1999,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2124,9 +2152,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001632", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001632.tgz", - "integrity": "sha512-udx3o7yHJfUxMLkGohMlVHCvFvWmirKh9JAH/d7WOLPetlH+LTL5cocMZ0t7oZx/mdlOWXti97xLZWc8uURRHg==", + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "dev": true, "funding": [ { @@ -2681,9 +2709,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.799", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.799.tgz", - "integrity": "sha512-3D3DwWkRTzrdEpntY0hMLYwj7SeBk1138CkPE8sBDSj3WzrzOiG2rHm3luw8jucpf+WiyLBCZyU9lMHyQI9M9Q==", + "version": "1.4.811", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz", + "integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA==", "dev": true }, "node_modules/error-ex": { @@ -2695,9 +2723,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -2707,29 +2735,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -3482,11 +3510,14 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4049,6 +4080,15 @@ "react-dom": "16 - 18" } }, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -4064,11 +4104,11 @@ } }, "node_modules/react-router": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", - "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "version": "6.24.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.24.0.tgz", + "integrity": "sha512-sQrgJ5bXk7vbcC4BxQxeNa5UmboFm35we1AFK0VvQaz9g0LzxEIuLOhHIoZ8rnu9BO21ishGeL9no1WB76W/eg==", "dependencies": { - "@remix-run/router": "1.16.1" + "@remix-run/router": "1.17.0" }, "engines": { "node": ">=14.0.0" @@ -4078,12 +4118,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", - "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "version": "6.24.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.24.0.tgz", + "integrity": "sha512-960sKuau6/yEwS8e+NVEidYQb1hNjAYM327gjEyXlc6r3Skf2vtwuJ2l7lssdegD2YjoKG5l8MsVyeTDlVeY8g==", "dependencies": { - "@remix-run/router": "1.16.1", - "react-router": "6.23.1" + "@remix-run/router": "1.17.0", + "react-router": "6.24.0" }, "engines": { "node": ">=14.0.0" @@ -4460,9 +4500,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -4579,12 +4619,12 @@ } }, "node_modules/vite": { - "version": "5.2.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", - "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.20.1", + "esbuild": "^0.21.3", "postcss": "^8.4.38", "rollup": "^4.13.0" }, diff --git a/Project/frontend/package.json b/Project/frontend/package.json index defeda8..ee3e5ab 100644 --- a/Project/frontend/package.json +++ b/Project/frontend/package.json @@ -13,6 +13,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.15.20", "@mui/material": "^5.15.19", "@react-sigma/core": "4.0.2", "@sigma/edge-curve": "*", @@ -27,6 +28,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-filepond": "^7.1.2", + "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", "react-sigma": "*", "sigma": "3.0.0-beta.16", diff --git a/Project/frontend/src/components/App/index.tsx b/Project/frontend/src/components/App/index.tsx index befdd81..c56dd26 100644 --- a/Project/frontend/src/components/App/index.tsx +++ b/Project/frontend/src/components/App/index.tsx @@ -1,20 +1,19 @@ import { BrowserRouter as Router, - Routes, - Route, Link as NavLink, + Route, + Routes, } from 'react-router-dom'; import { AppBar, - Toolbar, - Typography, + createTheme, CssBaseline, ThemeProvider, - createTheme, + Toolbar, + Typography, } from '@mui/material'; import logo from '../../assets/team-logo.png'; -import Home from '../Home'; import Graph from '../Graph/index_visjs'; import UploadPage from '../UploadPage'; import LandingPage from '../LandingPage'; diff --git a/Project/frontend/src/components/Graph/D3Graph.jsx b/Project/frontend/src/components/Graph/D3Graph.jsx new file mode 100644 index 0000000..c0e14a7 --- /dev/null +++ b/Project/frontend/src/components/Graph/D3Graph.jsx @@ -0,0 +1,145 @@ +import React, { useEffect, useRef } from 'react'; +import * as d3 from 'd3'; + +const D3Graph = ({ graphData, layout }) => { + const containerRef = useRef(null); + + useEffect(() => { + if (!graphData) return; + + // Set up SVG dimensions + const width = window.innerWidth; + const height = window.innerHeight - 50; + + // Clear previous graph + d3.select(containerRef.current).select('svg').remove(); + + // Create SVG element + const svg = d3.select(containerRef.current) + .append('svg') + .attr('width', width) + .attr('height', height) + .call(d3.zoom().on('zoom', (event) => { + svg.attr('transform', event.transform); + })) + .append('g'); + + // Set up the simulation + const simulation = d3.forceSimulation(graphData.nodes) + .force('link', d3.forceLink(graphData.edges).id(d => d.id).distance(100)) + .force('charge', d3.forceManyBody().strength(-300)) + .force('center', d3.forceCenter(width / 2, height / 2)); + + // Apply different layout algorithms + if (layout === 'hierarchical') { + simulation.force('y', d3.forceY().strength(0.1)); + simulation.force('x', d3.forceX().strength(0.1)); + } + + // Create links + const link = svg.append('g') + .attr('class', 'links') + .selectAll('line') + .data(graphData.edges) + .enter() + .append('line') + .attr('stroke-width', 2) + .attr('stroke', '#fff'); + + // Create link labels + const linkLabels = svg.append('g') + .attr('class', 'link-labels') + .selectAll('text') + .data(graphData.edges) + .enter() + .append('text') + .attr('class', 'link-label') + .attr('dx', 15) + .attr('dy', '.35em') + .text(d => d.label) // Correctly reading the label property for edges + .attr('fill', '#fff'); + + // Create nodes + const node = svg.append('g') + .attr('class', 'nodes') + .selectAll('circle') + .data(graphData.nodes) + .enter() + .append('circle') + .attr('r', 25) + .attr('fill', '#69b3a2') + .attr('stroke', '#508e7f') + .call(d3.drag() + .on('start', dragstarted) + .on('drag', dragged) + .on('end', dragended)); + + // Node labels + const nodeLabels = svg.append('g') + .attr('class', 'node-labels') + .selectAll('text') + .data(graphData.nodes) + .enter() + .append('text') + .attr('class', 'node-label') + .attr('dx', 15) + .attr('dy', '.35em') + .text(d => d.label) // Correctly reading the label property for nodes + .attr('fill', '#fff'); + + // Update simulation + simulation + .nodes(graphData.nodes) + .on('tick', ticked); + + simulation.force('link') + .links(graphData.edges); + + function ticked() { + link + .attr('x1', d => d.source.x) + .attr('y1', d => d.source.y) + .attr('x2', d => d.target.x) + .attr('y2', d => d.target.y); + + node + .attr('cx', d => d.x) + .attr('cy', d => d.y); + + nodeLabels + .attr('x', d => d.x) + .attr('y', d => d.y); + + linkLabels + .attr('x', d => (d.source.x + d.target.x) / 2) + .attr('y', d => (d.source.y + d.target.y) / 2); + } + + function dragstarted(event, d) { + if (!event.active) simulation.alphaTarget(0.3).restart(); + d.fx = d.x; + d.fy = d.y; + } + + function dragged(event, d) { + d.fx = event.x; + d.fy = event.y; + } + + function dragended(event, d) { + if (!event.active) simulation.alphaTarget(0); + d.fx = null; + d.fy = null; + } + + // Stabilize nodes after a certain time + setTimeout(() => { + simulation.alphaTarget(0).restart(); + }, 5000); // 5 seconds stabilization time + + }, [graphData, layout]); + + return
; +}; + +export default D3Graph; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/FloatingControlCard.jsx b/Project/frontend/src/components/Graph/FloatingControlCard.jsx new file mode 100644 index 0000000..568c794 --- /dev/null +++ b/Project/frontend/src/components/Graph/FloatingControlCard.jsx @@ -0,0 +1,315 @@ +import React from 'react'; +import { Card, CardContent, FormControl, InputLabel, Select, MenuItem, Slider, Typography, Box } from '@mui/material'; + +const FloatingControlCard = ({ layout, setLayout, physicsOptions, handlePhysicsChange, restartStabilization }) => { + const handleSliderChange = (name) => (event, value) => { + handlePhysicsChange(name, value); + restartStabilization(); + }; + + const renderSliders = () => { + switch (layout) { + case 'barnesHut': + return ( + + Gravitational Constant + + Spring Length + + Spring Constant + + Damping + + + ); + case 'forceAtlas2Based': + return ( + + Gravitational Constant + + Spring Length + + Spring Constant + + Damping + + + ); + case 'hierarchical': + return ( + + Level Separation + + Node Spacing + + Tree Spacing + + Block Shifting + + Edge Minimization + + Parent Centralization + + Direction + + Sort Method + + Shake Towards + + + ); + case 'repulsion': + return ( + + Node Distance + + Central Gravity + + Spring Length + + Spring Constant + + Damping + + + ); + default: + return null; + } + }; + + return ( + + + + Layout + + + {renderSliders()} + Stabilization Iterations + + + + ); + }; + + export default FloatingControlCard; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/FloatingControlCard_d3.jsx b/Project/frontend/src/components/Graph/FloatingControlCard_d3.jsx new file mode 100644 index 0000000..901b2db --- /dev/null +++ b/Project/frontend/src/components/Graph/FloatingControlCard_d3.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Card, CardContent, FormControl, InputLabel, Select, MenuItem, Box } from '@mui/material'; + +const FloatingControlCard = ({ layout, setLayout }) => { + return ( + + + + Layout + + + + + ); +}; + +export default FloatingControlCard; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/FloatingControlCard_sigma.jsx b/Project/frontend/src/components/Graph/FloatingControlCard_sigma.jsx new file mode 100644 index 0000000..628a9f0 --- /dev/null +++ b/Project/frontend/src/components/Graph/FloatingControlCard_sigma.jsx @@ -0,0 +1,113 @@ +import React from 'react'; +import { Card, CardContent, FormControl, InputLabel, Select, MenuItem, Slider, Typography, Box } from '@mui/material'; + +const FloatingControlCard = ({ layout, setLayout, physicsOptions, handlePhysicsChange }) => { + const handleSliderChange = (name) => (event, value) => { + handlePhysicsChange(name, value); + }; + + const renderSliders = () => { + return ( + + Iterations + + Barnes Hut Theta + + Gravity + + Scaling Ratio + + Edge Weight Influence + + Edge Length + + + ); + }; + + return ( + + + + Layout + + + {renderSliders()} + + + ); +}; + +export default FloatingControlCard; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/index.css b/Project/frontend/src/components/Graph/index.css index ec3e66e..2fa0a82 100644 --- a/Project/frontend/src/components/Graph/index.css +++ b/Project/frontend/src/components/Graph/index.css @@ -1,4 +1,11 @@ -.graph_container { +.container { + display: flex; + height: 100vh; + width: 100vw; +} + +.main_graph_container { + flex: 1; display: flex; flex-direction: column; gap: 50px; @@ -10,6 +17,39 @@ /* overflow: hidden; */ } +.graph_container { + flex: 1; + display: flex; + flex-direction: row; + gap: 50px; + text-align: center; + justify-content: flex-start; + height: 100vh; + width: 100vw; + + /* overflow: hidden; */ + +} + +.graph_info { + width: 25%; + padding: 20px; + overflow-y: auto; +} + +.graph_info h1 { + margin-bottom: 30px; + text-decoration: underline; +} + +.graph_info p { + margin-bottom: 30px; +} + +.search_container { + position: relative; +} + .sigma_container { background: var(--mui-palette-primary-main); } diff --git a/Project/frontend/src/components/Graph/index_sigma.tsx b/Project/frontend/src/components/Graph/index_sigma.tsx index 01399be..6a081b5 100644 --- a/Project/frontend/src/components/Graph/index_sigma.tsx +++ b/Project/frontend/src/components/Graph/index_sigma.tsx @@ -3,10 +3,7 @@ import { MultiDirectedGraph } from 'graphology'; import { SigmaContainer, useSigma } from '@react-sigma/core'; import { useParams } from 'react-router-dom'; import '@react-sigma/core/lib/react-sigma.min.css'; -import EdgeCurveProgram, { - DEFAULT_EDGE_CURVATURE, - indexParallelEdgesIndex, -} from '@sigma/edge-curve'; +import EdgeCurveProgram, { DEFAULT_EDGE_CURVATURE, indexParallelEdgesIndex } from '@sigma/edge-curve'; import { EdgeArrowProgram } from 'sigma/rendering'; import forceAtlas2 from 'graphology-layout-forceatlas2'; import './index.css'; @@ -44,8 +41,8 @@ const ForceAtlas2Layout = ({ maxIterations }) => { return null; }; -export default function Graph() { - const [graphData, setGraphData] = useState(null); +export default function GraphVisualization() { + const [graphData, setGraphData] = useState(null); const { fileId = '' } = useParams(); const [isLoading, setIsLoading] = useState(true); @@ -56,10 +53,7 @@ export default function Graph() { .then((graphData) => { const graph = new MultiDirectedGraph(); graphData?.nodes?.forEach( - (node: { - id: string; - [key: string]: string | number | boolean | null; - }) => { + (node) => { const { id, ...rest } = node; graph.addNode(id, { ...rest, @@ -70,10 +64,7 @@ export default function Graph() { }, ); graphData?.edges?.forEach( - (edge: { - id: string; - [key: string]: string | number | boolean | null; - }) => { + (edge) => { const { id, source, target, ...rest } = edge; graph.addEdgeWithKey(id, source, target, { ...rest, @@ -113,7 +104,7 @@ export default function Graph() { } if (!graphData) { return ( -
Sorry error has been occurred!
+
Sorry, an error has occurred!
); } return ( @@ -141,4 +132,4 @@ export default function Graph() { ); -} +} \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/index_visjs.tsx b/Project/frontend/src/components/Graph/index_visjs.tsx index ac9dbbe..14d4983 100644 --- a/Project/frontend/src/components/Graph/index_visjs.tsx +++ b/Project/frontend/src/components/Graph/index_visjs.tsx @@ -1,11 +1,20 @@ import React, { useEffect, useState, useRef } from 'react'; import { Network } from 'vis-network/standalone/esm/vis-network'; import { useParams } from 'react-router-dom'; +import FloatingControlCard from './FloatingControlCard'; import './index.css'; import { VISUALIZE_API_PATH } from '../../constant'; +import { CircularProgress, Typography, Box } from '@mui/material'; +import SearchIcon from '@mui/icons-material/Search'; +import TextField from '@mui/material/TextField'; +import { InputAdornment } from '@mui/material'; -const VisGraph = ({ graphData, options }) => { +const VisGraph = ({ graphData, options, setStabilizationComplete }) => { const containerRef = useRef(null); + const networkRef = useRef(null); + const [stabilizationProgress, setStabilizationProgress] = useState(0); + const [isStabilizing, setIsStabilizing] = useState(false); + const isStabilizingRef = useRef(false); useEffect(() => { if (!graphData) return; @@ -38,27 +47,66 @@ const VisGraph = ({ graphData, options }) => { })), }; + if (networkRef.current) { + networkRef.current.destroy(); + } + const network = new Network(containerRef.current, data, options); + networkRef.current = network; + + setIsStabilizing(true); + setStabilizationProgress(0); + isStabilizingRef.current = true; + + network.on('stabilizationProgress', function (params) { + const progress = (params.iterations / params.total) * 100; + setStabilizationProgress(progress); + }); - network.on('selectNode', function (params) { - network.setSelection({ - nodes: params.nodes, - edges: network.getConnectedEdges(params.nodes[0]), - }); + network.on('stabilizationIterationsDone', function () { + setStabilizationProgress(100); + setIsStabilizing(false); + setStabilizationComplete(true); + isStabilizingRef.current = false; + }); + + network.on('stabilized', function () { + if (isStabilizingRef.current) { + setStabilizationProgress(100); + setIsStabilizing(false); + setStabilizationComplete(true); + isStabilizingRef.current = false; + } }); - return () => network.destroy(); + return () => { + network.destroy(); + networkRef.current = null; + }; }, [graphData, options]); return ( -
+
+ {isStabilizing && ( + + + + Stabilizing... {Math.round(stabilizationProgress)}% + + + )} +
+
); }; @@ -67,25 +115,114 @@ const GraphVisualization = () => { const [graphData, setGraphData] = useState(null); const [isLoading, setIsLoading] = useState(true); const [layout, setLayout] = useState('barnesHut'); + const [stabilizationComplete, setStabilizationComplete] = useState(false); + const [physicsOptions, setPhysicsOptions] = useState({ + gravitationalConstant: -20000, + springLength: 100, + springConstant: 0.1, + damping: 0.09, + levelSeparation: 150, + nodeSpacing: 100, + treeSpacing: 200, + blockShifting: true, + edgeMinimization: true, + parentCentralization: true, + direction: 'UD', + sortMethod: 'hubsize', + shakeTowards: 'leaves', + iterations: 1000, // Stabilization iterations + }); - useEffect(() => { - const fetchGraphData = async () => { - try { - const response = await fetch( - `${import.meta.env.VITE_BACKEND_HOST}${VISUALIZE_API_PATH.replace(':fileId', fileId)}`, - ); - const data = await response.json(); - setGraphData(data); - } catch (error) { - console.error('Error fetching graph data:', error); - } finally { - setIsLoading(false); - } - }; + const fetchGraphData = async () => { + try { + const response = await fetch( + `${import.meta.env.VITE_BACKEND_HOST}${VISUALIZE_API_PATH.replace(':fileId', fileId)}`, + ); + const data = await response.json(); + setGraphData(data); + } catch (error) { + console.error('Error fetching graph data:', error); + } finally { + setIsLoading(false); + } + }; + useEffect(() => { fetchGraphData(); }, [fileId]); + useEffect(() => { + // Update physics options based on the selected layout + switch (layout) { + case 'barnesHut': + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + gravitationalConstant: -20000, + springLength: 100, + springConstant: 0.1, + damping: 0.09, + })); + break; + case 'forceAtlas2Based': + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + gravitationalConstant: -50, + springLength: 100, + springConstant: 0.08, + damping: 0.4, + })); + break; + case 'hierarchicalRepulsion': + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + gravitationalConstant: 0, + springLength: 120, + springConstant: 0, + damping: 0, + })); + break; + case 'repulsion': + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + gravitationalConstant: 0.2, + springLength: 200, + springConstant: 0.05, + damping: 0.09, + })); + break; + case 'hierarchical': + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + levelSeparation: 150, + nodeSpacing: 100, + treeSpacing: 200, + blockShifting: true, + edgeMinimization: true, + parentCentralization: true, + direction: 'UD', + sortMethod: 'hubsize', + shakeTowards: 'leaves', + })); + break; + default: + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + gravitationalConstant: -20000, + springLength: 100, + springConstant: 0.1, + damping: 0.09, + })); + } + }, [layout]); + + const handlePhysicsChange = (name, value) => { + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + [name]: value, + })); + setStabilizationComplete(false); + }; + const options = { nodes: { shape: 'dot', @@ -122,85 +259,81 @@ const GraphVisualization = () => { dragView: true, selectConnectedEdges: false, }, - physics: - layout === 'barnesHut' - ? { - enabled: true, - barnesHut: { - gravitationalConstant: -20000, - springLength: 100, - springConstant: 0.1, - }, - stabilization: { - iterations: 2500, - }, - } - : layout === 'forceAtlas2Based' - ? { - enabled: true, - forceAtlas2Based: { - gravitationalConstant: -50, - centralGravity: 0.01, - springConstant: 0.08, - springLength: 100, - damping: 0.4, - }, - stabilization: { - iterations: 2500, - }, - solver: 'forceAtlas2Based', - } - : layout === 'hierarchicalRepulsion' - ? { - enabled: true, - hierarchicalRepulsion: { - nodeDistance: 120, - }, - stabilization: { - iterations: 2500, - }, - } - : layout === 'repulsion' - ? { - enabled: true, - repulsion: { - nodeDistance: 200, - centralGravity: 0.2, - springLength: 50, - springConstant: 0.05, - damping: 0.09, - }, - stabilization: { - iterations: 2500, - }, - } - : layout === 'hierarchical' - ? { - enabled: true, - hierarchical: { - direction: 'UD', // UD, DU, LR, RL - sortMethod: 'hubsize', - }, - stabilization: { - iterations: 2500, - }, - } - : layout === 'grid' - ? { - enabled: false, - layout: { - hierarchical: false, - randomSeed: undefined, - improvedLayout: true, - }, - physics: { - enabled: false, - }, - } - : { - enabled: true, - randomSeed: 2, - }, + physics: { + enabled: true, + barnesHut: layout === 'barnesHut' ? { + gravitationalConstant: physicsOptions.gravitationalConstant, + centralGravity: 0.3, + springLength: physicsOptions.springLength, + springConstant: physicsOptions.springConstant, + damping: physicsOptions.damping, + avoidOverlap: 0.5, + } : undefined, + forceAtlas2Based: layout === 'forceAtlas2Based' ? { + gravitationalConstant: physicsOptions.gravitationalConstant, + centralGravity: 0.01, + springConstant: physicsOptions.springConstant, + springLength: physicsOptions.springLength, + damping: physicsOptions.damping, + } : undefined, + repulsion: layout === 'repulsion' ? { + nodeDistance: physicsOptions.nodeDistance, + centralGravity: physicsOptions.centralGravity, + springLength: physicsOptions.springLength, + springConstant: physicsOptions.springConstant, + damping: physicsOptions.damping, + } : undefined, + hierarchicalRepulsion: layout === 'hierarchicalRepulsion' ? { + nodeDistance: physicsOptions.nodeDistance, + centralGravity: 0.0, + springLength: physicsOptions.springLength, + springConstant: physicsOptions.springConstant, + damping: physicsOptions.damping, + } : undefined, + solver: layout === 'hierarchical' ? 'hierarchicalRepulsion' : layout, + stabilization: { + enabled: true, + iterations: physicsOptions.iterations, + updateInterval: 50, + onlyDynamicEdges: false, + fit: true, + adaptiveTimestep: true, + }, + timestep: 0.5, + }, + layout: layout === 'hierarchical' ? { + hierarchical: { + direction: physicsOptions.direction, + sortMethod: physicsOptions.sortMethod, + levelSeparation: physicsOptions.levelSeparation, + nodeSpacing: physicsOptions.nodeSpacing, + treeSpacing: physicsOptions.treeSpacing, + blockShifting: physicsOptions.blockShifting, + edgeMinimization: physicsOptions.edgeMinimization, + parentCentralization: physicsOptions.parentCentralization, + shakeTowards: physicsOptions.shakeTowards, + improvedLayout: false, + } + } : {} + }; + + const searchGraph = (event) => { + if (event.key === 'Enter') { + // Perform search logic based on searchQuery + } + }; + + const searchBarStyle = { + padding: '8px', + width: '100%', + marginBottom: '10px', + fontSize: '16px', + }; + + const answerAreaStyle = { + padding: '8px', + width: '100%', + fontSize: '16px', }; if (isLoading) { @@ -211,21 +344,65 @@ const GraphVisualization = () => { return
Sorry, an error has occurred!
; } + const formattedDate = new Date( + graphData.graph_created_at, + ).toLocaleDateString(); + + const formattedTime = new Date( + graphData.graph_created_at, + ).toLocaleTimeString(); + return ( -
-

Graph Visualization

- - +
+

Graph Visualization

+
+
+

Graph Information

+

+ Document Name:
{graphData.document_name} +

+ Created at:
{formattedDate} {formattedTime} +

+ + + + ), + }} + /> + +
+ + setStabilizationComplete(false)} + style={{ position: 'absolute', top: '10px', right: '10px', zIndex: 1000 }} + /> +
); }; -export default GraphVisualization; +export default GraphVisualization; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/index_visjs_d3.tsx b/Project/frontend/src/components/Graph/index_visjs_d3.tsx new file mode 100644 index 0000000..0a0e5f9 --- /dev/null +++ b/Project/frontend/src/components/Graph/index_visjs_d3.tsx @@ -0,0 +1,68 @@ +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import FloatingControlCard from './FloatingControlCard'; +import './index.css'; +import { VISUALIZE_API_PATH } from '../../constant'; +import D3Graph from './D3Graph'; +import { CircularProgress, Typography, Box } from '@mui/material'; + +const GraphVisualization = () => { + const { fileId = '' } = useParams(); + const [graphData, setGraphData] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [layout, setLayout] = useState('barnesHut'); + const [physicsOptions, setPhysicsOptions] = useState({ + gravitationalConstant: -20000, + springLength: 100, + springConstant: 0.1, + damping: 0.09, + }); + + const fetchGraphData = async () => { + try { + const response = await fetch( + `${import.meta.env.VITE_BACKEND_HOST}${VISUALIZE_API_PATH.replace(':fileId', fileId)}`, + ); + const data = await response.json(); + setGraphData(data); + } catch (error) { + console.error('Error fetching graph data:', error); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchGraphData(); + }, [fileId]); + + const handlePhysicsChange = (name, value) => { + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + [name]: value, + })); + }; + + if (isLoading) { + return
Loading graph...
; + } + + if (!graphData) { + return
Sorry, an error has occurred!
; + } + + return ( +
+

Graph Visualization

+ + +
+ ); +}; + +export default GraphVisualization; \ No newline at end of file diff --git a/Project/frontend/src/components/Graph/index_visjs_sigma.tsx b/Project/frontend/src/components/Graph/index_visjs_sigma.tsx new file mode 100644 index 0000000..fc0821d --- /dev/null +++ b/Project/frontend/src/components/Graph/index_visjs_sigma.tsx @@ -0,0 +1,167 @@ +import { useEffect, useState } from 'react'; +import { MultiDirectedGraph } from 'graphology'; +import { SigmaContainer, useSigma } from '@react-sigma/core'; +import { useParams } from 'react-router-dom'; +import '@react-sigma/core/lib/react-sigma.min.css'; +import EdgeCurveProgram, { DEFAULT_EDGE_CURVATURE, indexParallelEdgesIndex } from '@sigma/edge-curve'; +import { EdgeArrowProgram } from 'sigma/rendering'; +import forceAtlas2 from 'graphology-layout-forceatlas2'; +import FloatingControlCard from './FloatingControlCard_sigma'; +import './index.css'; +import { VISUALIZE_API_PATH } from '../../constant'; + +const ForceAtlas2Layout = ({ settings, onIteration, restart }) => { + const sigma = useSigma(); + const graph = sigma.getGraph(); + const [iterations, setIterations] = useState(0); + + useEffect(() => { + if (restart) { + setIterations(0); + } + + const applyLayout = () => { + forceAtlas2.assign(graph, { ...settings, adjustSizes: true }); + setIterations((prev) => { + const newIteration = prev + 1; + onIteration(newIteration); + return newIteration; + }); + }; + + if (iterations < settings.iterations) { + const interval = setInterval(applyLayout, 10); // Reduce interval for faster calculations + return () => clearInterval(interval); + } + }, [graph, iterations, settings, onIteration, restart]); + + return null; +}; + +export default function GraphVisualization() { + const [graphData, setGraphData] = useState(null); + const { fileId = '' } = useParams(); + const [isLoading, setIsLoading] = useState(true); + const [layout, setLayout] = useState('forceAtlas2Based'); + const [physicsOptions, setPhysicsOptions] = useState({ + iterations: 200, + barnesHutOptimize: true, + barnesHutTheta: 0.5, + slowDown: 0.1, // Faster calculations + gravity: 5, // Stronger gravity + scalingRatio: 10, + edgeWeightInfluence: 1, + strongGravityMode: true, + adjustSizes: true, + edgeLength: 100, // Added for edge length + }); + const [restart, setRestart] = useState(false); + + useEffect(() => { + const API = `${import.meta.env.VITE_BACKEND_HOST}${VISUALIZE_API_PATH.replace(':fileId', fileId)}`; + fetch(API) + .then((res) => res.json()) + .then((graphData) => { + const graph = new MultiDirectedGraph(); + graphData?.nodes?.forEach( + (node) => { + const { id, ...rest } = node; + graph.addNode(id, { + ...rest, + size: 15, // just for testing, i am making all the same size + x: Math.random() * 1000, + y: Math.random() * 1000, + }); + }, + ); + graphData?.edges?.forEach( + (edge) => { + const { id, source, target, ...rest } = edge; + graph.addEdgeWithKey(id, source, target, { + ...rest, + size: 2, // edge + length: physicsOptions.edgeLength, // Set edge length + }); + }, + ); + indexParallelEdgesIndex(graph, { + edgeIndexAttribute: 'parallelIndex', + edgeMaxIndexAttribute: 'parallelMaxIndex', + }); + graph.forEachEdge((edge, { parallelIndex, parallelMaxIndex }) => { + if (typeof parallelIndex === 'number') { + graph.mergeEdgeAttributes(edge, { + type: 'curved', + curvature: + DEFAULT_EDGE_CURVATURE + + (3 * DEFAULT_EDGE_CURVATURE * parallelIndex) / + (parallelMaxIndex || 1), + }); + } else { + graph.setEdgeAttribute(edge, 'type', 'straight'); + } + }); + setGraphData(graph); + }) + .catch((error) => { + console.log('Error fetching graphData:', error); + }) + .finally(() => { + setIsLoading(false); + }); + }, [fileId, physicsOptions.edgeLength]); // Re-fetch data when edge length changes + + const handlePhysicsChange = (name, value) => { + setPhysicsOptions((prevOptions) => ({ + ...prevOptions, + [name]: value, + })); + setRestart(true); + }; + + useEffect(() => { + if (restart) { + setRestart(false); + } + }, [restart]); + + if (isLoading) { + return
Loading graph...
; + } + if (!graphData) { + return ( +
Sorry, an error has occurred!
+ ); + } + return ( +
+

Graph Visualization

+ + + console.log(`Iteration: ${iteration}`)} restart={restart} /> + +
+ ); +} \ No newline at end of file diff --git a/Project/frontend/src/components/GraphList/index.css b/Project/frontend/src/components/GraphList/index.css index 5cab513..392ecdd 100644 --- a/Project/frontend/src/components/GraphList/index.css +++ b/Project/frontend/src/components/GraphList/index.css @@ -15,3 +15,7 @@ .error_graph_list { margin: 20px; } + +.main_action_button { + width: 150px; +} diff --git a/Project/frontend/src/components/GraphList/index.tsx b/Project/frontend/src/components/GraphList/index.tsx index 81df031..7f511b3 100644 --- a/Project/frontend/src/components/GraphList/index.tsx +++ b/Project/frontend/src/components/GraphList/index.tsx @@ -14,13 +14,16 @@ import Button from '@mui/material/Button'; import Stack from '@mui/material/Stack'; import { + GRAPH_DELETE_API_PATH, GRAPH_LIST_API_PATH, GraphStatus, - GRAPH_DELETE_API_PATH, - VISUALIZE_API_PATH, + // VISUALIZE_API_PATH, + GENERATE_API_PATH, + messageSeverity, } from '../../constant'; import './index.css'; +import CustomizedSnackbars from '../Snackbar'; interface IGraphList { id: string; @@ -31,6 +34,12 @@ interface IGraphList { updated_at: string | null; } +interface notification { + show: boolean; + severity: messageSeverity; + message: string; +} + const getStatus = (status: GraphStatus) => { if (status === GraphStatus.DOC_UPLOADED) { return 'Document uploaded'; @@ -45,10 +54,16 @@ const getDate = (isoDate: string) => { const GraphList = () => { const [list, setList] = React.useState([]); - const [offset, setOffset] = React.useState(0); - const [limit, setLimit] = React.useState(100); + const [offset] = React.useState(0); + const [limit] = React.useState(100); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); + const [generating, setGenerating] = React.useState(null); + const [notification, setNotification] = React.useState({ + show: false, + severity: messageSeverity.SUCCESS, + message: '', + }); React.useEffect(() => { fetchItems(offset, limit); @@ -78,6 +93,34 @@ const GraphList = () => { }); }; + const handleClick = () => { + setNotification({ + show: true, + severity: messageSeverity.SUCCESS, + message: 'message', + }); + }; + + //close notification + const handleClose = ( + event?: React.SyntheticEvent | Event, + reason?: string, + ) => { + if (reason === 'clickaway') { + return; + } + setNotification({ + show: false, + severity: notification.severity, + message: notification.message, + }); + }; + + //update notification variable to prompt notification + const notify = (n: notification) => { + setNotification(n); + }; + // makes call to delete api endpoint with graph_job_id and after that reloads the graph list const handleDelete = async (id: string) => { const API = `${import.meta.env.VITE_BACKEND_HOST}${GRAPH_DELETE_API_PATH.replace(':fileId', id)}`; @@ -95,69 +138,129 @@ const GraphList = () => { } }; + // makes call to generate endpoint with graph_job_id, notifies user about result and reloads graph list + const handleGenerate = async (id: string) => { + setGenerating(id); + const API = `${import.meta.env.VITE_BACKEND_HOST}${GENERATE_API_PATH.replace(':fileId', id)}`; + try { + await fetch(API, { + method: 'POST', + headers: { + 'Content-type': 'application/json; charset=UTF-8', + }, + body: JSON.stringify({ id }), + }); + fetchItems(offset, limit); + notify({ + show: true, + severity: messageSeverity.SUCCESS, + message: 'Success!', + }); + } catch (error) { + console.error('Error generating graph:', error); + notify({ + show: true, + severity: messageSeverity.ERROR, + message: 'Error!', + }); + } finally { + setGenerating(null); + } + }; + const navigate = useNavigate(); return ( - - {loading && ( - - -

Existing knowledge graphs list is loading...

-
- )} - {error && ( - - {error} - - )} - {!loading && !error && ( - - - - Name - Created at - Status - Actions - - - - {list.map((row) => ( - - - {row.name} - - {getDate(row.created_at)} - {getStatus(row.status)} - - - - - - +
+ + {loading && ( + + +

Existing knowledge graphs list is loading...

+
+ )} + {error && ( + + {error} + + )} + {!loading && !error && ( +
+ + + Name + Created at + Status + Actions - ))} - -
- )} -
+ + + {list.map((row) => ( + + + {row.name} + + {getDate(row.created_at)} + {getStatus(row.status)} + + + {row.status === GraphStatus.GRAPH_READY ? ( + + ) : ( + + )} + + + + + ))} + + + )} + + + ); }; diff --git a/Project/frontend/src/components/LandingPage/index.tsx b/Project/frontend/src/components/LandingPage/index.tsx index 2d51cd4..c37ef88 100644 --- a/Project/frontend/src/components/LandingPage/index.tsx +++ b/Project/frontend/src/components/LandingPage/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Typography, Container, Box, Button, Stack } from '@mui/material'; +import { Button, Container, Stack, Typography } from '@mui/material'; import GraphList from '../GraphList'; import { useNavigate } from 'react-router-dom'; diff --git a/Project/frontend/src/components/Snackbar/index.tsx b/Project/frontend/src/components/Snackbar/index.tsx index bfc8224..43bf2df 100644 --- a/Project/frontend/src/components/Snackbar/index.tsx +++ b/Project/frontend/src/components/Snackbar/index.tsx @@ -1,9 +1,24 @@ -// CustomizedSnackbars.js +// CustomizedSnackbars.tsx import * as React from 'react'; import Snackbar from '@mui/material/Snackbar'; import Alert from '@mui/material/Alert'; +import { messageSeverity } from '../../constant'; -function CustomizedSnackbars({ open, handleClick, handleClose }) { +interface CustomizedSnackbarsProps { + open: boolean; + handleClick: () => void; + handleClose: (event?: React.SyntheticEvent | Event, reason?: string) => void; + severity_value?: messageSeverity; + message?: string; +} + +const CustomizedSnackbars: React.FC = ({ + open, + handleClick, + handleClose, + message = 'Success!', + severity_value = messageSeverity.SUCCESS, +}) => { return (
- Success! + {message}
); -} +}; export default CustomizedSnackbars; diff --git a/Project/frontend/src/components/Upload/index.tsx b/Project/frontend/src/components/Upload/index.tsx index 84629b8..defb8d1 100644 --- a/Project/frontend/src/components/Upload/index.tsx +++ b/Project/frontend/src/components/Upload/index.tsx @@ -1,42 +1,74 @@ -import { FilePond, registerPlugin } from 'react-filepond'; +import { FilePond, registerPlugin, FilePondProps } from 'react-filepond'; import 'filepond/dist/filepond.min.css'; import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'; +import { GRAPH_DELETE_API_PATH, UPLOAD_API_PATH } from '../../constant'; + import './index.css'; -import { UPLOAD_API_PATH } from '../../constant'; registerPlugin(FilePondPluginFileValidateType); -interface FilePondFile { - serverId: string; -} - -interface FilePondError { - message: string; - code: number; +export interface IFile { + id: string; + file_location: string; + file_name: string; + status: string; } type UploadProps = { - handleAddFile: (error: FilePondError | null, file: FilePondFile) => void; - handleRemoveFile: () => void; - pondRef: React.RefObject; + handleAddFile: FilePondProps['onprocessfile']; + handleRemoveFile: FilePondProps['onremovefile']; + handleDeleteFile: () => void; + pondRef: React.RefObject; }; function Upload(props: UploadProps) { + const server: FilePondProps['server'] = { + url: `${import.meta.env.VITE_BACKEND_HOST}`, + process: { + url: `${UPLOAD_API_PATH}`, + method: 'POST', + onload: (response) => { + return JSON.parse(response).id; + }, + onerror: (err) => { + const parsedError = err ? JSON.parse(err).detail : ''; + const errMessage = parsedError.includes('already been uploaded') + ? 'File name already exists' + : 'Error during upload'; + return errMessage; + }, + }, + revert: (fileId, load, error) => { + const API = `${import.meta.env.VITE_BACKEND_HOST}${GRAPH_DELETE_API_PATH.replace(':fileId', fileId)}`; + fetch(API, { + method: 'DELETE', + }).then((response) => { + if (response.ok) { + load(); + props.handleDeleteFile(); + } else { + error('Error deleting file'); + } + }); + }, + }; + + const handleFileProcess: FilePondProps['onprocessfile'] = (error, file) => + props.handleAddFile?.(error, file); + return (
- props.handleAddFile(error as FilePondError, file as FilePondFile) - } + onprocessfile={handleFileProcess} onremovefile={props.handleRemoveFile} + labelFileProcessingError={(error) => error.body} />
); diff --git a/Project/frontend/src/components/UploadPage/index.css b/Project/frontend/src/components/UploadPage/index.css index 0e083f1..c3bb208 100644 --- a/Project/frontend/src/components/UploadPage/index.css +++ b/Project/frontend/src/components/UploadPage/index.css @@ -9,6 +9,6 @@ .buttons_container { display: flex; align-items: center; - justify-content: space-between; + justify-content: flex-end; width: 100%; } diff --git a/Project/frontend/src/components/UploadPage/index.tsx b/Project/frontend/src/components/UploadPage/index.tsx index b68341c..c5eecd3 100644 --- a/Project/frontend/src/components/UploadPage/index.tsx +++ b/Project/frontend/src/components/UploadPage/index.tsx @@ -1,55 +1,40 @@ -import { useRef, useState } from 'react'; +import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import { FilePondProps } from 'react-filepond'; +import { Box, Button, CircularProgress, Typography } from '@mui/material'; +import { GENERATE_API_PATH, GraphStatus } from '../../constant'; +import CustomizedSnackbars from '../Snackbar'; import Upload from '../Upload'; import './index.css'; -import { - GENERATE_API_PATH, - GRAPH_DELETE_API_PATH, - GraphStatus, -} from '../../constant'; -import CustomizedSnackbars from '../Snackbar'; -import { Box, Button, CircularProgress, Typography } from '@mui/material'; - -interface UploadedFile { - serverId: string; -} - -interface FilePondError { - message: string; - code: number; -} function UploadPage() { const [fileId, setFileId] = useState(''); const [isGenerating, setIsGenerating] = useState(false); - const [isDeleting, setIsDeleting] = useState(false); const navigate = useNavigate(); - const [open, setOpen] = useState(false); - const pondRef = useRef(null); + const [showSnackbar, setShowSnackbar] = useState(false); - const handleAddFile = (error: FilePondError | null, file: UploadedFile) => { + const handleAddFile: FilePondProps['onprocessfile'] = (error, file) => { if (!error) { - const fileId = JSON.parse(file.serverId).id; - setFileId(fileId); + setFileId(file.serverId); } else { - console.log('Error:', error.message); + console.log('Error:', error); } }; const handleClick = () => { - setOpen(true); + setShowSnackbar(true); }; const handleClose = ( - event?: React.SyntheticEvent | Event, + _event?: React.SyntheticEvent | Event, reason?: string, ) => { if (reason === 'clickaway') { return; } - setOpen(false); + setShowSnackbar(false); }; const notifySuccess = () => { @@ -58,9 +43,11 @@ function UploadPage() { const handleRemoveFile = () => { setFileId(''); - if (pondRef.current) { - pondRef.current.removeFiles(); - } + }; + + const handleDeleteGraph = () => { + handleRemoveFile(); + notifySuccess(); }; const handleGenerateGraph = () => { @@ -87,29 +74,6 @@ function UploadPage() { }); }; - const handleDeleteGraph = () => { - setIsDeleting(true); - - const API = `${import.meta.env.VITE_BACKEND_HOST}${GRAPH_DELETE_API_PATH.replace(':fileId', fileId)}`; - fetch(API, { - method: 'DELETE', - headers: { - 'Content-type': 'application/json; charset=UTF-8', - }, - }) - .then((response) => response.json()) - .then(() => { - handleRemoveFile(); - notifySuccess(); - }) - .catch((e) => { - console.log(e); - }) - .finally(() => { - setIsDeleting(false); - }); - }; - return (
- -
@@ -167,4 +115,4 @@ function UploadPage() { ); } -export default UploadPage; \ No newline at end of file +export default UploadPage; diff --git a/Project/frontend/src/constant.ts b/Project/frontend/src/constant.ts index 54128b2..c9b2cdd 100644 --- a/Project/frontend/src/constant.ts +++ b/Project/frontend/src/constant.ts @@ -8,3 +8,10 @@ export enum GraphStatus { DOC_UPLOADED = 'document_uploaded', GRAPH_READY = 'graph_ready', } + +export enum messageSeverity { + ERROR = 'error', + SUCCESS = 'success', + WARNING = 'info', + INFO = 'success', +} diff --git a/Project/frontend/src/vite-env.d.ts b/Project/frontend/src/vite-env.d.ts index 8ad87b5..aa19ff1 100644 --- a/Project/frontend/src/vite-env.d.ts +++ b/Project/frontend/src/vite-env.d.ts @@ -1,5 +1,4 @@ /// -declare module 'react-filepond'; declare module 'filepond-plugin-file-validate-size'; declare module 'filepond-plugin-file-validate-type'; declare module 'filepond-plugin-file-poster'; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..cdd4e23 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,102 @@ +{ + "name": "amos2024ss05-knowledge-graph-extractor", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/graphology-types": { + "version": "0.24.7", + "resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.7.tgz", + "integrity": "sha512-tdcqOOpwArNjEr0gNQKCXwaNCWnQJrog14nJNQPeemcLnXQUUGrsCWpWkVKt46zLjcS6/KGoayeJfHHyPDlvwA==", + "peer": true + }, + "node_modules/graphology-utils": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/graphology-utils/-/graphology-utils-2.5.2.tgz", + "integrity": "sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ==", + "peerDependencies": { + "graphology-types": ">=0.23.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-sigma": { + "version": "1.2.35", + "resolved": "https://registry.npmjs.org/react-sigma/-/react-sigma-1.2.35.tgz", + "integrity": "sha512-amjKjaQusefDp8dD9er3wE/lfubSQT5fJSRF4SsS0LjxRue4bpSapAQ1WpmSM6nQEgawbrKel+bQBmatl7MAIw==", + "engines": { + "node": ">=8.0" + }, + "peerDependencies": { + "react": ">=15.3", + "react-dom": ">=15.3" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/sigma": { + "version": "3.0.0-beta.19", + "resolved": "https://registry.npmjs.org/sigma/-/sigma-3.0.0-beta.19.tgz", + "integrity": "sha512-ShP6TwbxjD6PqypgVEuR++gGIUgCeWKO270i2m83fPDfSrPne1XsGbQRnFlEqrfZYRMTxKO4YtSvsU6reoR4/g==", + "dependencies": { + "events": "^3.3.0", + "graphology-utils": "^2.5.2" + } + } + } +}